Finished basic stats for tracks, playlists and albums

Finished downloading for albums and playlists
This commit is contained in:
nelsonlaquet 2013-08-18 23:19:04 -05:00
parent 2046b8e98d
commit 1c4bc006b7
9 changed files with 201 additions and 58 deletions

View file

@ -10,6 +10,7 @@
use Entities\Comment; use Entities\Comment;
use Entities\Image; use Entities\Image;
use Entities\Playlist; use Entities\Playlist;
use Entities\ResourceLogItem;
use Entities\Track; use Entities\Track;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Input; use Illuminate\Support\Facades\Input;
@ -33,64 +34,38 @@
} }
public function getShow($id) { public function getShow($id) {
$playlist = Playlist::with(['tracks' => function($query) { $query->details(); }, 'comments' => function($query) { $query->with('user'); }])->find($id); $playlist = Playlist::with(['tracks.user', 'tracks' => function($query) { $query->details(); }, 'comments', 'comments.user'])->details()->find($id);
if (!$playlist || !$playlist->canView(Auth::user())) if (!$playlist || !$playlist->canView(Auth::user()))
App::abort('404'); App::abort('404');
$tracks = []; if (Input::get('log')) {
foreach ($playlist->tracks as $track) { ResourceLogItem::logItem('playlist', $id, ResourceLogItem::VIEW);
$tracks[] = Track::mapPublicTrackSummary($track); $playlist->view_count++;
} }
$comments = []; return Response::json(Playlist::mapPublicPlaylistShow($playlist), 200);
foreach ($playlist->comments as $comment) {
$comments[] = Comment::mapPublic($comment);
}
return Response::json([
'id' => $playlist->id,
'title' => $playlist->title,
'description' => $playlist->description,
'slug' => $playlist->slug,
'created_at' => $playlist->created_at,
'url' => $playlist->url,
'covers' => [
'small' => $playlist->getCoverUrl(Image::SMALL),
'normal' => $playlist->getCoverUrl(Image::NORMAL)
],
'is_pinned' => true,
'is_public' => $playlist->is_public == 1,
'tracks' => $tracks,
'comments' => ['count' => count($comments), 'list' => $comments],
], 200);
} }
public function getPinned() { public function getPinned() {
$query = Playlist::join('pinned_playlists', function($join) { $query = Playlist
$join->on('playlist_id', '=', 'playlists.id'); ::with(['tracks.user', 'tracks' => function($query) {}, 'comments', 'comments.user'])
}) ->details()
->join('pinned_playlists', function($join) {
$join->on('playlist_id', '=', 'playlists.id');
})
->where('pinned_playlists.user_id', '=', Auth::user()->id) ->where('pinned_playlists.user_id', '=', Auth::user()->id)
->orderBy('title', 'asc') ->orderBy('title', 'asc')
->select('playlists.id', 'playlists.title', 'playlists.slug', 'playlists.created_at', 'playlists.user_id', 'playlists.is_public', 'playlists.description') ->select('playlists.*')
->get(); ->get();
$playlists = []; $playlists = [];
foreach ($query as $playlist) { foreach ($query as $playlist) {
$playlists[] = [ $mapped = Playlist::mapPublicPlaylistSummary($playlist);
'id' => $playlist->id, $mapped['description'] = $playlist->description;
'title' => $playlist->title, $mapped['is_pinned'] = true;
'description' => $playlist->description, $playlists[] = $mapped;
'slug' => $playlist->slug,
'created_at' => $playlist->created_at,
'url' => $playlist->url,
'covers' => [
'small' => $playlist->getCoverUrl(Image::SMALL),
'normal' => $playlist->getCoverUrl(Image::NORMAL)
],
'is_pinned' => true,
'is_public' => $playlist->is_public == 1
];
} }
return Response::json($playlists, 200); return Response::json($playlists, 200);
} }

View file

@ -1,6 +1,8 @@
<?php <?php
use Entities\Playlist; use Entities\Playlist;
use Entities\ResourceLogItem;
use Entities\Track;
use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\Redirect;
class PlaylistsController extends Controller { class PlaylistsController extends Controller {
@ -26,4 +28,28 @@
return Redirect::action('PlaylistsController@getPlaylist', [$id, $playlist->slug]); return Redirect::action('PlaylistsController@getPlaylist', [$id, $playlist->slug]);
} }
public function getDownload($id, $extension) {
$playlist = Playlist::with('tracks', 'user', 'tracks.album')->find($id);
if (!$playlist || !$playlist->is_public)
App::abort(404);
$format = null;
$formatName = null;
foreach (Track::$Formats as $name => $item) {
if ($item['extension'] == $extension) {
$format = $item;
$formatName = $name;
break;
}
}
if ($format == null)
App::abort(404);
ResourceLogItem::logItem('playlist', $id, ResourceLogItem::DOWNLOAD, $format['index']);
$downloader = new PlaylistDownloader($playlist, $formatName);
$downloader->download();
}
} }

View file

@ -106,7 +106,7 @@
return [ return [
'id' => $album->id, 'id' => $album->id,
'track_count' => $album->tracks->count(), 'track_count' => $album->tracks()->count(),
'title' => $album->title, 'title' => $album->title,
'slug' => $album->slug, 'slug' => $album->slug,
'created_at' => $album->created_at, 'created_at' => $album->created_at,

View file

@ -1,6 +1,10 @@
<?php <?php
namespace Entities; namespace Entities;
use Helpers;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\URL;
use Traits\SlugTrait; use Traits\SlugTrait;
class Playlist extends \Eloquent { class Playlist extends \Eloquent {
@ -10,7 +14,93 @@
use SlugTrait; use SlugTrait;
public static function summary() { public static function summary() {
return self::select('id', 'title', 'user_id', 'slug', 'created_at', 'is_public', 'description'); return self::select('id', 'title', 'user_id', 'slug', 'created_at', 'is_public', 'description', 'comment_count', 'download_count', 'view_count', 'favourite_count');
}
public function scopeDetails($query) {
if (Auth::check()) {
$query->with(['users' => function($query) {
$query->whereUserId(Auth::user()->id);
}]);
}
return !$query;
}
public static function mapPublicPlaylistShow($playlist) {
$tracks = [];
foreach ($playlist->tracks as $track) {
$tracks[] = Track::mapPublicTrackSummary($track);
}
$formats = [];
foreach (Track::$Formats as $name => $format) {
$formats[] = [
'name' => $name,
'extension' => $format['extension'],
'url' => $playlist->getDownloadUrl($name),
'size' => Helpers::formatBytes($playlist->getFilesize($name))
];
}
$comments = [];
foreach ($playlist->comments as $comment) {
$comments[] = Comment::mapPublic($comment);
}
$data = self::mapPublicPlaylistSummary($playlist);
$data['tracks'] = $tracks;
$data['comments'] = $comments;
$data['formats'] = $formats;
return $data;
}
public static function mapPublicPlaylistSummary($playlist) {
$userData = [
'stats' => [
'views' => 0,
'downloads' => 0
],
'is_favourited' => false
];
if ($playlist->users->count()) {
$userRow = $playlist->users[0];
$userData = [
'stats' => [
'views' => $userRow->view_count,
'downloads' => $userRow->download_count,
],
'is_favourited' => $userRow->is_favourited
];
}
return [
'id' => $playlist->id,
'track_count' => $playlist->tracks->count(),
'title' => $playlist->title,
'slug' => $playlist->slug,
'created_at' => $playlist->created_at,
'is_public' => $playlist->is_public,
'stats' => [
'views' => $playlist->view_count,
'downloads' => $playlist->download_count,
'comments' => $playlist->comment_count,
'favourites' => $playlist->favourite_count
],
'covers' => [
'small' => $playlist->getCoverUrl(Image::SMALL),
'normal' => $playlist->getCoverUrl(Image::NORMAL)
],
'url' => $playlist->url,
'user' => [
'id' => $playlist->user->id,
'name' => $playlist->user->display_name,
'url' => $playlist->user->url,
],
'user_data' => $userData
];
} }
public function tracks() { public function tracks() {
@ -21,6 +111,10 @@
->orderBy('position', 'asc'); ->orderBy('position', 'asc');
} }
public function users() {
return $this->hasMany('Entities\ResourceUser');
}
public function comments(){ public function comments(){
return $this->hasMany('Entities\Comment'); return $this->hasMany('Entities\Comment');
} }
@ -47,7 +141,26 @@
} }
public function getUrlAttribute() { public function getUrlAttribute() {
return '/playlist/' . $this->id . '-' . $this->slug; return URL::to('/playlist/' . $this->id . '-' . $this->slug);
}
public function getDownloadUrl($format) {
return URL::to('p' . $this->id . '/dl.' . Track::$Formats[$format]['extension']);
}
public function getFilesize($format) {
$tracks = $this->tracks()->get();
if (!count($tracks))
return 0;
return Cache::remember($this->getCacheKey('filesize-' . $format), 1440, function() use ($tracks, $format) {
$size = 0;
foreach ($tracks as $track) {
$size += $track->getFilesize($format);
}
return $size;
});
} }
public function getCoverUrl($type = Image::NORMAL) { public function getCoverUrl($type = Image::NORMAL) {
@ -63,4 +176,8 @@
$pin->user_id = $userId; $pin->user_id = $userId;
$pin->save(); $pin->save();
} }
private function getCacheKey($key) {
return 'album-' . $this->id . '-' . $key;
}
} }

View file

@ -245,6 +245,14 @@
return URL::to('/tracks/' . $this->id . '-' . $this->slug); return URL::to('/tracks/' . $this->id . '-' . $this->slug);
} }
public function getDownloadDirectoryAttribute() {
if ($this->album) {
return $this->user->display_name . '/' . $this->album->title;
}
return $this->user->display_name;
}
public function getReleaseDate() { public function getReleaseDate() {
if($this->attributes['released_at'] !== NULL) if($this->attributes['released_at'] !== NULL)
return $this->attributes['released_at']; return $this->attributes['released_at'];
@ -281,7 +289,7 @@
return $this->cover->getUrl($type); return $this->cover->getUrl($type);
} }
public function getStreamUrl($format) { public function getStreamUrl() {
return URL::to('/t' . $this->id . '/stream'); return URL::to('/t' . $this->id . '/stream');
} }

View file

@ -12,17 +12,15 @@
function download() { function download() {
$zip = new ZipStream($this->_playlist->user->display_name . ' - ' . $this->_playlist->title . '.zip'); $zip = new ZipStream($this->_playlist->user->display_name . ' - ' . $this->_playlist->title . '.zip');
$zip->setComment( $zip->setComment(
'Album: ' . $this->_playlist->title ."\r\n". 'Playlist: '. $this->_playlist->title ."\r\n".
'Artist: ' . $this->_playlist->user->display_name ."\r\n". 'Curator: ' . $this->_playlist->user->display_name ."\r\n".
'URL: ' . $this->_playlist->url ."\r\n"."\r\n". 'URL: ' . $this->_playlist->url ."\r\n"."\r\n".
'Downloaded on '. date('l, F jS, Y, \a\t h:i:s A') . '.' 'Downloaded on '. date('l, F jS, Y, \a\t h:i:s A') . '.'
); );
$directory = $this->_playlist->user->display_name . '/' . $this->_playlist->title . '/';
$notes = $notes =
'Album: ' . $this->_playlist->title ."\r\n". 'Playlist: '. $this->_playlist->title ."\r\n".
'Artist: ' . $this->_playlist->user->display_name ."\r\n". 'Curator: ' . $this->_playlist->user->display_name ."\r\n".
'URL: ' . $this->_playlist->url ."\r\n". 'URL: ' . $this->_playlist->url ."\r\n".
"\r\n". "\r\n".
$this->_playlist->description ."\r\n". $this->_playlist->description ."\r\n".
@ -31,18 +29,28 @@
'Tracks' ."\r\n". 'Tracks' ."\r\n".
"\r\n"; "\r\n";
$m3u = '';
$index = 1;
foreach ($this->_playlist->tracks as $track) { foreach ($this->_playlist->tracks as $track) {
if (!$track->is_downloadable) if (!$track->is_downloadable)
continue; continue;
$zip->addLargeFile($track->getFileFor($this->_format), $directory . $track->getDownloadFilenameFor($this->_format)); $trackTarget = $track->downloadDirectory . '/' . $track->getDownloadFilenameFor($this->_format);
$zip->addLargeFile($track->getFileFor($this->_format), $trackTarget);
$notes .= $notes .=
$track->track_number . '. ' . $track->title ."\r\n". $index . '. ' . $track->title ."\r\n".
$track->description ."\r\n". $track->description ."\r\n".
"\r\n"; "\r\n";
$m3u .= '#EXTINF:' . $track->duration . ',' . $track->title . "\r\n";
$m3u .= '../' . $trackTarget . "\r\n";
$index++;
} }
$zip->addFile($notes, $directory . 'Album Notes.txt'); $playlistDir = 'Pony.fm Playlists/';
$zip->addFile($notes, $playlistDir . $this->_playlist->title . '.txt');
$zip->addFile($m3u, $playlistDir . $this->_playlist->title . '.m3u');
$zip->finalize(); $zip->finalize();
} }
} }

View file

@ -41,6 +41,7 @@
Route::get('playlist/{id}-{slug}', 'PlaylistsController@getPlaylist'); Route::get('playlist/{id}-{slug}', 'PlaylistsController@getPlaylist');
Route::get('p{id}', 'PlaylistsController@getShortlink')->where('id', '\d+'); Route::get('p{id}', 'PlaylistsController@getShortlink')->where('id', '\d+');
Route::get('p{id}/dl.{extension}', 'PlaylistsController@getDownload' );
Route::group(['prefix' => 'api/web'], function() { Route::group(['prefix' => 'api/web'], function() {
Route::get('/taxonomies/all', 'Api\Web\TaxonomiesController@getAll'); Route::get('/taxonomies/all', 'Api\Web\TaxonomiesController@getAll');

View file

@ -11,7 +11,7 @@ angular.module('ponyfm').factory('playlists', [
force = force || false force = force || false
return playlists[id] if !force && playlists[id] return playlists[id] if !force && playlists[id]
def = new $.Deferred() def = new $.Deferred()
$http.get('/api/web/playlists/' + id).success (playlist) -> $http.get('/api/web/playlists/' + id + '?log=true').success (playlist) ->
def.resolve playlist def.resolve playlist
playlists[id] = def.promise() playlists[id] = def.promise()

View file

@ -5,12 +5,13 @@
</ul> </ul>
<div class="track-toolbar btn-group pull-right"> <div class="track-toolbar btn-group pull-right">
<pfm-favourite-button resource="playlist" type="playlist"></pfm-favourite-button>
<div class="dropdown"> <div class="dropdown">
<a href="#" class="btn btn-small btn-info dropdown-toggle"> <a href="#" class="btn btn-small btn-info dropdown-toggle">
Downloads <i class="caret"></i> Downloads <i class="caret"></i>
</a> </a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li ng-repeat="format in playlist.formats"><a href="{{format.url}}">{{format.name}}</a></li> <li ng-repeat="format in playlist.formats"><a target="_blank" href="{{format.url}}">{{format.name}} <small>({{format.size}})</small></a></li>
</ul> </ul>
</div> </div>
</div> </div>
@ -38,6 +39,13 @@
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script> <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
<a href="#" class="btn btn-info">Share or Embed</a> <a href="#" class="btn btn-info">Share or Embed</a>
<h2>Stats</h2>
<ul class="stats">
<li>Views: <strong>{{playlist.stats.views}}</strong></li>
<li>Downloads: <strong>{{playlist.stats.downloads}}</strong></li>
<li>Favourites: <strong>{{playlist.stats.favourites}}</strong></li>
</ul>
</div> </div>
</div> </div>
</div> </div>