mirror of
https://github.com/Poniverse/Pony.fm.git
synced 2024-11-25 22:47:59 +01:00
#4: Implement cached playlist downloads
This commit is contained in:
parent
80ad614b5f
commit
6c5155f583
8 changed files with 149 additions and 22 deletions
|
@ -282,7 +282,7 @@ class Album extends Model
|
|||
return $trackCount;
|
||||
}
|
||||
|
||||
public function countCacheableTrackFiles($format)
|
||||
public function countCachedTrackFiles($format)
|
||||
{
|
||||
$cachedCount = 0;
|
||||
|
||||
|
|
|
@ -102,7 +102,7 @@ class AlbumsController extends ApiControllerBase
|
|||
|
||||
$trackCount = $album->countDownloadableTracks();
|
||||
try {
|
||||
$cachedCount = $album->countCacheableTrackFiles($format);
|
||||
$cachedCount = $album->countCachedTrackFiles($format);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->notFound('Track file in album not found!');
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
namespace Poniverse\Ponyfm\Http\Controllers\Api\Web;
|
||||
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Poniverse\Ponyfm\Commands\AddTrackToPlaylistCommand;
|
||||
use Poniverse\Ponyfm\Commands\CreatePlaylistCommand;
|
||||
use Poniverse\Ponyfm\Commands\DeletePlaylistCommand;
|
||||
|
@ -31,6 +32,7 @@ use Poniverse\Ponyfm\ResourceLogItem;
|
|||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
use Poniverse\Ponyfm\Track;
|
||||
|
||||
class PlaylistsController extends ApiControllerBase
|
||||
{
|
||||
|
@ -110,6 +112,40 @@ class PlaylistsController extends ApiControllerBase
|
|||
return Response::json(Playlist::mapPublicPlaylistShow($playlist), 200);
|
||||
}
|
||||
|
||||
public function getCachedPlaylist($id, $format)
|
||||
{
|
||||
// Validation
|
||||
try {
|
||||
$playlist = Playlist::with('tracks.trackFiles')->findOrFail($id);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->notFound('Playlist not found!');
|
||||
}
|
||||
|
||||
if ((!$playlist->is_public && !Auth::check()) || (!$playlist->is_public && ($playlist->user_id !== Auth::user()->id))) {
|
||||
return $this->notFound('Playlist not found!');
|
||||
}
|
||||
|
||||
if (!in_array($format, Track::$CacheableFormats)) {
|
||||
return $this->notFound('Format not found!');
|
||||
}
|
||||
|
||||
$trackCount = $playlist->countDownloadableTracks();
|
||||
try {
|
||||
$cachedCount = $playlist->countCachedTrackFiles($format);
|
||||
} catch (ModelNotFoundException $e) {
|
||||
return $this->notFound('Track file in playlist not found!');
|
||||
}
|
||||
|
||||
if ($trackCount === $cachedCount) {
|
||||
$url = $playlist->getDownloadUrl($format);
|
||||
} else {
|
||||
$playlist->encodeCacheableTrackFiles($format);
|
||||
$url = null;
|
||||
}
|
||||
|
||||
return Response::json(['url' => $url], 200);
|
||||
}
|
||||
|
||||
public function getPinned()
|
||||
{
|
||||
$query = Playlist
|
||||
|
|
|
@ -79,14 +79,15 @@ 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('/tracks/cached/{id}/{format}', 'Api\Web\TracksController@getCachedTrack')->where(['id' => '\d+', 'format' => '.+']);
|
||||
|
||||
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('/albums/cached/{id}/{format}', 'Api\Web\AlbumsController@getCachedAlbum')->where(['id' => '\d+', 'format' => '.+']);
|
||||
|
||||
Route::get('/playlists', 'Api\Web\PlaylistsController@getIndex');
|
||||
Route::get('/playlists/{id}', 'Api\Web\PlaylistsController@getShow')->where('id', '\d+');
|
||||
Route::get('/playlists/cached/{id}/{format}', 'Api\Web\PlaylistsController@getCachedPlaylist')->where(['id' => '\d+', 'format' => '.+']);
|
||||
|
||||
Route::get('/comments/{type}/{id}', 'Api\Web\CommentsController@getIndex')->where('id', '\d+');
|
||||
|
||||
|
|
|
@ -20,19 +20,23 @@
|
|||
|
||||
namespace Poniverse\Ponyfm;
|
||||
|
||||
use File;
|
||||
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\URL;
|
||||
use Poniverse\Ponyfm\Jobs\EncodeTrackFile;
|
||||
use Poniverse\Ponyfm\Traits\SlugTrait;
|
||||
|
||||
class Playlist extends Model
|
||||
{
|
||||
protected $table = 'playlists';
|
||||
use SoftDeletes, SlugTrait, DispatchesJobs;
|
||||
|
||||
use SoftDeletes, SlugTrait;
|
||||
protected $table = 'playlists';
|
||||
|
||||
protected $dates = ['deleted_at'];
|
||||
|
||||
|
@ -68,7 +72,8 @@ class Playlist extends Model
|
|||
'name' => $name,
|
||||
'extension' => $format['extension'],
|
||||
'url' => $playlist->getDownloadUrl($name),
|
||||
'size' => Helpers::formatBytes($playlist->getFilesize($name))
|
||||
'size' => Helpers::formatBytes($playlist->getFilesize($name)),
|
||||
'isCacheable' => (in_array($name, Track::$CacheableFormats) ? true : false)
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -104,25 +109,25 @@ class Playlist extends Model
|
|||
$userRow = $playlist->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) $playlist->id,
|
||||
'id' => (int)$playlist->id,
|
||||
'track_count' => $playlist->track_count,
|
||||
'title' => $playlist->title,
|
||||
'slug' => $playlist->slug,
|
||||
'created_at' => $playlist->created_at,
|
||||
'is_public' => (bool) $playlist->is_public,
|
||||
'is_public' => (bool)$playlist->is_public,
|
||||
'stats' => [
|
||||
'views' => (int) $playlist->view_count,
|
||||
'downloads' => (int) $playlist->download_count,
|
||||
'comments' => (int) $playlist->comment_count,
|
||||
'favourites' => (int) $playlist->favourite_count
|
||||
'views' => (int)$playlist->view_count,
|
||||
'downloads' => (int)$playlist->download_count,
|
||||
'comments' => (int)$playlist->comment_count,
|
||||
'favourites' => (int)$playlist->favourite_count
|
||||
],
|
||||
'covers' => [
|
||||
'small' => $playlist->getCoverUrl(Image::SMALL),
|
||||
|
@ -130,7 +135,7 @@ class Playlist extends Model
|
|||
],
|
||||
'url' => $playlist->url,
|
||||
'user' => [
|
||||
'id' => (int) $playlist->user->id,
|
||||
'id' => (int)$playlist->user->id,
|
||||
'name' => $playlist->user->display_name,
|
||||
'url' => $playlist->user->url,
|
||||
],
|
||||
|
@ -197,6 +202,63 @@ class Playlist extends Model
|
|||
return URL::to('p' . $this->id . '/dl.' . Track::$Formats[$format]['extension']);
|
||||
}
|
||||
|
||||
public function countDownloadableTracks()
|
||||
{
|
||||
$trackCount = 0;
|
||||
|
||||
foreach ($this->tracks as $track) {
|
||||
if ($track->is_downloadable == true) {
|
||||
$trackCount++;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return $trackCount;
|
||||
}
|
||||
|
||||
public function countCachedTrackFiles($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 getFilesize($format)
|
||||
{
|
||||
$tracks = $this->tracks;
|
||||
|
@ -207,7 +269,10 @@ class Playlist extends Model
|
|||
return Cache::remember($this->getCacheKey('filesize-' . $format), 1440, function () use ($tracks, $format) {
|
||||
$size = 0;
|
||||
foreach ($tracks as $track) {
|
||||
$size += $track->getFilesize($format);
|
||||
// Ensure that only downloadable tracks are added onto the file size
|
||||
if ($track->is_downloadable == 1) {
|
||||
$size += $track->getFilesize($format);
|
||||
}
|
||||
}
|
||||
|
||||
return $size;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
</a>
|
||||
</li>
|
||||
<li ng-show="isInProgress" class="cache-loading"><img src="/images/loading.gif" /></li>
|
||||
<li ng-show="isInProgress" class="cache-loading"><small>We're getting your download ready! This may take up to a few minutes .</small></li>
|
||||
<li ng-show="isInProgress" class="cache-loading"><small>We're getting your download ready! This may take up to a few minutes.</small></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#" class="btn" pfm-eat-click ng-click="share()">Share</a></li>
|
||||
|
|
|
@ -5,7 +5,18 @@
|
|||
Downloads
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li bindonce ng-repeat="format in playlist.formats"><a target="_blank" bo-href="format.url"><span bo-text="format.name"></span> <small bo-text="'(' + format.size + ')'"></small></a></li>
|
||||
<li bindonce ng-repeat="format in playlist.formats" ng-hide="isInProgress">
|
||||
<a target="_blank" ng-if="!format.isCacheable" bo-href="format.url">
|
||||
<span bo-text="format.name"></span>
|
||||
<small bo-text="'(' + format.size + ')'"></small>
|
||||
</a>
|
||||
<a ng-if="format.isCacheable" ng-click="getCachedPlaylist(playlist.id, format.name);" href="">
|
||||
<span bo-text="format.name"></span>
|
||||
<small bo-text="'(' + format.size + ')'"></small>
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="isInProgress" class="cache-loading"><img src="/images/loading.gif" /></li>
|
||||
<li ng-show="isInProgress" class="cache-loading"><small>We're getting your download ready! This may take up to a few minutes.</small></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#" class="btn" pfm-eat-click ng-click="share()">Share</a></li>
|
||||
|
|
|
@ -21,8 +21,8 @@ window.pfm.preloaders['playlist'] = [
|
|||
]
|
||||
|
||||
angular.module('ponyfm').controller 'playlist', [
|
||||
'$scope', '$state', 'playlists', '$dialog'
|
||||
($scope, $state, playlists, $dialog) ->
|
||||
'$scope', '$state', 'playlists', '$dialog', 'download-cached', '$window', '$timeout'
|
||||
($scope, $state, playlists, $dialog, cachedPlaylist, $window, $timeout) ->
|
||||
playlist = null
|
||||
|
||||
playlists.fetch($state.params.id).done (playlistResponse) ->
|
||||
|
@ -34,4 +34,18 @@ angular.module('ponyfm').controller 'playlist', [
|
|||
templateUrl: '/templates/partials/playlist-share-dialog.html',
|
||||
controller: ['$scope', ($scope) -> $scope.playlist = playlist; $scope.close = () -> dialog.close()]
|
||||
dialog.open()
|
||||
|
||||
$scope.getCachedPlaylist = (id, format) ->
|
||||
$scope.isInProgress = true
|
||||
|
||||
cachedPlaylist.download('playlists', id, format).then (response) ->
|
||||
$scope.playlistUrl = response
|
||||
if $scope.playlistUrl == 'error'
|
||||
$scope.isInProgress = false
|
||||
else if $scope.playlistUrl == 'pending'
|
||||
$timeout $scope.getCachedPlaylist(id, format), 5000
|
||||
else
|
||||
$scope.isInProgress = false
|
||||
$window.open $scope.playlistUrl
|
||||
]
|
||||
|
||||
|
|
Loading…
Reference in a new issue