diff --git a/app/Album.php b/app/Album.php index 3a2b627a..a6b8c7be 100644 --- a/app/Album.php +++ b/app/Album.php @@ -21,17 +21,21 @@ namespace Poniverse\Ponyfm; use Exception; +use Helpers; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Cache; +use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\URL; +use Poniverse\Ponyfm\Jobs\EncodeTrackFile; use Poniverse\Ponyfm\Traits\SlugTrait; -use Helpers; class Album extends Model { - use SoftDeletes, SlugTrait; + use SoftDeletes, SlugTrait, DispatchesJobs; protected $dates = ['deleted_at']; @@ -100,7 +104,7 @@ class Album extends Model 'extension' => $format['extension'], 'url' => $album->getDownloadUrl($name), 'size' => Helpers::formatBytes($album->getFilesize($name)), - 'isCacheable' => (in_array($name, array_keys(Track::$CacheableFormats)) ? true : false) + 'isCacheable' => (in_array($name, Track::$CacheableFormats) ? true : false) ]; } @@ -146,24 +150,24 @@ class Album extends Model $userRow = $album->users[0]; $userData = [ 'stats' => [ - 'views' => (int) $userRow->view_count, - 'downloads' => (int) $userRow->download_count, + 'views' => (int)$userRow->view_count, + 'downloads' => (int)$userRow->download_count, ], - 'is_favourited' => (bool) $userRow->is_favourited + 'is_favourited' => (bool)$userRow->is_favourited ]; } return [ - 'id' => (int) $album->id, - 'track_count' => (int) $album->track_count, + 'id' => (int)$album->id, + 'track_count' => (int)$album->track_count, 'title' => $album->title, 'slug' => $album->slug, 'created_at' => $album->created_at, 'stats' => [ - 'views' => (int) $album->view_count, - 'downloads' => (int) $album->download_count, - 'comments' => (int) $album->comment_count, - 'favourites' => (int) $album->favourite_count + 'views' => (int)$album->view_count, + 'downloads' => (int)$album->download_count, + 'comments' => (int)$album->comment_count, + 'favourites' => (int)$album->favourite_count ], 'covers' => [ 'small' => $album->getCoverUrl(Image::SMALL), @@ -171,7 +175,7 @@ class Album extends Model ], 'url' => $album->url, 'user' => [ - 'id' => (int) $album->user->id, + 'id' => (int)$album->user->id, 'name' => $album->user->display_name, 'url' => $album->user->url, ], @@ -263,6 +267,63 @@ class Album extends Model } } + public function countDownloadableTracks() + { + $trackCount = 0; + + foreach ($this->tracks as $track) { + if ($track->is_downloadable == true) { + $trackCount++; + } else { + continue; + } + } + + return $trackCount; + } + + public function countCacheableTrackFiles($format) + { + $cachedCount = 0; + + foreach ($this->tracks as $track) { + if ($track->is_downloadable == false) { + continue; + } + + try { + $trackFile = $track->trackFiles()->where('format', $format)->firstOrFail(); + } catch (ModelNotFoundException $e) { + throw $e; + } + + if ($trackFile->expires_at != null && File::exists($trackFile->getFile())) { + $cachedCount++; + } + } + + return $cachedCount; + } + + public function encodeCacheableTrackFiles($format) + { + foreach ($this->tracks as $track) { + if ($track->is_downloadable == false) { + continue; + } + + try { + $trackFile = $track->trackFiles()->where('format', $format)->firstOrFail(); + } catch (ModelNotFoundException $e) { + throw $e; + } + + if (!File::exists($trackFile->getFile()) && $trackFile->is_in_progress != true) { + $this->dispatch(new EncodeTrackFile($trackFile, true)); + } + } + } + public function syncTrackIds($trackIds) { $trackIdsInAlbum = []; @@ -332,7 +393,7 @@ class Album extends Model } } - private function getCacheKey($key) + public function getCacheKey($key) { return 'album-' . $this->id . '-' . $key; } diff --git a/app/Commands/UploadTrackCommand.php b/app/Commands/UploadTrackCommand.php index ca14bc09..776c440f 100644 --- a/app/Commands/UploadTrackCommand.php +++ b/app/Commands/UploadTrackCommand.php @@ -136,7 +136,7 @@ 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) { + if (in_array($name, Track::$CacheableFormats) && $trackFile->is_master == false) { $trackFile->is_cacheable = true; } else { $trackFile->is_cacheable = false; @@ -144,7 +144,7 @@ class UploadTrackCommand extends CommandBase $track->trackFiles()->save($trackFile); // Encode track file - $target = $destination . '/' . $trackFile->getFilename(); + $target = $trackFile->getFile(); $command = $format['command']; $command = str_replace('{$source}', '"' . $source . '"', $command); @@ -161,7 +161,7 @@ class UploadTrackCommand extends CommandBase // Delete track file if it is cacheable if ($trackFile->is_cacheable == true) { - \Illuminate\Support\Facades\File::delete($trackFile->getFile()); + File::delete($trackFile->getFile()); } } diff --git a/app/Console/Commands/ClearTrackCache.php b/app/Console/Commands/ClearTrackCache.php index 10f14932..5c5feea1 100644 --- a/app/Console/Commands/ClearTrackCache.php +++ b/app/Console/Commands/ClearTrackCache.php @@ -60,45 +60,45 @@ class ClearTrackCache extends Command */ public function handle() { - if ($this->option('tracks') == 'all') { - // Get all cacheable tracks - $trackFiles = TrackFile::where('is_cacheable', true)->get(); - } else { - // Get all expired tracks + if ($this->option('tracks') === 'all') { + // Get all cacheable track files $trackFiles = TrackFile::where('is_cacheable', true) - ->where('expiration', '<=', Carbon::now()) + ->with('track.album') + ->get(); + } else { + // Get all expired track files + $trackFiles = TrackFile::where('is_cacheable', true) + ->where('expires_at', '<=', Carbon::now()) + ->with('track.album') ->get(); - } - // Delete above tracks + // Delete above track files 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)) { + if ($this->option('force') || $this->confirm(count($trackFiles) . ' cacheable track files found. Proceed to delete their files if they exist? [y|N]', false)) { $count = 0; foreach ($trackFiles as $trackFile) { // Set expiration to null (so can be re-cached upon request) - $trackFile->expiration = null; + $trackFile->expires_at = null; $trackFile->update(); - // Delete files if exists + // Delete file 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()); } + // Remove the cached file size for the album + Cache::forget($trackFile->track->album->getCacheKey('filesize-' . $trackFile->format)); + } $this->info($count . ' files deleted. Deletion complete. Exiting.'); } else { diff --git a/app/Console/Commands/RebuildFilesizes.php b/app/Console/Commands/RebuildFilesizes.php index 6678aff8..3d81a34a 100644 --- a/app/Console/Commands/RebuildFilesizes.php +++ b/app/Console/Commands/RebuildFilesizes.php @@ -21,7 +21,6 @@ namespace Poniverse\Ponyfm\Console\Commands; use Illuminate\Console\Command; -use Illuminate\Support\Facades\File; use Poniverse\Ponyfm\TrackFile; class RebuildFilesizes extends Command @@ -68,18 +67,12 @@ class RebuildFilesizes extends Command $this->info('========== Start Chunk =========='); foreach ($trackFiles as $trackFile) { - $file = $trackFile->getFile(); - - if (File::exists($file)) { - $size = File::size($file); + $size = $trackFile->updateFilesize(); + if ($size !== null) { $this->info('ID ' . $trackFile->id . ' processed - ' . $size . ' bytes'); } else { - $size = null; $this->info('ID ' . $trackFile->id . ' skipped'); } - - $trackFile->filesize = $size; - $trackFile->update(); } $this->info('=========== End Chunk ==========='); diff --git a/app/Console/Commands/RebuildTrackCache.php b/app/Console/Commands/RebuildTrackCache.php index 3eb461fb..510236ba 100644 --- a/app/Console/Commands/RebuildTrackCache.php +++ b/app/Console/Commands/RebuildTrackCache.php @@ -63,154 +63,192 @@ class RebuildTrackCache extends Command */ public function handle() { - $this->info('This will run \'php artisan down\' if you proceed and \'php artisan up\' when complete.'); $this->info('***'); - $this->info('If this is your first time running this command, it is *highly* recommended that you run `php artisan filesize:rebuild` to cache file sizes for all files before they are deleted.'); + $this->info('If this is your first time running this command, it is *highly* recommended that you ensure the file sizes for all track files have been populated.'); $this->info('***'); - 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]', + if ($this->option('force') || $this->confirm('Are you sure you want to delete all to-be-cached track files and encode missing non-cached track files?', false) ) { - $this->call('down'); - //========================================================================================================== - // Delete previously cached tracks + // Delete previously cached track files //========================================================================================================== - // Find files which are cacheable and NOT master - $trackFiles = TrackFile::where('is_cacheable', true) + $this->output->newLine(1); + $this->info('========== Step 1/4 - Deleting previously cached track files. =========='); + + $count = 0; + + // Chunk track files which are cacheable and NOT master + TrackFile::where('is_cacheable', true) ->where('is_master', false) - ->get(); + ->chunk(200, function ($trackFiles) use (&$count) { + // Delete chunked track files + foreach ($trackFiles as $trackFile) { + // Clear expiration so will be re-cached on next request + $trackFile->expires_at = null; + $trackFile->update(); - // 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()); + // 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.'); - } + $this->info($count . ' track files deleted. Deletion complete. Continuing.'); + }); //========================================================================================================== - // Update the database entries for cacheable files - non-cacheable to cacheable + // Update the database entries for cacheable track 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(); + $this->output->newLine(3); + $this->info('========== Step 2/4 - Updating is_cacheable entries in database. =========='); + $trackFileCount = 0; $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; + // Find track files which are meant to be cacheable and NOT master, but currently not cacheable + TrackFile::where('is_cacheable', false) + ->whereIn('format', Track::$CacheableFormats) + ->where('is_master', false) + ->chunk(200, function ($trackFiles) use (&$trackFileCount, &$formats) { + $this->output->newLine(1); + $this->info('---------- Start Chunk ----------'); - $trackFile->expiration = null; - $trackFile->is_cacheable = true; - $trackFile->update(); - } + // Set above files to cacheable in the database + foreach ($trackFiles as $trackFile) { + $trackFileCount++; + + // Let user know which formats, previously not cached, were made cacheable + $formats[] = $trackFile->format; + + $trackFile->expires_at = null; + $trackFile->is_cacheable = true; + $trackFile->update(); + } + + $this->info('----------- End Chunk -----------'); + $this->output->newLine(1); + }); $this->info('Format(s) set from non-cacheable to cacheable: ' . implode(' ', array_unique($formats))); - $this->info(count($trackFiles) . ' non-cacheable tracks set to cacheable.'); + $this->info($trackFileCount . ' non-cacheable track files set to cacheable.'); + + $this->output->newLine(2); //========================================================================================================== - // Update the database entries for cacheable files - cacheable to non-cacheable + // Update the database entries for cacheable track 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(); - + $trackFileCount = 0; $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; + // Chunk track files which are NOT meant to be cacheable, but currently cacheable + TrackFile::where('is_cacheable', true) + ->whereNotIn('format', Track::$CacheableFormats) + ->chunk(200, function ($trackFiles) use (&$trackFileCount, &$formats) { + $this->output->newLine(1); + $this->info('---------- Start Chunk ----------'); + + // Set chunked track files to non-cacheable in the database + foreach ($trackFiles as $trackFile) { + $trackFileCount++; + + // Let user know which formats, previously not cached, were made cacheable + $formats[] = $trackFile->format; + + $trackFile->expires_at = null; + $trackFile->is_cacheable = false; + $trackFile->update(); + } + + $this->info('----------- End Chunk -----------'); + $this->output->newLine(1); + $this->output->newLine(1); + }); - $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.'); + $this->info($trackFileCount . ' cacheable track files set to non-cacheable.'); //========================================================================================================== - // Delete files which have now been marked as cacheable + // Delete track files which have now been marked as cacheable //========================================================================================================== - $this->info('--- Step 3/4 - Deleting now-cacheable files. ---'); + $this->output->newLine(3); + $this->info('========== Step 3/4 - Deleting now-cacheable track files. =========='); - // Find files which are cacheable and NOT master - $trackFiles = TrackFile::whereIn('format', array_keys(Track::$CacheableFormats)) + $count = 0; + $trackFileCount = 0; + + // Find track files which are cacheable and NOT master + TrackFile::whereIn('format', Track::$CacheableFormats) ->where('is_master', false) - ->get(); + ->chunk(200, function ($trackFiles) use (&$count, &$trackFileCount) { + $this->output->newLine(1); + $this->info('---------- Start Chunk ----------'); + + foreach ($trackFiles as $trackFile) { + $trackFileCount++; + + // Delete track files if track 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('----------- End Chunk -----------'); + $this->output->newLine(1); + }); + + + $this->info(sprintf('%d track files deleted out of %d track files. Continuing.', $count, $trackFileCount)); + + //========================================================================================================== + // Encode missing (i.e., now non-cacheable) track files + //========================================================================================================== + + $this->output->newLine(3); + $this->info('========== Step 4/4 - Encoding missing track files. =========='); + + $count = 0; + + // Chunk non-cacheable track files + TrackFile::where('is_cacheable', false)->chunk(200, function ($trackFiles) use (&$count) { + $this->output->newLine(1); + $this->info('---------- Start Chunk ----------'); + + // Record the track files which do not exist (i.e., have not been encoded yet) + $emptyTrackFiles = []; - // 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) { + if (!File::exists($trackFile->getFile())) { $count++; - File::delete($trackFile->getFile()); - $this->info('Deleted ' . $trackFile->getFile()); + $emptyTrackFiles[] = $trackFile; } } - $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) - $emptyTrackFiles = []; - $count = 0; - foreach ($trackFiles as $trackFile) { - if (!File::exists($trackFile->getFile())) { - $count++; - $emptyTrackFiles[] = $trackFile; + // Encode recorded track files + foreach ($emptyTrackFiles as $emptyTrackFile) { + $this->info("Started encoding track file ID {$emptyTrackFile->id}"); + $this->dispatch(new EncodeTrackFile($emptyTrackFile, false)); } - } - // Encode recorded files - foreach ($emptyTrackFiles as $emptyTrackFile) { - $this->dispatch(new EncodeTrackFile($emptyTrackFile, false)); - } + $this->info('----------- End Chunk -----------'); + $this->output->newLine(1); + }); - $this->info($count . ' tracks encoded.'); - $this->call('up'); + $this->info($count . ' track files encoded.'); + $this->output->newLine(1); + $this->info('Rebuild complete. Exiting.'); } else { diff --git a/app/Http/Controllers/Api/Web/AlbumsController.php b/app/Http/Controllers/Api/Web/AlbumsController.php index fb9bee96..c2536145 100644 --- a/app/Http/Controllers/Api/Web/AlbumsController.php +++ b/app/Http/Controllers/Api/Web/AlbumsController.php @@ -21,6 +21,7 @@ namespace Poniverse\Ponyfm\Http\Controllers\Api\Web; use Illuminate\Database\Eloquent\ModelNotFoundException; +use Illuminate\Support\Facades\File; use Poniverse\Ponyfm\Album; use Poniverse\Ponyfm\Commands\CreateAlbumCommand; use Poniverse\Ponyfm\Commands\DeleteAlbumCommand; @@ -90,43 +91,26 @@ class AlbumsController extends ApiControllerBase { // Validation try { - $album = Album::findOrFail($id); + $album = Album::with('tracks.trackFiles')->findOrFail($id); } catch (ModelNotFoundException $e) { return $this->notFound('Album not found!'); } - if (!array_key_exists($format, Track::$CacheableFormats)) { + if (!in_array($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)); - } + $trackCount = $album->countDownloadableTracks(); + try { + $cachedCount = $album->countCacheableTrackFiles($format); + } catch (ModelNotFoundException $e) { + return $this->notFound('Track file in album not found!'); } if ($trackCount === $cachedCount) { $url = $album->getDownloadUrl($format); } else { + $album->encodeCacheableTrackFiles($format); $url = null; } diff --git a/app/Http/Controllers/Api/Web/TracksController.php b/app/Http/Controllers/Api/Web/TracksController.php index ca2913a0..81fefdce 100644 --- a/app/Http/Controllers/Api/Web/TracksController.php +++ b/app/Http/Controllers/Api/Web/TracksController.php @@ -85,7 +85,10 @@ class TracksController extends ApiControllerBase if (!$track->canView(Auth::user())) return $this->notFound('Track not found!'); - if (!in_array($format, array_keys(Track::$CacheableFormats))) { + if ($track->is_downloadable == false) + return $this->notFound('Track not found!'); + + if (!in_array($format, Track::$CacheableFormats)) { return $this->notFound('Format not found!'); } @@ -96,9 +99,9 @@ class TracksController extends ApiControllerBase } // Return URL or begin encoding - if ($trackFile->expiration != null && File::exists($trackFile->getFile())) { + if ($trackFile->expires_at != null && File::exists($trackFile->getFile())) { $url = $track->getUrlFor($format); - } elseif ($trackFile->in_progress === true) { + } elseif ($trackFile->is_in_progress === true) { $url = null; } else { $this->dispatch(new EncodeTrackFile($trackFile, true)); diff --git a/app/Jobs/EncodeTrackFile.php b/app/Jobs/EncodeTrackFile.php index b178aec6..9f535517 100644 --- a/app/Jobs/EncodeTrackFile.php +++ b/app/Jobs/EncodeTrackFile.php @@ -65,10 +65,10 @@ class EncodeTrackFile extends Job implements SelfHandling, ShouldQueue public function handle() { // Start the job - $this->trackFile->in_progress = true; + $this->trackFile->is_in_progress = true; $this->trackFile->update(); - // Assign the source to the track's master file + // Use the track's master file as the source $source = TrackFile::where('track_id', $this->trackFile->track_id) ->where('is_master', true) ->first() @@ -77,7 +77,7 @@ class EncodeTrackFile extends Job implements SelfHandling, ShouldQueue // Assign the target $destination = $this->trackFile->track->getDirectory(); $this->trackFile->track->ensureDirectoryExists(); - $target = $destination . '/' . $this->trackFile->getFilename(); + $target = $this->trackFile->getFile(); // Prepare the command $format = Track::$Formats[$this->trackFile->format]; @@ -100,21 +100,20 @@ class EncodeTrackFile extends Job implements SelfHandling, ShouldQueue } // Update the tags of the track - $this->trackFile->track->updateTags(); + $this->trackFile->track->updateTags($this->trackFile->format); // Insert the expiration time for cached tracks if ($this->isExpirable) { - $this->trackFile->expiration = Carbon::now()->addMinutes(Config::get('ponyfm.cache_duration')); + $this->trackFile->expires_at = Carbon::now()->addMinutes(Config::get('ponyfm.track_file_cache_duration')); $this->trackFile->update(); } - // Complete the job - $this->trackFile->in_progress = false; - $this->trackFile->update(); - // Update file size $this->trackFile->updateFilesize(); + // Complete the job + $this->trackFile->is_in_progress = false; + $this->trackFile->update(); } /** @@ -124,8 +123,8 @@ class EncodeTrackFile extends Job implements SelfHandling, ShouldQueue */ public function failed() { - $this->trackFile->in_progress = false; - $this->trackFile->expiration = null; + $this->trackFile->is_in_progress = false; + $this->trackFile->expires_at = null; $this->trackFile->update(); } } diff --git a/app/Track.php b/app/Track.php index 18b1027e..352d54a5 100644 --- a/app/Track.php +++ b/app/Track.php @@ -20,20 +20,20 @@ namespace Poniverse\Ponyfm; -use Poniverse\Ponyfm\Traits\SlugTrait; +use Auth; +use Cache; +use Config; +use DB; use Exception; use External; use getid3_writetags; use Helpers; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; -use Auth; -use Cache; -use Config; -use DB; -use Log; -use URL; use Illuminate\Support\Str; +use Log; +use Poniverse\Ponyfm\Traits\SlugTrait; +use URL; class Track extends Model { @@ -94,29 +94,14 @@ 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}' - ], + 'OGG Vorbis', + 'ALAC', ]; public static function summary() { - return self::select('tracks.id', 'title', 'user_id', 'slug', 'is_vocal', 'is_explicit', 'created_at', 'published_at', + return self::select('tracks.id', 'title', 'user_id', 'slug', 'is_vocal', 'is_explicit', 'created_at', + 'published_at', 'duration', 'is_downloadable', 'genre_id', 'track_type_id', 'cover_id', 'album_id', 'comment_count', 'download_count', 'view_count', 'play_count', 'favourite_count'); } @@ -269,41 +254,41 @@ class Track extends Model $userRow = $track->users[0]; $userData = [ 'stats' => [ - 'views' => (int) $userRow->view_count, - 'plays' => (int) $userRow->play_count, + 'views' => (int)$userRow->view_count, + 'plays' => (int)$userRow->play_count, 'downloads' => $userRow->download_count, ], - 'is_favourited' => (bool) $userRow->is_favourited + 'is_favourited' => (bool)$userRow->is_favourited ]; } return [ - 'id' => (int) $track->id, + 'id' => (int)$track->id, 'title' => $track->title, 'user' => [ - 'id' => (int) $track->user->id, + 'id' => (int)$track->user->id, 'name' => $track->user->display_name, 'url' => $track->user->url ], 'stats' => [ - 'views' => (int) $track->view_count, - 'plays' => (int) $track->play_count, - 'downloads' => (int) $track->download_count, - 'comments' => (int) $track->comment_count, - 'favourites' => (int) $track->favourite_count + 'views' => (int)$track->view_count, + 'plays' => (int)$track->play_count, + 'downloads' => (int)$track->download_count, + 'comments' => (int)$track->comment_count, + 'favourites' => (int)$track->favourite_count ], 'url' => $track->url, 'slug' => $track->slug, - 'is_vocal' => (bool) $track->is_vocal, - 'is_explicit' => (bool) $track->is_explicit, - 'is_downloadable' => (bool) $track->is_downloadable, - 'is_published' => (bool) $track->isPublished(), + 'is_vocal' => (bool)$track->is_vocal, + 'is_explicit' => (bool)$track->is_explicit, + 'is_downloadable' => (bool)$track->is_downloadable, + 'is_published' => (bool)$track->isPublished(), 'published_at' => $track->published_at, 'duration' => $track->duration, 'genre' => $track->genre != null ? [ - 'id' => (int) $track->genre->id, + 'id' => (int)$track->genre->id, 'slug' => $track->genre->slug, 'name' => $track->genre->name ] : null, @@ -571,11 +556,22 @@ class Track extends Model $this->hash = md5(Helpers::sanitizeInputForHashing($this->user->display_name) . ' - ' . Helpers::sanitizeInputForHashing($this->title)); } - public function updateTags() + public function updateTags($trackFileFormat = 'all') { - $this->trackFiles()->touch(); + if ($trackFileFormat === 'all') { + foreach ($this->trackFiles as $trackFile) { + $this->updateTagsForTrackFile($trackFile); + } + } else { + $trackFile = $this->trackFiles()->where('format', $trackFileFormat)->firstOrFail(); + $this->updateTagsForTrackFile($trackFile); + } + } - foreach ($this->trackFiles as $trackFile) { + private function updateTagsForTrackFile($trackFile) { + $trackFile->touch(); + + if (\File::exists($trackFile->getFile())) { $format = $trackFile->format; $data = self::$Formats[$format]; @@ -654,10 +650,12 @@ class Track extends Model if ($tagWriter->WriteTags()) { if (!empty($tagWriter->warnings)) { - Log::warning('Track #'.$this->id.': There were some warnings:
' . implode('

', $tagWriter->warnings)); + Log::warning('Track #' . $this->id . ': There were some warnings:
' . implode('

', + $tagWriter->warnings)); } } else { - Log::error('Track #' . $this->id . ': Failed to write tags!
' . implode('

', $tagWriter->errors)); + Log::error('Track #' . $this->id . ': Failed to write tags!
' . implode('

', + $tagWriter->errors)); } } diff --git a/app/TrackFile.php b/app/TrackFile.php index 8a1df20d..e1cf52bf 100644 --- a/app/TrackFile.php +++ b/app/TrackFile.php @@ -139,5 +139,7 @@ class TrackFile extends Model $this->filesize = $size; $this->update(); + + return $size; } } diff --git a/config/ponyfm.php b/config/ponyfm.php index 7ae9f250..1470dcd4 100644 --- a/config/ponyfm.php +++ b/config/ponyfm.php @@ -59,10 +59,10 @@ return [ | Cache Duration |-------------------------------------------------------------------------- | - | Duration in minutes for tracks to be stored in cache. + | Duration in minutes for track files to be stored in cache. | */ - 'cache_duration' => 1440, + 'track_file_cache_duration' => 1440, ]; 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 69aff5a1..746f5bce 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('is_in_progress')->default(false); + $table->dateTime('expires_at')->nullable(); }); } diff --git a/database/migrations/2015_10_29_153827_update_track_files_with_filesize.php b/database/migrations/2015_10_29_153827_update_track_files_with_filesize.php index d62a4244..70f80ef4 100644 --- a/database/migrations/2015_10_29_153827_update_track_files_with_filesize.php +++ b/database/migrations/2015_10_29_153827_update_track_files_with_filesize.php @@ -18,8 +18,9 @@ * along with this program. If not, see . */ -use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Artisan; class UpdateTrackFilesWithFilesize extends Migration { @@ -33,6 +34,11 @@ class UpdateTrackFilesWithFilesize extends Migration Schema::table('track_files', function (Blueprint $table) { $table->integer('filesize')->nullable()->unsigned(); }); + + // Populate file sizes + Artisan::call('rebuild:filesizes', [ + '--force' => true, + ]); } /** diff --git a/public/templates/albums/show.html b/public/templates/albums/show.html index 9c5d64f5..ea5c3c5f 100644 --- a/public/templates/albums/show.html +++ b/public/templates/albums/show.html @@ -5,12 +5,18 @@ 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