diff --git a/app/controllers/Api/V1/TracksController.php b/app/controllers/Api/V1/TracksController.php new file mode 100644 index 00000000..5461656d --- /dev/null +++ b/app/controllers/Api/V1/TracksController.php @@ -0,0 +1,94 @@ +published() + ->whereHash($hash)->first(); + + if (!$track) + return Response::json(['message' => 'Track not found.'], 403); + + $comments = []; + foreach ($track->comments as $comment) { + $comments[] = [ + 'id' => $comment->id, + 'created_at' => $comment->created_at, + 'content' => $comment->content, + 'user' => [ + 'name' => $comment->user->display_name, + 'id' => $comment->user->id, + 'url' => $comment->user->url, + 'avatars' => [ + 'normal' => $comment->user->getAvatarUrl(Image::NORMAL), + 'thumbnail' => $comment->user->getAvatarUrl(Image::THUMBNAIL), + 'small' => $comment->user->getAvatarUrl(Image::SMALL), + ] + ] + ]; + } + + return Response::json([ + 'id' => $track->id, + 'title' => $track->title, + 'description' => $track->description, + 'lyrics' => $track->lyrics, + 'user' => [ + 'id' => $track->user->id, + 'name' => $track->user->display_name, + 'url' => $track->user->url, + 'avatars' => [ + 'thumbnail' => $track->user->getAvatarUrl(Image::THUMBNAIL), + 'small' => $track->user->getAvatarUrl(Image::SMALL), + 'normal' => $track->user->getAvatarUrl(Image::NORMAL) + ] + ], + 'stats' => [ + 'views' => $track->view_count, + 'plays' => $track->play_count, + 'downloads' => $track->download_count, + 'comments' => $track->comment_count, + 'favourites' => $track->favourite_count + ], + 'url' => $track->url, + 'is_vocal' => !!$track->is_vocal, + 'is_explicit' => !!$track->is_explicit, + 'is_downloadable' => !!$track->is_downloadable, + 'published_at' => $track->published_at, + 'duration' => $track->duration, + 'genre' => $track->genre != null + ? + [ + 'id' => $track->genre->id, + 'name' => $track->genre->name + ] : null, + 'type' => [ + 'id' => $track->track_type->id, + 'name' => $track->track_type->title + ], + 'covers' => [ + 'thumbnail' => $track->getCoverUrl(Image::THUMBNAIL), + 'small' => $track->getCoverUrl(Image::SMALL), + 'normal' => $track->getCoverUrl(Image::NORMAL) + ], + 'comments' => $comments + ], 200); + } + } \ No newline at end of file diff --git a/app/controllers/Api/Web/ArtistsController.php b/app/controllers/Api/Web/ArtistsController.php index 3dfaee41..b485db0c 100644 --- a/app/controllers/Api/Web/ArtistsController.php +++ b/app/controllers/Api/Web/ArtistsController.php @@ -57,7 +57,7 @@ if (!$user) App::abort(404); - $query = Track::summary()->with('genre', 'cover', 'user')->userDetails()->whereUserId($user->id)->whereNotNull('published_at'); + $query = Track::summary()->published()->listed()->explicitFilter()->with('genre', 'cover', 'user')->userDetails()->whereUserId($user->id)->whereNotNull('published_at'); $tracks = []; $singles = []; @@ -88,7 +88,7 @@ if (!$user) App::abort(404); - $trackQuery = Track::summary()->with('genre', 'cover', 'user')->userDetails()->whereUserId($user->id)->whereNotNull('published_at')->orderBy('created_at', 'desc')->take(20); + $trackQuery = Track::summary()->published()->explicitFilter()->listed()->with('genre', 'cover', 'user')->userDetails()->whereUserId($user->id)->whereNotNull('published_at')->orderBy('created_at', 'desc')->take(20); $latestTracks = []; foreach ($trackQuery->get() as $track) { diff --git a/app/controllers/Api/Web/DashboardController.php b/app/controllers/Api/Web/DashboardController.php index 5fe6ee1e..e664dccb 100644 --- a/app/controllers/Api/Web/DashboardController.php +++ b/app/controllers/Api/Web/DashboardController.php @@ -18,6 +18,7 @@ $recentQuery = Track::summary() ->with(['genre', 'user', 'cover', 'user.avatar']) ->whereIsLatest(true) + ->listed() ->userDetails() ->explicitFilter() ->published() diff --git a/app/controllers/Api/Web/TracksController.php b/app/controllers/Api/Web/TracksController.php index 226b2587..000cbf84 100644 --- a/app/controllers/Api/Web/TracksController.php +++ b/app/controllers/Api/Web/TracksController.php @@ -52,6 +52,7 @@ $query = Track::summary() ->userDetails() + ->listed() ->explicitFilter() ->published() ->with('user', 'genre', 'cover', 'album', 'album.user'); @@ -64,7 +65,7 @@ $tracks = []; $ids = []; - foreach ($query->get() as $track) { + foreach ($query->get(['tracks.*']) as $track) { $tracks[] = Track::mapPublicTrackSummary($track); $ids[] = $track->id; } @@ -93,7 +94,6 @@ return Response::json(Track::mapPrivateTrackShow($track), 200); } - private function applyFilters($query) { if (Input::has('order')) { $order = \Input::get('order'); @@ -127,7 +127,6 @@ $join->on('tracks.id', '=', 'show_song_track.track_id'); }); $query->whereIn('show_song_track.show_song_id', Input::get('songs')); - $query->select('tracks.*'); } return $query; diff --git a/app/controllers/TracksController.php b/app/controllers/TracksController.php index d1c1d661..b0c204c2 100644 --- a/app/controllers/TracksController.php +++ b/app/controllers/TracksController.php @@ -138,7 +138,7 @@ $response->header('Content-Disposition', 'attachment; filename="' . $track->getDownloadFilenameFor($formatName) . '"'); } else { $response->header('X-Accel-Redirect', $filename); - $response->header('Content-Disposition', 'attachment; filename=' . $track->getDownloadFilenameFor($formatName)); + $response->header('Content-Disposition', 'attachment; filename="' . $track->getDownloadFilenameFor($formatName) . '"'); } $time = gmdate(filemtime($filename)); diff --git a/app/database/migrations/2013_09_23_031316_create_track_hashes.php b/app/database/migrations/2013_09_23_031316_create_track_hashes.php new file mode 100644 index 00000000..88da6afa --- /dev/null +++ b/app/database/migrations/2013_09_23_031316_create_track_hashes.php @@ -0,0 +1,23 @@ +string('hash', 32)->notNullable()->indexed(); + }); + + foreach (Track::with('user')->get() as $track) { + $track->updateHash(); + $track->save(); + } + } + + public function down() { + Schema::table('tracks', function($table) { + $table->dropColumn('hash'); + }); + } +} \ No newline at end of file diff --git a/app/database/migrations/2013_09_24_055911_track_is_listed.php b/app/database/migrations/2013_09_24_055911_track_is_listed.php new file mode 100644 index 00000000..184e8b8d --- /dev/null +++ b/app/database/migrations/2013_09_24_055911_track_is_listed.php @@ -0,0 +1,23 @@ +boolean('is_listed')->notNullable()->indexed(); + }); + + DB::update(' + UPDATE + tracks + SET + is_listed = true'); + } + + public function down() { + Schema::table('tracks', function($table) { + $table->dropColumn('is_listed'); + }); + } +} \ No newline at end of file diff --git a/app/library/Helpers.php b/app/library/Helpers.php index 771cb787..cd2eee46 100644 --- a/app/library/Helpers.php +++ b/app/library/Helpers.php @@ -1,6 +1,15 @@ track_type_id = $this->_input['track_type_id']; $track->is_explicit = $this->_input['is_explicit'] == 'true'; $track->is_downloadable = $this->_input['is_downloadable'] == 'true'; + $track->is_listed = $this->_input['is_listed'] == 'true'; $track->is_vocal = $isVocal; if (isset($this->_input['album_id']) && strlen(trim($this->_input['album_id']))) { diff --git a/app/models/Commands/UploadTrackCommand.php b/app/models/Commands/UploadTrackCommand.php index 8beb8af4..ab6f5248 100644 --- a/app/models/Commands/UploadTrackCommand.php +++ b/app/models/Commands/UploadTrackCommand.php @@ -40,6 +40,7 @@ $track->user_id = $user->id; $track->title = pathinfo($trackFile->getClientOriginalName(), PATHINFO_FILENAME); $track->duration = $audio->getDuration(); + $track->is_listed = true; $track->save(); diff --git a/app/models/Entities/Image.php b/app/models/Entities/Image.php index 2ffb3adc..60cb483b 100644 --- a/app/models/Entities/Image.php +++ b/app/models/Entities/Image.php @@ -92,6 +92,7 @@ public function ensureDirectoryExists() { $destination = $this->getDirectory(); + umask(0); if (!is_dir($destination)) mkdir($destination, 777, true); diff --git a/app/models/Entities/Track.php b/app/models/Entities/Track.php index 8485ed60..d0eeb4ec 100644 --- a/app/models/Entities/Track.php +++ b/app/models/Entities/Track.php @@ -19,7 +19,9 @@ class Track extends \Eloquent { protected $softDelete = true; - use SlugTrait; + use SlugTrait { + SlugTrait::setTitleAttribute as setTitleAttributeSlug; + } public static $Formats = [ 'FLAC' => ['index' => 0, 'extension' => 'flac', 'tag_format' => 'metaflac', 'tag_method' => 'updateTagsWithGetId3', 'mime_type' => 'audio/flac', 'command' => 'ffmpeg 2>&1 -y -i {$source} -acodec flac -aq 8 -f flac {$target}'], @@ -45,6 +47,10 @@ $query->whereNotNull('published_at'); } + public function scopeListed($query) { + $query->whereIsListed(true); + } + public function scopeExplicitFilter($query) { if (!Auth::check() || !Auth::user()->can_see_explicit_content) $query->whereIsExplicit(false); @@ -58,6 +64,7 @@ $trackIds = Cache::remember('popular_tracks' . $count . '-' . ($allowExplicit ? 'explicit' : 'safe'), 5, function() use ($allowExplicit, $count) { $query = static ::published() + ->listed() ->join(DB::raw(' ( SELECT `track_id`, `created_at` FROM `resource_log_items` @@ -247,7 +254,8 @@ 'duration' => $track->duration, 'genre_id' => $track->genre_id, 'track_type_id' => $track->track_type_id, - 'cover_url' => $track->getCoverUrl(Image::SMALL) + 'cover_url' => $track->getCoverUrl(Image::SMALL), + 'is_listed' => !!$track->is_listed ]; } @@ -257,6 +265,10 @@ return $this->belongsTo('Entities\Genre'); } + public function trackType() { + return $this->belongsTo('Entities\TrackType', 'track_type_id'); + } + public function comments(){ return $this->hasMany('Entities\Comment')->orderBy('created_at', 'desc'); } @@ -289,6 +301,11 @@ return date('Y', strtotime($this->release_date)); } + public function setTitleAttribute($value) { + $this->setTitleAttributeSlug($value);; + $this->updateHash(); + } + public function getFilesize($formatName) { return Cache::remember($this->getCacheKey('filesize-' . $formatName), 1440, function () use ($formatName) { $file = $this->getFileFor($formatName); @@ -332,6 +349,7 @@ public function ensureDirectoryExists() { $destination = $this->getDirectory(); + umask(0); if (!is_dir($destination)) mkdir($destination, 777); @@ -401,6 +419,10 @@ return URL::to('/t' . $this->id . '/dl.' . $format['extension']); } + public function updateHash() { + $this->hash = md5(Helpers::sanitizeInputForHashing($this->user->display_name) . '-' . Helpers::sanitizeInputForHashing($this->title)); + } + public function updateTags() { foreach (self::$Formats as $format => $data) { $this->{$data['tag_method']}($format); diff --git a/app/models/Entities/User.php b/app/models/Entities/User.php index 7cdfcb75..eb9941b5 100644 --- a/app/models/Entities/User.php +++ b/app/models/Entities/User.php @@ -57,7 +57,7 @@ return $this->email; } - public function setDisplayName($value) { + public function setDisplayNameAttribute($value) { $this->attributes['display_name'] = $value; $this->attributes['slug'] = Str::slug($value); } diff --git a/app/routes.php b/app/routes.php index 203ac3f5..5fcfdb4d 100644 --- a/app/routes.php +++ b/app/routes.php @@ -49,6 +49,11 @@ Route::get('p{id}', 'PlaylistsController@getShortlink')->where('id', '\d+'); Route::get('p{id}/dl.{extension}', 'PlaylistsController@getDownload' ); + Route::group(['prefix' => 'api/v1'], function() { + Route::get('/tracks/radio-details/{hash}', 'Api\V1\TracksController@getTrackRadioDetails'); + Route::post('/tracks/radio-details/{hash}', 'Api\V1\TracksController@getTrackRadioDetails'); + }); + Route::group(['prefix' => 'api/web'], function() { Route::get('/taxonomies/all', 'Api\Web\TaxonomiesController@getAll'); diff --git a/app/views/shared/_app_layout.blade.php b/app/views/shared/_app_layout.blade.php index 05689c54..60aeed37 100644 --- a/app/views/shared/_app_layout.blade.php +++ b/app/views/shared/_app_layout.blade.php @@ -24,7 +24,7 @@
- pony.fm + pony.fm (beta)
@if (Auth::check())
-
+
-
+
+
+ +
diff --git a/spa.pony.fm.iml b/spa.pony.fm.iml index 6ff7b7ed..a1427afa 100644 --- a/spa.pony.fm.iml +++ b/spa.pony.fm.iml @@ -27,6 +27,7 @@ + @@ -75,6 +76,7 @@ + @@ -115,6 +117,7 @@ +