From 3f7a63dd58f679e5429cc1375b9ca74183a03dad Mon Sep 17 00:00:00 2001 From: Peter Deltchev Date: Fri, 5 Feb 2016 14:01:45 -0800 Subject: [PATCH] Implemented a script to fix broken MLPMA cover art. --- app/Console/Commands/FixMLPMAImages.php | 154 ++++++++++++++++++++++++ app/Console/Kernel.php | 1 + app/Models/Image.php | 32 ++++- 3 files changed, 183 insertions(+), 4 deletions(-) create mode 100644 app/Console/Commands/FixMLPMAImages.php diff --git a/app/Console/Commands/FixMLPMAImages.php b/app/Console/Commands/FixMLPMAImages.php new file mode 100644 index 00000000..ef48157a --- /dev/null +++ b/app/Console/Commands/FixMLPMAImages.php @@ -0,0 +1,154 @@ +. + */ + +namespace Poniverse\Ponyfm\Console\Commands; + +use Config; +use DB; +use File; +use getID3; +use Illuminate\Console\Command; +use Poniverse\Ponyfm\Models\Image; +use Symfony\Component\HttpFoundation\File\UploadedFile; + +class FixMLPMAImages extends Command +{ + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'mlpma:fix-images + {--startAt=1 : Track to start importing from. Useful for resuming an interrupted import.}'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Re-imports MLPMA cover art'; + + /** + * Create a new command instance. + * + * @return void + */ + public function __construct() + { + parent::__construct(); + } + + protected $currentFile; + + + /** + * File extensions to ignore when importing the archive. + * + * @var array + */ + protected $ignoredExtensions = [ + 'db', + 'jpg', + 'png', + 'txt', + 'rtf', + 'wma', + 'wmv' + ]; + + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + $mlpmaPath = Config::get('ponyfm.files_directory') . '/mlpma'; + $tmpPath = Config::get('ponyfm.files_directory') . '/tmp'; + + $this->comment('Enumerating MLP Music Archive source files...'); + $files = File::allFiles($mlpmaPath); + $this->info(sizeof($files) . ' files 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 ++; + + $this->info('[' . $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; + } + // Get this track's MLPMA record + $importedTrack = DB::table('mlpma_tracks') + ->where('filename', '=', $file->getFilename()) + ->join('tracks', 'mlpma_tracks.track_id', '=', 'tracks.id') + ->first(); + $artistId = $importedTrack->user_id; + + + //========================================================================================================== + // Extract the original tags. + //========================================================================================================== + + $getId3 = new getID3; + // all tags read by getID3, including the cover art + $allTags = $getId3->analyze($file->getPathname()); + + + //========================================================================================================== + // Extract the cover art, if any exists. + //========================================================================================================== + $coverId = null; + + if (array_key_exists('comments', $allTags) && array_key_exists('picture', $allTags['comments'])) { + $this->comment('Extracting cover art!'); + $image = $allTags['comments']['picture'][0]; + if ($image['image_mime'] === 'image/png') { + $extension = 'png'; + } elseif ($image['image_mime'] === 'image/jpeg') { + $extension = 'jpg'; + } elseif ($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, $artistId, true); + $coverId = $cover->id; + + } else { + $this->comment('No cover art found!'); + } + } + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 988d835e..ade0d41f 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -44,6 +44,7 @@ class Kernel extends ConsoleKernel \Poniverse\Ponyfm\Console\Commands\RebuildFilesizes::class, \Poniverse\Ponyfm\Console\Commands\RebuildSearchIndex::class, \Poniverse\Ponyfm\Console\Commands\MergeAccounts::class, + \Poniverse\Ponyfm\Console\Commands\FixMLPMAImages::class, ]; /** diff --git a/app/Models/Image.php b/app/Models/Image.php index 0ad75856..75ac2c20 100644 --- a/app/Models/Image.php +++ b/app/Models/Image.php @@ -23,6 +23,7 @@ namespace Poniverse\Ponyfm\Models; use External; use Illuminate\Database\Eloquent\Model; use Config; +use Illuminate\Support\Str; use Symfony\Component\HttpFoundation\File\UploadedFile; /** @@ -65,7 +66,14 @@ class Image extends Model return null; } - public static function upload(UploadedFile $file, $user) + /** + * @param UploadedFile $file + * @param $user + * @param bool $forceReupload forces the image to be re-processed even if a matching hash is found + * @return Image + * @throws \Exception + */ + public static function upload(UploadedFile $file, $user, bool $forceReupload = false) { $userId = $user; if ($user instanceof User) { @@ -75,11 +83,27 @@ class Image extends Model $hash = md5_file($file->getPathname()); $image = Image::whereHash($hash)->whereUploadedBy($userId)->first(); - if ($image) { + if (!$forceReupload && $image) { return $image; } - $image = new Image(); + if ($forceReupload) { + // delete existing versions of the image + $filenames = scandir($image->getDirectory()); + $imagePrefix = $image->id.'_'; + + $filenames = array_filter($filenames, function(string $filename) use ($imagePrefix) { + return Str::startsWith($filename, $imagePrefix); + }); + + foreach($filenames as $filename) { + unlink($image->getDirectory().'/'.$filename); + } + + } else { + $image = new Image(); + } + try { $image->uploaded_by = $userId; $image->size = $file->getSize(); @@ -92,7 +116,7 @@ class Image extends Model $image->ensureDirectoryExists(); foreach (self::$ImageTypes as $coverType) { if ($coverType['id'] === self::ORIGINAL && $image->mime === 'image/jpeg') { - $command = 'cp '.$file->getPathname().' '.$image->getFile($coverType['id']); + $command = 'cp "'.$file->getPathname().'" '.$image->getFile($coverType['id']); } else { // ImageMagick options reference: http://www.imagemagick.org/script/command-line-options.php