mirror of
https://github.com/Poniverse/Pony.fm.git
synced 2024-11-24 22:18:00 +01:00
Many things
This commit is contained in:
parent
1aac8a8f64
commit
b71efac59f
79 changed files with 4297 additions and 233 deletions
64
app/commands/MigrateOldData.php
Normal file
64
app/commands/MigrateOldData.php
Normal file
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
|
||||
class MigrateOldData extends Command {
|
||||
protected $name = 'migrate-old-data';
|
||||
protected $description = 'Migrates data from the old pfm site.';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function fire() {
|
||||
$this->call('migrate:refresh');
|
||||
|
||||
$oldDb = DB::connection('old');
|
||||
$oldUsers = $oldDb->table('users')->get();
|
||||
|
||||
foreach ($oldUsers as $user) {
|
||||
$displayName = $user->display_name;
|
||||
if (!$displayName)
|
||||
$displayName = $user->username;
|
||||
|
||||
if (!$displayName)
|
||||
$displayName = $user->mlpforums_name;
|
||||
|
||||
if (!$displayName)
|
||||
continue;
|
||||
|
||||
DB::table('users')->insert([
|
||||
'id' => $user->id,
|
||||
'display_name' => $displayName,
|
||||
'email' => $user->email,
|
||||
'created_at' => $user->created_at,
|
||||
'updated_at' => $user->updated_at,
|
||||
'slug' => $user->slug,
|
||||
'password_hash' => $user->password_hash,
|
||||
'password_salt' => $user->password_salt,
|
||||
'bio' => $user->bio,
|
||||
'sync_names' => $user->sync_names,
|
||||
'can_see_explicit_content' => $user->can_see_explicit_content,
|
||||
'mlpforums_name' => $user->mlpforums_name,
|
||||
'uses_gravatar' => $user->uses_gravatar,
|
||||
'gravatar' => $user->gravatar
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
protected function getArguments()
|
||||
{
|
||||
return [
|
||||
['example', InputArgument::REQUIRED, 'An example argument.'],
|
||||
];
|
||||
}
|
||||
|
||||
protected function getOptions() {
|
||||
return [
|
||||
['example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -4,11 +4,9 @@
|
|||
|
||||
use Commands\CreateAlbumCommand;
|
||||
use Commands\DeleteAlbumCommand;
|
||||
use Commands\DeleteTrackCommand;
|
||||
use Commands\EditAlbumCommand;
|
||||
use Commands\EditTrackCommand;
|
||||
use Cover;
|
||||
use Entities\Album;
|
||||
use Entities\Comment;
|
||||
use Entities\Image;
|
||||
use Entities\Track;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
@ -29,7 +27,7 @@
|
|||
}
|
||||
|
||||
public function getShow($id) {
|
||||
$album = Album::with('tracks', 'user')->find($id);
|
||||
$album = Album::with(['tracks', 'user', 'comments' => function($query) { $query->with('user'); }])->details()->find($id);
|
||||
if (!$album)
|
||||
App::abort(404);
|
||||
|
||||
|
@ -47,6 +45,11 @@
|
|||
];
|
||||
}
|
||||
|
||||
$comments = [];
|
||||
foreach ($album->comments as $comment) {
|
||||
$comments[] = Comment::mapPublic($comment);
|
||||
}
|
||||
|
||||
return Response::json([
|
||||
'album' => [
|
||||
'id' => $album->id,
|
||||
|
@ -71,7 +74,8 @@
|
|||
'views' => 0,
|
||||
'downloads' => 0
|
||||
],
|
||||
'comments' => ['count' => 0, 'list' => []]
|
||||
'comments' => ['count' => count($comments), 'list' => $comments],
|
||||
'is_favourited' => $album->favourites->count() > 0
|
||||
]
|
||||
], 200);
|
||||
}
|
||||
|
@ -82,7 +86,8 @@
|
|||
$page = Input::get('page');
|
||||
|
||||
$query = Album::summary()
|
||||
->with('tracks', 'user')
|
||||
->with(['tracks' => function($query) { $query->details(); }, 'user'])
|
||||
->details()
|
||||
->orderBy('created_at', 'desc')
|
||||
->whereRaw('(SELECT COUNT(id) FROM tracks WHERE tracks.album_id = albums.id) > 0');
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
use Commands\EditTrackCommand;
|
||||
use Cover;
|
||||
use Entities\Album;
|
||||
use Entities\Comment;
|
||||
use Entities\Favourite;
|
||||
use Entities\Image;
|
||||
use Entities\Track;
|
||||
use Entities\User;
|
||||
|
@ -17,6 +19,33 @@
|
|||
use Illuminate\Support\Facades\Response;
|
||||
|
||||
class ArtistsController extends \ApiControllerBase {
|
||||
public function getFavourites($slug) {
|
||||
$user = User::whereSlug($slug)->first();
|
||||
if (!$user)
|
||||
App::abort(404);
|
||||
|
||||
$favs = Favourite::whereUserId($user->id)->with([
|
||||
'track' => function($query) { $query->details(); },
|
||||
'album' => function($query) { $query->details(); }])->get();
|
||||
|
||||
$tracks = [];
|
||||
$albums = [];
|
||||
|
||||
foreach ($favs as $fav) {
|
||||
if ($fav->type == 'Entities\Track') {
|
||||
$tracks[] = Track::mapPublicTrackSummary($fav->track);
|
||||
}
|
||||
else if ($fav->type == 'Entities\Album') {
|
||||
$albums[] = Album::mapPublicAlbumSummary($fav->album);
|
||||
}
|
||||
}
|
||||
|
||||
return Response::json([
|
||||
'tracks' => $tracks,
|
||||
'albums' => $albums
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function getContent($slug) {
|
||||
$user = User::whereSlug($slug)->first();
|
||||
if (!$user)
|
||||
|
@ -49,17 +78,22 @@
|
|||
}
|
||||
|
||||
public function getShow($slug) {
|
||||
$user = User::whereSlug($slug)->first();
|
||||
$user = User::whereSlug($slug)->with(['comments' => function ($query) { $query->with('user'); }])->first();
|
||||
if (!$user)
|
||||
App::abort(404);
|
||||
|
||||
$trackQuery = Track::summary()->whereUserId($user->id)->whereNotNull('published_at')->orderBy('created_at', 'desc')->take(10);
|
||||
$trackQuery = Track::summary()->whereUserId($user->id)->whereNotNull('published_at')->orderBy('created_at', 'desc')->take(20);
|
||||
$latestTracks = [];
|
||||
|
||||
foreach ($trackQuery->get() as $track) {
|
||||
$latestTracks[] = Track::mapPublicTrackSummary($track);
|
||||
}
|
||||
|
||||
$comments = [];
|
||||
foreach ($user->comments as $comment) {
|
||||
$comments[] = Comment::mapPublic($comment);
|
||||
}
|
||||
|
||||
return Response::json([
|
||||
'artist' => [
|
||||
'id' => $user->id,
|
||||
|
@ -73,7 +107,7 @@
|
|||
'followers' => [],
|
||||
'following' => [],
|
||||
'latest_tracks' => $latestTracks,
|
||||
'comments' => ['count' => 0, 'list' => []],
|
||||
'comments' => ['count' => count($comments), 'list' => $comments],
|
||||
'bio' => $user->bio,
|
||||
'mlpforums_username' => $user->mlpforums_name
|
||||
]
|
||||
|
|
42
app/controllers/Api/Web/CommentsController.php
Normal file
42
app/controllers/Api/Web/CommentsController.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace Api\Web;
|
||||
|
||||
use Commands\CreateCommentCommand;
|
||||
use Entities\Album;
|
||||
use Entities\Comment;
|
||||
use Entities\Image;
|
||||
use Entities\Playlist;
|
||||
use Entities\Track;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
|
||||
class CommentsController extends \ApiControllerBase {
|
||||
public function postCreate($type, $id) {
|
||||
return $this->execute(new CreateCommentCommand($type, $id, Input::all()));
|
||||
}
|
||||
|
||||
public function getIndex($type, $id) {
|
||||
$column = '';
|
||||
|
||||
if ($type == 'track')
|
||||
$column = 'track_id';
|
||||
else if ($type == 'user')
|
||||
$column = 'profile_id';
|
||||
else if ($type == 'album')
|
||||
$column = 'album_id';
|
||||
else if ($type == 'playlist')
|
||||
$column = 'playlist_id';
|
||||
else
|
||||
App::abort(500);
|
||||
|
||||
$query = Comment::where($column, '=', $id)->orderBy('created_at', 'desc')->with('user');
|
||||
$comments = [];
|
||||
|
||||
foreach ($query->get() as $comment) {
|
||||
$comments[] = Comment::mapPublic($comment);
|
||||
}
|
||||
|
||||
return Response::json(['list' => $comments, 'count' => count($comments)]);
|
||||
}
|
||||
}
|
|
@ -14,41 +14,14 @@
|
|||
|
||||
class DashboardController extends \ApiControllerBase {
|
||||
public function getIndex() {
|
||||
$query = Track::summary()->with(['genre', 'user', 'cover'])->whereNotNull('published_at')->orderBy('published_at', 'desc')->take(15);
|
||||
$query = Track::summary()->with(['genre', 'user', 'cover'])->details()->whereNotNull('published_at')->orderBy('published_at', 'desc')->take(30);
|
||||
if (!Auth::check() || !Auth::user()->can_see_explicit_content)
|
||||
$query->whereIsExplicit(false);
|
||||
|
||||
$tracks = [];
|
||||
|
||||
foreach ($query->get() as $track) {
|
||||
$tracks[] = [
|
||||
'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' => [
|
||||
'id' => $track->genre->id,
|
||||
'slug' => $track->genre->slug,
|
||||
'name' => $track->genre->name
|
||||
],
|
||||
'track_type_id' => $track->track_type_id,
|
||||
'covers' => [
|
||||
'thumbnail' => $track->getCoverUrl(Image::THUMBNAIL),
|
||||
'small' => $track->getCoverUrl(Image::SMALL),
|
||||
'normal' => $track->getCoverUrl(Image::NORMAL)
|
||||
]
|
||||
];
|
||||
$tracks[] = Track::mapPublicTrackSummary($track);
|
||||
}
|
||||
|
||||
return Response::json([
|
||||
|
|
12
app/controllers/Api/Web/FavouritesController.php
Normal file
12
app/controllers/Api/Web/FavouritesController.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace Api\Web;
|
||||
|
||||
use Commands\ToggleFavouriteCommand;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
|
||||
class FavouritesController extends \ApiControllerBase {
|
||||
public function postToggle() {
|
||||
return $this->execute(new ToggleFavouriteCommand(Input::get('type'), Input::get('id')));
|
||||
}
|
||||
}
|
|
@ -2,18 +2,13 @@
|
|||
|
||||
namespace Api\Web;
|
||||
|
||||
use Commands\CreateAlbumCommand;
|
||||
use Commands\AddTrackToPlaylistCommand;
|
||||
use Commands\CreatePlaylistCommand;
|
||||
use Commands\DeleteAlbumCommand;
|
||||
use Commands\DeletePlaylistCommand;
|
||||
use Commands\DeleteTrackCommand;
|
||||
use Commands\EditAlbumCommand;
|
||||
use Commands\EditPlaylistCommand;
|
||||
use Commands\EditTrackCommand;
|
||||
use Cover;
|
||||
use Entities\Album;
|
||||
use Entities\Comment;
|
||||
use Entities\Image;
|
||||
use Entities\PinnedPlaylist;
|
||||
use Entities\Playlist;
|
||||
use Entities\Track;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
@ -33,11 +28,25 @@
|
|||
return $this->execute(new DeletePlaylistCommand($id, Input::all()));
|
||||
}
|
||||
|
||||
public function postAddTrack($id) {
|
||||
return $this->execute(new AddTrackToPlaylistCommand($id, Input::get('track_id')));
|
||||
}
|
||||
|
||||
public function getShow($id) {
|
||||
$playlist = Playlist::find($id);
|
||||
$playlist = Playlist::with(['tracks' => function($query) { $query->details(); }, 'comments' => function($query) { $query->with('user'); }])->find($id);
|
||||
if (!$playlist || !$playlist->canView(Auth::user()))
|
||||
App::abort('404');
|
||||
|
||||
$tracks = [];
|
||||
foreach ($playlist->tracks as $track) {
|
||||
$tracks[] = Track::mapPublicTrackSummary($track);
|
||||
}
|
||||
|
||||
$comments = [];
|
||||
foreach ($playlist->comments as $comment) {
|
||||
$comments[] = Comment::mapPublic($comment);
|
||||
}
|
||||
|
||||
return Response::json([
|
||||
'id' => $playlist->id,
|
||||
'title' => $playlist->title,
|
||||
|
@ -50,7 +59,9 @@
|
|||
'normal' => $playlist->getCoverUrl(Image::NORMAL)
|
||||
],
|
||||
'is_pinned' => true,
|
||||
'is_public' => $playlist->is_public == 1
|
||||
'is_public' => $playlist->is_public == 1,
|
||||
'tracks' => $tracks,
|
||||
'comments' => ['count' => count($comments), 'list' => $comments],
|
||||
], 200);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
use Commands\EditTrackCommand;
|
||||
use Commands\UploadTrackCommand;
|
||||
use Cover;
|
||||
use Entities\Favourite;
|
||||
use Entities\Image;
|
||||
use Entities\Track;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
@ -27,7 +28,7 @@
|
|||
}
|
||||
|
||||
public function getShow($id) {
|
||||
$track = Track::find($id);
|
||||
$track = Track::details()->withComments()->find($id);
|
||||
if (!$track || !$track->canView(Auth::user()))
|
||||
return $this->notFound('Track not found!');
|
||||
|
||||
|
@ -35,7 +36,7 @@
|
|||
}
|
||||
|
||||
public function getRecent() {
|
||||
$query = Track::summary()->with(['genre', 'user', 'cover'])->whereNotNull('published_at')->orderBy('published_at', 'desc')->take(15);
|
||||
$query = Track::summary()->details()->with(['genre', 'user', 'cover'])->whereNotNull('published_at')->orderBy('published_at', 'desc')->take(30);
|
||||
if (!Auth::check() || !Auth::user()->can_see_explicit_content)
|
||||
$query->whereIsExplicit(false);
|
||||
|
||||
|
@ -54,15 +55,23 @@
|
|||
if (Input::has('page'))
|
||||
$page = Input::get('page');
|
||||
|
||||
$query = Track::summary()->whereNotNull('published_at');
|
||||
$query = Track::summary()
|
||||
->details()
|
||||
->whereNotNull('published_at')
|
||||
->with('user', 'genre');
|
||||
|
||||
$this->applyFilters($query);
|
||||
|
||||
$totalCount = $query->count();
|
||||
$query->take(30)->skip(30 * ($page - 1));
|
||||
|
||||
$tracks = [];
|
||||
foreach ($query->get() as $track)
|
||||
$ids = [];
|
||||
|
||||
foreach ($query->get() as $track) {
|
||||
$tracks[] = Track::mapPublicTrackSummary($track);
|
||||
$ids[] = $track->id;
|
||||
}
|
||||
|
||||
return Response::json(["tracks" => $tracks, "current_page" => $page, "total_pages" => ceil($totalCount / 30)], 200);
|
||||
}
|
||||
|
|
|
@ -26,4 +26,19 @@
|
|||
|
||||
return Redirect::action('TracksController@getTrack', [$id, $track->slug]);
|
||||
}
|
||||
|
||||
public function getStream($id) {
|
||||
$track = Track::find($id);
|
||||
if (!$track || !$track->canView(Auth::user()))
|
||||
App::abort(404);
|
||||
|
||||
$format = Track::$Formats['MP3'];
|
||||
|
||||
$response = Response::make('', 200);
|
||||
$response->header('X-Sendfile', $track->getFileFor('MP3'));
|
||||
$response->header('Content-Disposition', 'filename=' . $track->getFilenameFor('MP3'));
|
||||
$response->header('Content-Type', $format['mime_type']);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@ class CreateUsersTable extends Migration {
|
|||
$table->boolean('sync_names')->default(true);
|
||||
$table->string('password_hash', 32);
|
||||
$table->string('password_salt', 5);
|
||||
$table->string('email', 150)->unique();
|
||||
$table->string('email', 150)->indexed();
|
||||
$table->string('gravatar')->nullable();
|
||||
$table->string('slug');
|
||||
$table->boolean('uses_gravatar')->default(true);
|
||||
|
|
|
@ -2040,8 +2040,8 @@ Twilight Sparkle: Yes! Everything’s going to be just fine!",
|
|||
|
||||
public function down() {
|
||||
Schema::table('show_song_track', function($table){
|
||||
$table->drop_foreign('show_song_track_track_id_foreign');
|
||||
$table->drop_foreign('show_song_track_show_song_id_foreign');
|
||||
$table->dropForeign('show_song_track_track_id_foreign');
|
||||
$table->dropForeign('show_song_track_show_song_id_foreign');
|
||||
});
|
||||
|
||||
Schema::drop('show_song_track');
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateFavourites extends Migration {
|
||||
public function up() {
|
||||
Schema::create('favourites', function($table){
|
||||
$table->increments('id');
|
||||
$table->integer('user_id')->unsigned()->index();
|
||||
|
||||
$table->integer('track_id')->unsigned()->nullable()->index();
|
||||
$table->integer('album_id')->unsigned()->nullable()->index();
|
||||
$table->integer('playlist_id')->unsigned()->nullable()->index();
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
$table->foreign('user_id')->references('id')->on('users')->on_delete('cascade');
|
||||
$table->foreign('track_id')->references('id')->on('tracks');
|
||||
$table->foreign('album_id')->references('id')->on('albums');
|
||||
$table->foreign('playlist_id')->references('id')->on('playlists');
|
||||
});
|
||||
}
|
||||
|
||||
public function down() {
|
||||
Schema::table('favourites', function($table){
|
||||
$table->dropForeign('favourites_user_id_foreign');
|
||||
$table->dropForeign('favourites_track_id_foreign');
|
||||
$table->dropForeign('favourites_album_id_foreign');
|
||||
$table->dropForeign('favourites_playlist_id_foreign');
|
||||
});
|
||||
|
||||
Schema::drop('favourites');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateComments extends Migration {
|
||||
public function up() {
|
||||
Schema::create('comments', function($table){
|
||||
$table->increments('id');
|
||||
$table->integer('user_id')->unsigned();
|
||||
$table->timestamps();
|
||||
$table->string('ip_address', 46);
|
||||
$table->text('content');
|
||||
$table->timestamp('deleted_at')->nullable()->index();
|
||||
|
||||
$table->integer('profile_id')->unsigned()->nullable()->index();
|
||||
$table->integer('track_id')->unsigned()->nullable()->index();
|
||||
$table->integer('album_id')->unsigned()->nullable()->index();
|
||||
$table->integer('playlist_id')->unsigned()->nullable()->index();
|
||||
|
||||
$table->foreign('profile_id')->references('id')->on('users');
|
||||
$table->foreign('user_id')->references('id')->on('users');
|
||||
$table->foreign('track_id')->references('id')->on('tracks');
|
||||
$table->foreign('album_id')->references('id')->on('albums');
|
||||
$table->foreign('playlist_id')->references('id')->on('playlists');
|
||||
});
|
||||
}
|
||||
|
||||
public function down() {
|
||||
Schema::table('comments', function($table){
|
||||
$table->dropForeign('comments_user_id_foreign');
|
||||
$table->dropForeign('comments_track_id_foreign');
|
||||
$table->dropForeign('comments_album_id_foreign');
|
||||
$table->dropForeign('comments_playlist_id_foreign');
|
||||
});
|
||||
Schema::drop('comments');
|
||||
}
|
||||
}
|
|
@ -45,9 +45,11 @@
|
|||
return new AssetCollection([
|
||||
new FileAsset('scripts/base/jquery-2.0.2.js'),
|
||||
new FileAsset('scripts/base/jquery-ui.js'),
|
||||
new FileAsset('scripts/base/jquery.cookie.js'),
|
||||
new FileAsset('scripts/base/jquery.colorbox.js'),
|
||||
new FileAsset('scripts/base/underscore.js'),
|
||||
new FileAsset('scripts/base/moment.js'),
|
||||
new FileAsset('scripts/base/soundmanager2-nodebug.js'),
|
||||
new FileAsset('scripts/base/angular.js'),
|
||||
new FileAsset('scripts/base/ui-bootstrap-tpls-0.4.0.js'),
|
||||
new FileAsset('scripts/base/angular-ui-sortable.js'),
|
||||
|
|
37
app/models/Commands/AddTrackToPlaylistCommand.php
Normal file
37
app/models/Commands/AddTrackToPlaylistCommand.php
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace Commands;
|
||||
|
||||
use Entities\Album;
|
||||
use Entities\Favourite;
|
||||
use Entities\Playlist;
|
||||
use Entities\Track;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class AddTrackToPlaylistCommand extends CommandBase {
|
||||
private $_track;
|
||||
private $_playlist;
|
||||
|
||||
function __construct($playlistId, $trackId) {
|
||||
$this->_playlist = Playlist::find($playlistId);
|
||||
$this->_track = Track::find($trackId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize() {
|
||||
$user = Auth::user();
|
||||
return $user != null && $this->_playlist && $this->_track && $this->_playlist->user_id == $user->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
* @return CommandResponse
|
||||
*/
|
||||
public function execute() {
|
||||
$songIndex = $this->_playlist->tracks()->count() + 1;
|
||||
$this->_playlist->tracks()->attach($this->_track, ['position' => $songIndex]);
|
||||
return CommandResponse::succeed(['message' => 'Track added!']);
|
||||
}
|
||||
}
|
71
app/models/Commands/CreateCommentCommand.php
Normal file
71
app/models/Commands/CreateCommentCommand.php
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace Commands;
|
||||
|
||||
use Entities\Album;
|
||||
use Entities\Comment;
|
||||
use Entities\Image;
|
||||
use Entities\Track;
|
||||
use External;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class CreateCommentCommand extends CommandBase {
|
||||
private $_input;
|
||||
private $_id;
|
||||
private $_type;
|
||||
|
||||
function __construct($type, $id, $input) {
|
||||
$this->_input = $input;
|
||||
$this->_id = $id;
|
||||
$this->_type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize() {
|
||||
$user = \Auth::user();
|
||||
return $user != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
* @return CommandResponse
|
||||
*/
|
||||
public function execute() {
|
||||
$rules = [
|
||||
'content' => 'required',
|
||||
'track_id' => 'exists:tracks,id',
|
||||
'albums_id' => 'exists:albums,id',
|
||||
'playlist_id' => 'exists:playlists,id',
|
||||
'profile_id' => 'exists:users,id',
|
||||
];
|
||||
|
||||
$validator = Validator::make($this->_input, $rules);
|
||||
|
||||
if ($validator->fails())
|
||||
return CommandResponse::fail($validator);
|
||||
|
||||
$comment = new Comment();
|
||||
$comment->user_id = Auth::user()->id;
|
||||
$comment->content = $this->_input['content'];
|
||||
|
||||
if ($this->_type == 'track')
|
||||
$column = 'track_id';
|
||||
else if ($this->_type == 'user')
|
||||
$column = 'profile_id';
|
||||
else if ($this->_type == 'album')
|
||||
$column = 'album_id';
|
||||
else if ($this->_type == 'playlist')
|
||||
$column = 'playlist_id';
|
||||
else
|
||||
App::abort(500);
|
||||
|
||||
$comment->$column = $this->_id;
|
||||
$comment->save();
|
||||
|
||||
return CommandResponse::succeed(Comment::mapPublic($comment));
|
||||
}
|
||||
}
|
49
app/models/Commands/ToggleFavouriteCommand.php
Normal file
49
app/models/Commands/ToggleFavouriteCommand.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace Commands;
|
||||
|
||||
use Entities\Album;
|
||||
use Entities\Favourite;
|
||||
use Entities\Playlist;
|
||||
use Entities\Track;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class ToggleFavouriteCommand extends CommandBase {
|
||||
private $_resourceType;
|
||||
private $_resourceId;
|
||||
|
||||
function __construct($resourceType, $resourceId) {
|
||||
$this->_resourceId = $resourceId;
|
||||
$this->_resourceType = $resourceType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize() {
|
||||
$user = Auth::user();
|
||||
return$user != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
* @return CommandResponse
|
||||
*/
|
||||
public function execute() {
|
||||
$typeId = $this->_resourceType . '_id';
|
||||
$existing = Favourite::where($typeId, '=', $this->_resourceId)->first();
|
||||
$isFavourited = false;
|
||||
|
||||
if ($existing) {
|
||||
$existing->delete();
|
||||
} else {
|
||||
$fav = new Favourite();
|
||||
$fav->$typeId = $this->_resourceId;
|
||||
$fav->user_id = Auth::user()->id;
|
||||
$fav->save();
|
||||
$isFavourited = true;
|
||||
}
|
||||
|
||||
return CommandResponse::succeed(['is_favourited' => $isFavourited]);
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
namespace Entities;
|
||||
|
||||
use Cover;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
use Whoops\Example\Exception;
|
||||
use Traits\SlugTrait;
|
||||
|
@ -16,12 +17,26 @@
|
|||
return self::select('id', 'title', 'user_id', 'slug', 'created_at', 'cover_id');
|
||||
}
|
||||
|
||||
public function scopeDetails($query) {
|
||||
if (Auth::check()) {
|
||||
$query->with(['favourites' => function($query) {
|
||||
$query->whereUserId(Auth::user()->id);
|
||||
}]);
|
||||
}
|
||||
|
||||
return !$query;
|
||||
}
|
||||
|
||||
protected $table = 'albums';
|
||||
|
||||
public function user() {
|
||||
return $this->belongsTo('Entities\User');
|
||||
}
|
||||
|
||||
public function favourites() {
|
||||
return $this->hasMany('Entities\Favourite');
|
||||
}
|
||||
|
||||
public function cover() {
|
||||
return $this->belongsTo('Entities\Image');
|
||||
}
|
||||
|
@ -30,6 +45,10 @@
|
|||
return $this->hasMany('Entities\Track')->orderBy('track_number', 'asc');
|
||||
}
|
||||
|
||||
public function comments(){
|
||||
return $this->hasMany('Entities\Comment');
|
||||
}
|
||||
|
||||
public static function mapPublicAlbumSummary($album) {
|
||||
return [
|
||||
'id' => $album->id,
|
||||
|
@ -46,7 +65,8 @@
|
|||
'id' => $album->user->id,
|
||||
'name' => $album->user->display_name,
|
||||
'url' => $album->user->url,
|
||||
]
|
||||
],
|
||||
'is_favourited' => $album->favourites->count() > 0
|
||||
];
|
||||
}
|
||||
|
||||
|
|
62
app/models/Entities/Comment.php
Normal file
62
app/models/Entities/Comment.php
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
namespace Entities;
|
||||
|
||||
class Comment extends \Eloquent {
|
||||
protected $table = 'comments';
|
||||
protected $softDelete = true;
|
||||
|
||||
public function user(){
|
||||
return $this->belongsTo('Entities\User');
|
||||
}
|
||||
|
||||
public function track(){
|
||||
return $this->belongsTo('Entities\Track');
|
||||
}
|
||||
|
||||
public function album(){
|
||||
return $this->belongsTo('Entities\Album');
|
||||
}
|
||||
|
||||
public function playlist(){
|
||||
return $this->belongsTo('Entities\Playlist');
|
||||
}
|
||||
|
||||
public function profile(){
|
||||
return $this->belongsTo('Entities\User', 'profile_id');
|
||||
}
|
||||
|
||||
public static function mapPublic($comment) {
|
||||
return [
|
||||
'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),
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function getResourceAttribute(){
|
||||
if($this->track_id !== NULL)
|
||||
return $this->track;
|
||||
|
||||
else if($this->album_id !== NULL)
|
||||
return $this->album;
|
||||
|
||||
else if($this->playlist_id !== NULL)
|
||||
return $this->playlist;
|
||||
|
||||
else if($this->profile_id !== NULL)
|
||||
return $this->profile;
|
||||
|
||||
else return NULL;
|
||||
}
|
||||
}
|
53
app/models/Entities/Favourite.php
Normal file
53
app/models/Entities/Favourite.php
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
namespace Entities;
|
||||
|
||||
class Favourite extends \Eloquent {
|
||||
protected $table = 'favourites';
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Relationships
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public function user(){
|
||||
return $this->belongsTo('Entities\User');
|
||||
}
|
||||
|
||||
public function track(){
|
||||
return $this->belongsTo('Entities\Track');
|
||||
}
|
||||
|
||||
public function album(){
|
||||
return $this->belongsTo('Entities\Album');
|
||||
}
|
||||
|
||||
public function playlist(){
|
||||
return $this->belongsTo('Entities\Playlist');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the resource associated with this favourite.
|
||||
*
|
||||
* @return Resource|NULL
|
||||
*/
|
||||
public function getResourceAttribute(){
|
||||
if ($this->track_id)
|
||||
return $this->track;
|
||||
|
||||
else if($this->album_id)
|
||||
return $this->album;
|
||||
|
||||
else if($this->playlist_id)
|
||||
return $this->playlist;
|
||||
|
||||
// no resource - this should never happen under real circumstances
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
public function getTypeAttribute(){
|
||||
return get_class($this->resource);
|
||||
}
|
||||
}
|
|
@ -14,7 +14,15 @@
|
|||
}
|
||||
|
||||
public function tracks() {
|
||||
return $this->belongsToMany('Entities\Track')->orderBy('position', 'asc');
|
||||
return $this
|
||||
->belongsToMany('Entities\Track')
|
||||
->withPivot('position')
|
||||
->withTimestamps()
|
||||
->orderBy('position', 'asc');
|
||||
}
|
||||
|
||||
public function comments(){
|
||||
return $this->hasMany('Entities\Comment');
|
||||
}
|
||||
|
||||
public function pins() {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
use External;
|
||||
use getid3_writetags;
|
||||
use Helpers;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
use Illuminate\Support\Str;
|
||||
|
@ -29,6 +30,20 @@
|
|||
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 function scopeDetails($query) {
|
||||
if (Auth::check()) {
|
||||
$query->with(['favourites' => function($query) {
|
||||
$query->whereUserId(Auth::user()->id);
|
||||
}]);
|
||||
}
|
||||
|
||||
return !$query;
|
||||
}
|
||||
|
||||
public function scopeWithComments($query) {
|
||||
$query->with(['comments' => function($query) { $query->with('user'); }]);
|
||||
}
|
||||
|
||||
public static function mapPublicTrackShow($track) {
|
||||
$returnValue = self::mapPublicTrackSummary($track);
|
||||
$returnValue['description'] = $track->description;
|
||||
|
@ -38,7 +53,14 @@
|
|||
'plays' => 0,
|
||||
'downloads' => 0
|
||||
];
|
||||
$returnValue['comments'] = ['count' => 0, 'list' => []];
|
||||
|
||||
$comments = [];
|
||||
|
||||
foreach ($track->comments as $comment) {
|
||||
$comments[] = Comment::mapPublic($comment);
|
||||
}
|
||||
|
||||
$returnValue['comments'] = ['count' => count($comments), 'list' => $comments];
|
||||
|
||||
if ($track->album_id != null) {
|
||||
$returnValue['album'] = [
|
||||
|
@ -94,7 +116,9 @@
|
|||
'thumbnail' => $track->getCoverUrl(Image::THUMBNAIL),
|
||||
'small' => $track->getCoverUrl(Image::SMALL),
|
||||
'normal' => $track->getCoverUrl(Image::NORMAL)
|
||||
]
|
||||
],
|
||||
'is_favourited' => $track->favourites->count() > 0,
|
||||
'duration' => $track->duration
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -142,6 +166,14 @@
|
|||
return $this->belongsTo('Entities\Genre');
|
||||
}
|
||||
|
||||
public function comments(){
|
||||
return $this->hasMany('Entities\Comment');
|
||||
}
|
||||
|
||||
public function favourites() {
|
||||
return $this->hasMany('Entities\Favourite');
|
||||
}
|
||||
|
||||
public function cover() {
|
||||
return $this->belongsTo('Entities\Image');
|
||||
}
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
return $this->belongsTo('Entities\Image');
|
||||
}
|
||||
|
||||
public function comments(){
|
||||
return $this->hasMany('Entities\Comment', 'profile_id');
|
||||
}
|
||||
|
||||
public function getUrlAttribute() {
|
||||
return URL::to('/' . $this->slug);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
Route::get('tracks/{id}-{slug}', 'TracksController@getTrack');
|
||||
Route::get('t{id}', 'TracksController@getShortlink' );
|
||||
Route::get('t{id}/stream', 'TracksController@getStream' );
|
||||
Route::get('t{id}/dl.{extension}', 'TracksController@getDownload' );
|
||||
|
||||
Route::get('albums', 'AlbumsController@getIndex');
|
||||
|
@ -52,6 +53,10 @@
|
|||
Route::get('/albums', 'Api\Web\AlbumsController@getIndex');
|
||||
Route::get('/albums/{id}', 'Api\Web\AlbumsController@getShow')->where('id', '\d+');
|
||||
|
||||
Route::get('/playlists/{id}', 'Api\Web\PlaylistsController@getShow')->where('id', '\d+');
|
||||
|
||||
Route::get('/comments/{type}/{id}', 'Api\Web\CommentsController@getIndex')->where('id', '\d+');
|
||||
|
||||
Route::get('/artists', 'Api\Web\ArtistsController@getIndex');
|
||||
Route::get('/artists/{slug}', 'Api\Web\ArtistsController@getShow');
|
||||
Route::get('/artists/{slug}/content', 'Api\Web\ArtistsController@getContent');
|
||||
|
@ -71,8 +76,13 @@
|
|||
Route::post('/playlists/create', 'Api\Web\PlaylistsController@postCreate');
|
||||
Route::post('/playlists/delete/{id}', 'Api\Web\PlaylistsController@postDelete');
|
||||
Route::post('/playlists/edit/{id}', 'Api\Web\PlaylistsController@postEdit');
|
||||
Route::post('/playlists/{id}/add-track', 'Api\Web\PlaylistsController@postAddTrack');
|
||||
|
||||
Route::post('/comments/{type}/{id}', 'Api\Web\CommentsController@postCreate')->where('id', '\d+');
|
||||
|
||||
Route::post('/account/settings/save', 'Api\Web\AccountController@postSave');
|
||||
|
||||
Route::post('/favourites/toggle', 'Api\Web\FavouritesController@postToggle');
|
||||
});
|
||||
|
||||
Route::group(['before' => 'auth'], function() {
|
||||
|
|
|
@ -11,3 +11,4 @@
|
|||
|
|
||||
*/
|
||||
|
||||
Artisan::add(new MigrateOldData);
|
|
@ -5,22 +5,7 @@
|
|||
<div>
|
||||
<h1><a href="/">Pony.fm</a></h1>
|
||||
<div class="now-playing">
|
||||
<div class="current-track">
|
||||
<div class="transport">
|
||||
<div class="bar" style="width: 44%;"></div>
|
||||
</div>
|
||||
<div class="image"></div>
|
||||
<ul class="buttons">
|
||||
<li><a class="previous" href="#"><i class="icon-fast-backward"></i></a></li>
|
||||
<li><a class="play" href="#"><i class="icon-pause"></i></a></li>
|
||||
<li><a class="next" href="#"><i class="icon-fast-forward"></i></a></li>
|
||||
<li><a class="volume" href="#"><i class="icon-volume-up"></i></a></li>
|
||||
</ul>
|
||||
<div class="title">
|
||||
<span class="song"><a href="#">Love Me Cheerilee</a></span>
|
||||
<span class="artist"><a href="#">MandoPony</a></span>
|
||||
</div>
|
||||
</div>
|
||||
<pfm-player></pfm-player>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
@ -65,7 +50,7 @@
|
|||
Account
|
||||
</h3>
|
||||
</li>
|
||||
<li ng-class="{selected: $state.includes('account-favourites')}"><a href="/account/favourites">Favourites</a></li>
|
||||
{{-- <li ng-class="{selected: $state.includes('account-favourites')}"><a href="/account/favourites">Favourites</a></li> --}}
|
||||
<li ng-class="{selected: $state.includes('account-content')}"><a href="/account/tracks">Your Content</a></li>
|
||||
<li ng-class="{selected: isActive('/account')}"><a href="/account">Settings</a></li>
|
||||
@endif
|
||||
|
@ -74,7 +59,7 @@
|
|||
|
||||
@if (!Auth::check())
|
||||
<li ng-class="{selected: isActive('/login')}"><a href="/login">Login</a></li>
|
||||
<li ng-class="{selected: isActive('/register')}"><a href="/register">Register</a></li>
|
||||
{{-- <li ng-class="{selected: isActive('/register')}"><a href="/register">Register</a></li> --}}
|
||||
@endif
|
||||
|
||||
<li ng-class="{selected: isActive('/about')}"><a href="/about">About</a></li>
|
||||
|
|
|
@ -6,4 +6,8 @@
|
|||
RewriteRule ^ index.php [L]
|
||||
RewriteRule ^(.*\.(?:coffee))$ /asset.php?type=coffee&file=/$1 [L,QSA,NC]
|
||||
RewriteRule ^(.*\.(?:less))$ /asset.php?type=less&file=/$1 [L,QSA,NC]
|
||||
</IfModule>
|
||||
</IfModule>
|
||||
|
||||
<IfModule xsendfile_module>
|
||||
XSendFile On
|
||||
</IfModule>
|
||||
|
|
BIN
public/flash/soundmanager/soundmanager2.swf
Normal file
BIN
public/flash/soundmanager/soundmanager2.swf
Normal file
Binary file not shown.
BIN
public/flash/soundmanager/soundmanager2_debug.swf
Normal file
BIN
public/flash/soundmanager/soundmanager2_debug.swf
Normal file
Binary file not shown.
BIN
public/flash/soundmanager/soundmanager2_flash9.swf
Normal file
BIN
public/flash/soundmanager/soundmanager2_flash9.swf
Normal file
Binary file not shown.
BIN
public/flash/soundmanager/soundmanager2_flash9_debug.swf
Normal file
BIN
public/flash/soundmanager/soundmanager2_flash9_debug.swf
Normal file
Binary file not shown.
BIN
public/flash/soundmanager/soundmanager2_flash_xdomain.zip
Normal file
BIN
public/flash/soundmanager/soundmanager2_flash_xdomain.zip
Normal file
Binary file not shown.
|
@ -1,11 +1,19 @@
|
|||
angular.module('ponyfm').controller "application", [
|
||||
'$scope', 'auth', '$location', 'upload', '$state', '$stateParams', '$injector'
|
||||
($scope, auth, $location, upload, $state, $stateParams, $injector) ->
|
||||
'$scope', 'auth', '$location', 'upload', '$state', '$stateParams', '$injector', '$rootScope'
|
||||
($scope, auth, $location, upload, $state, $stateParams, $injector, $rootScope) ->
|
||||
$scope.auth = auth.data
|
||||
$scope.$state = $state
|
||||
$scope.$stateParams = $stateParams
|
||||
$loadingElement = null
|
||||
|
||||
$rootScope.safeApply = (fn) ->
|
||||
phase = $rootScope.$$phase
|
||||
if (phase == '$apply' || phase == 'digest')
|
||||
fn()
|
||||
return
|
||||
|
||||
$rootScope.$apply fn
|
||||
|
||||
$scope.logout = () ->
|
||||
auth.logout().done -> location.reload()
|
||||
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
window.pfm.preloaders['artist-favourites'] = [
|
||||
'artists', '$state'
|
||||
(artists, $state) ->
|
||||
artists.fetch $state.params.slug, true
|
||||
artists.fetchFavourites $state.params.slug, true
|
||||
]
|
||||
|
||||
angular.module('ponyfm').controller "artist-favourites", [
|
||||
'$scope', 'artists', '$state'
|
||||
($scope, artists, $state) ->
|
||||
artists.fetch($state.params.slug).done (artistResponse) ->
|
||||
$scope.artist = artistResponse.artist
|
||||
artists.fetchFavourites($state.params.slug).done (artistResponse) ->
|
||||
$scope.favourites = artistResponse
|
||||
console.log artistResponse
|
||||
]
|
|
@ -16,12 +16,12 @@ angular.module('ponyfm').controller "playlist-form", [
|
|||
playlists.editPlaylist($scope.form)
|
||||
|
||||
def
|
||||
.done ->
|
||||
dialog.close()
|
||||
.done (res) ->
|
||||
dialog.close(res)
|
||||
|
||||
.fail (errors)->
|
||||
$scope.errors = errors
|
||||
$scope.isLoading = false
|
||||
|
||||
$scope.close = () -> dialog.close()
|
||||
$scope.close = () -> dialog.close(null)
|
||||
]
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
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 ->
|
||||
$scope.playlist = playlist
|
||||
window.pfm.preloaders['playlist'] = [
|
||||
'$state', 'playlists'
|
||||
($state, playlists) ->
|
||||
playlists.fetch $state.params.id, true
|
||||
]
|
||||
|
||||
$scope.refresh()
|
||||
angular.module('ponyfm').controller 'playlist', [
|
||||
'$scope', '$state', 'playlists'
|
||||
($scope, $state, playlists) ->
|
||||
playlists.fetch($state.params.id).done (playlist) ->
|
||||
$scope.playlist = playlist
|
||||
]
|
|
@ -5,14 +5,47 @@ window.pfm.preloaders['track'] = [
|
|||
]
|
||||
|
||||
angular.module('ponyfm').controller "track", [
|
||||
'$scope', 'tracks', '$state', 'playlists', 'auth'
|
||||
($scope, tracks, $state, playlists, auth) ->
|
||||
'$scope', 'tracks', '$state', 'playlists', 'auth', 'favourites', '$dialog'
|
||||
($scope, tracks, $state, playlists, auth, favourites, $dialog) ->
|
||||
tracks.fetch($state.params.id).done (trackResponse) ->
|
||||
$scope.track = trackResponse.track
|
||||
$scope.trackArray = [$scope.track]
|
||||
|
||||
$scope.playlists = []
|
||||
|
||||
if auth.data.isLogged
|
||||
playlists.refreshOwned().done (lists) ->
|
||||
$scope.playlists.push list for list in lists
|
||||
|
||||
$scope.favouriteWorking = false
|
||||
|
||||
$scope.toggleFavourite = (track) ->
|
||||
$scope.favouriteWorking = true
|
||||
favourites.toggle('track', track.id).done (res) ->
|
||||
track.is_favourited = res.is_favourited
|
||||
$scope.favouriteWorking = false
|
||||
|
||||
$scope.addToNewPlaylist = () ->
|
||||
dialog = $dialog.dialog
|
||||
templateUrl: '/templates/partials/playlist-dialog.html'
|
||||
controller: 'playlist-form'
|
||||
resolve: {
|
||||
playlist: () ->
|
||||
is_public: true
|
||||
is_pinned: true
|
||||
name: ''
|
||||
description: ''
|
||||
}
|
||||
|
||||
dialog.open().then (playlist) ->
|
||||
return if !playlist
|
||||
|
||||
playlists.addTrackToPlaylist playlist.id, $scope.track.id
|
||||
$state.transitionTo 'playlist', {id: playlist.id}
|
||||
|
||||
$scope.addToPlaylist = (playlist) ->
|
||||
return if playlist.message
|
||||
|
||||
playlists.addTrackToPlaylist(playlist.id, $scope.track.id).done (res) ->
|
||||
playlist.message = res.message
|
||||
]
|
|
@ -6,6 +6,7 @@ angular.module('ponyfm').directive 'pfmAlbumsList', () ->
|
|||
class: '@class'
|
||||
|
||||
controller: [
|
||||
'$scope'
|
||||
($scope) ->
|
||||
'$scope', 'auth'
|
||||
($scope, auth) ->
|
||||
$scope.auth = auth.data
|
||||
]
|
29
public/scripts/app/directives/comments.coffee
Normal file
29
public/scripts/app/directives/comments.coffee
Normal file
|
@ -0,0 +1,29 @@
|
|||
angular.module('ponyfm').directive 'pfmComments', () ->
|
||||
restrict: 'E'
|
||||
templateUrl: '/templates/directives/comments.html'
|
||||
scope:
|
||||
resource: '=resource',
|
||||
type: '@type'
|
||||
|
||||
controller: [
|
||||
'$scope', 'comments'
|
||||
($scope, comments, auth) ->
|
||||
|
||||
$scope.isWorking = false
|
||||
$scope.content = ''
|
||||
$scope.auth = auth.data
|
||||
|
||||
refresh = () ->
|
||||
comments.fetchList($scope.type, $scope.resource.id, true).done (comments) ->
|
||||
$scope.resource.comments.count = comments.count
|
||||
$scope.resource.comments.list.length = 0
|
||||
$scope.resource.comments.list.push comment for comment in comments.list
|
||||
$scope.isWorking = false
|
||||
|
||||
$scope.addComment = () ->
|
||||
content = $scope.content
|
||||
$scope.content = ''
|
||||
$scope.isWorking = true
|
||||
comments.addComment($scope.type, $scope.resource.id, content).done () ->
|
||||
refresh()
|
||||
]
|
20
public/scripts/app/directives/favouriteButton.coffee
Normal file
20
public/scripts/app/directives/favouriteButton.coffee
Normal file
|
@ -0,0 +1,20 @@
|
|||
angular.module('ponyfm').directive 'pfmFavouriteButton', () ->
|
||||
restrict: 'E'
|
||||
templateUrl: '/templates/directives/favourite-button.html'
|
||||
scope:
|
||||
resource: '=resource',
|
||||
class: '@class',
|
||||
type: '@type'
|
||||
|
||||
controller: [
|
||||
'$scope', 'favourites', 'auth'
|
||||
($scope, favourites, auth) ->
|
||||
$scope.auth = auth.data
|
||||
|
||||
$scope.isWorking = false
|
||||
$scope.toggleFavourite = () ->
|
||||
$scope.isWorking = true
|
||||
favourites.toggle($scope.type, $scope.resource.id).done (res) ->
|
||||
$scope.isWorking = false
|
||||
$scope.resource.is_favourited = res.is_favourited
|
||||
]
|
73
public/scripts/app/directives/player.coffee
Normal file
73
public/scripts/app/directives/player.coffee
Normal file
|
@ -0,0 +1,73 @@
|
|||
angular.module('ponyfm').directive 'pfmPlayer', () ->
|
||||
$element = null
|
||||
|
||||
restrict: 'E'
|
||||
templateUrl: '/templates/directives/player.html'
|
||||
scope: {}
|
||||
|
||||
compile: (element) ->
|
||||
$element = element
|
||||
|
||||
controller: [
|
||||
'$scope', 'player', 'auth'
|
||||
($scope, player, auth) ->
|
||||
$scope.player = player
|
||||
$scope.auth = auth.data
|
||||
$scope.playPause = () ->
|
||||
$scope.player.playPause()
|
||||
|
||||
$scope.playNext = () ->
|
||||
$scope.player.playNext()
|
||||
|
||||
$scope.playPrev = () ->
|
||||
$scope.player.playPrev()
|
||||
|
||||
$scope.seek = (e) ->
|
||||
$transport = $ '.transport'
|
||||
percent = ((e.pageX - $transport.offset().left) / $transport.width())
|
||||
duration = parseFloat($scope.player.currentTrack.duration)
|
||||
|
||||
$scope.player.seek percent * duration * 1000
|
||||
|
||||
isSliding = false
|
||||
$slider = $element.find('.volume-slider')
|
||||
$knob = $element.find('.volume-slider .knob')
|
||||
$bar = $element.find('.volume-slider .bar')
|
||||
|
||||
player.readyDef.done ->
|
||||
initialY = (180 - (180 * (player.volume / 100))) - 7.5
|
||||
$knob.css {top: initialY}
|
||||
|
||||
moveVolumeSlider = (absoluteY) ->
|
||||
newY = absoluteY - $bar.offset().top;
|
||||
maxY = $bar.height() - ($knob.height() / 2)
|
||||
|
||||
newY = 0 if newY < 0
|
||||
newY = maxY if newY > maxY
|
||||
|
||||
percent = 100 - ((newY / maxY) * 100)
|
||||
$scope.player.setVolume percent
|
||||
$knob.css {top: newY}
|
||||
|
||||
$knob.click (e) ->
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
||||
$slider.click (e) -> $scope.$apply -> moveVolumeSlider(e.pageY)
|
||||
|
||||
$(document).mousemove (e) ->
|
||||
return if !isSliding
|
||||
moveVolumeSlider(e.pageY)
|
||||
|
||||
$knob.mousedown (e) ->
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
isSliding = true
|
||||
$slider.parent().addClass('keep-open')
|
||||
|
||||
$(document).mouseup (e) ->
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
isSliding = false
|
||||
$slider.parent().removeClass('keep-open')
|
||||
]
|
|
@ -2,4 +2,4 @@ angular.module('ponyfm').directive 'pfmProgressBar', () ->
|
|||
(scope, element, attrs) ->
|
||||
scope.$watch attrs.pfmProgressBar, (val) ->
|
||||
return if !val?
|
||||
$(element).css 'width', Math.floor(val) + '%'
|
||||
$(element).css 'width', val + '%'
|
|
@ -6,6 +6,15 @@ angular.module('ponyfm').directive 'pfmTracksList', () ->
|
|||
class: '@class'
|
||||
|
||||
controller: [
|
||||
'$scope'
|
||||
($scope) ->
|
||||
'$scope', 'favourites', 'player', 'auth'
|
||||
($scope, favourites, player, auth) ->
|
||||
$scope.auth = auth.data
|
||||
|
||||
$scope.toggleFavourite = (track) ->
|
||||
favourites.toggle('track', track.id).done (res) ->
|
||||
track.is_favourited = res.is_favourited
|
||||
|
||||
$scope.play = (track) ->
|
||||
index = _.indexOf $scope.tracks, (t) -> t.id == track.id
|
||||
player.playTracks $scope.tracks, index
|
||||
]
|
|
@ -1,2 +1,4 @@
|
|||
angular.module('ponyfm').filter 'newlines', () ->
|
||||
(input) -> input.replace(/\n/g, '<br/>')
|
||||
(input) ->
|
||||
return '' if !input
|
||||
input.replace(/\n/g, '<br/>')
|
|
@ -1,5 +1,7 @@
|
|||
angular.module('ponyfm').filter 'noHTML', () ->
|
||||
(input) ->
|
||||
return '' if !input
|
||||
|
||||
input.replace(/&/g, '&')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/</g, '<')
|
|
@ -4,6 +4,7 @@ angular.module('ponyfm').factory('artists', [
|
|||
artistPage = []
|
||||
artists = {}
|
||||
artistContent = {}
|
||||
artistFavourites = {}
|
||||
|
||||
self =
|
||||
filters: {}
|
||||
|
@ -39,5 +40,15 @@ angular.module('ponyfm').factory('artists', [
|
|||
|
||||
artistContent[slug] = artistsDef.promise()
|
||||
|
||||
fetchFavourites: (slug, force) ->
|
||||
force = force || false
|
||||
slug = 1 if !slug
|
||||
return artistFavourites[slug] if !force && artistFavourites[slug]
|
||||
artistsDef = new $.Deferred()
|
||||
$http.get('/api/web/artists/' + slug + '/favourites').success (albums) ->
|
||||
artistsDef.resolve albums
|
||||
|
||||
artistFavourites[slug] = artistsDef.promise()
|
||||
|
||||
self
|
||||
])
|
27
public/scripts/app/services/comments.coffee
Normal file
27
public/scripts/app/services/comments.coffee
Normal file
|
@ -0,0 +1,27 @@
|
|||
angular.module('ponyfm').factory('comments', [
|
||||
'$rootScope', '$http'
|
||||
($rootScope, $http) ->
|
||||
commentCache = []
|
||||
|
||||
self =
|
||||
filters: {}
|
||||
|
||||
addComment: (resourceType, resourceId, content) ->
|
||||
commentDef = new $.Deferred()
|
||||
$http.post('/api/web/comments/' + resourceType + '/' + resourceId, {content: content, _token: pfm.token}).success (comment) ->
|
||||
commentDef.resolve comment
|
||||
|
||||
commentDef.promise()
|
||||
|
||||
fetchList: (resourceType, resourceId, force) ->
|
||||
key = resourceType + '-' + resourceId
|
||||
force = force || false
|
||||
return commentCache[key] if !force && commentCache[key]
|
||||
commentDef = new $.Deferred()
|
||||
$http.get('/api/web/comments/' + resourceType + '/' + resourceId).success (comments) ->
|
||||
commentDef.resolve comments
|
||||
|
||||
commentCache[key] = commentDef.promise()
|
||||
|
||||
self
|
||||
])
|
13
public/scripts/app/services/favourites.coffee
Normal file
13
public/scripts/app/services/favourites.coffee
Normal file
|
@ -0,0 +1,13 @@
|
|||
angular.module('ponyfm').factory('favourites', [
|
||||
'$rootScope', '$http'
|
||||
($rootScope, $http) ->
|
||||
self =
|
||||
toggle: (type, id) ->
|
||||
def = new $.Deferred()
|
||||
$http.post('/api/web/favourites/toggle', {type: type, id: id, _token: pfm.token}).success (res) ->
|
||||
def.resolve res
|
||||
|
||||
def.promise()
|
||||
|
||||
self
|
||||
])
|
117
public/scripts/app/services/player.coffee
Normal file
117
public/scripts/app/services/player.coffee
Normal file
|
@ -0,0 +1,117 @@
|
|||
angular.module('ponyfm').factory('player', [
|
||||
'$rootScope'
|
||||
($rootScope) ->
|
||||
readyDef = new $.Deferred()
|
||||
|
||||
play = (track) ->
|
||||
self.currentTrack = track
|
||||
$rootScope.$broadcast 'player-starting-track', track
|
||||
self.currentSound = soundManager.createSound
|
||||
url: '/t' + track.id + '/stream',
|
||||
volume: self.volume
|
||||
|
||||
whileloading: () -> $rootScope.safeApply ->
|
||||
track.loadingProgress = (self.currentSound.bytesLoaded / self.currentSound.bytesTotal) * 100
|
||||
|
||||
whileplaying: () -> $rootScope.safeApply ->
|
||||
track.progress = (self.currentSound.position / (track.duration * 1000)) * 100
|
||||
|
||||
onfinish: () -> $rootScope.safeApply ->
|
||||
track.isPlaying = false
|
||||
self.playNext()
|
||||
|
||||
onstop: () -> $rootScope.safeApply ->
|
||||
track.isPlaying = false
|
||||
self.isPlaying = false
|
||||
|
||||
onplay: () -> $rootScope.safeApply ->
|
||||
track.isPlaying = true
|
||||
|
||||
onresume: () -> $rootScope.safeApply ->
|
||||
track.isPlaying = true
|
||||
|
||||
onpause: () -> $rootScope.safeApply ->
|
||||
track.isPlaying = false
|
||||
|
||||
track.isPlaying = true
|
||||
self.isPlaying = true
|
||||
self.currentSound.play()
|
||||
|
||||
self =
|
||||
ready: false
|
||||
isPlaying: false
|
||||
currentTrack: null
|
||||
currentSound: null
|
||||
playlist: []
|
||||
playlistIndex: 0
|
||||
volume: 0
|
||||
readyDef: readyDef.promise()
|
||||
|
||||
playPause: () ->
|
||||
return if !self.ready
|
||||
return if !self.isPlaying
|
||||
|
||||
if self.currentSound.paused
|
||||
self.currentSound.play()
|
||||
else
|
||||
self.currentSound.pause()
|
||||
|
||||
playNext: () ->
|
||||
self.currentSound.stop() if self.currentSound != null
|
||||
self.playlistIndex++
|
||||
if self.playlistIndex >= self.playlist.length
|
||||
self.playlist.length = 0
|
||||
self.currentTrack = null
|
||||
self.currentSong = null
|
||||
self.isPlaying = false
|
||||
return
|
||||
|
||||
play self.playlist[self.playlistIndex]
|
||||
|
||||
playPrev: () ->
|
||||
self.currentSound.stop() if self.currentSound != null
|
||||
self.playlistIndex--
|
||||
if self.playlistIndex <= 0
|
||||
self.playlist.length = 0
|
||||
self.currentTrack = null
|
||||
self.currentSong = null
|
||||
self.isPlaying = false
|
||||
return
|
||||
|
||||
play self.playlist[self.playlistIndex]
|
||||
|
||||
seek: (progress) ->
|
||||
return if !self.currentSound
|
||||
self.currentSound.setPosition(progress)
|
||||
|
||||
setVolume: (theVolume) ->
|
||||
theVolume = 100 if theVolume > 100
|
||||
self.currentSound.setVolume(theVolume) if self.currentSound
|
||||
$.cookie('pfm-volume', theVolume)
|
||||
self.volume = theVolume
|
||||
|
||||
playTracks: (tracks, index) ->
|
||||
return if !self.ready
|
||||
return if tracks.length == 0
|
||||
|
||||
if tracks[index].isPlaying
|
||||
self.playPause()
|
||||
return
|
||||
|
||||
self.currentSound.stop() if self.currentSound != null
|
||||
|
||||
$rootScope.$broadcast 'player-stopping-playlist'
|
||||
self.playlist.length = 0
|
||||
self.playlist.push track for track in tracks
|
||||
self.playlistIndex = index
|
||||
|
||||
$rootScope.$broadcast 'player-starting-playlist', tracks
|
||||
play tracks[index]
|
||||
|
||||
pfm.soundManager.done () ->
|
||||
self.ready = true
|
||||
self.setVolume($.cookie('pfm-volume') || 100)
|
||||
readyDef.resolve()
|
||||
|
||||
self
|
||||
])
|
|
@ -2,9 +2,20 @@ angular.module('ponyfm').factory('playlists', [
|
|||
'$rootScope', '$state', '$http'
|
||||
($rootScope, $state, $http) ->
|
||||
playlistDef = null
|
||||
playlists = {}
|
||||
|
||||
self =
|
||||
pinnedPlaylists: []
|
||||
|
||||
fetch: (id, force) ->
|
||||
force = force || false
|
||||
return playlists[id] if !force && playlists[id]
|
||||
def = new $.Deferred()
|
||||
$http.get('/api/web/playlists/' + id).success (playlist) ->
|
||||
def.resolve playlist
|
||||
|
||||
playlists[id] = def.promise()
|
||||
|
||||
refreshOwned: (force) ->
|
||||
force = force || false
|
||||
return playlistDef if !force && playlistDef
|
||||
|
@ -15,6 +26,13 @@ angular.module('ponyfm').factory('playlists', [
|
|||
|
||||
playlistDef
|
||||
|
||||
addTrackToPlaylist: (playlistId, trackId) ->
|
||||
def = new $.Deferred()
|
||||
$http.post('/api/web/playlists/' + playlistId + '/add-track', {track_id: trackId, _token: pfm.token}).success (res) ->
|
||||
def.resolve(res)
|
||||
|
||||
def
|
||||
|
||||
refresh: () ->
|
||||
$.getJSON('/api/web/playlists/pinned')
|
||||
.done (playlists) -> $rootScope.$apply ->
|
||||
|
|
95
public/scripts/base/jquery.cookie.js
Normal file
95
public/scripts/base/jquery.cookie.js
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*!
|
||||
* jQuery Cookie Plugin v1.3.1
|
||||
* https://github.com/carhartl/jquery-cookie
|
||||
*
|
||||
* Copyright 2013 Klaus Hartl
|
||||
* Released under the MIT license
|
||||
*/
|
||||
(function (factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD. Register as anonymous module.
|
||||
define(['jquery'], factory);
|
||||
} else {
|
||||
// Browser globals.
|
||||
factory(jQuery);
|
||||
}
|
||||
}(function ($) {
|
||||
|
||||
var pluses = /\+/g;
|
||||
|
||||
function raw(s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
function decoded(s) {
|
||||
return decodeURIComponent(s.replace(pluses, ' '));
|
||||
}
|
||||
|
||||
function converted(s) {
|
||||
if (s.indexOf('"') === 0) {
|
||||
// This is a quoted cookie as according to RFC2068, unescape
|
||||
s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
|
||||
}
|
||||
try {
|
||||
return config.json ? JSON.parse(s) : s;
|
||||
} catch(er) {}
|
||||
}
|
||||
|
||||
var config = $.cookie = function (key, value, options) {
|
||||
|
||||
// write
|
||||
if (value !== undefined) {
|
||||
options = $.extend({}, config.defaults, options);
|
||||
|
||||
if (typeof options.expires === 'number') {
|
||||
var days = options.expires, t = options.expires = new Date();
|
||||
t.setDate(t.getDate() + days);
|
||||
}
|
||||
|
||||
value = config.json ? JSON.stringify(value) : String(value);
|
||||
|
||||
return (document.cookie = [
|
||||
config.raw ? key : encodeURIComponent(key),
|
||||
'=',
|
||||
config.raw ? value : encodeURIComponent(value),
|
||||
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
|
||||
options.path ? '; path=' + options.path : '',
|
||||
options.domain ? '; domain=' + options.domain : '',
|
||||
options.secure ? '; secure' : ''
|
||||
].join(''));
|
||||
}
|
||||
|
||||
// read
|
||||
var decode = config.raw ? raw : decoded;
|
||||
var cookies = document.cookie.split('; ');
|
||||
var result = key ? undefined : {};
|
||||
for (var i = 0, l = cookies.length; i < l; i++) {
|
||||
var parts = cookies[i].split('=');
|
||||
var name = decode(parts.shift());
|
||||
var cookie = decode(parts.join('='));
|
||||
|
||||
if (key && key === name) {
|
||||
result = converted(cookie);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!key) {
|
||||
result[name] = converted(cookie);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
config.defaults = {};
|
||||
|
||||
$.removeCookie = function (key, options) {
|
||||
if ($.cookie(key) !== undefined) {
|
||||
// Must not alter options, thus extending a fresh object...
|
||||
$.cookie(key, '', $.extend({}, options, { expires: -1 }));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
}));
|
2643
public/scripts/base/soundmanager2-nodebug.js
Normal file
2643
public/scripts/base/soundmanager2-nodebug.js
Normal file
File diff suppressed because it is too large
Load diff
9
public/scripts/shared/init.coffee
Normal file
9
public/scripts/shared/init.coffee
Normal file
|
@ -0,0 +1,9 @@
|
|||
def = new $.Deferred()
|
||||
|
||||
pfm.soundManager = def.promise()
|
||||
|
||||
soundManager.setup
|
||||
url: '/flash/soundmanager/'
|
||||
flashVersion: 9
|
||||
onready: () ->
|
||||
def.resolve()
|
|
@ -18,9 +18,11 @@
|
|||
|
||||
&.empty {
|
||||
.alert();
|
||||
.border-radius(0px);
|
||||
float: none !important;
|
||||
width: auto !important;
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
padding: 5px;
|
||||
font-size: 9pt;
|
||||
}
|
||||
|
|
|
@ -200,7 +200,7 @@ html {
|
|||
|
||||
.pagination {
|
||||
border: none;
|
||||
background: #ccc;
|
||||
background: #ddd;
|
||||
margin: 5px 0px;
|
||||
padding: 0px;
|
||||
overflow: hidden;
|
||||
|
|
|
@ -13,7 +13,6 @@ html body {
|
|||
|
||||
.background-color {
|
||||
background: rgba(42, 42, 42, 1);
|
||||
background-image: url('/images/pattern4.jpg');
|
||||
position: fixed;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
|
@ -97,27 +96,46 @@ header {
|
|||
|
||||
.image {
|
||||
float: left;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: #aaa;
|
||||
|
||||
img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.transport {
|
||||
display: none;
|
||||
margin-top: 5px;
|
||||
margin-left: 6px;
|
||||
margin-top: -3px;
|
||||
margin-bottom: 3px;
|
||||
margin-left: 46px;
|
||||
height: 5px;
|
||||
background: #555;
|
||||
position: relative;
|
||||
margin-right: 6px;
|
||||
cursor: pointer;
|
||||
|
||||
.bar {
|
||||
background: #fd8500;
|
||||
&:hover {
|
||||
}
|
||||
|
||||
.bar, .loader-bar {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.loader-bar {
|
||||
background: #888;
|
||||
z-index: 200;
|
||||
}
|
||||
|
||||
.bar {
|
||||
background: #fd8500;
|
||||
z-index: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
|
@ -149,13 +167,14 @@ header {
|
|||
margin: 0px;
|
||||
padding: 0px;
|
||||
list-style: none;
|
||||
margin-top: 6px;
|
||||
margin-right: 6px;
|
||||
margin-top: 3px;
|
||||
margin-right: 5px;
|
||||
|
||||
li {
|
||||
float: left;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
position: relative;
|
||||
|
||||
a {
|
||||
display: block;
|
||||
|
@ -165,9 +184,52 @@ header {
|
|||
color: #ddd;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.volume-slider {
|
||||
.box-shadow(0px 5px 9px rgba(50, 50, 50, 0.5));
|
||||
|
||||
position: absolute;
|
||||
border-bottom: 1px solid #fff;
|
||||
border-top: 3px solid #3366CC;
|
||||
top: 30px;
|
||||
background: #eee;
|
||||
list-style: none;
|
||||
margin: 0px;
|
||||
display: none;
|
||||
width: 100%;
|
||||
padding: 10px 0px;
|
||||
z-index: 300;
|
||||
|
||||
.bar {
|
||||
width: 5px;
|
||||
height: 180px;
|
||||
background: #aaa;
|
||||
margin: auto;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
|
||||
.knob {
|
||||
.border-radius(20px);
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
display: block;
|
||||
background: #1F3D7B;
|
||||
border: 2px solid #1F3D7B;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: -7px;
|
||||
font-size: 1px;
|
||||
padding: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover, &.keep-open {
|
||||
#gradient>.vertical(#fff, #ddd);
|
||||
|
||||
.volume-slider {
|
||||
display: block;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #000;
|
||||
|
|
|
@ -1,8 +1,44 @@
|
|||
@import-once 'base/bootstrap/bootstrap';
|
||||
@import-once 'mixins';
|
||||
|
||||
.comments {
|
||||
ul {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
list-style: none;
|
||||
margin-bottom: 5px;
|
||||
|
||||
li {
|
||||
.clearfix();
|
||||
margin: 0px;
|
||||
padding: 3px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
|
||||
.meta {
|
||||
font-size: 8pt;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin-left: 45px;
|
||||
|
||||
}
|
||||
|
||||
img {
|
||||
.img-polaroid();
|
||||
|
||||
float: left;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
padding: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard {
|
||||
section {
|
||||
/*
|
||||
.box-sizing(border-box);
|
||||
|
||||
width: 50%;
|
||||
|
@ -15,6 +51,7 @@
|
|||
&:last-child {
|
||||
padding-left: 10px;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,8 +97,24 @@
|
|||
overflow: hidden;
|
||||
margin: 10px 0px;
|
||||
padding: 0px;
|
||||
line-height: normal;
|
||||
|
||||
&:hover {
|
||||
&.empty {
|
||||
.alert();
|
||||
.border-radius(0px);
|
||||
float: none !important;
|
||||
width: auto !important;
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
padding: 5px;
|
||||
font-size: 9pt;
|
||||
|
||||
&:hover {
|
||||
background-color: @warningBackground;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover, &.is-playing {
|
||||
background: #eee;
|
||||
|
||||
.image {
|
||||
|
@ -71,6 +124,22 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.is-favourited {
|
||||
.icon-favourite {
|
||||
color: @orange;
|
||||
text-decoration: none;
|
||||
|
||||
i {
|
||||
color: #FFD76E;
|
||||
text-shadow: 0px 0px 2px rgba(0,0,0,0.8);
|
||||
|
||||
&:before {
|
||||
content: "\f005"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.image {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
|
@ -109,13 +178,18 @@
|
|||
|
||||
.icons {
|
||||
float: right;
|
||||
font-size: 13px;
|
||||
font-size: 14px;
|
||||
margin-right: 2px;
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a, span {
|
||||
display: block;
|
||||
float: left;
|
||||
margin: 0px 3px;
|
||||
line-height: 0px;
|
||||
}
|
||||
|
||||
.icon-microphone-off {
|
||||
|
@ -166,7 +240,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.user-details, .track-details, .album-details {
|
||||
.user-details, .track-details, .album-details, .playlist-details {
|
||||
.comments {
|
||||
.alert {
|
||||
.border-radius(0px);
|
||||
|
@ -212,11 +286,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
.track-details, .album-details {
|
||||
.track-details, .album-details, .playlist-details {
|
||||
h1 {
|
||||
.box-shadow(0px 2px 3px rgba(0, 0, 0, .3));
|
||||
background: #eee;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.lyrics {
|
||||
|
@ -263,6 +334,45 @@
|
|||
}
|
||||
}
|
||||
|
||||
.track-details {
|
||||
h1 {
|
||||
margin-left: 55px;
|
||||
}
|
||||
|
||||
.tracks-listing li .image .play-button {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tracks-listing {
|
||||
float: left;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.tracks-listing li {
|
||||
margin: 0px;
|
||||
margin-bottom: 5px;
|
||||
float: left;
|
||||
|
||||
.image {
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
|
||||
.play-button {
|
||||
line-height: 48px;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
.icons, .info {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
html {
|
||||
.track-toolbar {
|
||||
padding: 5px;
|
||||
|
|
|
@ -5,10 +5,7 @@
|
|||
</ul>
|
||||
|
||||
<div class="track-toolbar btn-group pull-right">
|
||||
<a href="#" class="btn btn-small">
|
||||
Favourite This!
|
||||
<i class="icon-star-empty"></i>
|
||||
</a>
|
||||
<pfm-favourite-button resource="album" type="album"></pfm-favourite-button>
|
||||
<div class="dropdown">
|
||||
<a href="#" class="btn btn-small btn-info dropdown-toggle">
|
||||
Downloads <i class="caret"></i>
|
||||
|
@ -34,20 +31,10 @@
|
|||
</div>
|
||||
|
||||
<h2>Tracks</h2>
|
||||
<pfm-tracks-list tracks="album.tracks" />
|
||||
<pfm-tracks-list tracks="album.tracks"></pfm-tracks-list>
|
||||
|
||||
<h2>Comments</h2>
|
||||
<div class="comments">
|
||||
<div class="alert alert-info" ng-show="album.comments.count == 0">
|
||||
There are no comments yet!
|
||||
</div>
|
||||
<form class="pfm-form">
|
||||
<div class="form-row">
|
||||
<textarea></textarea>
|
||||
</div>
|
||||
<button type="submit" class="btn disabled">Post Comment</button>
|
||||
</form>
|
||||
</div>
|
||||
<pfm-comments type="album" resource="album"></pfm-comments>
|
||||
</div>
|
||||
<div class="span4 cover-image">
|
||||
<img ng-src="{{album.covers.normal}}" />
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
</ul>
|
||||
|
||||
<div class="track-toolbar btn-group pull-right">
|
||||
<a href="#" class="btn btn-small">
|
||||
<a href="#" class="btn btn-small" ng-show="auth.isLogged">
|
||||
Follow
|
||||
</a>
|
||||
<a href="#" class="btn btn-small">
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
|
||||
<div ng-show="content.singles.length">
|
||||
<h2>Singles</h2>
|
||||
<pfm-tracks-list tracks="content.singles" class="four-column no-artist" />
|
||||
<pfm-tracks-list tracks="content.singles" class="four-column no-artist"></pfm-tracks-list>
|
||||
</div>
|
||||
|
||||
<div ng-show="content.albumTracks.length">
|
||||
<h2>Part of an Album</h2>
|
||||
<pfm-tracks-list tracks="content.albumTracks" class="four-column no-artist" />
|
||||
<pfm-tracks-list tracks="content.albumTracks" class="four-column no-artist"></pfm-tracks-list>
|
||||
</div>
|
|
@ -1 +1,10 @@
|
|||
favourites!
|
||||
<div class="row-fluid">
|
||||
<div class="span6">
|
||||
<h2>Tracks</h2>
|
||||
<pfm-tracks-list tracks="favourites.tracks"></pfm-tracks-list>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<h2>Albums</h2>
|
||||
<pfm-albums-list albums="favourites.albums"></pfm-albums-list>
|
||||
</div>
|
||||
</div>
|
|
@ -8,17 +8,7 @@
|
|||
</div>
|
||||
|
||||
<h2>Comments</h2>
|
||||
<div class="comments">
|
||||
<div class="alert alert-info" ng-show="artist.comments.count == 0">
|
||||
There are no comments yet!
|
||||
</div>
|
||||
<form class="pfm-form">
|
||||
<div class="form-row">
|
||||
<textarea></textarea>
|
||||
</div>
|
||||
<button type="submit" class="btn disabled">Post Comment</button>
|
||||
</form>
|
||||
</div>
|
||||
<pfm-comments type="user" resource="artist"></pfm-comments>
|
||||
</div>
|
||||
<div class="span6 cover-image">
|
||||
<h2>Recent Tracks</h2>
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
<div>
|
||||
<h1>Login!</h1>
|
||||
<h1>Login</h1>
|
||||
<div class="alert">
|
||||
Only user accounts that were created as of the launch of the pre-release will be available.
|
||||
</div>
|
||||
<ng-include src="'/templates/partials/auth/login.html'" />
|
||||
</div>
|
|
@ -1,20 +1,11 @@
|
|||
<div class="dashboard">
|
||||
<section class="recent-tracks">
|
||||
<section class="recent-tracks stretch-to-bottom">
|
||||
<div>
|
||||
<h1>
|
||||
<a href="#"><i class="icon-music"></i> see more</a>
|
||||
The Newest Tunes
|
||||
</h1>
|
||||
<pfm-tracks-list tracks="recentTracks" />
|
||||
</div>
|
||||
</section>
|
||||
<section class="popular">
|
||||
<div>
|
||||
<h1>
|
||||
<a href="#"><i class="icon-star"></i> see more</a>
|
||||
What's Popular Today
|
||||
</h1>
|
||||
<pfm-tracks-list tracks="recentTracks" />
|
||||
<pfm-tracks-list tracks="recentTracks" class="two-column"></pfm-tracks-list>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
21
public/templates/directives/comments.html
Normal file
21
public/templates/directives/comments.html
Normal file
|
@ -0,0 +1,21 @@
|
|||
<div class="comments">
|
||||
<div class="alert alert-info" ng-show="resource.comments.count == 0">
|
||||
There are no comments yet!
|
||||
</div>
|
||||
<ul ng-show="resource.comments.count > 0">
|
||||
<li ng-repeat="comment in resource.comments.list">
|
||||
<div class="meta">
|
||||
<a href="{{comment.user.url}}">{{comment.user.name}}</a> posted
|
||||
{{comment.created_at.date | momentFromNow}}
|
||||
</div>
|
||||
<img ng-src="{{comment.user.avatars.thumbnail}}" />
|
||||
<div class="content">{{comment.content}}</div>
|
||||
</li>
|
||||
</ul>
|
||||
<form class="pfm-form" ng-submit="addComment()" ng-show="auth.isLogged">
|
||||
<div class="form-row">
|
||||
<textarea ng-model="content"></textarea>
|
||||
</div>
|
||||
<button type="submit" class="btn" ng-class="{disabled: content.length == 0}">Post Comment</button>
|
||||
</form>
|
||||
</div>
|
10
public/templates/directives/favourite-button.html
Normal file
10
public/templates/directives/favourite-button.html
Normal file
|
@ -0,0 +1,10 @@
|
|||
<a href="#" class="btn btn-small favourite-button" ng-class="{'is-favourited': resource.is_favourited, disabled: isWorking}" pfm-eat-click ng-click="toggleFavourite()" ng-show="auth.isLogged">
|
||||
<span ng-hide="resource.is_favourited">
|
||||
Favourite This!
|
||||
<i class="icon-star-empty"></i>
|
||||
</span>
|
||||
<span ng-show="resource.is_favourited">
|
||||
In Your Favourites
|
||||
<i class="icon-star"></i>
|
||||
</span>
|
||||
</a>
|
31
public/templates/directives/player.html
Normal file
31
public/templates/directives/player.html
Normal file
|
@ -0,0 +1,31 @@
|
|||
<div class="current-track" ng-show="player.isPlaying">
|
||||
<div class="image">
|
||||
<img ng-src="{{player.currentTrack.covers.thumbnail}}" />
|
||||
</div>
|
||||
<div class="transport" ng-click="seek($event)">
|
||||
<div class="bar" pfm-progress-bar="player.currentTrack.progress"></div>
|
||||
<div class="loader-bar" pfm-progress-bar="player.currentTrack.loadingProgress"></div>
|
||||
</div>
|
||||
<ul class="buttons">
|
||||
<li><a pfm-eat-click ng-click="playPrev()" class="previous" href="#"><i class="icon-fast-backward"></i></a></li>
|
||||
<li>
|
||||
<a pfm-eat-click ng-click="playPause()" class="play" href="#">
|
||||
<i class="icon-pause" ng-show="player.currentTrack.isPlaying"></i>
|
||||
<i class="icon-play" ng-hide="player.currentTrack.isPlaying"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li><a pfm-eat-click ng-click="playNext()" class="next" href="#"><i class="icon-fast-forward"></i></a></li>
|
||||
<li>
|
||||
<a pfm-eat-click ng-click="" class="volume" href="#">
|
||||
<i class="icon-volume-up"></i>
|
||||
</a>
|
||||
<div class="volume-slider">
|
||||
<div class="bar"><a href="#" class="knob"> </a></div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="title">
|
||||
<span class="song"><a href="{{player.currentTrack.url}}">{{player.currentTrack.title}}</a></span>
|
||||
<span class="artist"><a href="{{player.currentTrack.user.url}}">{{player.currentTrack.user.name}}</a></span>
|
||||
</div>
|
||||
</div>
|
|
@ -1,12 +1,15 @@
|
|||
<ul class="tracks-listing {{class}}">
|
||||
<li ng-repeat="track in tracks">
|
||||
<li ng-repeat="track in tracks" ng-class="{'can-favourite': auth.isLogged, 'is-favourited': track.is_favourited, 'is-playing': track.isPlaying}">
|
||||
<div class="image">
|
||||
<a href="#" class="play-button"><i class="icon-play"></i></a>
|
||||
<a href="#" class="play-button" pfm-eat-click ng-click="play(track)">
|
||||
<i class="icon-play" ng-show="!track.isPlaying"></i>
|
||||
<i class="icon-pause" ng-hide="!track.isPlaying"></i>
|
||||
</a>
|
||||
<img ng-src="{{track.covers.thumbnail}}" />
|
||||
</div>
|
||||
<div class="icons">
|
||||
<span><i ng-class="{'icon-microphone-off': !track.is_vocal, 'icon-microphone': track.is_vocal}"></i></span>
|
||||
<a href="#"><i class="icon-star-empty"></i></a>
|
||||
<a pfm-eat-click class="icon-favourite" href="#" ng-click="toggleFavourite(track)" ng-show="auth.isLogged"><i class="icon-star-empty"></i></a>
|
||||
</div>
|
||||
<a class="info" href="{{track.url}}">
|
||||
<span class="title">{{track.title}}</span>
|
||||
|
@ -17,4 +20,7 @@
|
|||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="!tracks.length" class="empty">
|
||||
No tracks found...
|
||||
</li>
|
||||
</ul>
|
|
@ -1,13 +1,37 @@
|
|||
<div>
|
||||
<h1>Look, it's a website!</h1>
|
||||
<h1>Pony.fm BETA 2 Preview</h1>
|
||||
|
||||
<p>
|
||||
This page should basically be a big advert for PFM. But that comes later. For now, you may do two things:
|
||||
Welcome to Pony.fm's BETA 2 preview! If you were looking for the functional website, head on over to <a href="http://pony.fm" target="_blank">Pony.fm</a>.
|
||||
</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="span6 panel">
|
||||
<h2>Login</h2>
|
||||
<ng-include src="'/templates/partials/auth/login.html'" ng-controller="login" />
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
This is an early look at the next Pony.fm release. <a href="http://pony.fm" target="_blank">Pony.fm</a> is a music hosting website
|
||||
for Bronies - and you can learn more about it <a href="http://pony.fm/about" target="_blank">here</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This web application is under <strong>heavy development</strong>. While you are free to browse around, please note
|
||||
that although the track and user data on this site is a copy of Pony.fm - all data will be <strong>erased</strong> when
|
||||
the preview ends, or whenever we feel like. As such, please do not use this application for hosting your new music.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
At this time, many features are notably missing - such as:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Mobile friendly design</li>
|
||||
<li>Artist following</li>
|
||||
<li>Notifications</li>
|
||||
<li>Public playlists</li>
|
||||
<li>Music Downloads</li>
|
||||
</ul>
|
||||
<p>
|
||||
And more. The layout and design is also subject to change in the future.
|
||||
</p>
|
||||
<p>
|
||||
However, we welcome any and all feedback - so if you have a suggestion or bug report, you can hop on over to
|
||||
<a href="http://mlpforums.com/forum/62-ponyfm/" target="_blank">Pony.fm's Forum</a>.
|
||||
</p>
|
||||
<p>We hope you enjoy taking a look at the future of Pony.fm as much as we did building it!</p>
|
||||
</div>
|
|
@ -1,11 +1,37 @@
|
|||
<div>
|
||||
<h1>About!</h1>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Assumenda id, illum in incidunt nemo nisi perspiciatis
|
||||
quibusdam quos repellat veniam? Accusamus animi ducimus id iure repellendus tempore veniam voluptates
|
||||
voluptatibus!</p>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aut beatae commodi corporis doloremque dolorum ex facilis
|
||||
impedit perferendis praesentium quasi quis quisquam repellat sint temporibus, totam. Excepturi magni tempora
|
||||
voluptates.</p>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Assumenda atque corporis debitis doloremque est expedita
|
||||
illo ipsam itaque maiores modi nam placeat qui sit suscipit, totam unde vel veniam. Temporibus?</p>
|
||||
<h1>What exactly <em>is</em> Pony.fm, anyway?</h1>
|
||||
<div class="stretch-to-bottom">
|
||||
<div class="row-fluid">
|
||||
<div class="span12 columns">
|
||||
<p>Some <em>My Little Pony: Friendship is Magic</em> fans - typically referred to as "bronies" are the musical type, and show their appreciation for the show by pouring their talent into <strong>fan music</strong>.
|
||||
<p>The brony fan music community is diverse, spanning genres from symphonic metal to trance and everything in between. But most importantly, the community creates music.</p>
|
||||
<p>A <em>lot</em> of music.</p>
|
||||
<p>All this music has to go somewhere. YouTube, SoundCloud, and Bandcamp are popular outlets that many brony musicians use to host their tunes. But no mainstream sites are specifically designed for our fandom's needs, and they're not particularly helpful if, as a listener, you're looking for pony fan music.</p>
|
||||
<p>That's where Pony.fm comes in. <strong>Pony.fm is a community, hosting service, and music database rolled into one, with a generous dash of pony on top.</strong></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<h2>So it's SoundCloud with ponies?</h2>
|
||||
<p>Eenope!</p>
|
||||
<p>Pony.fm is an original project. Although it takes inspiration from a number of well-known services for the general public, Pony.fm is not specifically modeled after any one of them. As a fan site itself, Pony.fm is an experience all its own.</p>
|
||||
<p>Simply put, <strong>"Pony.fm is Pony.fm."</strong></p>
|
||||
|
||||
<h2>What makes Pony.fm special?</h2>
|
||||
<p>Pony.fm is a service created by a brony, for bronies. Every inch of the Pony.fm experience is crafted with ponies and bronies in mind. Some of the features necessarily resemble what you may find on other sites - lossless uploads, for example - but some features are specific to the pony fan music community.</p>
|
||||
<p>Created as a service for the fandom, Pony.fm aims to be the one-stop shop for all things pony music, for artists and listeners alike.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<h2>What does MLP Forums have to do with Pony.fm?</h2>
|
||||
<p>MLP Forums and Pony.fm share an owner, and each encompasses a different segment of the global <em>My Little Pony: Friendship is Magic</em> community. Put together, both sites are able to offer a richer "supercommunity" experience than either site could offer on its own.</p>
|
||||
|
||||
<h2>Who is behind Pony.fm?</h2>
|
||||
<p>Pony.fm is built and owned by Feld0, a pony-loving teenager who heard the call of code. Recognizing the need for a true pony-specific music hosting site, and realizing that MLP Forums provided him with the resources he needed to make it happen, he created a blank text file and started pumping code into his computer.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,23 +1,77 @@
|
|||
<div>
|
||||
<h1>FAQ!</h1>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ab asperiores autem beatae blanditiis earum enim illo nisi
|
||||
nulla numquam, odio saepe sed sunt tenetur! Ab aperiam enim error harum soluta!</p>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquid animi blanditiis corporis debitis dolore dolorum
|
||||
expedita facere facilis fuga ipsa labore libero non odit praesentium quidem quo, repudiandae veniam voluptatem!</p>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Corporis doloribus hic ipsam, laudantium minima
|
||||
necessitatibus, officia perferendis provident ratione sunt unde vitae. Consectetur, ducimus harum maiores molestias
|
||||
possimus ratione vero!</p>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ab at beatae, blanditiis culpa dicta dolor ducimus ex harum
|
||||
ipsam iure laboriosam, mollitia nesciunt obcaecati pariatur quibusdam quod recusandae, sapiente veritatis!</p>
|
||||
<h1>Pony.fm FAQ</h1>
|
||||
<div class="stretch-to-bottom">
|
||||
<ul class="faq-tos">
|
||||
<li><a href="#mp3">Why doesn't Pony.fm support MP3 files?</a></li>
|
||||
<li><a href="#not-accepted">Why isn't my file being accepted for Upload?</a></li>
|
||||
<li><a href="#upload">How do I Upload a song?</a></li>
|
||||
<li><a href="#avatar">How do you set an avatar?</a></li>
|
||||
<li><a href="#mlp-forums">Why the connection to MLP Forums?</a></li>
|
||||
<li><a href="#feedback">How do I send Feedback to the Developers?</a></li>
|
||||
<li><a href="#poniverse">What is the "Poniverse" and what does Pony FM have to do with it?</a></li>
|
||||
<li><a href="#stats">Can I view any site statistics?</a></li>
|
||||
<li><a href="#contact">How do I get in contact with other Musicians on Pony.fm?</a></li>
|
||||
<li><a href="#report">How do I report someone?</a></li>
|
||||
<li><a href="#download">How do I download an artist' song?</a></li>
|
||||
</ul>
|
||||
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis dignissimos esse nihil non odio possimus
|
||||
ratione sapiente ullam! Assumenda corporis doloremque et ipsum laudantium nihil quae quidem sapiente temporibus,
|
||||
veritatis!</p>
|
||||
<a name="mp3"></a>
|
||||
<h2>Why doesn't Pony.fm support MP3 files?</h2>
|
||||
<p>MP3 encoding is "lossy." Lossy means that, during the encoding process, quality gets sacrificed for a decrease in size.</p>
|
||||
<p>Pony.fm does not provide only MP3's; it also provides OGG's and lossless FLAC's. Uploading a lossless file puts a "perfect" copy of your track in Pony.fm's file store, which can be offered up for download on its own for audiophiles who like CD or better-than-CD sound quality, but starting from a lossless original also allows Pony.fm to transcode a song to other lossy formats with only one degree of loss.</p>
|
||||
|
||||
<p>Adipisci aperiam cupiditate ea error et eum exercitationem facilis, hic minus molestiae nulla, omnis possimus
|
||||
repudiandae temporibus voluptatem. Ab accusamus aspernatur assumenda dicta dolorum eos, inventore nam quo
|
||||
recusandae tenetur.</p>
|
||||
<p>Pony.fm accepts a lossless upload, which is converted to FLAC (if it isn't already FLAC) for storage. This leaves a "perfect," unblemished copy of the track in Pony.fm's file store.</p>
|
||||
<p>An MP3 file can be created from the FLAC. Minimal quality is lost because creating an MP3 from the FLAC is as good as creating an MP3 directly from your DAW.</p>
|
||||
<p>An OGG Vorbis file can be created from the FLAC. Minimal quality is lost because Pony.fm has a lossless copy of the track on file; thus, we don't have the "recompressing a compressed MP3" issue that is present if Pony.fm's "master file" was an MP3.</p>
|
||||
|
||||
<p>Accusamus ad alias aliquam architecto blanditiis dolor eos, est eveniet, impedit maxime nam officia quaerat
|
||||
quibusdam, ratione sed. Aut eum ex illum ipsum, minus nobis nulla quibusdam quidem repellat unde?</p>
|
||||
<a name="not-accepted"></a>
|
||||
<h2>Why isn't my file being accepted for Upload?</h2>
|
||||
<p>Pony.fm analyzes all uploads to determine their format and check it against a whitelist; the file extension is ignored. Unfortunately, slight variations in AIFF and WAV files exist that need to be individually whitelisted.</p>
|
||||
<p>The alpha should have nailed most of these by now, but if there are some that still are not being accepted, contact an admin with the specific file details and they will try to add them to the White List.</p>
|
||||
|
||||
<a name="upload"></a>
|
||||
<h2>How do I Upload a song?</h2>
|
||||
<p>At the top right of your screen there should be a button titled "Upload" next to the "send feedback" one. Select the Upload button and a drop down menu will appear, select the first option titled "Track Uploader". You should now be on a screen displaying the uploader. Select the Green button titled "Add Files" and select your song from your computer. The track should now start its download.</p>
|
||||
<p>Please be aware that Pony.fm doesn't support MP3 uploads.</p>
|
||||
|
||||
<a name="avatar"></a>
|
||||
<h2>How do you set an avatar?</h2>
|
||||
<p>Avatars in Pony.fm use a free service called Gravatar. To learn more about it, and setup your own Gravatar account, <a href="https://gravatar.com/" target="_blank">click here</a>!</p>
|
||||
|
||||
<a name="mlp-forums"></a>
|
||||
<h2>Why the connection to MLP Forums?</h2>
|
||||
<p>MLP Forums is one of the web's largest and most well known <em>My Little Pony: Friendship is Magic</em> forum communities. Formally linking the two sites together paves the way for a rich, cross-site community experience. Members of one site can easily jump into the other without the hassle of managing yet another account, and content can seamlessly be brought from MLP Forums to Pony.fm and vice versa in meaningful ways.</p>
|
||||
|
||||
<a name="feedback"></a>
|
||||
<h2>How do I send Feedback to the Developers?</h2>
|
||||
<p>At the top of your page should be a nifty little button to the left of the upload button that says "Send Feedback".</p>
|
||||
<p>Click this and a form will pop up, just follow the two simple instructions and enter the information needed and click "submit".</p>
|
||||
<p>All feedback is greatly appreciated on Pony FM and we do our hardest to keep this site functional and to keep all of you happy.</p>
|
||||
|
||||
<a name="poniverse"></a>
|
||||
<h2>What is the "Poniverse" and what does Pony FM have to do with it?</h2>
|
||||
<p>The Poniverse is a network that links together several Brony sites ,such as MLP Forums, together to form a super community of sorts that provides sites that satisfy everyone's needs.</p>
|
||||
<p>Pony FM is just one of those sites and sets out to provide Brony Musicians with their own special corner to share their work with others and to receive feedback from other musicians, and in lots of cases to form collaborations that can end up in great partnerships.</p>
|
||||
|
||||
<a name="stats"></a>
|
||||
<h2>Can I view any site statistics?</h2>
|
||||
<p>You sure can!</p>
|
||||
<p>At the bottom left of your screen there is a small button that says Site Stats that's nestled just below a button for Pony.fm Forum.</p>
|
||||
<p>Click on the "Site Stats" button and you will be taken to a screen that shows you graphs depicting the number of Track Views, Track Downloads, Track Plays and User Registrations.</p>
|
||||
|
||||
<a name="contact"></a>
|
||||
<h2>How do I get in contact with other Musicians on Pony.fm?</h2>
|
||||
<p>On each user's screen there is a nifty little section where you can leave comments. This is used best for providing feedback and to show them your support, but if you plan on trying to start a collaboration and would prefer a more private means of communication, underneath the user Bio, there is a "send a message" which will utilise the "Personal Messenger" from MLP Forums to allow you to send a message to that artist.</p>
|
||||
|
||||
<a name="report"></a>
|
||||
<h2>How do I report someone?</h2>
|
||||
<p>At the current time a report feature isn't quite installed into the site, however, email feld0@pony.fm and he would be glad to handle any moderating issues that you have. But to reiterate what was said before, there IS a report function in the works.</p>
|
||||
|
||||
<a name="download"></a>
|
||||
<h2>How do I download an artist' song?</h2>
|
||||
<p>Click on the song that you are looking to download and you will notice to the right of the screen is a button titled "Downloads".</p>
|
||||
<p>Click this button and you will be brought a drop down menu with FLAC, MP3, OGG, AAC and ALAC file types for you to download.</p>
|
||||
<p>Select your preferred file type to start the download and it should all be smooth sailing from there.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,3 +1,44 @@
|
|||
<div>
|
||||
<h1>{{playlist.title}}</h1>
|
||||
<div class="playlist-details">
|
||||
<ul class="breadcrumb">
|
||||
<li><a href="/account/playlists">Your Playlists</a> <span class="divider">/</span></li>
|
||||
<li class="active">{{playlist.title}}</li>
|
||||
</ul>
|
||||
|
||||
<div class="track-toolbar btn-group pull-right">
|
||||
<div class="dropdown">
|
||||
<a href="#" class="btn btn-small btn-info dropdown-toggle">
|
||||
Downloads <i class="caret"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li ng-repeat="format in playlist.formats"><a href="{{format.url}}">{{format.name}}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h1>
|
||||
{{playlist.title}}
|
||||
</h1>
|
||||
|
||||
<div class="stretch-to-bottom">
|
||||
<div class="row-fluid">
|
||||
<div class="span9">
|
||||
<div class="description">
|
||||
<p ng-bind-html-unsafe="playlist.description | noHTML | newlines"></p>
|
||||
</div>
|
||||
|
||||
<h2>Tracks</h2>
|
||||
<pfm-tracks-list tracks="playlist.tracks"></pfm-tracks-list>
|
||||
|
||||
<h2>Comments</h2>
|
||||
<pfm-comments type="playlist" resource="playlist"></pfm-comments>
|
||||
</div>
|
||||
<div class="span3 cover-image">
|
||||
<div class="fb-like" data-href="{{playlist.url}}" data-send="false" data-layout="button_count" data-width="20" data-show-faces="false"></div>
|
||||
<a href="https://twitter.com/share" class="twitter-share-button" data-url="{{playlist.url}}" data-text="{{playlist.title + ' by ' + playlist.user.name + ' on Pony.fm'}}" data-via="ponyfm">Tweet</a>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,8 +1,10 @@
|
|||
<div>
|
||||
<ul class="tabs">
|
||||
<li ng-class="{active: $state.includes('tracks.search')}"><a href="/tracks">Search</a></li>
|
||||
<!--
|
||||
<li ng-class="{active: $state.includes('tracks.popular')}"><a href="/tracks/popular">Popular</a></li>
|
||||
<li ng-class="{active: $state.includes('tracks.random')}"><a href="/tracks/random">Random</a></li>
|
||||
-->
|
||||
</ul>
|
||||
|
||||
<ui-view></ui-view>
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
<div class="stretch-to-bottom">
|
||||
<pfm-tracks-list tracks="tracks" class="two-column" />
|
||||
<pfm-tracks-list tracks="tracks" class="two-column"></pfm-tracks-list>
|
||||
</div>
|
|
@ -1,6 +1,6 @@
|
|||
<ul class="dropdowns">
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle btn">
|
||||
<a class="dropdown-toggle btn" ng-class="{'btn-info': query.filters.trackTypes.selectedArray.length}">
|
||||
Type: <strong>{{query.filters.trackTypes.title}}</strong>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
|
@ -11,7 +11,7 @@
|
|||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle btn">
|
||||
<a class="dropdown-toggle btn" ng-class="{'btn-info': query.filters.showSongs.selectedArray.length}">
|
||||
Show Songs: <strong>{{query.filters.showSongs.title}}</strong>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
|
@ -22,7 +22,7 @@
|
|||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle btn">
|
||||
<a class="dropdown-toggle btn" ng-class="{'btn-info': query.filters.genres.selectedArray.length}">
|
||||
Genre: <strong>{{query.filters.genres.title}}</strong>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
|
@ -33,7 +33,7 @@
|
|||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle btn">
|
||||
<a class="dropdown-toggle btn" ng-class="{'btn-info': !query.filters.isVocal.isDefault}">
|
||||
Is Vocal: <strong>{{query.filters.isVocal.title}}</strong>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
|
@ -43,7 +43,7 @@
|
|||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle btn">
|
||||
<a class="dropdown-toggle btn" ng-class="{'btn-info': !query.filters.sort.isDefault}">
|
||||
Order: <strong>{{query.filters.sort.title}}</strong>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="track-details">
|
||||
<div class="track-details" xmlns="http://www.w3.org/1999/html">
|
||||
<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>
|
||||
|
@ -6,10 +6,7 @@
|
|||
</ul>
|
||||
|
||||
<div class="track-toolbar btn-group pull-right">
|
||||
<a href="#" class="btn btn-small">
|
||||
Favourite This!
|
||||
<i class="icon-star-empty"></i>
|
||||
</a>
|
||||
<pfm-favourite-button resource="track" type="track"></pfm-favourite-button>
|
||||
<div class="dropdown">
|
||||
<a href="#" class="btn btn-small btn-info dropdown-toggle">
|
||||
Downloads <i class="caret"></i>
|
||||
|
@ -19,16 +16,22 @@
|
|||
</ul>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<a href="#" class="btn btn-small dropdown-toggle">
|
||||
<a href="#" class="btn btn-small dropdown-toggle" ng-show="auth.isLogged">
|
||||
Add to Playlist <i class="caret"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li ng-repeat="playlist in playlists"><a href="{{playlist.url}}">{{playlist.title}}</a></li>
|
||||
<li><a href="#" class="btn-primary">Add to New Playlist</a></li>
|
||||
<li ng-repeat="playlist in playlists">
|
||||
<a ng-class="{disabled: playlist.message, 'btn-success': playlist.message}" href="{{playlist.url}}" pfm-eat-click ng-click="addToPlaylist(playlist); $event.stopPropagation()">
|
||||
<span ng-hide="playlist.message">{{playlist.title}}</span>
|
||||
<span ng-show="playlist.message">{{playlist.message}}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li><a href="#" class="btn-primary" pfm-eat-click ng-click="addToNewPlaylist()">Add to New Playlist</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<pfm-tracks-list tracks="trackArray"></pfm-tracks-list>
|
||||
<h1>
|
||||
{{track.title}}
|
||||
<span class="subtitle">
|
||||
|
@ -58,17 +61,7 @@
|
|||
</div>
|
||||
|
||||
<h2>Comments</h2>
|
||||
<div class="comments">
|
||||
<div class="alert alert-info" ng-show="track.comments.count == 0">
|
||||
There are no comments yet!
|
||||
</div>
|
||||
<form class="pfm-form">
|
||||
<div class="form-row">
|
||||
<textarea></textarea>
|
||||
</div>
|
||||
<button type="submit" class="btn disabled">Post Comment</button>
|
||||
</form>
|
||||
</div>
|
||||
<pfm-comments type="track" resource="track"></pfm-comments>
|
||||
</div>
|
||||
<div class="span4 cover-image">
|
||||
<img ng-src="{{track.covers.normal}}" />
|
||||
|
|
2
vendor/autoload.php
vendored
2
vendor/autoload.php
vendored
|
@ -4,4 +4,4 @@
|
|||
|
||||
require_once __DIR__ . '/composer' . '/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInit00affa5bd26689f95e075708487b8b91::getLoader();
|
||||
return ComposerAutoloaderInit99e3f8067509f9d0b122eb51fad39842::getLoader();
|
||||
|
|
16
vendor/composer/autoload_classmap.php
vendored
16
vendor/composer/autoload_classmap.php
vendored
|
@ -10,8 +10,12 @@ return array(
|
|||
'AccountController' => $baseDir . '/app/controllers/AccountController.php',
|
||||
'AlbumsController' => $baseDir . '/app/controllers/AlbumsController.php',
|
||||
'ApiControllerBase' => $baseDir . '/app/controllers/ApiControllerBase.php',
|
||||
'Api\\Web\\AccountController' => $baseDir . '/app/controllers/Api/Web/AccountController.php',
|
||||
'Api\\Web\\AlbumsController' => $baseDir . '/app/controllers/Api/Web/AlbumsController.php',
|
||||
'Api\\Web\\ArtistsController' => $baseDir . '/app/controllers/Api/Web/ArtistsController.php',
|
||||
'Api\\Web\\AuthController' => $baseDir . '/app/controllers/Api/Web/AuthController.php',
|
||||
'Api\\Web\\DashboardController' => $baseDir . '/app/controllers/Api/Web/DashboardController.php',
|
||||
'Api\\Web\\FavouritesController' => $baseDir . '/app/controllers/Api/Web/FavouritesController.php',
|
||||
'Api\\Web\\ImagesController' => $baseDir . '/app/controllers/Api/Web/ImagesController.php',
|
||||
'Api\\Web\\PlaylistsController' => $baseDir . '/app/controllers/Api/Web/PlaylistsController.php',
|
||||
'Api\\Web\\TaxonomiesController' => $baseDir . '/app/controllers/Api/Web/TaxonomiesController.php',
|
||||
|
@ -126,16 +130,24 @@ return array(
|
|||
'ClassPreloader\\Parser\\DirVisitor' => $vendorDir . '/classpreloader/classpreloader/src/ClassPreloader/Parser/DirVisitor.php',
|
||||
'ClassPreloader\\Parser\\FileVisitor' => $vendorDir . '/classpreloader/classpreloader/src/ClassPreloader/Parser/FileVisitor.php',
|
||||
'ClassPreloader\\Parser\\NodeTraverser' => $vendorDir . '/classpreloader/classpreloader/src/ClassPreloader/Parser/NodeTraverser.php',
|
||||
'Commands\\AddTrackToPlaylistCommand' => $baseDir . '/app/models/Commands/AddTrackToPlaylistCommand.php',
|
||||
'Commands\\CommandBase' => $baseDir . '/app/models/Commands/CommandBase.php',
|
||||
'Commands\\CommandResponse' => $baseDir . '/app/models/Commands/CommandResponse.php',
|
||||
'Commands\\CreateAlbumCommand' => $baseDir . '/app/models/Commands/CreateAlbumCommand.php',
|
||||
'Commands\\CreatePlaylistCommand' => $baseDir . '/app/models/Commands/CreatePlaylistCommand.php',
|
||||
'Commands\\DeleteAlbumCommand' => $baseDir . '/app/models/Commands/DeleteAlbumCommand.php',
|
||||
'Commands\\DeletePlaylistCommand' => $baseDir . '/app/models/Commands/DeletePlaylistCommand.php',
|
||||
'Commands\\DeleteTrackCommand' => $baseDir . '/app/models/Commands/DeleteTrackCommand.php',
|
||||
'Commands\\EditAlbumCommand' => $baseDir . '/app/models/Commands/EditAlbumCommand.php',
|
||||
'Commands\\EditPlaylistCommand' => $baseDir . '/app/models/Commands/EditPlaylistCommand.php',
|
||||
'Commands\\EditTrackCommand' => $baseDir . '/app/models/Commands/EditTrackCommand.php',
|
||||
'Commands\\SaveAccountSettingsCommand' => $baseDir . '/app/models/Commands/SaveAccountSettingsCommand.php',
|
||||
'Commands\\ToggleFavouriteCommand' => $baseDir . '/app/models/Commands/ToggleFavouriteCommand.php',
|
||||
'Commands\\UploadTrackCommand' => $baseDir . '/app/models/Commands/UploadTrackCommand.php',
|
||||
'ContentController' => $baseDir . '/app/controllers/ContentController.php',
|
||||
'CreateAlbums' => $baseDir . '/app/database/migrations/2013_07_28_060804_create_albums.php',
|
||||
'CreateComments' => $baseDir . '/app/database/migrations/2013_08_01_051337_create_comments.php',
|
||||
'CreateFavourites' => $baseDir . '/app/database/migrations/2013_08_01_024827_create_favourites.php',
|
||||
'CreateImagesTable' => $baseDir . '/app/database/migrations/2013_07_26_230827_create_images_table.php',
|
||||
'CreatePlaylists' => $baseDir . '/app/database/migrations/2013_07_28_135136_create_playlists.php',
|
||||
'CreateSongsTable' => $baseDir . '/app/database/migrations/2013_07_28_034328_create_songs_table.php',
|
||||
|
@ -408,9 +420,12 @@ return array(
|
|||
'Doctrine\\DBAL\\Types\\VarDateTimeType' => $vendorDir . '/doctrine/dbal/lib/Doctrine/DBAL/Types/VarDateTimeType.php',
|
||||
'Doctrine\\DBAL\\Version' => $vendorDir . '/doctrine/dbal/lib/Doctrine/DBAL/Version.php',
|
||||
'Entities\\Album' => $baseDir . '/app/models/Entities/Album.php',
|
||||
'Entities\\Favourite' => $baseDir . '/app/models/Entities/Favourite.php',
|
||||
'Entities\\Genre' => $baseDir . '/app/models/Entities/Genre.php',
|
||||
'Entities\\Image' => $baseDir . '/app/models/Entities/Image.php',
|
||||
'Entities\\License' => $baseDir . '/app/models/Entities/License.php',
|
||||
'Entities\\PinnedPlaylist' => $baseDir . '/app/models/Entities/PinnedPlaylist.php',
|
||||
'Entities\\Playlist' => $baseDir . '/app/models/Entities/Playlist.php',
|
||||
'Entities\\ShowSong' => $baseDir . '/app/models/Entities/ShowSong.php',
|
||||
'Entities\\Track' => $baseDir . '/app/models/Entities/Track.php',
|
||||
'Entities\\TrackType' => $baseDir . '/app/models/Entities/TrackType.php',
|
||||
|
@ -1834,6 +1849,7 @@ return array(
|
|||
'Symfony\\Component\\Translation\\Writer\\TranslationWriter' => $vendorDir . '/symfony/translation/Symfony/Component/Translation/Writer/TranslationWriter.php',
|
||||
'TestCase' => $baseDir . '/app/tests/TestCase.php',
|
||||
'TracksController' => $baseDir . '/app/controllers/TracksController.php',
|
||||
'Traits\\SlugTrait' => $baseDir . '/app/models/Traits/SlugTrait.php',
|
||||
'UsersController' => $baseDir . '/app/controllers/UsersController.php',
|
||||
'Whoops\\Exception\\ErrorException' => $vendorDir . '/filp/whoops/src/Whoops/Exception/ErrorException.php',
|
||||
'Whoops\\Exception\\Frame' => $vendorDir . '/filp/whoops/src/Whoops/Exception/Frame.php',
|
||||
|
|
6
vendor/composer/autoload_real.php
vendored
6
vendor/composer/autoload_real.php
vendored
|
@ -2,7 +2,7 @@
|
|||
|
||||
// autoload_real.php generated by Composer
|
||||
|
||||
class ComposerAutoloaderInit00affa5bd26689f95e075708487b8b91
|
||||
class ComposerAutoloaderInit99e3f8067509f9d0b122eb51fad39842
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
|
@ -19,9 +19,9 @@ class ComposerAutoloaderInit00affa5bd26689f95e075708487b8b91
|
|||
return self::$loader;
|
||||
}
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInit00affa5bd26689f95e075708487b8b91', 'loadClassLoader'), true, true);
|
||||
spl_autoload_register(array('ComposerAutoloaderInit99e3f8067509f9d0b122eb51fad39842', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit00affa5bd26689f95e075708487b8b91', 'loadClassLoader'));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit99e3f8067509f9d0b122eb51fad39842', 'loadClassLoader'));
|
||||
|
||||
$vendorDir = dirname(__DIR__);
|
||||
$baseDir = dirname($vendorDir);
|
||||
|
|
Loading…
Reference in a new issue