From 21009713f3f10550b5afe6166c0b42515592fd27 Mon Sep 17 00:00:00 2001 From: nelsonlaquet Date: Wed, 31 Jul 2013 18:04:04 -0500 Subject: [PATCH] Intermediate commit (power is going on and off) --- app/controllers/Api/Web/TracksController.php | 100 +++--------------- app/controllers/TracksController.php | 19 ++++ app/models/Entities/Playlist.php | 2 +- app/models/Entities/Track.php | 87 ++++++++++++++- app/routes.php | 5 +- app/views/shared/_app_layout.blade.php | 2 +- app/views/tracks/show.blade.php | 6 ++ public/scripts/app/app.coffee | 7 +- .../scripts/app/controllers/playlist.coffee | 1 + public/scripts/app/controllers/track.coffee | 12 +++ .../app/controllers/tracks-list.coffee | 4 +- public/scripts/app/controllers/tracks.coffee | 8 ++ public/scripts/app/filters/newlines.coffee | 2 + public/scripts/app/filters/noHTML.coffee | 5 + public/scripts/app/services/tracks.coffee | 31 ++++-- public/scripts/shared/layout.coffee | 11 ++ public/styles/components.less | 55 +++++++--- public/styles/layout.less | 28 ++++- public/styles/tracks.less | 60 +++++++++++ public/templates/tracks/search.html | 2 +- public/templates/tracks/show.html | 57 ++++++++++ 21 files changed, 386 insertions(+), 118 deletions(-) create mode 100644 app/views/tracks/show.blade.php create mode 100644 public/scripts/app/controllers/track.coffee create mode 100644 public/scripts/app/filters/newlines.coffee create mode 100644 public/scripts/app/filters/noHTML.coffee create mode 100644 public/templates/tracks/show.html diff --git a/app/controllers/Api/Web/TracksController.php b/app/controllers/Api/Web/TracksController.php index 883527fd..ae8e15bc 100644 --- a/app/controllers/Api/Web/TracksController.php +++ b/app/controllers/Api/Web/TracksController.php @@ -26,6 +26,14 @@ return $this->execute(new EditTrackCommand($id, Input::all())); } + public function getShow($id) { + $track = Track::find($id); + if (!$track || !$track->canView(Auth::user())) + return $this->notFound('Track not found!'); + + return Response::json(['track' => Track::mapPublicTrackShow($track)], 200); + } + public function getRecent() { $query = Track::summary()->with(['genre', 'user', 'cover'])->whereNotNull('published_at')->orderBy('published_at', 'desc')->take(15); if (!Auth::check() || !Auth::user()->can_see_explicit_content) @@ -34,7 +42,7 @@ $tracks = []; foreach ($query->get() as $track) { - $tracks[] = $this->mapPublicTrack($track); + $tracks[] = Track::mapPublicTrackSummary($track); } return Response::json($tracks, 200); @@ -51,11 +59,10 @@ $totalCount = $query->count(); $query->take(30)->skip(30 * ($page - 1)); - $tracks = []; - foreach ($query->get() as $track) { - $tracks[] = $this->mapPublicTrack($track); - } + $tracks = []; + foreach ($query->get() as $track) + $tracks[] = Track::mapPublicTrackSummary($track); return Response::json(["tracks" => $tracks, "current_page" => $page, "total_pages" => ceil($totalCount / 30)], 200); } @@ -73,27 +80,9 @@ $this->applyFilters($query); - $dbTracks = $query->get(); $tracks = []; - - foreach ($dbTracks as $track) { - $tracks[] = [ - 'id' => $track->id, - 'title' => $track->title, - 'user_id' => $track->user_id, - 'slug' => $track->slug, - 'is_vocal' => $track->is_vocal, - 'is_explicit' => $track->is_explicit, - 'is_downloadable' => $track->is_downloadable, - 'is_published' => $track->isPublished(), - 'created_at' => $track->created_at, - 'published_at' => $track->published_at, - 'duration' => $track->duration, - 'genre_id' => $track->genre_id, - 'track_type_id' => $track->track_type_id, - 'cover_url' => $track->getCoverUrl(Image::SMALL) - ]; - } + foreach ($query->get() as $track) + $tracks[] = Track::mapPrivateTrackSummary($track); return Response::json($tracks, 200); } @@ -106,68 +95,9 @@ if ($track->user_id != Auth::user()->id) return $this->notAuthorized(); - $showSongs = []; - foreach ($track->showSongs as $showSong) { - $showSongs[] = ['id' => $showSong->id, 'title' => $showSong->title]; - } - - return Response::json([ - 'id' => $track->id, - 'title' => $track->title, - 'user_id' => $track->user_id, - 'slug' => $track->slug, - 'is_vocal' => (bool)$track->is_vocal, - 'is_explicit' => (bool)$track->is_explicit, - 'is_downloadable' => !$track->isPublished() ? true : (bool)$track->is_downloadable, - 'is_published' => $track->published_at != null, - 'created_at' => $track->created_at, - 'published_at' => $track->published_at, - 'duration' => $track->duration, - 'genre_id' => $track->genre_id, - 'track_type_id' => $track->track_type_id, - 'license_id' => $track->license_id != null ? $track->license_id : 3, - 'description' => $track->description, - 'lyrics' => $track->lyrics, - 'released_at' => $track->released_at, - 'cover_url' => $track->hasCover() ? $track->getCoverUrl(Image::NORMAL) : null, - 'real_cover_url' => $track->getCoverUrl(Image::NORMAL), - 'show_songs' => $showSongs, - 'album_id' => $track->album_id - ], 200); + return Response::json(Track::mapPrivateTrackShow($track), 200); } - private function mapPublicTrack($track) { - return [ - 'id' => $track->id, - 'title' => $track->title, - 'user' => [ - 'id' => $track->user->id, - 'name' => $track->user->display_name, - 'url' => $track->user->url - ], - 'url' => $track->url, - 'slug' => $track->slug, - 'is_vocal' => $track->is_vocal, - 'is_explicit' => $track->is_explicit, - 'is_downloadable' => $track->is_downloadable, - 'is_published' => $track->isPublished(), - 'published_at' => $track->published_at, - 'duration' => $track->duration, - 'genre' => $track->genre != null - ? - [ - 'id' => $track->genre->id, - 'slug' => $track->genre->slug, - 'name' => $track->genre->name - ] : null, - 'track_type_id' => $track->track_type_id, - 'covers' => [ - 'thumbnail' => $track->getCoverUrl(Image::THUMBNAIL), - 'small' => $track->getCoverUrl(Image::SMALL), - 'normal' => $track->getCoverUrl(Image::NORMAL) - ] - ]; - } private function applyFilters($query) { if (Input::has('order')) { diff --git a/app/controllers/TracksController.php b/app/controllers/TracksController.php index 8f14352b..f863d10f 100644 --- a/app/controllers/TracksController.php +++ b/app/controllers/TracksController.php @@ -7,4 +7,23 @@ public function getIndex() { return View::make('tracks.index'); } + + public function getTrack($id, $slug) { + $track = Track::find($id); + if (!$track || !$track->canView(Auth::user())) + App::abort(404); + + if ($track->slug != $slug) + return Redirect::action('TracksController@getTrack', [$id, $track->slug]); + + return View::make('tracks.show'); + } + + public function getShortlink($id) { + $track = Track::find($id); + if (!$track || !$track->canView(Auth::user())) + App::abort(404); + + return Redirect::action('TracksController@getTrack', [$id, $track->slug]); + } } \ No newline at end of file diff --git a/app/models/Entities/Playlist.php b/app/models/Entities/Playlist.php index e69508e6..08072dc2 100644 --- a/app/models/Entities/Playlist.php +++ b/app/models/Entities/Playlist.php @@ -39,7 +39,7 @@ } public function getUrlAttribute() { - return '/playlist/' . $this->id . '/' . $this->slug; + return '/playlist/' . $this->id . '-' . $this->slug; } public function getCoverUrl($type = Image::NORMAL) { diff --git a/app/models/Entities/Track.php b/app/models/Entities/Track.php index c64e012c..d3406071 100644 --- a/app/models/Entities/Track.php +++ b/app/models/Entities/Track.php @@ -28,6 +28,84 @@ return self::select('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'); } + public static function mapPublicTrackShow($track) { + $returnValue = self::mapPublicTrackSummary($track); + $returnValue['description'] = $track->description; + $returnValue['lyrics'] = $track->lyrics; + return $returnValue; + } + + public static function mapPublicTrackSummary($track) { + return [ + 'id' => $track->id, + 'title' => $track->title, + 'user' => [ + 'id' => $track->user->id, + 'name' => $track->user->display_name, + 'url' => $track->user->url + ], + 'url' => $track->url, + 'slug' => $track->slug, + 'is_vocal' => $track->is_vocal, + 'is_explicit' => $track->is_explicit, + 'is_downloadable' => $track->is_downloadable, + 'is_published' => $track->isPublished(), + 'published_at' => $track->published_at, + 'duration' => $track->duration, + 'genre' => $track->genre != null + ? + [ + 'id' => $track->genre->id, + 'slug' => $track->genre->slug, + 'name' => $track->genre->name + ] : null, + 'track_type_id' => $track->track_type_id, + 'covers' => [ + 'thumbnail' => $track->getCoverUrl(Image::THUMBNAIL), + 'small' => $track->getCoverUrl(Image::SMALL), + 'normal' => $track->getCoverUrl(Image::NORMAL) + ] + ]; + } + + public static function mapPrivateTrackShow($track) { + $showSongs = []; + foreach ($track->showSongs as $showSong) { + $showSongs[] = ['id' => $showSong->id, 'title' => $showSong->title]; + } + + $returnValue = self::mapPrivateTrackSummary($track); + $returnValue['album_id'] = $track->album_id; + $returnValue['show_songs'] = $showSongs; + $returnValue['real_cover_url'] = $track->getCoverUrl(Image::NORMAL); + $returnValue['cover_url'] = $track->hasCover() ? $track->getCoverUrl(Image::NORMAL) : null; + $returnValue['released_at'] = $track->released_at; + $returnValue['lyrics'] = $track->lyrics; + $returnValue['description'] = $track->description; + $returnValue['is_downloadable'] = !$track->isPublished() ? true : (bool)$track->is_downloadable; + $returnValue['license_id'] = $track->license_id != null ? $track->license_id : 3; + return $returnValue; + } + + public static function mapPrivateTrackSummary($track) { + return [ + 'id' => $track->id, + 'title' => $track->title, + 'user_id' => $track->user_id, + 'slug' => $track->slug, + 'is_vocal' => $track->is_vocal, + 'is_explicit' => $track->is_explicit, + 'is_downloadable' => $track->is_downloadable, + 'is_published' => $track->isPublished(), + 'created_at' => $track->created_at, + 'published_at' => $track->published_at, + 'duration' => $track->duration, + 'genre_id' => $track->genre_id, + 'track_type_id' => $track->track_type_id, + 'cover_url' => $track->getCoverUrl(Image::SMALL) + ]; + } + protected $table = 'tracks'; public function genre() { @@ -54,8 +132,15 @@ return date('Y', strtotime($this->release_date)); } + public function canView($user) { + if ($this->isPublished()) + return true; + + return $this->user_id == $user->id; + } + public function getUrlAttribute() { - return URL::to('/tracks/' . $this->id . '/' . $this->slug); + return URL::to('/tracks/' . $this->id . '-' . $this->slug); } public function getReleaseDate() { diff --git a/app/routes.php b/app/routes.php index b9536b62..2ca6efc8 100644 --- a/app/routes.php +++ b/app/routes.php @@ -16,6 +16,9 @@ Route::get('/tracks/popular', 'TracksController@getIndex'); Route::get('/tracks/random', 'TracksController@getIndex'); + Route::get('tracks/{id}-{slug}', 'TracksController@getTrack'); + Route::get('t{id}', 'TracksController@getShortlink' ); + Route::get('/albums', 'AlbumsController@getIndex'); Route::get('/artists', 'ArtistsController@getIndex'); Route::get('/playlists', 'PlaylistsController@getIndex'); @@ -30,7 +33,6 @@ Route::get('u{id}/avatar_{type}.png', 'UsersController@getAvatar'); - Route::get('playlist/{id}/{slug}', 'PlaylistsController@getPlaylist'); Route::get('playlist/{id}-{slug}', 'PlaylistsController@getPlaylist'); Route::get('p{id}', 'PlaylistsController@getShortlink'); @@ -41,6 +43,7 @@ Route::get('/tracks/recent', 'Api\Web\TracksController@getRecent'); Route::get('/tracks', 'Api\Web\TracksController@getIndex'); + Route::get('/tracks/{id}', 'Api\Web\TracksController@getShow')->where('id', '\d+'); Route::get('/dashboard', 'Api\Web\DashboardController@getIndex'); diff --git a/app/views/shared/_app_layout.blade.php b/app/views/shared/_app_layout.blade.php index 4ed5ce06..5d00acd9 100644 --- a/app/views/shared/_app_layout.blade.php +++ b/app/views/shared/_app_layout.blade.php @@ -35,7 +35,7 @@
  • Home
  • @endif
  • Discover

  • -
  • Music
  • +
  • Music
  • Albums
  • Playlists
  • Artists
  • diff --git a/app/views/tracks/show.blade.php b/app/views/tracks/show.blade.php new file mode 100644 index 00000000..007bb625 --- /dev/null +++ b/app/views/tracks/show.blade.php @@ -0,0 +1,6 @@ +@extends('shared._app_layout') + +@section('app_content') +

    Track Listing!

    +

    This page should be what search engines see

    +@endsection \ No newline at end of file diff --git a/public/scripts/app/app.coffee b/public/scripts/app/app.coffee index cff53032..6c09af2b 100644 --- a/public/scripts/app/app.coffee +++ b/public/scripts/app/app.coffee @@ -67,6 +67,11 @@ angular.module 'ponyfm', ['ui.bootstrap', 'ui.state', 'ui.date', 'ui.sortable'], # Tracks + state.state 'track', + url: '/tracks/{id:[^\-]+}-{slug}' + templateUrl: '/templates/tracks/show.html' + controller: 'track' + state.state 'tracks', url: '/tracks' templateUrl: '/templates/tracks/_layout.html' @@ -104,7 +109,7 @@ angular.module 'ponyfm', ['ui.bootstrap', 'ui.state', 'ui.date', 'ui.sortable'], templateUrl: '/templates/playlists/index.html' state.state 'playlist', - url: '/playlist/:id/:slug' + url: '/playlist/{id:[^\-]+}-{slug}' templateUrl: '/templates/playlists/show.html' controller: 'playlist' diff --git a/public/scripts/app/controllers/playlist.coffee b/public/scripts/app/controllers/playlist.coffee index fa6e4313..8fc97e7f 100644 --- a/public/scripts/app/controllers/playlist.coffee +++ b/public/scripts/app/controllers/playlist.coffee @@ -1,6 +1,7 @@ angular.module('ponyfm').controller 'playlist', [ '$scope', '$state' ($scope, $state) -> + console.log $state.params.id $scope.refresh = () -> $.getJSON('/api/web/playlists/show/' + $state.params.id) .done (playlist) -> $scope.$apply -> diff --git a/public/scripts/app/controllers/track.coffee b/public/scripts/app/controllers/track.coffee new file mode 100644 index 00000000..17ddb00f --- /dev/null +++ b/public/scripts/app/controllers/track.coffee @@ -0,0 +1,12 @@ +window.pfm.preloaders['track'] = [ + 'tracks', '$state' + (tracks, $state) -> + tracks.fetch $state.params.id +] + +angular.module('ponyfm').controller "track", [ + '$scope', 'tracks', '$state' + ($scope, tracks, $state) -> + tracks.fetch($state.params.id).done (trackResponse) -> + $scope.track = trackResponse.track +] \ No newline at end of file diff --git a/public/scripts/app/controllers/tracks-list.coffee b/public/scripts/app/controllers/tracks-list.coffee index e183494c..79e35496 100644 --- a/public/scripts/app/controllers/tracks-list.coffee +++ b/public/scripts/app/controllers/tracks-list.coffee @@ -1,14 +1,14 @@ window.pfm.preloaders['tracks-list'] = [ 'tracks', '$state' (tracks, $state) -> - $.when.all [tracks.loadFilters().then(-> + tracks.loadFilters().then(-> if !tracks.mainQuery.hasLoadedFilters tracks.mainQuery.fromFilterString($state.params.filter) if $state.params.page tracks.mainQuery.setPage $state.params.page tracks.mainQuery.fetch() - )] + ) ] angular.module('ponyfm').controller "tracks-list", [ diff --git a/public/scripts/app/controllers/tracks.coffee b/public/scripts/app/controllers/tracks.coffee index dc31f2ac..c6c89919 100644 --- a/public/scripts/app/controllers/tracks.coffee +++ b/public/scripts/app/controllers/tracks.coffee @@ -1,3 +1,9 @@ +window.pfm.preloaders['tracks'] = [ + 'tracks', '$state' + (tracks) -> + tracks.loadFilters() +] + angular.module('ponyfm').controller "tracks", [ '$scope', 'tracks', '$state' ($scope, tracks, $state) -> @@ -30,4 +36,6 @@ angular.module('ponyfm').controller "tracks", [ $scope.gotoPage = (page) -> $state.transitionTo 'tracks.search.list', {filter: $state.params.filter, page: page} + + $scope.$on '$destroy', -> tracks.mainQuery = tracks.createQuery() ] \ No newline at end of file diff --git a/public/scripts/app/filters/newlines.coffee b/public/scripts/app/filters/newlines.coffee new file mode 100644 index 00000000..37ecfc8d --- /dev/null +++ b/public/scripts/app/filters/newlines.coffee @@ -0,0 +1,2 @@ +angular.module('ponyfm').filter 'newlines', () -> + (input) -> input.replace(/\n/g, '
    ') \ No newline at end of file diff --git a/public/scripts/app/filters/noHTML.coffee b/public/scripts/app/filters/noHTML.coffee new file mode 100644 index 00000000..c5add856 --- /dev/null +++ b/public/scripts/app/filters/noHTML.coffee @@ -0,0 +1,5 @@ +angular.module('ponyfm').filter 'noHTML', () -> + (input) -> + input.replace(/&/g, '&') + .replace(/>/g, '>') + .replace(/ - def = null + filterDef = null + trackCache = {} class Query cachedDef: null @@ -97,7 +98,7 @@ angular.module('ponyfm').factory('tracks', [ fetch: () -> return @cachedDef if @cachedDef @cachedDef = new $.Deferred() - def = @cachedDef + trackDef = @cachedDef query = '/api/web/tracks?' parts = ['page=' + @page] @@ -115,18 +116,28 @@ angular.module('ponyfm').factory('tracks', [ for listener in @listeners listener tracks - def.resolve tracks + trackDef.resolve tracks - def.promise() + trackDef.promise() self = filters: {} - createQuery: -> new Query self.filters - loadFilters: -> - return def if def + fetch: (id, force) -> + force = force || false + return trackCache[id] if !force && trackCache[id] + trackDef = new $.Deferred() + $http.get('/api/web/tracks/' + id).success (track) -> + trackDef.resolve track - def = new $.Deferred() + trackCache[id] = trackDef.promise() + + createQuery: -> new Query self.filters + + loadFilters: -> + return filterDef if filterDef + + filterDef = new $.Deferred() self.filters.isVocal = type: 'single' values: [ @@ -174,9 +185,9 @@ angular.module('ponyfm').factory('tracks', [ id: song.id self.mainQuery = self.createQuery() - def.resolve self + filterDef.resolve self - def.promise() + filterDef.promise() self ]) \ No newline at end of file diff --git a/public/scripts/shared/layout.coffee b/public/scripts/shared/layout.coffee index 9f58acc4..ef72fb4e 100644 --- a/public/scripts/shared/layout.coffee +++ b/public/scripts/shared/layout.coffee @@ -9,6 +9,17 @@ window.handleResize = () -> if newHeight > 0 $this.height newHeight + $('.revealable').each () -> + $this = $ this + $this.data 'real-height', $this.height() + $this.css + height: '15em' + + $this.find('.reveal').click (e) -> + e.preventDefault() + $this.css {height: 'auto'} + $(this).fadeOut 200 + window.alignVertically = (element) -> $element = $(element) $parent = $element.parent() diff --git a/public/styles/components.less b/public/styles/components.less index ccc4f6d6..a10a21ff 100644 --- a/public/styles/components.less +++ b/public/styles/components.less @@ -98,11 +98,11 @@ html .dropdown-menu { li.selected { a { - background: @green; + background: @blue; color: #fff; &:hover { - background: fadeout(@green, 20%); + background: fadeout(@blue, 20%); } } } @@ -191,22 +191,51 @@ html .dropdown-menu { } html { + .breadcrumb { + .border-radius(0px); + background: #eee; + margin-bottom: 10px; + font-size: 10pt; + } + .pagination { border: none; + background: #ccc; + margin: 5px 0px; + padding: 0px; + overflow: hidden; + + ul { + .border-radius(0px); + margin: 5px; + display: block; + overflow: hidden; + + > li:first-child > a, > li:last-child > a { + .border-radius(0px); + } + + li { + display: block; + float: left; + + a { + .border-radius(0px); + border: none; + padding: 1px 10px; + display: block; + float: left; + } + } + + li.active a { + background: #444; + color: #ddd; + } + } &.pagination-right { float: right; } - - li a { - .border-radius(0px); - border: none; - padding: 1px 10px; - } - - li.active a { - background: #444; - color: #ddd; - } } } \ No newline at end of file diff --git a/public/styles/layout.less b/public/styles/layout.less index 09375a59..36b734d4 100644 --- a/public/styles/layout.less +++ b/public/styles/layout.less @@ -403,12 +403,11 @@ header { } .site-content { - h1 { + h1, h2 { border: none; background: none; color: #747474; font-weight: 300; - font-size: 24px; line-height: normal; font-weight: normal; margin: 0px; @@ -421,6 +420,27 @@ header { margin-top: 8px; text-decoration: none; } + + .subtitle { + font-size: 10pt; + display: block; + padding: 3px 0px; + + a { + float: none; + display: inline; + } + } + } + + h1 { + font-size: 24px; + } + + h2 { + font-size: 20px; + border-bottom: 2px solid #ddd; + margin-bottom: 2px; } > div > .tabs { @@ -606,4 +626,8 @@ html { .upload-queue-leave { .transform(scale(1)); +} + +.stretch-to-bottom { + overflow-y: auto; } \ No newline at end of file diff --git a/public/styles/tracks.less b/public/styles/tracks.less index 654c2d2c..7d4284f6 100644 --- a/public/styles/tracks.less +++ b/public/styles/tracks.less @@ -125,4 +125,64 @@ } } } +} + +.track-details { + .cover-image { + img { + .img-polaroid(); + } + } + + .lyrics { + position: relative; + overflow: hidden; + padding: 0px; + margin: 0px; + + h2 { + } + + .reveal { + #gradient>.vertical(rgba(255,255,255,0), rgba(255,255,255,1)); + .box-sizing(border-box); + position: absolute; + top: 0px; + left: 0px; + width: 100%; + height: 100%; + z-index: 400; + border: 2px solid #fff; + cursor: pointer; + + &:hover { + border: 2px solid @blue; + } + + a { + .box-sizing(border-box); + display: block; + position: absolute; + bottom: 0px; + left: 0px; + width: 100%; + background: #eee; + padding: 3px; + z-index: 500; + text-decoration: none; + font-size: 10pt; + } + } + } +} + +html { + .track-toolbar { + background: #eee; + padding: 5px; + + > .btn:first-child, > .btn:last-child { + .border-radius(0px); + } + } } \ No newline at end of file diff --git a/public/templates/tracks/search.html b/public/templates/tracks/search.html index bd869805..20323387 100644 --- a/public/templates/tracks/search.html +++ b/public/templates/tracks/search.html @@ -54,7 +54,7 @@ -