From cbebc254528113dbae71f2014a2db46a291fe2a2 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Mon, 26 Oct 2015 19:33:11 +0000 Subject: [PATCH 01/44] Add cache-related columns to track_files table --- ...6_192855_update_track_files_with_cache.php | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 database/migrations/2015_10_26_192855_update_track_files_with_cache.php diff --git a/database/migrations/2015_10_26_192855_update_track_files_with_cache.php b/database/migrations/2015_10_26_192855_update_track_files_with_cache.php new file mode 100644 index 00000000..c0a51e75 --- /dev/null +++ b/database/migrations/2015_10_26_192855_update_track_files_with_cache.php @@ -0,0 +1,53 @@ +. + */ + +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Migrations\Migration; + +class UpdateTrackFilesWithCache extends Migration +{ + /** + * Run the migrations. + * + * @return void + */ + public function up() + { + Schema::table('track_files', function (Blueprint $table) { + $table->boolean('is_cacheable')->default(false); + $table->dateTime('expiration')->nullable(); + $table->boolean('in_progress')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('track_files', function (Blueprint $table) { + $table->dropColumn('is_cacheable'); + $table->dropColumn('expiration'); + $table->dropColumn('in_progress'); + }); + } +} From a9f80fde6ea2fcd3d51a2053f83ad08e63c67a6a Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Mon, 26 Oct 2015 19:47:42 +0000 Subject: [PATCH 02/44] Add console commands --- app/Console/Commands/ClearTrackCache.php | 111 +++++++++++ app/Console/Commands/RebuildTrackCache.php | 210 +++++++++++++++++++++ app/Console/Kernel.php | 2 + 3 files changed, 323 insertions(+) create mode 100644 app/Console/Commands/ClearTrackCache.php create mode 100644 app/Console/Commands/RebuildTrackCache.php diff --git a/app/Console/Commands/ClearTrackCache.php b/app/Console/Commands/ClearTrackCache.php new file mode 100644 index 00000000..ab534a13 --- /dev/null +++ b/app/Console/Commands/ClearTrackCache.php @@ -0,0 +1,111 @@ +. + */ + +namespace Poniverse\Ponyfm\Console\Commands; + +use Carbon\Carbon; +use File; +use Illuminate\Console\Command; +use Illuminate\Support\Facades\Cache; +use Poniverse\Ponyfm\TrackFile; + +class ClearTrackCache extends Command +{ + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'track-cache:clear + [--tracks=expired : Clear only [expired] (default) or [all] cached tracks.] + [--force : Skip all prompts.]'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Clears cached tracks. Defaults to expired tracks. Usage: php artisan track-cache:clear [--tracks=expired|all]'; + + /** + * Create a new command instance. + * + */ + public function __construct() + { + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + if ($this->option('tracks') == 'all') { + // Get all cacheable tracks + $trackFiles = TrackFile::where('is_cacheable', true)->get(); + } else { + // Get all expired tracks + $trackFiles = TrackFile::where('is_cacheable', true) + ->where('expiration', '<=', Carbon::now()) + ->get(); + + } + + // Delete above tracks + if (count($trackFiles) === 0) { + $this->info('No tracks found. Exiting.'); + } else { + + if ($this->option('force') || $this->confirm(count($trackFiles) . ' tracks found. Proceed to delete? [y|N]', false)) { + + $count = 0; + + foreach ($trackFiles as $trackFile) { + + // Set expiration to null (so can be re-cached upon request) + $trackFile->expiration = null; + $trackFile->update(); + + // Delete files if exists + if (File::exists($trackFile->getFile())) { + $count++; + File::delete($trackFile->getFile()); + + // Remove the cached file sizes for main, trackfile and format + Cache::forget($trackFile->getCacheKey('filesize')); + Cache::forget($trackFile->track()->getCacheKey('filesize-' . $trackFile->format)); + Cache::forget($trackFile->track()->album()->getCacheKey('filesize-' . $trackFile->format)); + + $this->info('Deleted ' . $trackFile->getFile()); + } + + } + $this->info($count . ' files deleted. Deletion complete. Exiting.'); + } else { + $this->info('Deletion cancelled. Exiting.'); + } + + } + } + +} \ No newline at end of file diff --git a/app/Console/Commands/RebuildTrackCache.php b/app/Console/Commands/RebuildTrackCache.php new file mode 100644 index 00000000..e2fc36e5 --- /dev/null +++ b/app/Console/Commands/RebuildTrackCache.php @@ -0,0 +1,210 @@ +. + */ + +namespace Poniverse\Ponyfm\Console\Commands; + +use Illuminate\Console\Command; +use Poniverse\Ponyfm\Track; +use Poniverse\Ponyfm\TrackFile; +use Symfony\Component\HttpFoundation\File\File; + +class RebuildTrackCache extends Command +{ + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'track-cache:rebuild'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Rebuilds the track cache for when $CacheableFormats is changed. Deletes cacheable files and encodes missing files which are not cacheable.'; + + /** + * Create a new command instance. + * + */ + public function __construct() + { + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + $this->info('This will run \'php artisan down\' if you proceed and \'php artisan up\' when complete.'); + + if ($this->option('force') || $this->confirm('Are you sure you want to delete all to-be-cached files and encode missing non-cached files? [y|N]', + false) + ) { + + $this->call('down'); + + //========================================================================================================== + // Delete previously cached tracks + //========================================================================================================== + + // Find files which are cacheable and NOT master + $trackFiles = TrackFile::where('is_cacheable', true) + ->where('is_master', false) + ->get(); + + // Delete above files + if (count($trackFiles) == 0) { + $this->info('No tracks found. Continuing.'); + } else { + $this->info(count($trackFiles) . ' tracks found.'); + $count = 0; + + foreach ($trackFiles as $trackFile) { + // Clear expiration so will be re-cached on next request + $trackFile->expiration = null; + $trackFile->update(); + + // Delete files + if (File::exists($trackFile->getFile())) { + $count++; + File::delete($trackFile->getFile()); + $this->info('Deleted ' . $trackFile->getFile()); + } + } + + $this->info($count . ' files deleted. Deletion complete. Continuing.'); + } + + //========================================================================================================== + // Update the database entries for cacheable files - non-cacheable to cacheable + //========================================================================================================== + + $this->info('--- Step 2/4 - Updating is_cacheable entries in database. ---'); + + // Find files which are meant to be cacheable and NOT master, but currently not cacheable + $trackFiles = TrackFile::where('is_cacheable', false) + ->whereIn('format', array_keys(Track::$CacheableFormats)) + ->where('is_master', false) + ->get(); + + $formats = []; + + // Set above files to cacheable in the database + foreach ($trackFiles as $trackFile) { + // Let user know which formats, previously not cached, were made cacheable + $formats[] = $trackFile->format; + + $trackFile->expiration = null; + $trackFile->is_cacheable = true; + $trackFile->update(); + } + + $this->info('Format(s) set from non-cacheable to cacheable: ' . implode(' ', array_unique($formats))); + $this->info(count($trackFiles) . ' non-cacheable tracks set to cacheable.'); + + //========================================================================================================== + // Update the database entries for cacheable files - cacheable to non-cacheable + //========================================================================================================== + + // Find files which are NOT meant to be cacheable, but currently cacheable + $trackFiles = TrackFile::where('is_cacheable', true) + ->whereNotIn('format', array_keys(Track::$CacheableFormats)) + ->get(); + + $formats = []; + + // Set above files to non-cacheable in the database + foreach ($trackFiles as $trackFile) { + // Let user know which formats, previously not cached, were made cacheable + $formats[] = $trackFile->format; + + $trackFile->expiration = null; + $trackFile->is_cacheable = false; + $trackFile->update(); + } + + $this->info('Format(s) set from cacheable to non-cacheable: ' . implode(' ', array_unique($formats))); + $this->info(count($trackFiles) . ' cacheable tracks set to non-cacheable.'); + + //========================================================================================================== + // Delete files which have now been marked as cacheable + //========================================================================================================== + + $this->info('--- Step 3/4 - Deleting now-cacheable files. ---'); + + // Find files which are cacheable and NOT master + $trackFiles = TrackFile::whereIn('format', array_keys(Track::$CacheableFormats)) + ->where('is_master', false) + ->get(); + + // Delete above files + if (count($trackFiles) == 0) { + $this->info('No tracks to delete found. Continuing.'); + } else { + $count = 0; + foreach ($trackFiles as $trackFile) { + // Delete files if files exist; double-check that they are NOT master files + if (File::exists($trackFile->getFile()) && $trackFile->is_master == false) { + $count++; + File::delete($trackFile->getFile()); + $this->info('Deleted ' . $trackFile->getFile()); + } + } + $this->info(sprintf('%d files deleted out of %d tracks. Continuing.', $count, count($trackFiles))); + } + + //========================================================================================================== + // Encode missing (i.e., now non-cacheable) files + //========================================================================================================== + + $this->info('--- Step 4/4 - Encoding missing files. ---'); + + // Get non-cacheable files + $trackFiles = TrackFile::where('is_cacheable', false)->get(); + + // Record the above files which do not exist (i.e., have not been encoded yet) + $trackFileIds = []; + $count = 0; + foreach ($trackFiles as $trackFile) { + if (!File::exists($trackFile->getFile())) { + $count++; + $trackFileIds[] = $trackFile->id; + } + } + + // Encode recorded files + $encodeTrackFileCommand = new EncodeTrackFileCommand($trackFileIds); + $encodeTrackFileCommand->execute(); + + $this->info($count . ' tracks encoded.'); + + $this->call('up'); + $this->info('Rebuild complete. Exiting.'); + + } else { + $this->info('Rebuild cancelled. Exiting.'); + } + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 94c282af..6f76ff2b 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -39,6 +39,8 @@ class Kernel extends ConsoleKernel \Poniverse\Ponyfm\Console\Commands\FixYearZeroLogs::class, \Poniverse\Ponyfm\Console\Commands\BootstrapLocalEnvironment::class, \Poniverse\Ponyfm\Console\Commands\PoniverseApiSetup::class, + \Poniverse\Ponyfm\Console\Commands\ClearTrackCache::class, + \Poniverse\Ponyfm\Console\Commands\RebuildTrackCache::class, ]; /** From 9470faaaa290cdefe1c1997aaf62e6bc33f4b246 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Mon, 26 Oct 2015 19:48:55 +0000 Subject: [PATCH 03/44] Add $CacheableFormats to Track.php --- app/Track.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/app/Track.php b/app/Track.php index 027ed6a3..7e06db09 100644 --- a/app/Track.php +++ b/app/Track.php @@ -93,6 +93,27 @@ class Track extends Model ], ]; + public static $CacheableFormats = [ + '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}' + ], + '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() { return self::select('tracks.id', 'title', 'user_id', 'slug', 'is_vocal', 'is_explicit', 'created_at', 'published_at', From fdb95560e7f811c4f9acaaaabfb50c01488fd2c2 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Mon, 26 Oct 2015 19:50:58 +0000 Subject: [PATCH 04/44] Add --force option to RebuildTrackCache --- app/Console/Commands/RebuildTrackCache.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Console/Commands/RebuildTrackCache.php b/app/Console/Commands/RebuildTrackCache.php index e2fc36e5..86e51f22 100644 --- a/app/Console/Commands/RebuildTrackCache.php +++ b/app/Console/Commands/RebuildTrackCache.php @@ -32,7 +32,8 @@ class RebuildTrackCache extends Command * * @var string */ - protected $signature = 'track-cache:rebuild'; + protected $signature = 'track-cache:rebuild + [--force : Skip all prompts.]'; /** * The console command description. From 8f76b4d59dffffdb56af8293a6c94bf3dd0dc9d7 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Mon, 26 Oct 2015 20:55:15 +0000 Subject: [PATCH 05/44] Add cache duration to ponyfm.php config --- config/ponyfm.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/config/ponyfm.php b/config/ponyfm.php index add3e98f..7ae9f250 100644 --- a/config/ponyfm.php +++ b/config/ponyfm.php @@ -54,4 +54,15 @@ return [ 'use_powered_by_footer' => env('USE_POWERED_BY_FOOTER', true), + /* + |-------------------------------------------------------------------------- + | Cache Duration + |-------------------------------------------------------------------------- + | + | Duration in minutes for tracks to be stored in cache. + | + */ + + 'cache_duration' => 1440, + ]; From 5380d0b45a22cabe1e9482a5e21091894ab5c6ee Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Tue, 27 Oct 2015 15:31:14 +0000 Subject: [PATCH 06/44] Add loading.gif --- public/images/loading.gif | Bin 0 -> 7771 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 public/images/loading.gif diff --git a/public/images/loading.gif b/public/images/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..724eacb53fedbc037cdc380e383cbd86e5ab3cd8 GIT binary patch literal 7771 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 literal 0 HcmV?d00001 From 097073464863d8352fafb397259cb4cd74ec091c Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Tue, 27 Oct 2015 16:21:03 +0000 Subject: [PATCH 07/44] Update UploadTrackCommand with selective uploading using Process --- app/Commands/UploadTrackCommand.php | 34 +++++++++++++++-------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/app/Commands/UploadTrackCommand.php b/app/Commands/UploadTrackCommand.php index 3432feb8..9e170705 100644 --- a/app/Commands/UploadTrackCommand.php +++ b/app/Commands/UploadTrackCommand.php @@ -26,6 +26,8 @@ use AudioCache; use File; use Illuminate\Support\Facades\Log; use Illuminate\Support\Str; +use Symfony\Component\Process\Exception\ProcessFailedException; +use Symfony\Component\Process\Process; class UploadTrackCommand extends CommandBase { @@ -94,8 +96,6 @@ class UploadTrackCommand extends CommandBase $source = $trackFile->getPathname(); $index = 0; - $processes = []; - // Lossy uploads need to be identified and set as the master file // without being re-encoded. $audioObject = AudioCache::get($source); @@ -136,29 +136,31 @@ class UploadTrackCommand extends CommandBase $trackFile = new TrackFile(); $trackFile->is_master = $name === 'FLAC' ? true : false; $trackFile->format = $name; + if (array_key_exists($name, Track::$CacheableFormats) && $trackFile->is_master == false) { + $trackFile->is_cacheable = true; + } else { + $trackFile->is_cacheable = false; + } $track->trackFiles()->save($trackFile); - $target = $destination . '/' . $trackFile->getFilename(); //$track->getFilenameFor($name); + if ($trackFile->is_cacheable == false) { + $target = $destination . '/' . $trackFile->getFilename(); - $command = $format['command']; - $command = str_replace('{$source}', '"' . $source . '"', $command); - $command = str_replace('{$target}', '"' . $target . '"', $command); + $command = $format['command']; + $command = str_replace('{$source}', '"' . $source . '"', $command); + $command = str_replace('{$target}', '"' . $target . '"', $command); - Log::info('Encoding ' . $track->id . ' into ' . $target); - $this->notify('Encoding ' . $name, $index / count(Track::$Formats) * 100); + Log::info('Encoding ' . $track->id . ' into ' . $target); + $this->notify('Encoding ' . $name, $index / count(Track::$Formats) * 100); - $pipes = []; - $proc = proc_open($command, [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'a']], $pipes); - $processes[] = $proc; - } - - foreach ($processes as $proc) { - proc_close($proc); + $process = new Process($command); + $process->mustRun(); + } } $track->updateTags(); - } catch (\Exception $e) { + } catch (ProcessFailedException $e) { $track->delete(); throw $e; } From 628b6f5f86f66ca73418532df94d964d43375815 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Tue, 27 Oct 2015 16:35:04 +0000 Subject: [PATCH 08/44] Update migration -> change default of in_progress to false --- .../2015_10_26_192855_update_track_files_with_cache.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/migrations/2015_10_26_192855_update_track_files_with_cache.php b/database/migrations/2015_10_26_192855_update_track_files_with_cache.php index c0a51e75..3bc34189 100644 --- a/database/migrations/2015_10_26_192855_update_track_files_with_cache.php +++ b/database/migrations/2015_10_26_192855_update_track_files_with_cache.php @@ -32,8 +32,8 @@ class UpdateTrackFilesWithCache extends Migration { Schema::table('track_files', function (Blueprint $table) { $table->boolean('is_cacheable')->default(false); + $table->boolean('in_progress')->default(false); $table->dateTime('expiration')->nullable(); - $table->boolean('in_progress')->nullable(); }); } From c651c44d34c7d760a0d1303550fdccfdd9e8d2c9 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Tue, 27 Oct 2015 17:20:43 +0000 Subject: [PATCH 09/44] Add EncodeTrackFile job --- app/Jobs/EncodeTrackFile.php | 128 +++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 app/Jobs/EncodeTrackFile.php diff --git a/app/Jobs/EncodeTrackFile.php b/app/Jobs/EncodeTrackFile.php new file mode 100644 index 00000000..60b3953d --- /dev/null +++ b/app/Jobs/EncodeTrackFile.php @@ -0,0 +1,128 @@ +. + */ + +namespace Poniverse\Ponyfm\Jobs; + +use Carbon\Carbon; +use Illuminate\Support\Facades\Config; +use Illuminate\Support\Facades\Log; +use OAuth2\Exception; +use Poniverse\Ponyfm\Jobs\Job; +use Illuminate\Queue\SerializesModels; +use Illuminate\Queue\InteractsWithQueue; +use Illuminate\Contracts\Bus\SelfHandling; +use Illuminate\Contracts\Queue\ShouldQueue; +use Poniverse\Ponyfm\Track; +use Poniverse\Ponyfm\TrackFile; +use Symfony\Component\Process\Exception\ProcessFailedException; +use Symfony\Component\Process\Process; + +class EncodeTrackFile extends Job implements SelfHandling, ShouldQueue +{ + use InteractsWithQueue, SerializesModels; + /** + * @var TrackFile + */ + private $trackFile; + /** + * @var + */ + private $isExpirable; + + /** + * Create a new job instance. + * @param TrackFile $trackFile + * @param $isExpirable + */ + public function __construct(TrackFile $trackFile, $isExpirable) + { + $this->trackFile = $trackFile; + $this->isExpirable = $isExpirable; + } + + /** + * Execute the job. + * + * @return void + */ + public function handle() + { + // Start the job + $this->trackFile->in_progress = true; + $this->trackFile->update(); + + // Assign the source to the track's master file + $source = TrackFile::where('track_id', $this->trackFile->track_id) + ->where('is_master', true) + ->first() + ->getFile(); + + // Assign the target + $destination = $this->trackFile->track()->getDirectory(); + $this->trackFile->track()->ensureDirectoryExists(); + $target = $destination . '/' . $this->trackFile->getFilename(); + + // Prepare the command + $format = Track::$Formats[$this->trackFile->format]; + $command = $format['command']; + $command = str_replace('{$source}', '"' . $source . '"', $command); + $command = str_replace('{$target}', '"' . $target . '"', $command); + + Log::info('Encoding track file ' . $this->trackFile->id . ' into ' . $target); + + // Start a synchronous process to encode the file + $process = new Process($command); + try { + $process->mustRun(); + } catch (ProcessFailedException $e) { + Log::error('An exception occured in the encoding process for track file ' . $this->trackFile->id . ' - ' . $e->getMessage()); + // Ensure queue fails + throw $e; + } finally { + Log::info($process->getOutput()); + } + + // Update the tags of the track + $this->trackFile->track()->updateTags(); + + // Insert the expiration time for cached tracks + if ($this->isExpirable) { + $this->trackFile->expiration = Carbon::now()->addMinutes(Config::get('ponyfm.cache_duration')); + $this->trackFile->update(); + } + + // Complete the job + $this->trackFile->in_progress = false; + $this->trackFile->update(); + + } + + /** + * Handle a job failure. + * + * @return void + */ + public function failed() + { + $this->trackFile->in_progress = false; + $this->trackFile->expiration = null; + $this->trackFile->update(); + } +} From 683aa568e9aa07cc080a027b20f851ec3116cf7f Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Tue, 27 Oct 2015 17:21:14 +0000 Subject: [PATCH 10/44] Revert to catch Exception in UploadTrackCommand --- app/Commands/UploadTrackCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Commands/UploadTrackCommand.php b/app/Commands/UploadTrackCommand.php index 9e170705..0679352e 100644 --- a/app/Commands/UploadTrackCommand.php +++ b/app/Commands/UploadTrackCommand.php @@ -160,7 +160,7 @@ class UploadTrackCommand extends CommandBase $track->updateTags(); - } catch (ProcessFailedException $e) { + } catch (\Exception $e) { $track->delete(); throw $e; } From 43c45adece2d014e49634e82a6f713bbf4034509 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Tue, 27 Oct 2015 17:29:51 +0000 Subject: [PATCH 11/44] Fix options and imports for commands --- app/Console/Commands/ClearTrackCache.php | 4 ++-- app/Console/Commands/RebuildTrackCache.php | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/app/Console/Commands/ClearTrackCache.php b/app/Console/Commands/ClearTrackCache.php index ab534a13..7ac592ee 100644 --- a/app/Console/Commands/ClearTrackCache.php +++ b/app/Console/Commands/ClearTrackCache.php @@ -34,8 +34,8 @@ class ClearTrackCache extends Command * @var string */ protected $signature = 'track-cache:clear - [--tracks=expired : Clear only [expired] (default) or [all] cached tracks.] - [--force : Skip all prompts.]'; + {--tracks=expired : Clear only [expired] (default) or [all] cached tracks.} + {--force : Skip all prompts.}'; /** * The console command description. diff --git a/app/Console/Commands/RebuildTrackCache.php b/app/Console/Commands/RebuildTrackCache.php index 86e51f22..ef5d5582 100644 --- a/app/Console/Commands/RebuildTrackCache.php +++ b/app/Console/Commands/RebuildTrackCache.php @@ -20,20 +20,25 @@ namespace Poniverse\Ponyfm\Console\Commands; +use File; use Illuminate\Console\Command; +use Illuminate\Foundation\Bus\DispatchesJobs; +use Poniverse\Ponyfm\Jobs\EncodeTrackFile; use Poniverse\Ponyfm\Track; use Poniverse\Ponyfm\TrackFile; -use Symfony\Component\HttpFoundation\File\File; class RebuildTrackCache extends Command { + + use DispatchesJobs; + /** * The name and signature of the console command. * * @var string */ protected $signature = 'track-cache:rebuild - [--force : Skip all prompts.]'; + {--force : Skip all prompts.}'; /** * The console command description. @@ -186,18 +191,19 @@ class RebuildTrackCache extends Command $trackFiles = TrackFile::where('is_cacheable', false)->get(); // Record the above files which do not exist (i.e., have not been encoded yet) - $trackFileIds = []; + $emptyTrackFiles = []; $count = 0; foreach ($trackFiles as $trackFile) { if (!File::exists($trackFile->getFile())) { $count++; - $trackFileIds[] = $trackFile->id; + $emptyTrackFiles[] = $trackFile; } } // Encode recorded files - $encodeTrackFileCommand = new EncodeTrackFileCommand($trackFileIds); - $encodeTrackFileCommand->execute(); + foreach($emptyTrackFiles as $emptyTrackFile) { + $this->dispatch(new EncodeTrackFile($emptyTrackFile, false)); + } $this->info($count . ' tracks encoded.'); From f205cf6d9308423d91208b8d123f0563dfe593a3 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Tue, 27 Oct 2015 17:35:38 +0000 Subject: [PATCH 12/44] Implement EncodeTrackFile job --- app/Jobs/EncodeTrackFile.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Jobs/EncodeTrackFile.php b/app/Jobs/EncodeTrackFile.php index 60b3953d..af168add 100644 --- a/app/Jobs/EncodeTrackFile.php +++ b/app/Jobs/EncodeTrackFile.php @@ -75,8 +75,8 @@ class EncodeTrackFile extends Job implements SelfHandling, ShouldQueue ->getFile(); // Assign the target - $destination = $this->trackFile->track()->getDirectory(); - $this->trackFile->track()->ensureDirectoryExists(); + $destination = $this->trackFile->track->getDirectory(); + $this->trackFile->track->ensureDirectoryExists(); $target = $destination . '/' . $this->trackFile->getFilename(); // Prepare the command @@ -100,7 +100,7 @@ class EncodeTrackFile extends Job implements SelfHandling, ShouldQueue } // Update the tags of the track - $this->trackFile->track()->updateTags(); + $this->trackFile->track->updateTags(); // Insert the expiration time for cached tracks if ($this->isExpirable) { From a03c44aadb713331ee58d5c53e5d0baef786e471 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Wed, 28 Oct 2015 17:32:44 +0000 Subject: [PATCH 13/44] Add cache routes --- app/Http/routes.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/Http/routes.php b/app/Http/routes.php index 64bc0691..a2358339 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -79,9 +79,11 @@ Route::group(['prefix' => 'api/web'], function() { Route::get('/tracks', 'Api\Web\TracksController@getIndex'); Route::get('/tracks/{id}', 'Api\Web\TracksController@getShow')->where('id', '\d+'); + Route::get('/tracks/cached/{id}/{format}', 'Api\Web\TracksController@getCachedTrack')->where(['id' => '\d+', 'name' => '.+']); Route::get('/albums', 'Api\Web\AlbumsController@getIndex'); Route::get('/albums/{id}', 'Api\Web\AlbumsController@getShow')->where('id', '\d+'); + Route::get('/albums/cached/{id}/{format}', 'Api\Web\AlbumsController@getCachedAlbum')->where(['id' => '\d+', 'name' => '.+']); Route::get('/playlists', 'Api\Web\PlaylistsController@getIndex'); Route::get('/playlists/{id}', 'Api\Web\PlaylistsController@getShow')->where('id', '\d+'); From 629b9913ceb950a9f20fc095fce22b173ea4b28c Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Wed, 28 Oct 2015 17:55:21 +0000 Subject: [PATCH 14/44] Add cache handling for controllers --- .../Controllers/Api/Web/AlbumsController.php | 50 +++++++++++++++++++ .../Controllers/Api/Web/TracksController.php | 37 ++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/app/Http/Controllers/Api/Web/AlbumsController.php b/app/Http/Controllers/Api/Web/AlbumsController.php index 068d2d6c..fb9bee96 100644 --- a/app/Http/Controllers/Api/Web/AlbumsController.php +++ b/app/Http/Controllers/Api/Web/AlbumsController.php @@ -20,16 +20,19 @@ namespace Poniverse\Ponyfm\Http\Controllers\Api\Web; +use Illuminate\Database\Eloquent\ModelNotFoundException; use Poniverse\Ponyfm\Album; use Poniverse\Ponyfm\Commands\CreateAlbumCommand; use Poniverse\Ponyfm\Commands\DeleteAlbumCommand; use Poniverse\Ponyfm\Commands\EditAlbumCommand; use Poniverse\Ponyfm\Http\Controllers\ApiControllerBase; use Poniverse\Ponyfm\Image; +use Poniverse\Ponyfm\Jobs\EncodeTrackFile; use Poniverse\Ponyfm\ResourceLogItem; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Input; use Illuminate\Support\Facades\Response; +use Poniverse\Ponyfm\Track; class AlbumsController extends ApiControllerBase { @@ -83,6 +86,53 @@ class AlbumsController extends ApiControllerBase ], 200); } + public function getCachedAlbum($id, $format) + { + // Validation + try { + $album = Album::findOrFail($id); + } catch (ModelNotFoundException $e) { + return $this->notFound('Album not found!'); + } + + if (!array_key_exists($format, Track::$CacheableFormats)) { + return $this->notFound('Format not found!'); + } + + $tracks = $album->tracks; + + $trackCount = 0; + $cachedCount = 0; + + foreach($tracks as $track) { + if ($track->is_downloadable == false) { + continue; + } else { + $trackCount++; + } + + try { + $trackFile = $track->trackFiles()->where('format', $format)->firstOrFail(); + } catch (ModelNotFoundException $e) { + return $this->notFound('Track file for track ID ' . $track->id . ' not found!'); + } + + if ($trackFile->expiration != null) { + $cachedCount++; + } elseif ($trackFile->in_progress != true) { + $this->dispatch(new EncodeTrackFile($trackFile, true)); + } + } + + if ($trackCount === $cachedCount) { + $url = $album->getDownloadUrl($format); + } else { + $url = null; + } + + return Response::json(['url' => $url], 200); + } + public function getIndex() { $page = 1; diff --git a/app/Http/Controllers/Api/Web/TracksController.php b/app/Http/Controllers/Api/Web/TracksController.php index 95580a79..77ba94de 100644 --- a/app/Http/Controllers/Api/Web/TracksController.php +++ b/app/Http/Controllers/Api/Web/TracksController.php @@ -20,10 +20,13 @@ namespace Poniverse\Ponyfm\Http\Controllers\Api\Web; +use Illuminate\Database\Eloquent\ModelNotFoundException; +use Illuminate\Support\Facades\File; use Poniverse\Ponyfm\Commands\DeleteTrackCommand; use Poniverse\Ponyfm\Commands\EditTrackCommand; use Poniverse\Ponyfm\Commands\UploadTrackCommand; use Poniverse\Ponyfm\Http\Controllers\ApiControllerBase; +use Poniverse\Ponyfm\Jobs\EncodeTrackFile; use Poniverse\Ponyfm\ResourceLogItem; use Poniverse\Ponyfm\Track; use Cover; @@ -70,6 +73,40 @@ class TracksController extends ApiControllerBase return Response::json(['track' => $returned_track], 200); } + public function getCachedTrack($id, $format) + { + // Validation + try { + $track = Track::findOrFail($id); + } catch (ModelNotFoundException $e) { + return $this->notFound('Track not found!'); + } + + if (!$track->canView(Auth::user())) + return $this->notFound('Track not found!'); + + if (!in_array($format, array_keys(Track::$CacheableFormats))) { + return $this->notFound('Format not found!'); + } + + try { + $trackFile = $track->trackFiles()->where('format', $format)->firstOrFail(); + } catch (ModelNotFoundException $e) { + return $this->notFound('Track file not found!'); + } + + // Return URL or begin encoding + if ($trackFile->expiration != null && File::exists($trackFile->getFile())) { + $url = $track->getUrlFor($format); + } elseif ($trackFile->in_progress === true) { + $url = null; + } else { + $this->dispatch(new EncodeTrackFile($trackFile, true)); + $url = null; + } + + } + public function getIndex() { $page = 1; From 65159f31a3426ec9c23f01a8c2ca8cb7c53cd087 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Thu, 29 Oct 2015 14:11:06 +0000 Subject: [PATCH 15/44] Fix returning of cached tracks --- app/Http/Controllers/Api/Web/TracksController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Http/Controllers/Api/Web/TracksController.php b/app/Http/Controllers/Api/Web/TracksController.php index 77ba94de..ca2913a0 100644 --- a/app/Http/Controllers/Api/Web/TracksController.php +++ b/app/Http/Controllers/Api/Web/TracksController.php @@ -105,6 +105,7 @@ class TracksController extends ApiControllerBase $url = null; } + return Response::json(['url' => $url], 200); } public function getIndex() From 4c5a03329ac455824539590c61ff9bb48f6940c0 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Thu, 29 Oct 2015 14:13:01 +0000 Subject: [PATCH 16/44] Add loading styling --- resources/assets/styles/content.less | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/resources/assets/styles/content.less b/resources/assets/styles/content.less index dd6824f9..b937aa45 100644 --- a/resources/assets/styles/content.less +++ b/resources/assets/styles/content.less @@ -360,6 +360,16 @@ html { background-color: lighten(@pfm-purple, 30%); } } + .cache-loading { + display: block; + margin-left: auto; + margin-right: auto; + text-align: center; + line-height: 100%; + font-size: 93%; + padding-left: 3px; + padding-right: 3px; + } } } From d4526852cfd4e3a07bf778ef103ed2ea2609d70e Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Thu, 29 Oct 2015 14:14:30 +0000 Subject: [PATCH 17/44] Add download-cached service --- .../app/services/download-cached.coffee | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 resources/assets/scripts/app/services/download-cached.coffee diff --git a/resources/assets/scripts/app/services/download-cached.coffee b/resources/assets/scripts/app/services/download-cached.coffee new file mode 100644 index 00000000..729988b5 --- /dev/null +++ b/resources/assets/scripts/app/services/download-cached.coffee @@ -0,0 +1,20 @@ +angular.module('ponyfm').factory('download-cached', [ + '$rootScope', '$http', '$log' + ($rootScope, $http, $log) -> + download = (type, id, format) -> + url = '/api/web/' + type + '/download-cached/' + id + '/' + format + + encodingComplete = (response) -> + if response.data.url == null + 'pending' + else + response.data.url + + encodingFailed = (error) -> + $log.error 'Error downloading encoded file - Status: ' + error.status + '- Message: ' + error.data + 'error' + + $http.get(url).then(encodingComplete).catch encodingFailed + + {download: download} +]) \ No newline at end of file From 4876775f312c4d7f622be4100156d2ea21d95071 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Thu, 29 Oct 2015 14:16:58 +0000 Subject: [PATCH 18/44] Add copyright notice to download-cached.coffee --- .../scripts/app/services/download-cached.coffee | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/resources/assets/scripts/app/services/download-cached.coffee b/resources/assets/scripts/app/services/download-cached.coffee index 729988b5..397c69e4 100644 --- a/resources/assets/scripts/app/services/download-cached.coffee +++ b/resources/assets/scripts/app/services/download-cached.coffee @@ -1,3 +1,19 @@ +# Pony.fm - A community for pony fan music. +# Copyright (C) 2015 Peter Deltchev +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + angular.module('ponyfm').factory('download-cached', [ '$rootScope', '$http', '$log' ($rootScope, $http, $log) -> From 88b57a631a3628dcf053f5353cf911653528889b Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Thu, 29 Oct 2015 14:36:13 +0000 Subject: [PATCH 19/44] Update models with isCached --- app/Album.php | 3 ++- app/Track.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/Album.php b/app/Album.php index d71cc1fb..3a2b627a 100644 --- a/app/Album.php +++ b/app/Album.php @@ -99,7 +99,8 @@ class Album extends Model 'name' => $name, 'extension' => $format['extension'], 'url' => $album->getDownloadUrl($name), - 'size' => Helpers::formatBytes($album->getFilesize($name)) + 'size' => Helpers::formatBytes($album->getFilesize($name)), + 'isCacheable' => (in_array($name, array_keys(Track::$CacheableFormats)) ? true : false) ]; } diff --git a/app/Track.php b/app/Track.php index 7e06db09..51ff35d8 100644 --- a/app/Track.php +++ b/app/Track.php @@ -235,7 +235,8 @@ class Track extends Model 'name' => $trackFile->format, 'extension' => $trackFile->extension, 'url' => $trackFile->url, - 'size' => $trackFile->size + 'size' => $trackFile->size, + 'isCacheable' => $trackFile->is_cacheable ]; } From a5bc7491e060cff9caba59620add84f041955f3a Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Thu, 29 Oct 2015 14:36:36 +0000 Subject: [PATCH 20/44] Fix URL for download-cached service --- resources/assets/scripts/app/services/download-cached.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/assets/scripts/app/services/download-cached.coffee b/resources/assets/scripts/app/services/download-cached.coffee index 397c69e4..fcbfef5b 100644 --- a/resources/assets/scripts/app/services/download-cached.coffee +++ b/resources/assets/scripts/app/services/download-cached.coffee @@ -18,7 +18,7 @@ angular.module('ponyfm').factory('download-cached', [ '$rootScope', '$http', '$log' ($rootScope, $http, $log) -> download = (type, id, format) -> - url = '/api/web/' + type + '/download-cached/' + id + '/' + format + url = '/api/web/' + type + '/cached/' + id + '/' + format encodingComplete = (response) -> if response.data.url == null From 58e49cc2f5a2a9de98b7c413d4f0312c7837c5c3 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Thu, 29 Oct 2015 14:37:00 +0000 Subject: [PATCH 21/44] Implement ng-controllers for cached track downloads --- .../scripts/app/controllers/album.coffee | 18 ++++++++++++++++-- .../scripts/app/controllers/track.coffee | 19 +++++++++++++++++-- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/resources/assets/scripts/app/controllers/album.coffee b/resources/assets/scripts/app/controllers/album.coffee index ae91498c..1815ea96 100644 --- a/resources/assets/scripts/app/controllers/album.coffee +++ b/resources/assets/scripts/app/controllers/album.coffee @@ -21,8 +21,8 @@ window.pfm.preloaders['album'] = [ ] angular.module('ponyfm').controller "album", [ - '$scope', 'albums', '$state', 'playlists', 'auth', '$dialog' - ($scope, albums, $state, playlists, auth, $dialog) -> + '$scope', 'albums', '$state', 'playlists', 'auth', '$dialog', 'download-cached', '$window', '$timeout' + ($scope, albums, $state, playlists, auth, $dialog, cachedAlbum, $window, $timeout) -> album = null albums.fetch($state.params.id).done (albumResponse) -> @@ -40,4 +40,18 @@ angular.module('ponyfm').controller "album", [ if auth.data.isLogged playlists.refreshOwned().done (lists) -> $scope.playlists.push list for list in lists + + $scope.getCachedAlbum = (id, format) -> + $scope.isEncoding = true + + cachedAlbum.download('albums', id, format).then (response) -> + albumUrl = response + $scope.albumUrl = albumUrl + if albumUrl == 'error' + $scope.isEncoding = false + else if albumUrl == 'pending' + $timeout $scope.getCachedAlbum(id, format), 5000 + else + $scope.isEncoding = false + $window.open albumUrl, '_blank' ] diff --git a/resources/assets/scripts/app/controllers/track.coffee b/resources/assets/scripts/app/controllers/track.coffee index 2ebe9246..76cb49fb 100644 --- a/resources/assets/scripts/app/controllers/track.coffee +++ b/resources/assets/scripts/app/controllers/track.coffee @@ -21,8 +21,8 @@ window.pfm.preloaders['track'] = [ ] angular.module('ponyfm').controller "track", [ - '$scope', 'tracks', '$state', 'playlists', 'auth', 'favourites', '$dialog' - ($scope, tracks, $state, playlists, auth, favourites, $dialog) -> + '$scope', 'tracks', '$state', 'playlists', 'auth', 'favourites', '$dialog', 'download-cached', '$window', '$timeout' + ($scope, tracks, $state, playlists, auth, favourites, $dialog, cachedTrack, $window, $timeout) -> track = null tracks.fetch($state.params.id).done (trackResponse) -> @@ -72,4 +72,19 @@ angular.module('ponyfm').controller "track", [ playlists.addTrackToPlaylist(playlist.id, $scope.track.id).done (res) -> playlist.message = res.message + + $scope.getCachedTrack = (id, format) -> + $scope.isEncoding = true + + cachedTrack.download('tracks', id, format).then (response) -> + trackUrl = response + $scope.trackUrl = trackUrl + console.log(trackUrl); + if trackUrl == 'error' + $scope.isEncoding = false + else if trackUrl == 'pending' + $timeout $scope.getCachedTrack(id, format), 5000 + else + $scope.isEncoding = false + $window.open trackUrl, '_blank' ] From 7686533d64e2bd61074c3e7a83109c9be63fa5b7 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Thu, 29 Oct 2015 14:37:25 +0000 Subject: [PATCH 22/44] Implement templates for frontend --- public/templates/albums/show.html | 7 ++++++- public/templates/tracks/show.html | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/public/templates/albums/show.html b/public/templates/albums/show.html index ad2f7e06..9c5d64f5 100644 --- a/public/templates/albums/show.html +++ b/public/templates/albums/show.html @@ -5,7 +5,12 @@ Downloads
  • Share
  • diff --git a/public/templates/tracks/show.html b/public/templates/tracks/show.html index 8fce26d1..e01209aa 100644 --- a/public/templates/tracks/show.html +++ b/public/templates/tracks/show.html @@ -5,7 +5,12 @@ Downloads
  • Share
  • diff --git a/public/templates/tracks/show.html b/public/templates/tracks/show.html index e01209aa..9ef0ec11 100644 --- a/public/templates/tracks/show.html +++ b/public/templates/tracks/show.html @@ -5,12 +5,18 @@ Downloads