mirror of
https://github.com/Poniverse/Pony.fm.git
synced 2024-11-25 06:27:59 +01:00
Intermediate commit (power is going on and off)
This commit is contained in:
parent
8d3d126550
commit
21009713f3
21 changed files with 386 additions and 118 deletions
|
@ -26,6 +26,14 @@
|
||||||
return $this->execute(new EditTrackCommand($id, Input::all()));
|
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() {
|
public function getRecent() {
|
||||||
$query = Track::summary()->with(['genre', 'user', 'cover'])->whereNotNull('published_at')->orderBy('published_at', 'desc')->take(15);
|
$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)
|
if (!Auth::check() || !Auth::user()->can_see_explicit_content)
|
||||||
|
@ -34,7 +42,7 @@
|
||||||
$tracks = [];
|
$tracks = [];
|
||||||
|
|
||||||
foreach ($query->get() as $track) {
|
foreach ($query->get() as $track) {
|
||||||
$tracks[] = $this->mapPublicTrack($track);
|
$tracks[] = Track::mapPublicTrackSummary($track);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Response::json($tracks, 200);
|
return Response::json($tracks, 200);
|
||||||
|
@ -51,11 +59,10 @@
|
||||||
|
|
||||||
$totalCount = $query->count();
|
$totalCount = $query->count();
|
||||||
$query->take(30)->skip(30 * ($page - 1));
|
$query->take(30)->skip(30 * ($page - 1));
|
||||||
$tracks = [];
|
|
||||||
|
|
||||||
foreach ($query->get() as $track) {
|
$tracks = [];
|
||||||
$tracks[] = $this->mapPublicTrack($track);
|
foreach ($query->get() as $track)
|
||||||
}
|
$tracks[] = Track::mapPublicTrackSummary($track);
|
||||||
|
|
||||||
return Response::json(["tracks" => $tracks, "current_page" => $page, "total_pages" => ceil($totalCount / 30)], 200);
|
return Response::json(["tracks" => $tracks, "current_page" => $page, "total_pages" => ceil($totalCount / 30)], 200);
|
||||||
}
|
}
|
||||||
|
@ -73,27 +80,9 @@
|
||||||
|
|
||||||
$this->applyFilters($query);
|
$this->applyFilters($query);
|
||||||
|
|
||||||
$dbTracks = $query->get();
|
|
||||||
$tracks = [];
|
$tracks = [];
|
||||||
|
foreach ($query->get() as $track)
|
||||||
foreach ($dbTracks as $track) {
|
$tracks[] = Track::mapPrivateTrackSummary($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)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return Response::json($tracks, 200);
|
return Response::json($tracks, 200);
|
||||||
}
|
}
|
||||||
|
@ -106,68 +95,9 @@
|
||||||
if ($track->user_id != Auth::user()->id)
|
if ($track->user_id != Auth::user()->id)
|
||||||
return $this->notAuthorized();
|
return $this->notAuthorized();
|
||||||
|
|
||||||
$showSongs = [];
|
return Response::json(Track::mapPrivateTrackShow($track), 200);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
private function applyFilters($query) {
|
||||||
if (Input::has('order')) {
|
if (Input::has('order')) {
|
||||||
|
|
|
@ -7,4 +7,23 @@
|
||||||
public function getIndex() {
|
public function getIndex() {
|
||||||
return View::make('tracks.index');
|
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]);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -39,7 +39,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUrlAttribute() {
|
public function getUrlAttribute() {
|
||||||
return '/playlist/' . $this->id . '/' . $this->slug;
|
return '/playlist/' . $this->id . '-' . $this->slug;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCoverUrl($type = Image::NORMAL) {
|
public function getCoverUrl($type = Image::NORMAL) {
|
||||||
|
|
|
@ -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');
|
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';
|
protected $table = 'tracks';
|
||||||
|
|
||||||
public function genre() {
|
public function genre() {
|
||||||
|
@ -54,8 +132,15 @@
|
||||||
return date('Y', strtotime($this->release_date));
|
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() {
|
public function getUrlAttribute() {
|
||||||
return URL::to('/tracks/' . $this->id . '/' . $this->slug);
|
return URL::to('/tracks/' . $this->id . '-' . $this->slug);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getReleaseDate() {
|
public function getReleaseDate() {
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
Route::get('/tracks/popular', 'TracksController@getIndex');
|
Route::get('/tracks/popular', 'TracksController@getIndex');
|
||||||
Route::get('/tracks/random', '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('/albums', 'AlbumsController@getIndex');
|
||||||
Route::get('/artists', 'ArtistsController@getIndex');
|
Route::get('/artists', 'ArtistsController@getIndex');
|
||||||
Route::get('/playlists', 'PlaylistsController@getIndex');
|
Route::get('/playlists', 'PlaylistsController@getIndex');
|
||||||
|
@ -30,7 +33,6 @@
|
||||||
|
|
||||||
Route::get('u{id}/avatar_{type}.png', 'UsersController@getAvatar');
|
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('playlist/{id}-{slug}', 'PlaylistsController@getPlaylist');
|
||||||
Route::get('p{id}', 'PlaylistsController@getShortlink');
|
Route::get('p{id}', 'PlaylistsController@getShortlink');
|
||||||
|
|
||||||
|
@ -41,6 +43,7 @@
|
||||||
|
|
||||||
Route::get('/tracks/recent', 'Api\Web\TracksController@getRecent');
|
Route::get('/tracks/recent', 'Api\Web\TracksController@getRecent');
|
||||||
Route::get('/tracks', 'Api\Web\TracksController@getIndex');
|
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');
|
Route::get('/dashboard', 'Api\Web\DashboardController@getIndex');
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
<li ng-class="{selected: $state.includes('home')}"><a href="/">Home</a></li>
|
<li ng-class="{selected: $state.includes('home')}"><a href="/">Home</a></li>
|
||||||
@endif
|
@endif
|
||||||
<li><h3>Discover</h3></li>
|
<li><h3>Discover</h3></li>
|
||||||
<li ng-class="{selected: $state.includes('tracks')}"><a href="/tracks">Music <i class="icon-music"></i></a></li>
|
<li ng-class="{selected: $state.includes('tracks') || $state.includes('track')}"><a href="/tracks">Music <i class="icon-music"></i></a></li>
|
||||||
<li ng-class="{selected: $state.includes('albums')}"><a href="/albums">Albums <i class="icon-music"></i></a></li>
|
<li ng-class="{selected: $state.includes('albums')}"><a href="/albums">Albums <i class="icon-music"></i></a></li>
|
||||||
<li ng-class="{selected: $state.includes('playlists')}"><a href="/playlists">Playlists <i class="icon-music"></i></a></li>
|
<li ng-class="{selected: $state.includes('playlists')}"><a href="/playlists">Playlists <i class="icon-music"></i></a></li>
|
||||||
<li ng-class="{selected: $state.includes('artists')}"><a href="/artists">Artists <i class="icon-user"></i></a></li>
|
<li ng-class="{selected: $state.includes('artists')}"><a href="/artists">Artists <i class="icon-user"></i></a></li>
|
||||||
|
|
6
app/views/tracks/show.blade.php
Normal file
6
app/views/tracks/show.blade.php
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
@extends('shared._app_layout')
|
||||||
|
|
||||||
|
@section('app_content')
|
||||||
|
<h1>Track Listing!</h1>
|
||||||
|
<p>This page should be what search engines see</p>
|
||||||
|
@endsection
|
|
@ -67,6 +67,11 @@ angular.module 'ponyfm', ['ui.bootstrap', 'ui.state', 'ui.date', 'ui.sortable'],
|
||||||
|
|
||||||
# Tracks
|
# Tracks
|
||||||
|
|
||||||
|
state.state 'track',
|
||||||
|
url: '/tracks/{id:[^\-]+}-{slug}'
|
||||||
|
templateUrl: '/templates/tracks/show.html'
|
||||||
|
controller: 'track'
|
||||||
|
|
||||||
state.state 'tracks',
|
state.state 'tracks',
|
||||||
url: '/tracks'
|
url: '/tracks'
|
||||||
templateUrl: '/templates/tracks/_layout.html'
|
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'
|
templateUrl: '/templates/playlists/index.html'
|
||||||
|
|
||||||
state.state 'playlist',
|
state.state 'playlist',
|
||||||
url: '/playlist/:id/:slug'
|
url: '/playlist/{id:[^\-]+}-{slug}'
|
||||||
templateUrl: '/templates/playlists/show.html'
|
templateUrl: '/templates/playlists/show.html'
|
||||||
controller: 'playlist'
|
controller: 'playlist'
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
angular.module('ponyfm').controller 'playlist', [
|
angular.module('ponyfm').controller 'playlist', [
|
||||||
'$scope', '$state'
|
'$scope', '$state'
|
||||||
($scope, $state) ->
|
($scope, $state) ->
|
||||||
|
console.log $state.params.id
|
||||||
$scope.refresh = () ->
|
$scope.refresh = () ->
|
||||||
$.getJSON('/api/web/playlists/show/' + $state.params.id)
|
$.getJSON('/api/web/playlists/show/' + $state.params.id)
|
||||||
.done (playlist) -> $scope.$apply ->
|
.done (playlist) -> $scope.$apply ->
|
||||||
|
|
12
public/scripts/app/controllers/track.coffee
Normal file
12
public/scripts/app/controllers/track.coffee
Normal file
|
@ -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
|
||||||
|
]
|
|
@ -1,14 +1,14 @@
|
||||||
window.pfm.preloaders['tracks-list'] = [
|
window.pfm.preloaders['tracks-list'] = [
|
||||||
'tracks', '$state'
|
'tracks', '$state'
|
||||||
(tracks, $state) ->
|
(tracks, $state) ->
|
||||||
$.when.all [tracks.loadFilters().then(->
|
tracks.loadFilters().then(->
|
||||||
if !tracks.mainQuery.hasLoadedFilters
|
if !tracks.mainQuery.hasLoadedFilters
|
||||||
tracks.mainQuery.fromFilterString($state.params.filter)
|
tracks.mainQuery.fromFilterString($state.params.filter)
|
||||||
if $state.params.page
|
if $state.params.page
|
||||||
tracks.mainQuery.setPage $state.params.page
|
tracks.mainQuery.setPage $state.params.page
|
||||||
|
|
||||||
tracks.mainQuery.fetch()
|
tracks.mainQuery.fetch()
|
||||||
)]
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
angular.module('ponyfm').controller "tracks-list", [
|
angular.module('ponyfm').controller "tracks-list", [
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
window.pfm.preloaders['tracks'] = [
|
||||||
|
'tracks', '$state'
|
||||||
|
(tracks) ->
|
||||||
|
tracks.loadFilters()
|
||||||
|
]
|
||||||
|
|
||||||
angular.module('ponyfm').controller "tracks", [
|
angular.module('ponyfm').controller "tracks", [
|
||||||
'$scope', 'tracks', '$state'
|
'$scope', 'tracks', '$state'
|
||||||
($scope, tracks, $state) ->
|
($scope, tracks, $state) ->
|
||||||
|
@ -30,4 +36,6 @@ angular.module('ponyfm').controller "tracks", [
|
||||||
|
|
||||||
$scope.gotoPage = (page) ->
|
$scope.gotoPage = (page) ->
|
||||||
$state.transitionTo 'tracks.search.list', {filter: $state.params.filter, page: page}
|
$state.transitionTo 'tracks.search.list', {filter: $state.params.filter, page: page}
|
||||||
|
|
||||||
|
$scope.$on '$destroy', -> tracks.mainQuery = tracks.createQuery()
|
||||||
]
|
]
|
2
public/scripts/app/filters/newlines.coffee
Normal file
2
public/scripts/app/filters/newlines.coffee
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
angular.module('ponyfm').filter 'newlines', () ->
|
||||||
|
(input) -> input.replace(/\n/g, '<br/>')
|
5
public/scripts/app/filters/noHTML.coffee
Normal file
5
public/scripts/app/filters/noHTML.coffee
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
angular.module('ponyfm').filter 'noHTML', () ->
|
||||||
|
(input) ->
|
||||||
|
input.replace(/&/g, '&')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/</g, '<')
|
|
@ -1,7 +1,8 @@
|
||||||
angular.module('ponyfm').factory('tracks', [
|
angular.module('ponyfm').factory('tracks', [
|
||||||
'$rootScope', '$http', 'taxonomies'
|
'$rootScope', '$http', 'taxonomies'
|
||||||
($rootScope, $http, taxonomies) ->
|
($rootScope, $http, taxonomies) ->
|
||||||
def = null
|
filterDef = null
|
||||||
|
trackCache = {}
|
||||||
|
|
||||||
class Query
|
class Query
|
||||||
cachedDef: null
|
cachedDef: null
|
||||||
|
@ -97,7 +98,7 @@ angular.module('ponyfm').factory('tracks', [
|
||||||
fetch: () ->
|
fetch: () ->
|
||||||
return @cachedDef if @cachedDef
|
return @cachedDef if @cachedDef
|
||||||
@cachedDef = new $.Deferred()
|
@cachedDef = new $.Deferred()
|
||||||
def = @cachedDef
|
trackDef = @cachedDef
|
||||||
|
|
||||||
query = '/api/web/tracks?'
|
query = '/api/web/tracks?'
|
||||||
parts = ['page=' + @page]
|
parts = ['page=' + @page]
|
||||||
|
@ -115,18 +116,28 @@ angular.module('ponyfm').factory('tracks', [
|
||||||
for listener in @listeners
|
for listener in @listeners
|
||||||
listener tracks
|
listener tracks
|
||||||
|
|
||||||
def.resolve tracks
|
trackDef.resolve tracks
|
||||||
|
|
||||||
def.promise()
|
trackDef.promise()
|
||||||
|
|
||||||
self =
|
self =
|
||||||
filters: {}
|
filters: {}
|
||||||
|
|
||||||
createQuery: -> new Query self.filters
|
fetch: (id, force) ->
|
||||||
loadFilters: ->
|
force = force || false
|
||||||
return def if def
|
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 =
|
self.filters.isVocal =
|
||||||
type: 'single'
|
type: 'single'
|
||||||
values: [
|
values: [
|
||||||
|
@ -174,9 +185,9 @@ angular.module('ponyfm').factory('tracks', [
|
||||||
id: song.id
|
id: song.id
|
||||||
|
|
||||||
self.mainQuery = self.createQuery()
|
self.mainQuery = self.createQuery()
|
||||||
def.resolve self
|
filterDef.resolve self
|
||||||
|
|
||||||
def.promise()
|
filterDef.promise()
|
||||||
|
|
||||||
self
|
self
|
||||||
])
|
])
|
|
@ -9,6 +9,17 @@ window.handleResize = () ->
|
||||||
if newHeight > 0
|
if newHeight > 0
|
||||||
$this.height newHeight
|
$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) ->
|
window.alignVertically = (element) ->
|
||||||
$element = $(element)
|
$element = $(element)
|
||||||
$parent = $element.parent()
|
$parent = $element.parent()
|
||||||
|
|
|
@ -98,11 +98,11 @@ html .dropdown-menu {
|
||||||
|
|
||||||
li.selected {
|
li.selected {
|
||||||
a {
|
a {
|
||||||
background: @green;
|
background: @blue;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: fadeout(@green, 20%);
|
background: fadeout(@blue, 20%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,22 +191,51 @@ html .dropdown-menu {
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
|
.breadcrumb {
|
||||||
|
.border-radius(0px);
|
||||||
|
background: #eee;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 10pt;
|
||||||
|
}
|
||||||
|
|
||||||
.pagination {
|
.pagination {
|
||||||
border: none;
|
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 {
|
&.pagination-right {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
li a {
|
|
||||||
.border-radius(0px);
|
|
||||||
border: none;
|
|
||||||
padding: 1px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
li.active a {
|
|
||||||
background: #444;
|
|
||||||
color: #ddd;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -403,12 +403,11 @@ header {
|
||||||
}
|
}
|
||||||
|
|
||||||
.site-content {
|
.site-content {
|
||||||
h1 {
|
h1, h2 {
|
||||||
border: none;
|
border: none;
|
||||||
background: none;
|
background: none;
|
||||||
color: #747474;
|
color: #747474;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-size: 24px;
|
|
||||||
line-height: normal;
|
line-height: normal;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
|
@ -421,6 +420,27 @@ header {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
text-decoration: none;
|
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 {
|
> div > .tabs {
|
||||||
|
@ -606,4 +626,8 @@ html {
|
||||||
|
|
||||||
.upload-queue-leave {
|
.upload-queue-leave {
|
||||||
.transform(scale(1));
|
.transform(scale(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
.stretch-to-bottom {
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -54,7 +54,7 @@
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="pagination" ng-show="totalPages > 0">
|
<div class="pagination" ng-show="totalPages > 1">
|
||||||
<ul>
|
<ul>
|
||||||
<li ng-class="{disabled: !prevPage}"><a href="#" ng-click="gotoPage(prevPage);" pfm-eat-click>Prev</a></li>
|
<li ng-class="{disabled: !prevPage}"><a href="#" ng-click="gotoPage(prevPage);" pfm-eat-click>Prev</a></li>
|
||||||
<li ng-repeat="page in pages" ng-class="{active: page == currentPage}">
|
<li ng-repeat="page in pages" ng-class="{active: page == currentPage}">
|
||||||
|
|
57
public/templates/tracks/show.html
Normal file
57
public/templates/tracks/show.html
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
<div>
|
||||||
|
<ul class="breadcrumb">
|
||||||
|
<li><a href="/tracks">Tracks</a> <span class="divider">/</span></li>
|
||||||
|
<li><a href="/tracks?filter=genres-{{track.genre.id}}">{{track.genre.name}}</a> <span class="divider">/</span></li>
|
||||||
|
<li class="active">{{track.title}}</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="track-toolbar btn-group pull-right">
|
||||||
|
<a href="#" class="btn btn-small">
|
||||||
|
Favourite This!
|
||||||
|
<i class="icon-star-empty"></i>
|
||||||
|
</a>
|
||||||
|
<a href="#" class="btn btn-small">
|
||||||
|
Add to Playlist <i class="caret"></i>
|
||||||
|
</a>
|
||||||
|
<div class="dropdown">
|
||||||
|
<a href="#" class="btn btn-small btn-info dropdown-toggle">
|
||||||
|
Downloads <i class="caret"></i>
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><a href="#"></a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1>
|
||||||
|
{{track.title}}
|
||||||
|
<span class="subtitle">
|
||||||
|
by: <a href="{{track.user.url}}">{{track.user.name}}</a>
|
||||||
|
</span>
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<div class="track-details">
|
||||||
|
<div class="row-fluid">
|
||||||
|
<div class="span7">
|
||||||
|
<div class="description">
|
||||||
|
<p ng-bind-html-unsafe="track.description | noHTML | newlines"></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div ng-show="track.is_vocal && track.lyrics.length" class="lyrics-panel">
|
||||||
|
<h2>Lyrics</h2>
|
||||||
|
<div class="lyrics revealable">
|
||||||
|
<div class="reveal">
|
||||||
|
<a href="#">Click to reveal full lyrics...</a>
|
||||||
|
</div>
|
||||||
|
<p class="content" ng-bind-html-unsafe="track.lyrics | noHTML | newlines"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="span5 cover-image">
|
||||||
|
<img ng-src="{{track.covers.normal}}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2>Comments</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
Loading…
Reference in a new issue