diff --git a/.arcconfig b/.arcconfig index fe223088..adbd0155 100644 --- a/.arcconfig +++ b/.arcconfig @@ -1,3 +1,4 @@ { - "phabricator.uri" : "https://phabricator.poniverse.net/" + "phabricator.uri" : "https://phabricator.poniverse.net/", + "history.immutable" : true } diff --git a/app/commands/ClassifyMLPMA.php b/app/commands/ClassifyMLPMA.php new file mode 100644 index 00000000..b44cbf20 --- /dev/null +++ b/app/commands/ClassifyMLPMA.php @@ -0,0 +1,231 @@ +orderBy('id') + ->get(); + + $this->comment('Importing tracks...'); + + $totalTracks = sizeof($tracks); + + $fileToStartAt = (int) $this->option('startAt') - 1; + $this->comment("Skipping $fileToStartAt files..." . PHP_EOL); + + $tracks = array_slice($tracks, $fileToStartAt); + $this->currentTrack = $fileToStartAt; + + foreach ($tracks as $track) { + $this->currentTrack++; + $this->comment('[' . $this->currentTrack . '/' . $totalTracks . '] Classifying track [' . $track->filename . ']...'); + + $parsedTags = json_decode($track->parsed_tags, true); + + + //========================================================================================================== + // Original, show song remix, fan song remix, show audio remix, or ponified song? + //========================================================================================================== + $sanitizedTrackTitle = $parsedTags['title']; + $sanitizedTrackTitle = str_replace([' - ', 'ft.', '*'], ' ', $sanitizedTrackTitle); + + $queriedTitle = DB::connection()->getPdo()->quote($sanitizedTrackTitle); + $officialSongs = ShowSong::select(['id', 'title']) + ->whereRaw(" + MATCH (title) + AGAINST ($queriedTitle IN BOOLEAN MODE) + ") + ->get(); + + + // If it has "Ingram" in the name, it's definitely an official song remix. + if (Str::contains(Str::lower($track->filename), 'ingram')) { + $this->info('This is an official song remix!'); + + list($trackType, $linkedSongIds) = $this->classifyTrack($track->filename, $officialSongs, true); + + + // If it has "remix" in the name, it's definitely a remix. + } else if (Str::contains(Str::lower($sanitizedTrackTitle), 'remix')) { + $this->info('This is some kind of remix!'); + + list($trackType, $linkedSongIds) = $this->classifyTrack($track->filename, $officialSongs); + + // No idea what this is. Have the pony at the terminal figure it out! + } else { + list($trackType, $linkedSongIds) = $this->classifyTrack($track->filename, $officialSongs); + } + + + //========================================================================================================== + // Attach the data and publish the track! + //========================================================================================================== + + $track = Track::find($track->track_id); + + $track->track_type_id = $trackType; + $track->published_at = $parsedTags['released_at']; + $track->save(); + + if (sizeof($linkedSongIds) > 0) { + $track->showSongs()->attach($linkedSongIds); + } + + echo PHP_EOL; + } + + } + + /** + * Get the console command arguments. + * + * @return array + */ + protected function getArguments() + { + return array(); + } + + /** + * Get the console command options. + * + * @return array + */ + protected function getOptions() + { + return array( + array('startAt', null, InputOption::VALUE_OPTIONAL, 'Track to start importing from. Useful for resuming an interrupted import.', 1), + ); + } + + + /** + * Determines what type of track the given file is. If unable to guess, the user + * is asked to identify it interactively. + * + * @param string $filename + * @param \Entities\ShowSong[] $officialSongs + * @param bool|false $isRemixOfOfficialTrack + * @return array + */ + protected function classifyTrack($filename, $officialSongs, $isRemixOfOfficialTrack = false) { + $trackTypeId = null; + $linkedSongIds = []; + + + foreach ($officialSongs as $song) { + $this->comment('=> Matched official song: [' . $song->id . '] ' . $song->title); + } + + + if ($isRemixOfOfficialTrack && sizeof($officialSongs) === 1) { + $linkedSongIds = [$officialSongs[0]->id]; + + } else { + if ($isRemixOfOfficialTrack && sizeof($officialSongs) > 1) { + $this->question('Multiple official songs matched! Please enter the ID of the correct one.'); + + } else if (sizeof($officialSongs) > 0) { + $this->question('This looks like a remix of an official song!'); + $this->question('Press "r" if the match above is right!'); + + } else { + $this->question('Exactly what kind of track is this?'); + + } + $this->question('If this is a medley, multiple song ID\'s can be separated by commas. '); + $this->question(' '); + $this->question(' ' . $filename . ' '); + $this->question(' '); + $this->question(' r = official song remix (accept all "guessed" matches) '); + $this->question(' # = official song remix (enter the ID(s) of the show song(s)) '); + $this->question(' a = show audio remix '); + $this->question(' f = fan track remix '); + $this->question(' p = ponified track '); + $this->question(' o = original track '); + $this->question(' '); + $input = $this->ask('[r/#/a/f/p/o]: '); + + switch ($input) { + case 'r': + $trackTypeId = TrackType::OFFICIAL_TRACK_REMIX; + foreach ($officialSongs as $officialSong) { + $linkedSongIds[] = (int) $officialSong->id; + } + break; + + case 'a': + $trackTypeId = TrackType::OFFICIAL_AUDIO_REMIX; + break; + + case 'f': + $trackTypeId = TrackType::FAN_TRACK_REMIX; + break; + + case 'p': + $trackTypeId = TrackType::PONIFIED_TRACK; + break; + + case 'o': + $trackTypeId = TrackType::ORIGINAL_TRACK; + break; + + default: + $trackTypeId = TrackType::OFFICIAL_TRACK_REMIX; + $linkedSongIds = explode(',', $input); + $linkedSongIds = array_map(function ($item) { + return (int) $item; + }, $linkedSongIds); + } + } + + return [$trackTypeId, $linkedSongIds]; + } + +} diff --git a/app/commands/ImportMLPMA.php b/app/commands/ImportMLPMA.php new file mode 100644 index 00000000..8e0ab371 --- /dev/null +++ b/app/commands/ImportMLPMA.php @@ -0,0 +1,417 @@ +error('Import aborted!'); + $this->error('Resume it from here using: --startAt='.$this->currentFile); + $this->isInterrupted = true; + } + + /** + * Execute the console command. + * + * @return void + */ + public function fire() + { + pcntl_signal(SIGINT, [$this, 'handleInterrupt']); + + $mlpmaPath = Config::get('app.files_directory').'mlpma'; + $tmpPath = Config::get('app.files_directory').'tmp'; + + if (!File::exists($tmpPath)) { + File::makeDirectory($tmpPath); + } + + $this->comment('Enumerating MLP Music Archive source files...'); + $files = File::allFiles($mlpmaPath); + $this->info(sizeof($files).' files found!'); + + $this->comment('Enumerating artists...'); + $artists = File::directories($mlpmaPath); + $this->info(sizeof($artists).' artists found!'); + + $this->comment('Importing tracks...'); + + $totalFiles = sizeof($files); + + $fileToStartAt = (int) $this->option('startAt') - 1; + $this->comment("Skipping $fileToStartAt files...".PHP_EOL); + + $files = array_slice($files, $fileToStartAt); + $this->currentFile = $fileToStartAt; + + foreach($files as $file) { + $this->currentFile++; + + pcntl_signal_dispatch(); + if ($this->isInterrupted) { + break; + } + + $this->comment('['.$this->currentFile.'/'.$totalFiles.'] Importing track ['. $file->getFilename() .']...'); + + if (in_array($file->getExtension(), $this->ignoredExtensions)) { + $this->comment('This is not an audio file! Skipping...'.PHP_EOL); + continue; + } + + + // Has this track already been imported? + $importedTrack = DB::table('mlpma_tracks') + ->where('filename', '=', $file->getFilename()) + ->first(); + + if ($importedTrack) { + $this->comment('This track has already been imported! Skipping...' . PHP_EOL); + continue; + } + + + //========================================================================================================== + // Extract the original tags. + //========================================================================================================== + $getId3 = new getID3; + + // all tags read by getID3, including the cover art + $allTags = $getId3->analyze($file->getPathname()); + + // tags specific to a file format (ID3 or Atom), pre-normalization but with cover art removed + $rawTags = []; + + // normalized tags used by Pony.fm + $parsedTags = []; + + if ($file->getExtension() === 'mp3') { + list($parsedTags, $rawTags) = $this->getId3Tags($allTags); + + } else if ($file->getExtension() === 'm4a') { + list($parsedTags, $rawTags) = $this->getAtomTags($allTags); + } + + + //========================================================================================================== + // Determine the release date. + //========================================================================================================== + $modifiedDate = Carbon::createFromTimeStampUTC(File::lastModified($file->getPathname())); + $taggedYear = $parsedTags['year']; + + $this->info('Modification year: '.$modifiedDate->year); + $this->info('Tagged year: '.$taggedYear); + + if ($taggedYear !== null && $modifiedDate->year === $taggedYear) { + $releasedAt = $modifiedDate; + + } else if ($taggedYear !== null && $modifiedDate->year !== $taggedYear) { + $this->error('Release years don\'t match! Using the tagged year...'); + $releasedAt = Carbon::create($taggedYear); + + } else { + // $taggedYear is null + $this->error('This track isn\'t tagged with its release year! Using the track\'s last modified date...'); + $releasedAt = $modifiedDate; + } + + // This is later used by the classification/publishing script to determine the publication date. + $parsedTags['released_at'] = $releasedAt->toDateTimeString(); + + //========================================================================================================== + // Does this track have vocals? + //========================================================================================================== + $isVocal = $parsedTags['lyrics'] !== null; + + + //========================================================================================================== + // Determine which artist account this file belongs to using the containing directory. + //========================================================================================================== + $this->info('Path to file: '.$file->getRelativePath()); + $path_components = explode(DIRECTORY_SEPARATOR, $file->getRelativePath()); + $artist_name = $path_components[0]; + $album_name = array_key_exists(1, $path_components) ? $path_components[1] : null; + + $this->info('Artist: '.$artist_name); + $this->info('Album: '.$album_name); + + $artist = User::where('display_name', '=', $artist_name)->first(); + + if (!$artist) { + $artist = new User; + $artist->display_name = $artist_name; + $artist->email = null; + $artist->is_archived = true; + + $artist->slug = Str::slug($artist_name); + + $slugExists = User::where('slug', '=', $artist->slug)->first(); + if ($slugExists) { + $this->error('Horsefeathers! The slug '.$artist->slug.' is already taken!'); + $artist->slug = $artist->slug.'-'.Str::random(4); + } + + $artist->save(); + } + + //========================================================================================================== + // Extract the cover art, if any exists. + //========================================================================================================== + + $this->comment('Extracting cover art!'); + $coverId = null; + if (array_key_exists('comments', $allTags) && array_key_exists('picture', $allTags['comments'])) { + $image = $allTags['comments']['picture'][0]; + + if ($image['image_mime'] === 'image/png') { + $extension = 'png'; + + } else if ($image['image_mime'] === 'image/jpeg') { + $extension = 'jpg'; + + } else if ($image['image_mime'] === 'image/gif') { + $extension = 'gif'; + + } else { + $this->error('Unknown cover art format!'); + } + + // write temporary image file + $imageFilename = $file->getFilename() . ".cover.$extension"; + $imageFilePath = "$tmpPath/".$imageFilename; + File::put($imageFilePath, $image['data']); + + + $imageFile = new UploadedFile($imageFilePath, $imageFilename, $image['image_mime']); + + $cover = Image::upload($imageFile, $artist); + $coverId = $cover->id; + + } else { + $this->comment('No cover art found!'); + } + + + //========================================================================================================== + // Is this part of an album? + //========================================================================================================== + // Find the album if it exists and create it if it doesn't. + $albumId = null; + $albumName = $parsedTags['album']; + + if ($albumName !== null) { + $album = Album::where('user_id', '=', $artist->id) + ->where('title', '=', $albumName) + ->first(); + + if (!$album) { + $album = new Album; + + $album->title = $albumName; + $album->user_id = $artist->id; + $album->cover_id = $coverId; + + $album->save(); + } + + $albumId = $album->id; + } + + + //========================================================================================================== + // Save this track. + //========================================================================================================== + + // "Upload" the track to Pony.fm + $this->comment('Transcoding the track!'); + Auth::loginUsingId($artist->id); + + $trackFile = new UploadedFile($file->getPathname(), $file->getFilename(), $allTags['mime_type']); + Input::instance()->files->add(['track' => $trackFile]); + + $upload = new UploadTrackCommand(true); + $result = $upload->execute(); + + if ($result->didFail()) { + $this->error(json_encode($result->getValidator()->messages()->getMessages(), JSON_PRETTY_PRINT)); + + } else { + // Save metadata. + $track = Track::find($result->getResponse()['id']); + + $track->title = $parsedTags['title']; + $track->cover_id = $coverId; + $track->album_id = $albumId; + $track->track_number = $parsedTags['track_number']; + $track->released_at = $releasedAt; + $track->description = $parsedTags['comments']; + $track->is_downloadable = true; + $track->lyrics = $parsedTags['lyrics']; + $track->is_vocal = $isVocal; + $track->license_id = 2; + $track->save(); + + // If we made it to here, the track is intact! Log the import. + DB::table('mlpma_tracks') + ->insert([ + 'track_id' => $result->getResponse()['id'], + 'path' => $file->getRelativePath(), + 'filename' => $file->getFilename(), + 'extension' => $file->getExtension(), + 'imported_at' => Carbon::now(), + 'parsed_tags' => json_encode($parsedTags), + 'raw_tags' => json_encode($rawTags), + ]); + } + + echo PHP_EOL.PHP_EOL; + } + } + + /** + * Get the console command arguments. + * + * @return array + */ + protected function getArguments() + { + return array(); + } + + /** + * Get the console command options. + * + * @return array + */ + protected function getOptions() + { + return array( + array('startAt', null, InputOption::VALUE_OPTIONAL, 'Track to start importing from. Useful for resuming an interrupted import.', 1), + ); + } + + + /** + * @param array $rawTags + * @return array + */ + protected function getId3Tags($rawTags) { + $tags = $rawTags['tags']['id3v2']; + $comment = null; + + if (isset($tags['comment'])) { + // The "comment" tag comes in with a badly encoded string index + // so its array key has to be used implicitly. + $key = array_keys($tags['comment'])[0]; + + // The comment may have a null byte at the end. trim() removes it. + $comment = trim($tags['comment'][$key]); + + // Replace the malformed comment with the "fixed" one. + unset($tags['comment'][$key]); + $tags['comment'][0] = $comment; + } + + return [ + [ + 'title' => $tags['title'][0], + 'artist' => $tags['artist'][0], + 'band' => isset($tags['band']) ? $tags['band'][0] : null, + 'genre' => isset($tags['genre']) ? $tags['genre'][0] : null, + 'track_number' => isset($tags['track_number']) ? $tags['track_number'][0] : null, + 'album' => isset($tags['album']) ? $tags['album'][0] : null, + 'year' => isset($tags['year']) ? (int) $tags['year'][0] : null, + 'comments' => $comment, + 'lyrics' => isset($tags['unsynchronised_lyric']) ? $tags['unsynchronised_lyric'][0] : null, + ], + $tags]; + } + + /** + * @param array $rawTags + * @return array + */ + protected function getAtomTags($rawTags) { + $tags = $rawTags['tags']['quicktime']; + + $trackNumber = null; + if (isset($tags['track_number'])) { + $trackNumberComponents = explode('/', $tags['track_number'][0]); + $trackNumber = $trackNumberComponents[0]; + } + + return [ + [ + 'title' => $tags['title'][0], + 'artist' => $tags['artist'][0], + 'band' => isset($tags['band']) ? $tags['band'][0] : null, + 'album_artist' => isset($tags['album_artist']) ? $tags['album_artist'][0] : null, + 'genre' => isset($tags['genre']) ? $tags['genre'][0] : null, + 'track_number' => $trackNumber, + 'album' => isset($tags['album']) ? $tags['album'][0] : null, + 'year' => isset($tags['year']) ? (int) $tags['year'][0] : null, + 'comments' => isset($tags['comments']) ? $tags['comments'][0] : null, + 'lyrics' => isset($tags['lyrics']) ? $tags['lyrics'][0] : null, + ], + $tags]; + } + +} diff --git a/app/database/migrations/2015_09_04_160648_make_email_nullable.php b/app/database/migrations/2015_09_04_160648_make_email_nullable.php new file mode 100644 index 00000000..39d32d40 --- /dev/null +++ b/app/database/migrations/2015_09_04_160648_make_email_nullable.php @@ -0,0 +1,27 @@ +index('hash'); + }); + + Schema::table('track_files', function ($table) { + $table->index('is_master'); + $table->index('format'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + DB::statement('ALTER TABLE `show_songs` DROP INDEX show_songs_title_fulltext'); + + Schema::table('images', function ($table) { + $table->dropIndex('images_hash_index'); + }); + + Schema::table('track_files', function ($table) { + $table->dropIndex('track_files_is_master_index'); + $table->dropIndex('track_files_format_index'); + }); + } + +} diff --git a/app/database/migrations/2015_09_05_143300_create_mlpma_table.php b/app/database/migrations/2015_09_05_143300_create_mlpma_table.php new file mode 100644 index 00000000..be114960 --- /dev/null +++ b/app/database/migrations/2015_09_05_143300_create_mlpma_table.php @@ -0,0 +1,38 @@ +increments('id'); + $table->integer('track_id')->unsigned()->index(); + $table->string('path')->index(); + $table->string('filename')->index(); + $table->string('extension')->index(); + $table->dateTime('imported_at'); + $table->longText('parsed_tags'); + $table->longText('raw_tags'); + + $table->foreign('track_id')->references('id')->on('tracks'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('mlpma_tracks'); + } + +} diff --git a/app/library/PfmValidator.php b/app/library/PfmValidator.php index aa1df4ad..ffb24c9e 100644 --- a/app/library/PfmValidator.php +++ b/app/library/PfmValidator.php @@ -144,4 +144,4 @@ public function validateTextareaLength($attribute, $value, $parameters) { return strlen(str_replace("\r\n", "\n", $value)) <= $parameters[0]; } - } \ No newline at end of file + } diff --git a/app/models/Commands/UploadTrackCommand.php b/app/models/Commands/UploadTrackCommand.php index a6954b1c..2a9f8cdb 100644 --- a/app/models/Commands/UploadTrackCommand.php +++ b/app/models/Commands/UploadTrackCommand.php @@ -4,9 +4,28 @@ use Entities\Track; use Entities\TrackFile; + use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\Log; + use AudioCache; + use Illuminate\Support\Str; class UploadTrackCommand extends CommandBase { + private $_allowLossy; + private $_losslessFormats = [ + 'flac', + 'pcm_s16le ([1][0][0][0] / 0x0001)', + 'pcm_s16be', + 'adpcm_ms ([2][0][0][0] / 0x0002)', + 'pcm_s24le ([1][0][0][0] / 0x0001)', + 'pcm_s24be', + 'pcm_f32le ([3][0][0][0] / 0x0003)', + 'pcm_f32be (fl32 / 0x32336C66)' + ]; + + public function __construct($allowLossy = false) { + $this->_allowLossy = $allowLossy; + } + /** * @return bool */ @@ -26,7 +45,7 @@ $validator = \Validator::make(['track' => $trackFile], [ 'track' => 'required|' - . 'audio_format:flac,pcm_s16le ([1][0][0][0] / 0x0001),pcm_s16be,adpcm_ms ([2][0][0][0] / 0x0002),pcm_s24le ([1][0][0][0] / 0x0001),pcm_s24be,pcm_f32le ([3][0][0][0] / 0x0003),pcm_f32be (fl32 / 0x32336C66)|' + . ($this->_allowLossy ? '' : 'audio_format:'. implode(',', $this->_losslessFormats).'|') . 'audio_channels:1,2|' . 'sample_rate:44100,48000,88200,96000,176400,192000|' . 'min_duration:30' @@ -53,7 +72,40 @@ $processes = []; + // Lossy uploads need to be identified and set as the master file + // without being re-encoded. + $audioObject = AudioCache::get($source); + $isLossyUpload = !in_array($audioObject->getAudioCodec(), $this->_losslessFormats); + + if ($isLossyUpload) { + if ($audioObject->getAudioCodec() === 'mp3') { + $masterFormat = 'MP3'; + + } else if (Str::startsWith($audioObject->getAudioCodec(), 'aac')) { + $masterFormat = 'AAC'; + + } else { + $validator->messages()->add('track', 'The track does not contain audio in a known lossy format.'); + return CommandResponse::fail($validator); + } + + $trackFile = new TrackFile(); + $trackFile->is_master = true; + $trackFile->format = $masterFormat; + $trackFile->track_id = $track->id; + $trackFile->save(); + + // Lossy masters are copied into the datastore - no re-encoding involved. + File::copy($source, $trackFile->getFile()); + } + foreach (Track::$Formats as $name => $format) { + // Don't bother with lossless transcodes of lossy uploads, and + // don't re-encode the lossy master. + if ($isLossyUpload && ($format['is_lossless'] || $name === $masterFormat)) { + continue; + } + $trackFile = new TrackFile(); $trackFile->is_master = $name === 'FLAC' ? true : false; $trackFile->format = $name; diff --git a/app/models/Entities/Track.php b/app/models/Entities/Track.php index 4c8569f8..8edf51bb 100644 --- a/app/models/Entities/Track.php +++ b/app/models/Entities/Track.php @@ -24,11 +24,11 @@ } public static $Formats = [ - 'FLAC' => ['index' => 0, 'extension' => 'flac', 'tag_format' => 'metaflac', 'tag_method' => 'updateTagsWithGetId3', 'mime_type' => 'audio/flac', 'command' => 'ffmpeg 2>&1 -y -i {$source} -acodec flac -aq 8 -f flac {$target}'], - 'MP3' => ['index' => 1, 'extension' => 'mp3', 'tag_format' => 'id3v2.3', 'tag_method' => 'updateTagsWithGetId3', 'mime_type' => 'audio/mpeg', 'command' => 'ffmpeg 2>&1 -y -i {$source} -acodec libmp3lame -ab 320k -f mp3 {$target}'], - 'OGG Vorbis' => ['index' => 2, 'extension' => 'ogg', 'tag_format' => 'vorbiscomment', 'tag_method' => 'updateTagsWithGetId3', 'mime_type' => 'audio/ogg', 'command' => 'ffmpeg 2>&1 -y -i {$source} -acodec libvorbis -aq 7 -f ogg {$target}'], - 'AAC' => ['index' => 3, 'extension' => 'm4a', 'tag_format' => 'AtomicParsley', 'tag_method' => 'updateTagsWithAtomicParsley', 'mime_type' => 'audio/mp4', 'command' => 'ffmpeg 2>&1 -y -i {$source} -acodec libfaac -ab 256k -f mp4 {$target}'], - 'ALAC' => ['index' => 4, 'extension' => 'alac.m4a', 'tag_format' => 'AtomicParsley', 'tag_method' => 'updateTagsWithAtomicParsley', 'mime_type' => 'audio/mp4', 'command' => 'ffmpeg 2>&1 -y -i {$source} -acodec alac {$target}'], + 'FLAC' => ['index' => 0, 'is_lossless' => true, 'extension' => 'flac', 'tag_format' => 'metaflac', 'tag_method' => 'updateTagsWithGetId3', 'mime_type' => 'audio/flac', 'command' => 'ffmpeg 2>&1 -y -i {$source} -acodec flac -aq 8 -f flac {$target}'], + 'MP3' => ['index' => 1, 'is_lossless' => false, 'extension' => 'mp3', 'tag_format' => 'id3v2.3', 'tag_method' => 'updateTagsWithGetId3', 'mime_type' => 'audio/mpeg', 'command' => 'ffmpeg 2>&1 -y -i {$source} -acodec libmp3lame -ab 320k -f mp3 {$target}'], + 'OGG Vorbis' => ['index' => 2, 'is_lossless' => false, 'extension' => 'ogg', 'tag_format' => 'vorbiscomment', 'tag_method' => 'updateTagsWithGetId3', 'mime_type' => 'audio/ogg', 'command' => 'ffmpeg 2>&1 -y -i {$source} -acodec libvorbis -aq 7 -f ogg {$target}'], + 'AAC' => ['index' => 3, 'is_lossless' => false, 'extension' => 'm4a', 'tag_format' => 'AtomicParsley', 'tag_method' => 'updateTagsWithAtomicParsley', 'mime_type' => 'audio/mp4', 'command' => 'ffmpeg 2>&1 -y -i {$source} -acodec libfaac -ab 256k -f mp4 {$target}'], + 'ALAC' => ['index' => 4, 'is_lossless' => true, 'extension' => 'alac.m4a', 'tag_format' => 'AtomicParsley', 'tag_method' => 'updateTagsWithAtomicParsley', 'mime_type' => 'audio/mp4', 'command' => 'ffmpeg 2>&1 -y -i {$source} -acodec alac {$target}'], ]; public static function summary() { @@ -430,7 +430,11 @@ public function updateTags() { $this->trackFiles()->touch(); - foreach (self::$Formats as $format => $data) { + + foreach ($this->trackFiles as $trackFile) { + $format = $trackFile->format; + $data = self::$Formats[$format]; + $this->{$data['tag_method']}($format); } } @@ -444,8 +448,7 @@ $command .= '--genre ' . escapeshellarg($this->genre != null ? $this->genre->name : '') . ' '; $command .= '--copyright ' . escapeshellarg('© '.$this->year.' '.$this->user->display_name).' '; $command .= '--comment "' . 'Downloaded from: https://pony.fm/' . '" '; - $command .= '--encodingTool "' . 'Pony.fm' . '" '; - $command .= '--encodedBy "' . 'Pony.fm - https://pony.fm/' . '" '; + $command .= '--encodingTool "' . 'Pony.fm - https://pony.fm/' . '" '; if ($this->album_id !== NULL) { $command .= '--album ' . escapeshellarg($this->album->title) . ' '; diff --git a/app/models/Entities/TrackType.php b/app/models/Entities/TrackType.php index 336c0e5a..43ea73ea 100644 --- a/app/models/Entities/TrackType.php +++ b/app/models/Entities/TrackType.php @@ -4,4 +4,10 @@ class TrackType extends \Eloquent { protected $table = 'track_types'; - } \ No newline at end of file + + const ORIGINAL_TRACK = 1; + const OFFICIAL_TRACK_REMIX = 2; + const FAN_TRACK_REMIX = 3; + const PONIFIED_TRACK = 4; + const OFFICIAL_AUDIO_REMIX = 5; + } diff --git a/app/start/artisan.php b/app/start/artisan.php index e475bac7..9a804152 100644 --- a/app/start/artisan.php +++ b/app/start/artisan.php @@ -12,4 +12,6 @@ */ Artisan::add(new MigrateOldData); - Artisan::add(new RefreshCache); \ No newline at end of file + Artisan::add(new RefreshCache); + Artisan::add(new ImportMLPMA); + Artisan::add(new ClassifyMLPMA); diff --git a/vagrant/config/app.php b/vagrant/config/app.php index 8170ee19..d88079ec 100644 --- a/vagrant/config/app.php +++ b/vagrant/config/app.php @@ -8,7 +8,8 @@ return array( 'debug' => true, 'url' => 'pony.fm.local', 'files_directory' => '/vagrant-files/', + 'mlpma_directory' => '/vagrant-files/mlpma/', 'node' => null, 'node_paths' => ['/usr/lib/node_modules/'], 'secure' => false, -); \ No newline at end of file +);