jenkins-bot has submitted this change and it was merged. ( https://gerrit.wikimedia.org/r/402590 )
Change subject: Use MP3 with LAME instead of OGG for MIDI conversion ...................................................................... Use MP3 with LAME instead of OGG for MIDI conversion This patch utilizes the lame command in order to convert from fluidsynth/timidty generated WAV files to MP3. Also increased max filesize for large MIDIs. Depends on change 402148. Bug: T181875 Change-Id: I4b87d0bb665e824fe934d714bf2e282b1bbe8318 --- M README M extension.json M i18n/en.json M i18n/qqq.json M includes/Score.php 5 files changed, 134 insertions(+), 79 deletions(-) Approvals: Ebe123: Looks good to me, approved jenkins-bot: Verified diff --git a/README b/README index d12f9fb..b407698 100644 --- a/README +++ b/README @@ -42,10 +42,11 @@ $wgScoreAbc2Ly = '/path/to/your/abc2ly/executable'; /* if you want ABC to LilyPond conversion */ $wgScoreFluidsynth = '/path/to/your/fluidsynth/executable'; /* if you want MIDI to - Vorbis conversion */ + MP3 conversion */ $wgScoreSoundfont = '/path/to/your/soundfont/file'; /* required for Fluidsynth */ $wgScoreTimidity = '/path/to/your/timidity/executable'; /* fallback when Fluidsynth is not installed */ + $wgScoreLame = '/path/to/your/lame/executable' /* required to convert sound */ $wgScoreTrim = true; /* Set to false if you don't want score trimming */ $wgScoreSafeMode = false; /* Set to true if the Lilypond executable is running in a Firejail or equivalent */ diff --git a/extension.json b/extension.json index 7dc5b2c..5c27e5f 100644 --- a/extension.json +++ b/extension.json @@ -90,6 +90,7 @@ "ScoreFluidsynth": "/usr/bin/fluidsynth", "ScoreSoundfont": "/usr/share/sounds/sf2/FluidR3_GM.sf2", "ScoreTimidity": "/usr/bin/timidity", + "ScoreLame": "/usr/bin/lame", "ScoreSafeMode": true, "ScorePath": false, "ScoreDirectory": false, diff --git a/i18n/en.json b/i18n/en.json index 3ec220c..87a2363 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -4,37 +4,39 @@ }, "score-abc2lynotexecutable": "ABC to LilyPond converter could not be executed: $1 is not an executable file. Make sure <code>$wgScoreAbc2Ly</code> is set correctly.", "score-abcconversionerr": "Unable to convert ABC file to LilyPond format:\n$1", + "score-audioconversionerr": "Unable to convert MIDI to MP3:\n$1", + "score-audiooverridenotfound": "The file \"<nowiki>$1</nowiki>\" you specified with override_audio does not exist.", + "score-backend-error": "Unable to copy the generated files to their final location:\n$1", "score-chdirerr": "Unable to change to directory $1", "score-cleanerr": "Unable to clean out old files before re-rendering", "score-compilererr": "Unable to compile LilyPond input file:\n$1", - "score-backend-error": "Unable to copy the generated files to their final location:\n$1", + "score-convertoverrideaudio": "You cannot request audio rendering and specify override_audio at the same time.", "score-desc": "Adds a tag for rendering musical scores with LilyPond", "score-download-midi-file": "Download MIDI file", "score-download-source-file": "Download lilypond file", "score-error-category": "Pages with score rendering errors", "score-error-category-desc": "There was an error while rendering the score.", + "score-fallbacknotexecutable": "TiMidity++ could not be executed as fallback: $1 is not an executable file. Make sure <code>$wgScoreTimidity</code> or <code>$wgScoreFluidsynth</code> is set correctly.", "score-getcwderr": "Unable to obtain current working directory", + "score-invalidaudiooverride": "The file \"<nowiki>$1</nowiki>\" you specified with override_audio is invalid. Please specify the file name only, omit <nowiki>[[…]]</nowiki> and the \"{{ns:file}}:\" prefix.", "score-invalidlang": "Invalid score language lang=\"<nowiki>$1</nowiki>\". Currently recognized languages are lang=\"lilypond\" (the default) and lang=\"ABC\".", "score-invalidnotelanguage": "Invalid note-language=\"<nowiki>$1</nowiki>\". Currently recognized note languages are: $2", - "score-invalidaudiooverride": "The file \"<nowiki>$1</nowiki>\" you specified with override_audio is invalid. Please specify the file name only, omit <nowiki>[[…]]</nowiki> and the \"{{ns:file}}:\" prefix.", - "score-notelanguagewithraw": "Attribute \"note-language\" cannot be used for raw mode scores", + "score-lamenotexecutable": "LAME could not be executed: $1 is not an executable file. Make sure <code>$wgScoreLame</code> is set correctly.", "score-midioverridenotfound": "The file \"<nowiki>$1</nowiki>\" you specified with override_midi could not be found. Please specify the file name only, omit <nowiki>[[…]]</nowiki> and the \"{{ns:file}}:\" prefix.", "score-noabcinput": "ABC source file $1 could not be created.", + "score-nocontent": "Could not load file $1 from server.", "score-noimages": "No score images were generated. Please check your score code.", "score-noinput": "Failed to create LilyPond input file $1.", - "score-nomediahandler": "Ogg/Vorbis conversion requires an installed and configured version of the [https://www.mediawiki.org/wiki/Extension:TimedMediaHandler TimedMediaHandler extension].", + "score-nomediahandler": "Audio conversion requires an installed and configured version of the [https://www.mediawiki.org/wiki/Extension:TimedMediaHandler TimedMediaHandler extension].", "score-nomidi": "No MIDI file generated despite being requested. If you are working in raw LilyPond mode, make sure to provide a proper \\midi block.", "score-nooutput": "Failed to create output directory $1.", + "score-notelanguagewithraw": "Attribute \"note-language\" cannot be used for raw mode scores", "score-notexecutable": "Could not execute LilyPond: $1 is not an executable file. Make sure <code>$wgScoreLilyPond</code> is set correctly.", - "score-nocontent": "Could not load file $1 from server.", - "score-oggconversionerr": "Unable to convert MIDI to Ogg/Vorbis:\n$1", - "score-audiooverridenotfound": "The file \"<nowiki>$1</nowiki>\" you specified with override_audio does not exist.", "score-page": "Page $1", "score-pregreplaceerr": "PCRE regular expression replacement failed", "score-readerr": "Unable to read file $1.", - "score-fallbacknotexecutable": "TiMidity++ could not be executed as fallback: $1 is not an executable file. Make sure <code>$wgScoreTimidity</code> or <code>$wgScoreFluidsynth</code> is set correctly.", - "score-soundfontnotexists": "Soundfont could not be found: $1 does not exists. Make sure <code>$wgScoreSoundfont</code> is set correctly.", "score-renameerr": "Error moving score files to upload directory.", + "score-soundfontnotexists": "Soundfont could not be found: $1 does not exists. Make sure <code>$wgScoreSoundfont</code> is set correctly.", "score-trimerr": "Image could not be trimmed:\n$1\nSet <code>$wgScoreTrim=false</code> if this problem persists.", "score-versionerr": "Unable to obtain LilyPond version:\n$1", "score-visualeditor-mwscoreinspector-card-advanced": "Advanced", @@ -50,6 +52,5 @@ "score-visualeditor-mwscoreinspector-override-ogg-placeholder": "Name of existing audio file (must be Ogg/Vorbis)", "score-visualeditor-mwscoreinspector-raw": "This is a complete LilyPond file", "score-visualeditor-mwscoreinspector-title": "Musical notation", - "score-visualeditor-mwscoreinspector-vorbis": "Include an audio file (auto-generated by default)", - "score-vorbisoverrideaudio": "You cannot request audio rendering and specify override_audio at the same time." + "score-visualeditor-mwscoreinspector-vorbis": "Include an audio file (auto-generated by default)" } diff --git a/i18n/qqq.json b/i18n/qqq.json index d2593ad..241191c 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -10,37 +10,39 @@ }, "score-abc2lynotexecutable": "Displayed if the ABC to LilyPond converter could not be executed. $1 is the path to the abc2ly binary.", "score-abcconversionerr": "Displayed if the ABC to LilyPond conversion failed. $1 is the error (generally big block of text in a pre tag)", + "score-audioconversionerr": "Displayed if the MIDI to MP3 conversion failed. $1 is the error (generally big block of text in a pre tag)", + "score-audiooverridenotfound": "Displayed if the file specified with the override_audio=\"…\" attribute could not be found. $1 is the value of the override_ogg attribute.", + "score-backend-error": "Parameters:\n* $1 - result message which was returned", "score-chdirerr": "Displayed if the extension cannot change its working directory. $1 is the path to the target directory.", "score-cleanerr": "Displayed if an old file cleanup operation fails.", "score-compilererr": "Displayed if the LilyPond code could not be compiled. $1 is the error (generally big block of text in a pre tag)", - "score-backend-error": "Parameters:\n* $1 - result message which was returned", + "score-convertoverrideaudio": "Displayed if both sound=\"1\" and override_audio=\"…\" were specified.", "score-desc": "{{desc|name=Score|url=https://www.mediawiki.org/wiki/Extension:Score}}", "score-download-midi-file": "Content of link to download MIDI file of score shown in score popup", "score-download-source-file": "Content of link to download the lilypond file of score shown in score popup", "score-error-category": "Name of [[mw:Help:Tracking categories|tracking category]] to list pages where there was an error rendering the <code><nowiki><score></nowiki></code> tag.", "score-error-category-desc": "Description on [[Special:TrackingCategories]] for the {{msg-mw|score-error-category}} tracking category.", + "score-fallbacknotexecutable": "Displayed if TiMidity++ could not be executed as fallback. $1 is the path to the TiMidity++ binary.", "score-getcwderr": "Displayed if the extension cannot obtain the current working directory.", + "score-invalidaudiooverride": "Displayed if the file specified with the override_audio=\"…\" attribute is invalid. $1 is the value of the override_audio attribute.", "score-invalidlang": "Displayed if the lang=\"…\" attribute contains an unrecognized score language. $1 is the unrecognized language.", "score-invalidnotelanguage": "Displayed if the note-language=\"…\" attribute contains an unrecognized note language. $1 is the unrecognized note language. $2 is comma separated list of available languages.", - "score-invalidaudiooverride": "Displayed if the file specified with the override_audio=\"…\" attribute is invalid. $1 is the value of the override_audio attribute.", - "score-notelanguagewithraw": "Displayed if the \"note-language\" attribute is used for scores in raw mode", + "score-lamenotexecutable": "Displayed if LAME could not be executed. $1 is the path to the LAME binary.", "score-midioverridenotfound": "Displayed if the file specified with the override_midi=\"…\" attribute could not be found. $1 is the value of the override_midi attribute.", "score-noabcinput": "Displayed if an ABC source file could not be created for lang=\"ABC\". $1 is the path to the file that could not be created.", + "score-nocontent": "Parameters:\n* $1 - filename", "score-noimages": "Displayed if no score images were rendered.", "score-noinput": "Displayed if the LilyPond input file cannot be created. $1 is the path to the input file.", - "score-nomediahandler": "Displayed if Ogg/Vorbis rendering was requested without the TimedMediaHandler extension installed.", + "score-nomediahandler": "Displayed if audio rendering was requested without the TimedMediaHandler extension installed.", "score-nomidi": "Displayed if MIDI file generation was requested but no MIDI file was generated.", "score-nooutput": "Displayed if an output directory could not be created. $1 is the name of the directory.", + "score-notelanguagewithraw": "Displayed if the \"note-language\" attribute is used for scores in raw mode", "score-notexecutable": "Displayed if LilyPond binary cannot be executed. $1 is the path to the LilyPond binary.", - "score-nocontent": "Parameters:\n* $1 - filename", - "score-oggconversionerr": "Displayed if the MIDI to Ogg/Vorbis conversion failed. $1 is the error (generally big block of text in a pre tag)", - "score-audiooverridenotfound": "Displayed if the file specified with the override_audio=\"…\" attribute could not be found. $1 is the value of the override_ogg attribute.", "score-page": "The word \"Page\" as used in pagination. Parameters:\n* $1 - the page number\n{{Identical|Page}}", "score-pregreplaceerr": "Displayed if a PCRE regular expression replacement failed.", "score-readerr": "Displayed if the extension could not read a file. $1 is the path to the file that could not be read.", - "score-fallbacknotexecutable": "Displayed if TiMidity++ could not be executed as fallback. $1 is the path to the TiMidity++ binary.", - "score-soundfontnotexists": "Displayed if soundfont could not be found. $1 is the path to the soundfont file.", "score-renameerr": "Displayed if moving the resultant files from the working environment to the upload directory fails.", + "score-soundfontnotexists": "Displayed if soundfont could not be found. $1 is the path to the soundfont file.", "score-trimerr": "Displayed if the extension failed to trim an output image. $1 is the error (generally big block of text in a pre tag)", "score-versionerr": "Displayed if the extension failed to obtain the version string of LilyPond. $1 is the LilyPond stdout output generated by the attempt.", "score-visualeditor-mwscoreinspector-card-advanced": "Label for the advanced card of the score inspector\n{{Identical|Advanced}}", @@ -56,6 +58,5 @@ "score-visualeditor-mwscoreinspector-override-ogg-placeholder": "Placeholder for the label for the override_ogg attribute of the score node", "score-visualeditor-mwscoreinspector-raw": "Label for the raw attribute of the score node", "score-visualeditor-mwscoreinspector-title": "Title for the inspector to edit <nowiki><score></nowiki> blocks.", - "score-visualeditor-mwscoreinspector-vorbis": "Label for the vorbis attribute of the score node", - "score-vorbisoverrideaudio": "Displayed if both sound=\"1\" and override_audio=\"…\" were specified." + "score-visualeditor-mwscoreinspector-vorbis": "Label for the vorbis attribute of the score node" } diff --git a/includes/Score.php b/includes/Score.php index b7a2583..3016194 100644 --- a/includes/Score.php +++ b/includes/Score.php @@ -219,7 +219,7 @@ * @return string Image link HTML, and possibly anchor to MIDI file. */ public static function render( $code, array $args, Parser $parser, PPFrame $frame ) { - global $wgTmpDirectory; + global $wgTmpDirectory, $wgScoreLame; try { $baseUrl = self::getBaseUrl(); @@ -242,6 +242,9 @@ htmlspecialchars( $options['lang'] ) ) ); } + // Set extension for audio output + $options['audio_extension'] = is_executable( $wgScoreLame ) ? 'mp3' : 'ogg'; + /* Override MIDI file? */ if ( array_key_exists( 'override_midi', $args ) ) { $file = wfFindFile( $args['override_midi'] ); @@ -252,13 +255,13 @@ $parser->getOutput()->addImage( $file->getName() ); $options['override_midi'] = true; $options['midi_file'] = $file; - /* Set OGG stuff in case Vorbis rendering is requested */ + /* Set output stuff in case audio rendering is requested */ $sha1 = $file->getSha1(); - $oggRelDir = "override-midi/{$sha1[0]}/{$sha1[1]}"; - $oggRel = "$oggRelDir/$sha1.ogg"; - $options['audio_storage_dir'] = "$baseStoragePath/$oggRelDir"; - $options['audio_storage_path'] = "$baseStoragePath/$oggRel"; - $options['audio_url'] = "$baseUrl/$oggRel"; + $audioRelDir = "override-midi/{$sha1[0]}/{$sha1[1]}"; + $audioRel = "$audioRelDir/$sha1.{$options['audio_extension']}"; + $options['audio_storage_dir'] = "$baseStoragePath/$audioRelDir"; + $options['audio_storage_path'] = "$baseStoragePath/$audioRel"; + $options['audio_url'] = "$baseUrl/$audioRel"; } else { $options['override_midi'] = false; } @@ -307,16 +310,16 @@ } /* Audio rendering? */ - $options['generate_ogg'] = array_key_exists( 'sound', $args ) + $options['generate_audio'] = array_key_exists( 'sound', $args ) || array_key_exists( 'vorbis', $args ); - if ( $options['generate_ogg'] + if ( $options['generate_audio'] && !class_exists( 'TimedMediaTransformOutput' ) ) { throw new ScoreException( wfMessage( 'score-nomediahandler' ) ); } - if ( $options['generate_ogg'] && ( $options['override_audio'] !== false ) ) { - throw new ScoreException( wfMessage( 'score-vorbisoverrideaudio' ) ); + if ( $options['generate_audio'] && ( $options['override_audio'] !== false ) ) { + throw new ScoreException( wfMessage( 'score-convertoverrideaudio' ) ); } // Input for cache key @@ -361,7 +364,7 @@ * - factory_directory: string Path to directory in which files * may be generated without stepping on someone else's * toes. The directory may not exist yet. Required. - * - generate_ogg: bool Whether to create an Ogg/Vorbis file in + * - generate_audio: bool Whether to create an audio file in * TimedMediaHandler. If set to true, the override_audio option * must be set to false. Required. * - dest_storage_path: The path of the destination directory relative to @@ -373,15 +376,17 @@ * - override_midi: bool Whether to use a user-provided MIDI file. * Required. * - midi_file: If override_midi is true, MIDI file object. - * - audio_storage_dir: If override_midi and generate_ogg are true, the + * - audio_extension: string If override_midi and generate_audio are true, + * the audio output format in which the audio file is to be generated. + * - audio_storage_dir: If override_midi and generate_audio are true, the * backend directory in which the audio file is to be stored. - * - audio_storage_path: string If override_midi and generate_ogg are true, + * - audio_storage_path: string If override_midi and generate_audio are true, * the backend path at which the generated audio file is to be * stored. - * - audio_url: string If override_midi and generate_ogg is true, + * - audio_url: string If override_midi and generate_audio is true, * the URL corresponding to audio_storage_path * - override_audio: bool Whether to generate a wikilink to a - * user-provided audio file. If set to true, the vorbis + * user-provided audio file. If set to true, the sound * option must be set to false. Required. * - audio_name: string If override_audio is true, the audio file name * - raw: bool Whether to assume raw LilyPond code. Ignored if the @@ -432,24 +437,24 @@ $existingFiles += self::generatePngAndMidi( $code, $options, $metaData ); } - /* Generate Ogg/Vorbis file if necessary */ - if ( $options['generate_ogg'] ) { + /* Generate audio file if necessary */ + if ( $options['generate_audio'] ) { if ( $options['override_midi'] ) { - $oggUrl = $options['audio_url']; - $oggPath = $options['audio_storage_path']; + $audioUrl = $options['audio_url']; + $audioPath = $options['audio_storage_path']; $exists = $backend->fileExists( [ 'src' => $options['audio_storage_path'] ] ); if ( !$exists ) { $backend->prepare( [ 'dir' => $options['audio_storage_dir'] ] ); $sourcePath = $options['midi_file']->getLocalRefPath(); - self::generateOgg( $sourcePath, $options, $oggPath, $metaData ); + self::generateAudio( $sourcePath, $options, $audioPath, $metaData ); } } else { - $oggFileName = "{$options['file_name_prefix']}.ogg"; - $oggUrl = "{$options['dest_url']}/$oggFileName"; - $oggPath = "{$options['dest_storage_path']}/$oggFileName"; + $audioFileName = "{$options['file_name_prefix']}.{$options['audio_extension']}"; + $audioUrl = "{$options['dest_url']}/$audioFileName"; + $audioPath = "{$options['dest_storage_path']}/$audioFileName"; if ( - !isset( $existingFiles[$oggFileName] ) || - !isset( $metaData[$oggFileName]['length'] ) + !isset( $existingFiles[$audioFileName] ) || + !isset( $metaData[$audioFileName]['length'] ) ) { // Maybe we just generated it $sourcePath = "{$options['factory_directory']}/file.midi"; @@ -459,7 +464,7 @@ [ 'src' => "{$options['dest_storage_path']}/$midiFileName" ] ); $sourcePath = $sourceFileRef->getPath(); } - self::generateOgg( $sourcePath, $options, $oggPath, $metaData ); + self::generateAudio( $sourcePath, $options, $audioPath, $metaData ); } } } @@ -497,14 +502,17 @@ /* No images; this may happen in raw mode or when the user omits the score code */ throw new ScoreException( wfMessage( 'score-noimages' ) ); } - if ( $options['generate_ogg'] ) { - $length = $metaData[basename( $oggPath )]['length']; + if ( $options['generate_audio'] ) { + $length = $metaData[basename( $audioPath )]['length']; + $mimetype = pathinfo( $audioUrl, PATHINFO_EXTENSION ) === 'mp3' + ? 'audio/mpeg' + : 'audio/ogg; codecs="vorbis"'; $player = new TimedMediaTransformOutput( [ 'length' => $length, 'sources' => [ [ - 'src' => $oggUrl, - 'type' => 'audio/ogg; codecs="vorbis"' + 'src' => $audioUrl, + 'type' => $mimetype ] ], 'disablecontrols' => 'options,timedText', @@ -627,7 +635,7 @@ $options['factory_directory'] ); } $needMidi = false; - if ( !$options['raw'] || $options['generate_ogg'] && !$options['override_midi'] ) { + if ( !$options['raw'] || $options['generate_audio'] && !$options['override_midi'] ) { $needMidi = true; if ( !file_exists( $factoryMidi ) ) { throw new ScoreException( wfMessage( 'score-nomidi' ) ); @@ -798,23 +806,28 @@ } /** - * Generates an Ogg/Vorbis file from a MIDI file using fluidsynth with TiMidity as fallback. + * Generates an audio file from a MIDI file using fluidsynth with TiMidity as fallback. * * @param string $sourceFile The local filename of the MIDI file * @param array $options array of rendering options. - * @param string $remoteDest The backend storage path to upload the Ogg file to + * @param string $remoteDest The backend storage path to upload the audio file to * @param array $metaData Array with metadata information * * @throws ScoreException if an error occurs. */ - private static function generateOgg( $sourceFile, $options, $remoteDest, &$metaData ) { - global $wgScoreFluidsynth, $wgScoreSoundfont; + private static function generateAudio( $sourceFile, $options, $remoteDest, &$metaData ) { + global $wgScoreFluidsynth, $wgScoreSoundfont, $wgScoreLame; global $wgScoreTimidity; // TODO: Remove TiMidity++ as fallback + + // Check whether the output is mp3 or ogg by extension + $extension = pathinfo( $remoteDest, PATHINFO_EXTENSION ); + $isOutputMp3 = $extension === 'mp3'; /* Working environment */ $factoryDir = $options['factory_directory']; self::createDirectory( $factoryDir, 0700 ); - $factoryOgg = "$factoryDir/file.ogg"; + $factoryOutput = "$factoryDir/output.wav"; + $factoryFile = "$factoryDir/file.$extension"; if ( is_executable( $wgScoreFluidsynth ) ) { if ( !file_exists( $wgScoreSoundfont ) ) { @@ -825,9 +838,9 @@ $cmdArgs = [ $wgScoreFluidsynth, '-T', - 'oga', // Vorbis output + $isOutputMp3 ? 'wav' : 'oga', // wav output if mp3 '-F', - $factoryOgg, + $factoryOutput, $wgScoreSoundfont, $sourceFile ]; @@ -835,8 +848,8 @@ // Use TiMidity++ as a fallback $cmdArgs = [ $wgScoreTimidity, - '-Ov', // Vorbis output - '--output-file=' . $factoryOgg, + $isOutputMp3 ? '-Ow' : '-Ov', // wav output if mp3 + '--output-file=' . $factoryOutput, $sourceFile ]; } else { @@ -847,32 +860,61 @@ $result = Shell::command( $cmdArgs ) ->includeStderr() ->restrict( Shell::RESTRICT_DEFAULT | Shell::NO_NETWORK ) + ->limits( [ 'filesize' => 153600 ] ) // 150 MB max. filesize (for large MIDIs) ->execute(); - if ( ( $result->getExitCode() != 0 ) || !file_exists( $factoryOgg ) ) { + if ( ( $result->getExitCode() != 0 ) || !file_exists( $factoryOutput ) ) { self::throwCallException( - wfMessage( 'score-oggconversionerr' ), $result->getStdout(), $factoryDir + wfMessage( 'score-audioconversionerr' ), $result->getStdout(), $factoryDir ); } - $ops = []; - // Move resultant file to proper place - $ops[] = [ + + if ( $isOutputMp3 ) { + if ( !is_executable( $wgScoreLame ) ) { + throw new ScoreException( wfMessage( 'score-lamenotexecutable', $wgScoreLame ) ); + } + + /* Convert wav -> mp3 using LAME */ + $result = Shell::command( $wgScoreLame, $factoryOutput, $factoryFile ) + ->includeStderr() + ->restrict( Shell::RESTRICT_DEFAULT | Shell::NO_NETWORK ) + ->execute(); + + if ( ( $result->getExitCode() != 0 ) || !file_exists( $factoryFile ) ) { + self::throwCallException( + wfMessage( 'score-audioconversionerr' ), $result->getStdout(), $factoryDir + ); + } + } else { + // No conversion required for ogg + $factoryFile = $factoryOutput; + } + + // Move file to the final destination + $backend = self::getBackend(); + $status = $backend->doQuickOperation( [ 'op' => 'store', - 'src' => $factoryOgg, - 'dst' => $remoteDest ]; + 'src' => $factoryFile, + 'dst' => $remoteDest + ] ); + + if ( !$status->isOK() ) { + throw new ScoreException( wfMessage( 'score-backend-error', $status->getWikiText() ) ); + } // Create metadata json - $metaData[basename( $remoteDest )]['length'] = self::getLength( $factoryOgg ); + $metaData[basename( $remoteDest )]['length'] = self::getLength( $remoteDest ); $dstFileName = "{$options['file_name_prefix']}.json"; $dest = "{$options['dest_storage_path']}/$dstFileName"; - $ops[] = [ + + // Store metadata in backend + $backend = self::getBackend(); + $status = $backend->doQuickOperation( [ 'op' => 'create', 'content' => FormatJson::encode( $metaData ), - 'dst' => $dest ]; + 'dst' => $dest + ] ); - // Execute the batch - $backend = self::getBackend(); - $status = $backend->doQuickOperations( $ops ); if ( !$status->isOK() ) { throw new ScoreException( wfMessage( 'score-backend-error', $status->getWikiText() ) ); } @@ -967,14 +1009,23 @@ } /** - * get length of ogg vorbis file + * get length of audio file * * @param string $path file system path to file * * @return float duration in seconds */ private static function getLength( $path ) { - $f = new File_Ogg( $path ); + $isFileMp3 = pathinfo( $path, PATHINFO_EXTENSION ) === 'mp3'; + $repo = new FileRepo( [ + 'name' => 'foo', + 'backend' => self::$backend + ] ); + + $f = new UnregisteredLocalFile( false, $repo, $path, $isFileMp3 + ? 'audio/mpeg' + : 'audio/ogg' + ); return $f->getLength(); } -- To view, visit https://gerrit.wikimedia.org/r/402590 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I4b87d0bb665e824fe934d714bf2e282b1bbe8318 Gerrit-PatchSet: 20 Gerrit-Project: mediawiki/extensions/Score Gerrit-Branch: master Gerrit-Owner: Divadsn <divad.nnamtd...@gmail.com> Gerrit-Reviewer: Brion VIBBER <br...@wikimedia.org> Gerrit-Reviewer: Divadsn <divad.nnamtd...@gmail.com> Gerrit-Reviewer: Ebe123 <beauleetien...@gmail.com> Gerrit-Reviewer: Siebrand <siebr...@kitano.nl> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits