mirror of
https://github.com/Poniverse/Pony.fm.git
synced 2024-11-22 04:58:01 +01:00
T350: Resolved merge conflicts.
This commit is contained in:
commit
86a3248a7c
548 changed files with 12839 additions and 9390 deletions
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"phabricator.uri" : "https://phabricator.poniverse.net/",
|
||||
"history.immutable" : true
|
||||
}
|
||||
}
|
7
.gitattributes
vendored
7
.gitattributes
vendored
|
@ -1,4 +1,7 @@
|
|||
* text=auto
|
||||
app/config/production/* filter=git-crypt diff=git-crypt
|
||||
app/config/stage/* filter=git-crypt diff=git-crypt
|
||||
|
||||
resources/environments/.env.stage filter=git-crypt diff=git-crypt
|
||||
resources/environments/.env.production filter=git-crypt diff=git-crypt
|
||||
|
||||
*.css linguist-vendored
|
||||
*.less linguist-vendored
|
||||
|
|
52
.gitignore
vendored
52
.gitignore
vendored
|
@ -1,48 +1,8 @@
|
|||
.vagrant
|
||||
|
||||
# Numerous always-ignore extensions
|
||||
*.diff
|
||||
*.err
|
||||
*.orig
|
||||
*.log
|
||||
*.rej
|
||||
*.swo
|
||||
*.swp
|
||||
*.vi
|
||||
*~
|
||||
*.sass-cache
|
||||
|
||||
# OS or Editor folders
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
.cache
|
||||
.project
|
||||
.settings
|
||||
.tmproj
|
||||
*.esproj
|
||||
nbproject
|
||||
*.iml
|
||||
|
||||
# Dreamweaver added files
|
||||
_notes
|
||||
dwsync.xml
|
||||
|
||||
# Komodo
|
||||
*.komodoproject
|
||||
.komodotools
|
||||
|
||||
# Folders to ignore
|
||||
.hg
|
||||
.svn
|
||||
.CVS
|
||||
intermediate
|
||||
publish
|
||||
.idea
|
||||
|
||||
node_modules
|
||||
/public/build/
|
||||
/bootstrap/compiled.php
|
||||
/vendor
|
||||
composer.phar
|
||||
atlassian-ide-plugin.xml
|
||||
/node_modules
|
||||
/public/build
|
||||
/logs
|
||||
Homestead.yaml
|
||||
.env
|
||||
.vagrant
|
||||
_ide_helper.php
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
# Contribution Guidelines
|
||||
|
||||
Please submit all issues and pull requests to the [laravel/framework](http://github.com/laravel/framework) repository!
|
319
app/Album.php
Normal file
319
app/Album.php
Normal file
|
@ -0,0 +1,319 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
use App\Traits\SlugTrait;
|
||||
|
||||
class Album extends Model
|
||||
{
|
||||
use SoftDeletes, SlugTrait;
|
||||
|
||||
protected $dates = ['deleted_at'];
|
||||
|
||||
public static function summary()
|
||||
{
|
||||
return self::select('id', 'title', 'user_id', 'slug', 'created_at', 'cover_id', 'comment_count',
|
||||
'download_count', 'view_count', 'favourite_count');
|
||||
}
|
||||
|
||||
public function scopeUserDetails($query)
|
||||
{
|
||||
if (Auth::check()) {
|
||||
$query->with([
|
||||
'users' => function ($query) {
|
||||
$query->whereUserId(Auth::user()->id);
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
return !$query;
|
||||
}
|
||||
|
||||
protected $table = 'albums';
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('App\User');
|
||||
}
|
||||
|
||||
public function users()
|
||||
{
|
||||
return $this->hasMany('App\ResourceUser');
|
||||
}
|
||||
|
||||
public function favourites()
|
||||
{
|
||||
return $this->hasMany('App\Favourite');
|
||||
}
|
||||
|
||||
public function cover()
|
||||
{
|
||||
return $this->belongsTo('App\Image');
|
||||
}
|
||||
|
||||
public function tracks()
|
||||
{
|
||||
return $this->hasMany('App\Track')->orderBy('track_number', 'asc');
|
||||
}
|
||||
|
||||
public function comments()
|
||||
{
|
||||
return $this->hasMany('App\Comment')->orderBy('created_at', 'desc');
|
||||
}
|
||||
|
||||
public static function mapPublicAlbumShow($album)
|
||||
{
|
||||
$tracks = [];
|
||||
foreach ($album->tracks as $track) {
|
||||
$tracks[] = Track::mapPublicTrackSummary($track);
|
||||
}
|
||||
|
||||
$formats = [];
|
||||
foreach (Track::$Formats as $name => $format) {
|
||||
$formats[] = [
|
||||
'name' => $name,
|
||||
'extension' => $format['extension'],
|
||||
'url' => $album->getDownloadUrl($name),
|
||||
'size' => Helpers::formatBytes($album->getFilesize($name))
|
||||
];
|
||||
}
|
||||
|
||||
$comments = [];
|
||||
foreach ($album->comments as $comment) {
|
||||
$comments[] = Comment::mapPublic($comment);
|
||||
}
|
||||
|
||||
$is_downloadable = 0;
|
||||
foreach ($album->tracks as $track) {
|
||||
if ($track->is_downloadable == 1) {
|
||||
$is_downloadable = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$data = self::mapPublicAlbumSummary($album);
|
||||
$data['tracks'] = $tracks;
|
||||
$data['comments'] = $comments;
|
||||
$data['formats'] = $formats;
|
||||
$data['description'] = $album->description;
|
||||
$data['is_downloadable'] = $is_downloadable;
|
||||
$data['share'] = [
|
||||
'url' => URL::to('/a' . $album->id),
|
||||
'tumblrUrl' => 'http://www.tumblr.com/share/link?url=' . urlencode($album->url) . '&name=' . urlencode($album->title) . '&description=' . urlencode($album->description),
|
||||
'twitterUrl' => 'https://platform.twitter.com/widgets/tweet_button.html?text=' . $album->title . ' by ' . $album->user->display_name . ' on Pony.fm'
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public static function mapPublicAlbumSummary($album)
|
||||
{
|
||||
$userData = [
|
||||
'stats' => [
|
||||
'views' => 0,
|
||||
'downloads' => 0
|
||||
],
|
||||
'is_favourited' => false
|
||||
];
|
||||
|
||||
if (Auth::check() && $album->users->count()) {
|
||||
$userRow = $album->users[0];
|
||||
$userData = [
|
||||
'stats' => [
|
||||
'views' => (int) $userRow->view_count,
|
||||
'downloads' => (int) $userRow->download_count,
|
||||
],
|
||||
'is_favourited' => (bool) $userRow->is_favourited
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => (int) $album->id,
|
||||
'track_count' => (int) $album->track_count,
|
||||
'title' => $album->title,
|
||||
'slug' => $album->slug,
|
||||
'created_at' => $album->created_at,
|
||||
'stats' => [
|
||||
'views' => (int) $album->view_count,
|
||||
'downloads' => (int) $album->download_count,
|
||||
'comments' => (int) $album->comment_count,
|
||||
'favourites' => (int) $album->favourite_count
|
||||
],
|
||||
'covers' => [
|
||||
'small' => $album->getCoverUrl(Image::SMALL),
|
||||
'normal' => $album->getCoverUrl(Image::NORMAL)
|
||||
],
|
||||
'url' => $album->url,
|
||||
'user' => [
|
||||
'id' => (int) $album->user->id,
|
||||
'name' => $album->user->display_name,
|
||||
'url' => $album->user->url,
|
||||
],
|
||||
'user_data' => $userData,
|
||||
'permissions' => [
|
||||
'delete' => Auth::check() && Auth::user()->id == $album->user_id,
|
||||
'edit' => Auth::check() && Auth::user()->id == $album->user_id
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function hasCover()
|
||||
{
|
||||
return $this->cover_id != null;
|
||||
}
|
||||
|
||||
public function getUrlAttribute()
|
||||
{
|
||||
return URL::to('albums/' . $this->id . '-' . $this->slug);
|
||||
}
|
||||
|
||||
public function getDownloadUrl($format)
|
||||
{
|
||||
return URL::to('a' . $this->id . '/dl.' . Track::$Formats[$format]['extension']);
|
||||
}
|
||||
|
||||
public function getFilesize($format)
|
||||
{
|
||||
$tracks = $this->tracks;
|
||||
if (!count($tracks)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Cache::remember($this->getCacheKey('filesize-' . $format), 1440, function () use ($tracks, $format) {
|
||||
$size = 0;
|
||||
foreach ($tracks as $track) {
|
||||
// Ensure that only downloadable tracks are added onto the file size
|
||||
if ($track->is_downloadable == 1) {
|
||||
$size += $track->getFilesize($format);
|
||||
}
|
||||
}
|
||||
|
||||
return $size;
|
||||
});
|
||||
}
|
||||
|
||||
public function getCoverUrl($type = Image::NORMAL)
|
||||
{
|
||||
if (!$this->hasCover()) {
|
||||
return $this->user->getAvatarUrl($type);
|
||||
}
|
||||
|
||||
return $this->cover->getUrl($type);
|
||||
}
|
||||
|
||||
public function getDirectory()
|
||||
{
|
||||
$dir = (string)(floor($this->id / 100) * 100);
|
||||
|
||||
return \Config::get('ponyfm.files_directory') . '/tracks/' . $dir;
|
||||
}
|
||||
|
||||
public function getDates()
|
||||
{
|
||||
return ['created_at', 'deleted_at', 'published_at'];
|
||||
}
|
||||
|
||||
public function getFilenameFor($format)
|
||||
{
|
||||
if (!isset(Track::$Formats[$format])) {
|
||||
throw new Exception("$format is not a valid format!");
|
||||
}
|
||||
|
||||
$format = Track::$Formats[$format];
|
||||
|
||||
return "{$this->id}.{$format['extension']}.zip";
|
||||
}
|
||||
|
||||
public function updateTrackNumbers()
|
||||
{
|
||||
$tracks = Track::whereAlbumId($this->id)->get();
|
||||
$index = 1;
|
||||
|
||||
foreach ($tracks as $track) {
|
||||
$track->track_number = $index;
|
||||
$index++;
|
||||
$track->updateTags();
|
||||
$track->save();
|
||||
}
|
||||
}
|
||||
|
||||
public function syncTrackIds($trackIds)
|
||||
{
|
||||
$trackIdsInAlbum = [];
|
||||
foreach ($this->tracks as $track) {
|
||||
$trackIdsInAlbum[] = $track->id;
|
||||
}
|
||||
|
||||
$trackIdsCount = count($trackIds);
|
||||
$trackIdsInAlbumCount = count($trackIdsInAlbum);
|
||||
$isSame = true;
|
||||
|
||||
if ($trackIdsInAlbumCount != $trackIdsCount) {
|
||||
$isSame = false;
|
||||
} else {
|
||||
for ($i = 0; $i < $trackIdsInAlbumCount; $i++) {
|
||||
if ($i >= $trackIdsCount || $trackIdsInAlbum[$i] != $trackIds[$i]) {
|
||||
$isSame = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($isSame) {
|
||||
return;
|
||||
}
|
||||
|
||||
$index = 1;
|
||||
$tracksToRemove = [];
|
||||
$albumsToFix = [];
|
||||
|
||||
foreach ($this->tracks as $track) {
|
||||
$tracksToRemove[$track->id] = $track;
|
||||
}
|
||||
|
||||
foreach ($trackIds as $trackId) {
|
||||
if (!strlen(trim($trackId))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$track = Track::find($trackId);
|
||||
if ($track->album_id != null && $track->album_id != $this->id) {
|
||||
$albumsToFix[] = $track->album;
|
||||
}
|
||||
|
||||
$track->album_id = $this->id;
|
||||
$track->track_number = $index;
|
||||
$track->updateTags();
|
||||
$track->save();
|
||||
|
||||
unset($tracksToRemove[$track->id]);
|
||||
$index++;
|
||||
}
|
||||
|
||||
foreach ($tracksToRemove as $track) {
|
||||
$track->album_id = null;
|
||||
$track->track_number = null;
|
||||
$track->updateTags();
|
||||
$track->save();
|
||||
}
|
||||
|
||||
foreach ($albumsToFix as $album) {
|
||||
$album->updateTrackNumbers();
|
||||
}
|
||||
|
||||
foreach (Track::$Formats as $name => $format) {
|
||||
Cache::forget($this->getCacheKey('filesize' . $name));
|
||||
}
|
||||
}
|
||||
|
||||
private function getCacheKey($key)
|
||||
{
|
||||
return 'album-' . $this->id . '-' . $key;
|
||||
}
|
||||
}
|
53
app/AlbumDownloader.php
Normal file
53
app/AlbumDownloader.php
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
class AlbumDownloader
|
||||
{
|
||||
private $_album;
|
||||
private $_format;
|
||||
|
||||
function __construct($album, $format)
|
||||
{
|
||||
$this->_album = $album;
|
||||
$this->_format = $format;
|
||||
}
|
||||
|
||||
function download()
|
||||
{
|
||||
$zip = new ZipStream($this->_album->user->display_name . ' - ' . $this->_album->title . '.zip');
|
||||
$zip->setComment(
|
||||
'Album: ' . $this->_album->title . "\r\n" .
|
||||
'Artist: ' . $this->_album->user->display_name . "\r\n" .
|
||||
'URL: ' . $this->_album->url . "\r\n" . "\r\n" .
|
||||
'Downloaded on ' . date('l, F jS, Y, \a\t h:i:s A') . '.'
|
||||
);
|
||||
|
||||
$directory = $this->_album->user->display_name . '/' . $this->_album->title . '/';
|
||||
|
||||
$notes =
|
||||
'Album: ' . $this->_album->title . "\r\n" .
|
||||
'Artist: ' . $this->_album->user->display_name . "\r\n" .
|
||||
'URL: ' . $this->_album->url . "\r\n" .
|
||||
"\r\n" .
|
||||
$this->_album->description . "\r\n" .
|
||||
"\r\n" .
|
||||
"\r\n" .
|
||||
'Tracks' . "\r\n" .
|
||||
"\r\n";
|
||||
|
||||
foreach ($this->_album->tracks as $track) {
|
||||
if (!$track->is_downloadable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$zip->addLargeFile($track->getFileFor($this->_format),
|
||||
$directory . $track->getDownloadFilenameFor($this->_format));
|
||||
$notes .=
|
||||
$track->track_number . '. ' . $track->title . "\r\n" .
|
||||
$track->description . "\r\n" .
|
||||
"\r\n";
|
||||
}
|
||||
|
||||
$zip->addFile($notes, $directory . 'Album Notes.txt');
|
||||
$zip->finalize();
|
||||
}
|
||||
}
|
46
app/Commands/AddTrackToPlaylistCommand.php
Normal file
46
app/Commands/AddTrackToPlaylistCommand.php
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace App\Commands;
|
||||
|
||||
use App\Playlist;
|
||||
use App\Track;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
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]);
|
||||
|
||||
Playlist::whereId($this->_playlist->id)->update([
|
||||
'track_count' => DB::raw('(SELECT COUNT(id) FROM playlist_track WHERE playlist_id = ' . $this->_playlist->id . ')')
|
||||
]);
|
||||
|
||||
return CommandResponse::succeed(['message' => 'Track added!']);
|
||||
}
|
||||
}
|
33
app/Commands/CommandBase.php
Normal file
33
app/Commands/CommandBase.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace App\Commands;
|
||||
|
||||
abstract class CommandBase
|
||||
{
|
||||
private $_listeners = array();
|
||||
|
||||
public function listen($listener)
|
||||
{
|
||||
$this->_listeners[] = $listener;
|
||||
}
|
||||
|
||||
protected function notify($message, $progress)
|
||||
{
|
||||
foreach ($this->_listeners as $listener) {
|
||||
$listener($message, $progress);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CommandResponse
|
||||
*/
|
||||
public abstract function execute();
|
||||
}
|
58
app/Commands/CommandResponse.php
Normal file
58
app/Commands/CommandResponse.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace App\Commands;
|
||||
|
||||
use Illuminate\Validation\Validator;
|
||||
|
||||
class CommandResponse
|
||||
{
|
||||
public static function fail($validator)
|
||||
{
|
||||
$response = new CommandResponse();
|
||||
$response->_didFail = true;
|
||||
$response->_validator = $validator;
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public static function succeed($response = null)
|
||||
{
|
||||
$cmdResponse = new CommandResponse();
|
||||
$cmdResponse->_didFail = false;
|
||||
$cmdResponse->_response = $response;
|
||||
|
||||
return $cmdResponse;
|
||||
}
|
||||
|
||||
private $_validator;
|
||||
private $_response;
|
||||
private $_didFail;
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function didFail()
|
||||
{
|
||||
return $this->_didFail;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getResponse()
|
||||
{
|
||||
return $this->_response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Validator
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return $this->_validator;
|
||||
}
|
||||
}
|
72
app/Commands/CreateAlbumCommand.php
Normal file
72
app/Commands/CreateAlbumCommand.php
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
namespace App\Commands;
|
||||
|
||||
use App\Album;
|
||||
use App\Image;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class CreateAlbumCommand extends CommandBase
|
||||
{
|
||||
private $_input;
|
||||
|
||||
function __construct($input)
|
||||
{
|
||||
$this->_input = $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
$user = \Auth::user();
|
||||
|
||||
return $user != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
* @return CommandResponse
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
$rules = [
|
||||
'title' => 'required|min:3|max:50',
|
||||
'cover' => 'image|mimes:png|min_width:350|min_height:350',
|
||||
'cover_id' => 'exists:images,id',
|
||||
'track_ids' => 'exists:tracks,id'
|
||||
];
|
||||
|
||||
$validator = Validator::make($this->_input, $rules);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return CommandResponse::fail($validator);
|
||||
}
|
||||
|
||||
$album = new Album();
|
||||
$album->user_id = Auth::user()->id;
|
||||
$album->title = $this->_input['title'];
|
||||
$album->description = $this->_input['description'];
|
||||
|
||||
if (isset($this->_input['cover_id'])) {
|
||||
$album->cover_id = $this->_input['cover_id'];
|
||||
} else {
|
||||
if (isset($this->_input['cover'])) {
|
||||
$cover = $this->_input['cover'];
|
||||
$album->cover_id = Image::upload($cover, Auth::user())->id;
|
||||
} else {
|
||||
if (isset($this->_input['remove_cover']) && $this->_input['remove_cover'] == 'true') {
|
||||
$album->cover_id = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$trackIds = explode(',', $this->_input['track_ids']);
|
||||
$album->save();
|
||||
$album->syncTrackIds($trackIds);
|
||||
|
||||
return CommandResponse::succeed(['id' => $album->id]);
|
||||
}
|
||||
}
|
79
app/Commands/CreateCommentCommand.php
Normal file
79
app/Commands/CreateCommentCommand.php
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
namespace App\Commands;
|
||||
|
||||
use App\Comment;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
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));
|
||||
}
|
||||
}
|
69
app/Commands/CreatePlaylistCommand.php
Normal file
69
app/Commands/CreatePlaylistCommand.php
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
namespace App\Commands;
|
||||
|
||||
use App\Playlist;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class CreatePlaylistCommand extends CommandBase
|
||||
{
|
||||
private $_input;
|
||||
|
||||
function __construct($input)
|
||||
{
|
||||
$this->_input = $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
$user = \Auth::user();
|
||||
|
||||
return $user != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
* @return CommandResponse
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
$rules = [
|
||||
'title' => 'required|min:3|max:50',
|
||||
'is_public' => 'required',
|
||||
'is_pinned' => 'required'
|
||||
];
|
||||
|
||||
$validator = Validator::make($this->_input, $rules);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return CommandResponse::fail($validator);
|
||||
}
|
||||
|
||||
$playlist = new Playlist();
|
||||
$playlist->user_id = Auth::user()->id;
|
||||
$playlist->title = $this->_input['title'];
|
||||
$playlist->description = $this->_input['description'];
|
||||
$playlist->is_public = $this->_input['is_public'] == 'true';
|
||||
|
||||
$playlist->save();
|
||||
|
||||
if ($this->_input['is_pinned'] == 'true') {
|
||||
$playlist->pin(Auth::user()->id);
|
||||
}
|
||||
|
||||
return CommandResponse::succeed([
|
||||
'id' => $playlist->id,
|
||||
'title' => $playlist->title,
|
||||
'slug' => $playlist->slug,
|
||||
'created_at' => $playlist->created_at,
|
||||
'description' => $playlist->description,
|
||||
'url' => $playlist->url,
|
||||
'is_pinned' => $this->_input['is_pinned'] == 'true',
|
||||
'is_public' => $this->_input['is_public'] == 'true'
|
||||
]);
|
||||
}
|
||||
}
|
46
app/Commands/DeleteAlbumCommand.php
Normal file
46
app/Commands/DeleteAlbumCommand.php
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace App\Commands;
|
||||
|
||||
use App\Album;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class DeleteAlbumCommand extends CommandBase
|
||||
{
|
||||
private $_albumId;
|
||||
private $_album;
|
||||
|
||||
function __construct($albumId)
|
||||
{
|
||||
$this->_albumId = $albumId;
|
||||
$this->_album = ALbum::find($albumId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
return $this->_album && $user != null && $this->_album->user_id == $user->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
* @return CommandResponse
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
foreach ($this->_album->tracks as $track) {
|
||||
$track->album_id = null;
|
||||
$track->track_number = null;
|
||||
$track->updateTags();
|
||||
$track->save();
|
||||
}
|
||||
|
||||
$this->_album->delete();
|
||||
|
||||
return CommandResponse::succeed();
|
||||
}
|
||||
}
|
43
app/Commands/DeletePlaylistCommand.php
Normal file
43
app/Commands/DeletePlaylistCommand.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace App\Commands;
|
||||
|
||||
use App\Playlist;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class DeletePlaylistCommand extends CommandBase
|
||||
{
|
||||
private $_playlistId;
|
||||
private $_playlist;
|
||||
|
||||
function __construct($playlistId)
|
||||
{
|
||||
$this->_playlistId = $playlistId;
|
||||
$this->_playlist = Playlist::find($playlistId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
return $this->_playlist && $user != null && $this->_playlist->user_id == $user->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
* @return CommandResponse
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
foreach ($this->_playlist->pins as $pin) {
|
||||
$pin->delete();
|
||||
}
|
||||
|
||||
$this->_playlist->delete();
|
||||
|
||||
return CommandResponse::succeed();
|
||||
}
|
||||
}
|
46
app/Commands/DeleteTrackCommand.php
Normal file
46
app/Commands/DeleteTrackCommand.php
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace App\Commands;
|
||||
|
||||
use App\Track;
|
||||
|
||||
class DeleteTrackCommand extends CommandBase
|
||||
{
|
||||
private $_trackId;
|
||||
private $_track;
|
||||
|
||||
function __construct($trackId)
|
||||
{
|
||||
$this->_trackId = $trackId;
|
||||
$this->_track = Track::find($trackId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
$user = \Auth::user();
|
||||
|
||||
return $this->_track && $user != null && $this->_track->user_id == $user->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
* @return CommandResponse
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
if ($this->_track->album_id != null) {
|
||||
$album = $this->_track->album;
|
||||
$this->_track->album_id = null;
|
||||
$this->_track->track_number = null;
|
||||
$this->_track->delete();
|
||||
$album->updateTrackNumbers();
|
||||
} else {
|
||||
$this->_track->delete();
|
||||
}
|
||||
|
||||
return CommandResponse::succeed();
|
||||
}
|
||||
}
|
79
app/Commands/EditAlbumCommand.php
Normal file
79
app/Commands/EditAlbumCommand.php
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
namespace App\Commands;
|
||||
|
||||
use App\Album;
|
||||
use App\Image;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class EditAlbumCommand extends CommandBase
|
||||
{
|
||||
private $_input;
|
||||
private $_albumId;
|
||||
private $_album;
|
||||
|
||||
function __construct($trackId, $input)
|
||||
{
|
||||
$this->_input = $input;
|
||||
$this->_albumId = $trackId;
|
||||
$this->_album = Album::find($trackId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
return $this->_album && $user != null && $this->_album->user_id == $user->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
* @return CommandResponse
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
$rules = [
|
||||
'title' => 'required|min:3|max:50',
|
||||
'cover' => 'image|mimes:png|min_width:350|min_height:350',
|
||||
'cover_id' => 'exists:images,id',
|
||||
'track_ids' => 'exists:tracks,id'
|
||||
];
|
||||
|
||||
$validator = Validator::make($this->_input, $rules);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return CommandResponse::fail($validator);
|
||||
}
|
||||
|
||||
$this->_album->title = $this->_input['title'];
|
||||
$this->_album->description = $this->_input['description'];
|
||||
|
||||
if (isset($this->_input['cover_id'])) {
|
||||
$this->_album->cover_id = $this->_input['cover_id'];
|
||||
} else {
|
||||
if (isset($this->_input['cover'])) {
|
||||
$cover = $this->_input['cover'];
|
||||
$this->_album->cover_id = Image::upload($cover, Auth::user())->id;
|
||||
} else {
|
||||
if (isset($this->_input['remove_cover']) && $this->_input['remove_cover'] == 'true') {
|
||||
$this->_album->cover_id = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$trackIds = explode(',', $this->_input['track_ids']);
|
||||
$this->_album->syncTrackIds($trackIds);
|
||||
$this->_album->save();
|
||||
|
||||
Album::whereId($this->_album->id)->update([
|
||||
'track_count' => DB::raw('(SELECT COUNT(id) FROM tracks WHERE album_id = ' . $this->_album->id . ')')
|
||||
]);
|
||||
|
||||
return CommandResponse::succeed(['real_cover_url' => $this->_album->getCoverUrl(Image::NORMAL)]);
|
||||
}
|
||||
}
|
77
app/Commands/EditPlaylistCommand.php
Normal file
77
app/Commands/EditPlaylistCommand.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
namespace App\Commands;
|
||||
|
||||
use App\PinnedPlaylist;
|
||||
use App\Playlist;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class EditPlaylistCommand extends CommandBase
|
||||
{
|
||||
private $_input;
|
||||
private $_playlistId;
|
||||
private $_playlist;
|
||||
|
||||
function __construct($playlistId, $input)
|
||||
{
|
||||
$this->_input = $input;
|
||||
$this->_playlistId = $playlistId;
|
||||
$this->_playlist = Playlist::find($playlistId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
return $this->_playlist && $user != null && $this->_playlist->user_id == $user->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
* @return CommandResponse
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
$rules = [
|
||||
'title' => 'required|min:3|max:50',
|
||||
'is_public' => 'required',
|
||||
'is_pinned' => 'required'
|
||||
];
|
||||
|
||||
$validator = Validator::make($this->_input, $rules);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return CommandResponse::fail($validator);
|
||||
}
|
||||
|
||||
$this->_playlist->title = $this->_input['title'];
|
||||
$this->_playlist->description = $this->_input['description'];
|
||||
$this->_playlist->is_public = $this->_input['is_public'] == 'true';
|
||||
|
||||
$this->_playlist->save();
|
||||
|
||||
$pin = PinnedPlaylist::whereUserId(Auth::user()->id)->wherePlaylistId($this->_playlistId)->first();
|
||||
if ($pin && $this->_input['is_pinned'] != 'true') {
|
||||
$pin->delete();
|
||||
} else {
|
||||
if (!$pin && $this->_input['is_pinned'] == 'true') {
|
||||
$this->_playlist->pin(Auth::user()->id);
|
||||
}
|
||||
}
|
||||
|
||||
return CommandResponse::succeed([
|
||||
'id' => $this->_playlist->id,
|
||||
'title' => $this->_playlist->title,
|
||||
'slug' => $this->_playlist->slug,
|
||||
'created_at' => $this->_playlist->created_at,
|
||||
'description' => $this->_playlist->description,
|
||||
'url' => $this->_playlist->url,
|
||||
'is_pinned' => $this->_input['is_pinned'] == 'true',
|
||||
'is_public' => $this->_input['is_public'] == 'true'
|
||||
]);
|
||||
}
|
||||
}
|
161
app/Commands/EditTrackCommand.php
Normal file
161
app/Commands/EditTrackCommand.php
Normal file
|
@ -0,0 +1,161 @@
|
|||
<?php
|
||||
|
||||
namespace App\Commands;
|
||||
|
||||
use App\Album;
|
||||
use App\Image;
|
||||
use App\Track;
|
||||
use App\User;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class EditTrackCommand extends CommandBase
|
||||
{
|
||||
private $_trackId;
|
||||
private $_track;
|
||||
private $_input;
|
||||
|
||||
function __construct($trackId, $input)
|
||||
{
|
||||
$this->_trackId = $trackId;
|
||||
$this->_track = Track::find($trackId);
|
||||
$this->_input = $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
$user = \Auth::user();
|
||||
|
||||
return $this->_track && $user != null && $this->_track->user_id == $user->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
* @return CommandResponse
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
$isVocal = (isset($this->_input['is_vocal']) && $this->_input['is_vocal'] == 'true') ? true : false;
|
||||
|
||||
$rules = [
|
||||
'title' => 'required|min:3|max:80',
|
||||
'released_at' => 'before:' . (date('Y-m-d',
|
||||
time() + (86400 * 2))) . (isset($this->_input['released_at']) && $this->_input['released_at'] != "" ? '|date' : ''),
|
||||
'license_id' => 'required|exists:licenses,id',
|
||||
'genre_id' => 'required|exists:genres,id',
|
||||
'cover' => 'image|mimes:png|min_width:350|min_height:350',
|
||||
'track_type_id' => 'required|exists:track_types,id',
|
||||
'songs' => 'required_when:track_type,2|exists:songs,id',
|
||||
'cover_id' => 'exists:images,id',
|
||||
'album_id' => 'exists:albums,id'
|
||||
];
|
||||
|
||||
if ($isVocal) {
|
||||
$rules['lyrics'] = 'required';
|
||||
}
|
||||
|
||||
if (isset($this->_input['track_type_id']) && $this->_input['track_type_id'] == 2) {
|
||||
$rules['show_song_ids'] = 'required|exists:show_songs,id';
|
||||
}
|
||||
|
||||
$validator = \Validator::make($this->_input, $rules);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return CommandResponse::fail($validator);
|
||||
}
|
||||
|
||||
$track = $this->_track;
|
||||
$track->title = $this->_input['title'];
|
||||
$track->released_at = isset($this->_input['released_at']) && $this->_input['released_at'] != "" ? strtotime($this->_input['released_at']) : null;
|
||||
$track->description = isset($this->_input['description']) ? $this->_input['description'] : '';
|
||||
$track->lyrics = isset($this->_input['lyrics']) ? $this->_input['lyrics'] : '';
|
||||
$track->license_id = $this->_input['license_id'];
|
||||
$track->genre_id = $this->_input['genre_id'];
|
||||
$track->track_type_id = $this->_input['track_type_id'];
|
||||
$track->is_explicit = $this->_input['is_explicit'] == 'true';
|
||||
$track->is_downloadable = $this->_input['is_downloadable'] == 'true';
|
||||
$track->is_listed = $this->_input['is_listed'] == 'true';
|
||||
$track->is_vocal = $isVocal;
|
||||
|
||||
if (isset($this->_input['album_id']) && strlen(trim($this->_input['album_id']))) {
|
||||
if ($track->album_id != null && $track->album_id != $this->_input['album_id']) {
|
||||
$this->removeTrackFromAlbum($track);
|
||||
}
|
||||
|
||||
if ($track->album_id != $this->_input['album_id']) {
|
||||
$album = Album::find($this->_input['album_id']);
|
||||
$track->track_number = $album->tracks()->count() + 1;
|
||||
$track->album_id = $this->_input['album_id'];
|
||||
|
||||
Album::whereId($album->id)->update([
|
||||
'track_count' => DB::raw('(SELECT COUNT(id) FROM tracks WHERE album_id = ' . $album->id . ')')
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
if ($track->album_id != null) {
|
||||
$this->removeTrackFromAlbum($track);
|
||||
}
|
||||
|
||||
$track->track_number = null;
|
||||
$track->album_id = null;
|
||||
}
|
||||
|
||||
if ($track->track_type_id == 2) {
|
||||
$track->showSongs()->sync(explode(',', $this->_input['show_song_ids']));
|
||||
} else {
|
||||
$track->showSongs()->sync([]);
|
||||
}
|
||||
|
||||
if ($track->published_at == null) {
|
||||
$track->published_at = new \DateTime();
|
||||
|
||||
DB::table('tracks')->whereUserId($track->user_id)->update(['is_latest' => false]);
|
||||
$track->is_latest = true;
|
||||
}
|
||||
|
||||
if (isset($this->_input['cover_id'])) {
|
||||
$track->cover_id = $this->_input['cover_id'];
|
||||
} else {
|
||||
if (isset($this->_input['cover'])) {
|
||||
$cover = $this->_input['cover'];
|
||||
$track->cover_id = Image::upload($cover, Auth::user())->id;
|
||||
} else {
|
||||
if ($this->_input['remove_cover'] == 'true') {
|
||||
$track->cover_id = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$track->updateTags();
|
||||
$track->save();
|
||||
|
||||
User::whereId($this->_track->user_id)->update([
|
||||
'track_count' => DB::raw('(SELECT COUNT(id) FROM tracks WHERE deleted_at IS NULL AND published_at IS NOT NULL AND user_id = ' . $this->_track->user_id . ')')
|
||||
]);
|
||||
|
||||
return CommandResponse::succeed(['real_cover_url' => $track->getCoverUrl(Image::NORMAL)]);
|
||||
}
|
||||
|
||||
private function removeTrackFromAlbum($track)
|
||||
{
|
||||
$album = $track->album;
|
||||
$index = 0;
|
||||
|
||||
foreach ($album->tracks as $track) {
|
||||
if ($track->id == $this->_trackId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$track->track_number = ++$index;
|
||||
$track->updateTags();
|
||||
$track->save();
|
||||
}
|
||||
|
||||
Album::whereId($album->id)->update([
|
||||
'track_count' => DB::raw('(SELECT COUNT(id) FROM tracks WHERE album_id = ' . $album->id . ')')
|
||||
]);
|
||||
}
|
||||
}
|
88
app/Commands/SaveAccountSettingsCommand.php
Normal file
88
app/Commands/SaveAccountSettingsCommand.php
Normal file
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
namespace App\Commands;
|
||||
|
||||
use App\Image;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class SaveAccountSettingsCommand extends CommandBase
|
||||
{
|
||||
private $_input;
|
||||
|
||||
function __construct($input)
|
||||
{
|
||||
$this->_input = $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return Auth::user() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
* @return CommandResponse
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
$rules = [
|
||||
'display_name' => 'required|min:3|max:26',
|
||||
'bio' => 'textarea_length:250'
|
||||
];
|
||||
|
||||
if ($this->_input['sync_names'] == 'true') {
|
||||
$this->_input['display_name'] = $user->mlpforums_name;
|
||||
}
|
||||
|
||||
if ($this->_input['uses_gravatar'] == 'true') {
|
||||
$rules['gravatar'] = 'email';
|
||||
} else {
|
||||
$rules['avatar'] = 'image|mimes:png|min_width:350|min_height:350';
|
||||
$rules['avatar_id'] = 'exists:images,id';
|
||||
}
|
||||
|
||||
$validator = Validator::make($this->_input, $rules);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return CommandResponse::fail($validator);
|
||||
}
|
||||
|
||||
if ($this->_input['uses_gravatar'] != 'true') {
|
||||
if ($user->avatar_id == null && !isset($this->_input['avatar']) && !isset($this->_input['avatar_id'])) {
|
||||
$validator->messages()->add('avatar',
|
||||
'You must upload or select an avatar if you are not using gravatar!');
|
||||
|
||||
return CommandResponse::fail($validator);
|
||||
}
|
||||
}
|
||||
|
||||
$user->bio = $this->_input['bio'];
|
||||
$user->display_name = $this->_input['display_name'];
|
||||
$user->sync_names = $this->_input['sync_names'] == 'true';
|
||||
$user->can_see_explicit_content = $this->_input['can_see_explicit_content'] == 'true';
|
||||
$user->uses_gravatar = $this->_input['uses_gravatar'] == 'true';
|
||||
|
||||
if ($user->uses_gravatar) {
|
||||
$user->avatar_id = null;
|
||||
$user->gravatar = $this->_input['gravatar'];
|
||||
} else {
|
||||
if (isset($this->_input['avatar_id'])) {
|
||||
$user->avatar_id = $this->_input['avatar_id'];
|
||||
} else {
|
||||
if (isset($this->_input['avatar'])) {
|
||||
$user->avatar_id = Image::upload($this->_input['avatar'], $user)->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$user->save();
|
||||
|
||||
return CommandResponse::succeed();
|
||||
}
|
||||
}
|
75
app/Commands/ToggleFavouriteCommand.php
Normal file
75
app/Commands/ToggleFavouriteCommand.php
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
namespace App\Commands;
|
||||
|
||||
use App\Favourite;
|
||||
use App\ResourceUser;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
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)->whereUserId(Auth::user()->id)->first();
|
||||
$isFavourited = false;
|
||||
|
||||
if ($existing) {
|
||||
$existing->delete();
|
||||
} else {
|
||||
$fav = new Favourite();
|
||||
$fav->$typeId = $this->_resourceId;
|
||||
$fav->user_id = Auth::user()->id;
|
||||
$fav->created_at = time();
|
||||
$fav->save();
|
||||
$isFavourited = true;
|
||||
}
|
||||
|
||||
$resourceUser = ResourceUser::get(Auth::user()->id, $this->_resourceType, $this->_resourceId);
|
||||
$resourceUser->is_favourited = $isFavourited;
|
||||
$resourceUser->save();
|
||||
|
||||
$resourceTable = $this->_resourceType . 's';
|
||||
|
||||
// We do this to prevent a race condition. Sure I could simply increment the count columns and re-save back to the db
|
||||
// but that would require an additional SELECT and the operation would be non-atomic. If two log items are created
|
||||
// for the same resource at the same time, the cached values will still be correct with this method.
|
||||
|
||||
DB::table($resourceTable)->whereId($this->_resourceId)->update([
|
||||
'favourite_count' =>
|
||||
DB::raw('(
|
||||
SELECT
|
||||
COUNT(id)
|
||||
FROM
|
||||
favourites
|
||||
WHERE ' .
|
||||
$typeId . ' = ' . $this->_resourceId . ')')
|
||||
]);
|
||||
|
||||
return CommandResponse::succeed(['is_favourited' => $isFavourited]);
|
||||
}
|
||||
}
|
57
app/Commands/ToggleFollowingCommand.php
Normal file
57
app/Commands/ToggleFollowingCommand.php
Normal file
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
namespace App\Commands;
|
||||
|
||||
use App\Follower;
|
||||
use App\ResourceUser;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class ToggleFollowingCommand 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 = Follower::where($typeId, '=', $this->_resourceId)->whereUserId(Auth::user()->id)->first();
|
||||
$isFollowed = false;
|
||||
|
||||
if ($existing) {
|
||||
$existing->delete();
|
||||
} else {
|
||||
$follow = new Follower();
|
||||
$follow->$typeId = $this->_resourceId;
|
||||
$follow->user_id = Auth::user()->id;
|
||||
$follow->created_at = time();
|
||||
$follow->save();
|
||||
$isFollowed = true;
|
||||
}
|
||||
|
||||
$resourceUser = ResourceUser::get(Auth::user()->id, $this->_resourceType, $this->_resourceId);
|
||||
$resourceUser->is_followed = $isFollowed;
|
||||
$resourceUser->save();
|
||||
|
||||
return CommandResponse::succeed(['is_followed' => $isFollowed]);
|
||||
}
|
||||
}
|
154
app/Commands/UploadTrackCommand.php
Normal file
154
app/Commands/UploadTrackCommand.php
Normal file
|
@ -0,0 +1,154 @@
|
|||
<?php
|
||||
|
||||
namespace App\Commands;
|
||||
|
||||
use App\Track;
|
||||
use App\TrackFile;
|
||||
use AudioCache;
|
||||
use File;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class UploadTrackCommand extends CommandBase
|
||||
{
|
||||
private $_allowLossy;
|
||||
private $_allowShortTrack;
|
||||
private $_losslessFormats = [
|
||||
'flac',
|
||||
'pcm_s16le ([1][0][0][0] / 0x0001)',
|
||||
'pcm_s16be',
|
||||
'adpcm_ms ([2][0][0][0] / 0x0002)',
|
||||
'pcm_s24le ([1][0][0][0] / 0x0001)',
|
||||
'pcm_s24be',
|
||||
'pcm_f32le ([3][0][0][0] / 0x0003)',
|
||||
'pcm_f32be (fl32 / 0x32336C66)'
|
||||
];
|
||||
|
||||
public function __construct($allowLossy = false, $allowShortTrack = false)
|
||||
{
|
||||
$this->_allowLossy = $allowLossy;
|
||||
$this->_allowShortTrack = $allowShortTrack;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return \Auth::user() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
* @return CommandResponse
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
$user = \Auth::user();
|
||||
$trackFile = \Input::file('track');
|
||||
$audio = \AudioCache::get($trackFile->getPathname());
|
||||
|
||||
$validator = \Validator::make(['track' => $trackFile], [
|
||||
'track' =>
|
||||
'required|'
|
||||
. ($this->_allowLossy ? '' : 'audio_format:'. implode(',', $this->_losslessFormats).'|')
|
||||
. ($this->_allowShortTrack ? '' : 'min_duration:30|')
|
||||
. 'audio_channels:1,2|'
|
||||
. 'sample_rate:44100,48000,88200,96000,176400,192000'
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return CommandResponse::fail($validator);
|
||||
}
|
||||
|
||||
$track = new Track();
|
||||
|
||||
try {
|
||||
$track->user_id = $user->id;
|
||||
$track->title = pathinfo($trackFile->getClientOriginalName(), PATHINFO_FILENAME);
|
||||
$track->duration = $audio->getDuration();
|
||||
$track->is_listed = true;
|
||||
|
||||
$track->save();
|
||||
|
||||
$destination = $track->getDirectory();
|
||||
$track->ensureDirectoryExists();
|
||||
|
||||
$source = $trackFile->getPathname();
|
||||
$index = 0;
|
||||
|
||||
$processes = [];
|
||||
|
||||
// Lossy uploads need to be identified and set as the master file
|
||||
// without being re-encoded.
|
||||
$audioObject = AudioCache::get($source);
|
||||
$isLossyUpload = !in_array($audioObject->getAudioCodec(), $this->_losslessFormats);
|
||||
|
||||
if ($isLossyUpload) {
|
||||
if ($audioObject->getAudioCodec() === 'mp3') {
|
||||
$masterFormat = 'MP3';
|
||||
|
||||
} else if (Str::startsWith($audioObject->getAudioCodec(), 'aac')) {
|
||||
$masterFormat = 'AAC';
|
||||
|
||||
} else if ($audioObject->getAudioCodec() === 'vorbis') {
|
||||
$masterFormat = 'OGG Vorbis';
|
||||
|
||||
} else {
|
||||
$validator->messages()->add('track', 'The track does not contain audio in a known lossy format.');
|
||||
return CommandResponse::fail($validator);
|
||||
}
|
||||
|
||||
$trackFile = new TrackFile();
|
||||
$trackFile->is_master = true;
|
||||
$trackFile->format = $masterFormat;
|
||||
$trackFile->track_id = $track->id;
|
||||
$trackFile->save();
|
||||
|
||||
// Lossy masters are copied into the datastore - no re-encoding involved.
|
||||
File::copy($source, $trackFile->getFile());
|
||||
}
|
||||
|
||||
foreach (Track::$Formats as $name => $format) {
|
||||
// Don't bother with lossless transcodes of lossy uploads, and
|
||||
// don't re-encode the lossy master.
|
||||
if ($isLossyUpload && ($format['is_lossless'] || $name === $masterFormat)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$trackFile = new TrackFile();
|
||||
$trackFile->is_master = $name === 'FLAC' ? true : false;
|
||||
$trackFile->format = $name;
|
||||
$track->trackFiles()->save($trackFile);
|
||||
|
||||
$target = $destination . '/' . $trackFile->getFilename(); //$track->getFilenameFor($name);
|
||||
|
||||
$command = $format['command'];
|
||||
$command = str_replace('{$source}', '"' . $source . '"', $command);
|
||||
$command = str_replace('{$target}', '"' . $target . '"', $command);
|
||||
|
||||
Log::info('Encoding ' . $track->id . ' into ' . $target);
|
||||
$this->notify('Encoding ' . $name, $index / count(Track::$Formats) * 100);
|
||||
|
||||
$pipes = [];
|
||||
$proc = proc_open($command, [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'a']], $pipes);
|
||||
$processes[] = $proc;
|
||||
}
|
||||
|
||||
foreach ($processes as $proc) {
|
||||
proc_close($proc);
|
||||
}
|
||||
|
||||
$track->updateTags();
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$track->delete();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return CommandResponse::succeed([
|
||||
'id' => $track->id,
|
||||
'name' => $track->name
|
||||
]);
|
||||
}
|
||||
}
|
81
app/Comment.php
Normal file
81
app/Comment.php
Normal file
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Comment extends Model
|
||||
{
|
||||
|
||||
use SoftDeletes;
|
||||
|
||||
protected $table = 'comments';
|
||||
|
||||
protected $dates = ['deleted_at'];
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('App\User');
|
||||
}
|
||||
|
||||
public function track()
|
||||
{
|
||||
return $this->belongsTo('App\Track');
|
||||
}
|
||||
|
||||
public function album()
|
||||
{
|
||||
return $this->belongsTo('App\Album');
|
||||
}
|
||||
|
||||
public function playlist()
|
||||
{
|
||||
return $this->belongsTo('App\Playlist');
|
||||
}
|
||||
|
||||
public function profile()
|
||||
{
|
||||
return $this->belongsTo('App\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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
221
app/Console/Commands/ClassifyMLPMA.php
Normal file
221
app/Console/Commands/ClassifyMLPMA.php
Normal file
|
@ -0,0 +1,221 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\ShowSong;
|
||||
use App\Track;
|
||||
use App\TrackType;
|
||||
use DB;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ClassifyMLPMA extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'mlpma:classify
|
||||
{--startAt=1 : Track to start importing from. Useful for resuming an interrupted import.}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Adds Pony.fm-specific metadata to imported MLPMA tracks.';
|
||||
|
||||
/**
|
||||
* A counter for the number of processed tracks.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $currentTrack = 0;
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
// Get the list of tracks that need classification
|
||||
$tracks = DB::table('mlpma_tracks')
|
||||
->orderBy('id')
|
||||
->get();
|
||||
|
||||
$this->comment('Importing tracks...');
|
||||
|
||||
$totalTracks = sizeof($tracks);
|
||||
|
||||
$fileToStartAt = (int)$this->option('startAt') - 1;
|
||||
$this->comment("Skipping $fileToStartAt files..." . PHP_EOL);
|
||||
|
||||
$tracks = array_slice($tracks, $fileToStartAt);
|
||||
$this->currentTrack = $fileToStartAt;
|
||||
|
||||
foreach ($tracks as $track) {
|
||||
$this->currentTrack++;
|
||||
$this->comment('[' . $this->currentTrack . '/' . $totalTracks . '] Classifying track [' . $track->filename . ']...');
|
||||
|
||||
$parsedTags = json_decode($track->parsed_tags, true);
|
||||
|
||||
|
||||
//==========================================================================================================
|
||||
// Original, show song remix, fan song remix, show audio remix, or ponified song?
|
||||
//==========================================================================================================
|
||||
$sanitizedTrackTitle = $parsedTags['title'];
|
||||
$sanitizedTrackTitle = str_replace(['-', '+', '~', 'ft.', '*', '(', ')', '.'], ' ', $sanitizedTrackTitle);
|
||||
|
||||
$queriedTitle = DB::connection()->getPdo()->quote($sanitizedTrackTitle);
|
||||
$officialSongs = ShowSong::select(['id', 'title'])
|
||||
->whereRaw("
|
||||
MATCH (title)
|
||||
AGAINST ($queriedTitle IN BOOLEAN MODE)
|
||||
")
|
||||
->get();
|
||||
|
||||
|
||||
// If it has "Ingram" in the name, it's definitely an official song remix.
|
||||
if (Str::contains(Str::lower($track->filename), 'ingram')) {
|
||||
$this->info('This is an official song remix!');
|
||||
|
||||
list($trackType, $linkedSongIds) = $this->classifyTrack($track->filename, $officialSongs, true,
|
||||
$parsedTags);
|
||||
|
||||
|
||||
// If it has "remix" in the name, it's definitely a remix.
|
||||
} else {
|
||||
if (Str::contains(Str::lower($sanitizedTrackTitle), 'remix')) {
|
||||
$this->info('This is some kind of remix!');
|
||||
|
||||
list($trackType, $linkedSongIds) = $this->classifyTrack($track->filename, $officialSongs, false,
|
||||
$parsedTags);
|
||||
|
||||
// No idea what this is. Have the pony at the terminal figure it out!
|
||||
} else {
|
||||
list($trackType, $linkedSongIds) = $this->classifyTrack($track->filename, $officialSongs, false,
|
||||
$parsedTags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================================================
|
||||
// Attach the data and publish the track!
|
||||
//==========================================================================================================
|
||||
|
||||
$track = Track::find($track->track_id);
|
||||
|
||||
$track->track_type_id = $trackType;
|
||||
$track->published_at = $parsedTags['released_at'];
|
||||
$track->save();
|
||||
|
||||
if (sizeof($linkedSongIds) > 0) {
|
||||
$track->showSongs()->sync($linkedSongIds);
|
||||
}
|
||||
|
||||
echo PHP_EOL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines what type of track the given file is. If unable to guess, the user
|
||||
* is asked to identify it interactively.
|
||||
*
|
||||
* @param string $filename
|
||||
* @param ShowSong[] $officialSongs
|
||||
* @param bool|false $isRemixOfOfficialTrack
|
||||
* @return array
|
||||
*/
|
||||
protected function classifyTrack($filename, $officialSongs, $isRemixOfOfficialTrack = false, $tags)
|
||||
{
|
||||
$trackTypeId = null;
|
||||
$linkedSongIds = [];
|
||||
|
||||
|
||||
foreach ($officialSongs as $song) {
|
||||
$this->comment('=> Matched official song: [' . $song->id . '] ' . $song->title);
|
||||
}
|
||||
|
||||
|
||||
if ($isRemixOfOfficialTrack && sizeof($officialSongs) === 1) {
|
||||
$linkedSongIds = [$officialSongs[0]->id];
|
||||
|
||||
} else {
|
||||
if ($isRemixOfOfficialTrack && sizeof($officialSongs) > 1) {
|
||||
$this->question('Multiple official songs matched! Please enter the ID of the correct one.');
|
||||
|
||||
} else {
|
||||
if (sizeof($officialSongs) > 0) {
|
||||
$this->question('This looks like a remix of an official song!');
|
||||
$this->question('Press "r" if the match above is right!');
|
||||
|
||||
} else {
|
||||
$this->question('Exactly what kind of track is this?');
|
||||
|
||||
}
|
||||
}
|
||||
$this->question('If this is a medley, multiple song ID\'s can be separated by commas. ');
|
||||
$this->question(' ');
|
||||
$this->question(' ' . $filename . ' ');
|
||||
$this->question(' ');
|
||||
$this->question(' Title: ' . $tags['title'] . ' ');
|
||||
$this->question(' Album: ' . $tags['album'] . ' ');
|
||||
$this->question(' Artist: ' . $tags['artist'] . ' ');
|
||||
$this->question(' ');
|
||||
$this->question(' r = official song remix (accept all "guessed" matches) ');
|
||||
$this->question(' # = official song remix (enter the ID(s) of the show song(s)) ');
|
||||
$this->question(' a = show audio remix ');
|
||||
$this->question(' f = fan track remix ');
|
||||
$this->question(' p = ponified track ');
|
||||
$this->question(' o = original track ');
|
||||
$this->question(' ');
|
||||
$input = $this->ask('[r/#/a/f/p/o]: ');
|
||||
|
||||
switch ($input) {
|
||||
case 'r':
|
||||
$trackTypeId = TrackType::OFFICIAL_TRACK_REMIX;
|
||||
foreach ($officialSongs as $officialSong) {
|
||||
$linkedSongIds[] = (int)$officialSong->id;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
$trackTypeId = TrackType::OFFICIAL_AUDIO_REMIX;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
$trackTypeId = TrackType::FAN_TRACK_REMIX;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
$trackTypeId = TrackType::PONIFIED_TRACK;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
$trackTypeId = TrackType::ORIGINAL_TRACK;
|
||||
break;
|
||||
|
||||
default:
|
||||
$trackTypeId = TrackType::OFFICIAL_TRACK_REMIX;
|
||||
$linkedSongIds = explode(',', $input);
|
||||
$linkedSongIds = array_map(function ($item) {
|
||||
return (int)$item;
|
||||
}, $linkedSongIds);
|
||||
}
|
||||
}
|
||||
|
||||
return [$trackTypeId, $linkedSongIds];
|
||||
}
|
||||
}
|
498
app/Console/Commands/ImportMLPMA.php
Normal file
498
app/Console/Commands/ImportMLPMA.php
Normal file
|
@ -0,0 +1,498 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Album;
|
||||
use App\Commands\UploadTrackCommand;
|
||||
use App\Genre;
|
||||
use App\Image;
|
||||
use App\Track;
|
||||
use App\User;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Config;
|
||||
use DB;
|
||||
use File;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Str;
|
||||
use Input;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
|
||||
require_once(app_path() . '/Library/getid3/getid3/getid3.php');
|
||||
|
||||
class ImportMLPMA extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'mlpma:import
|
||||
{--startAt=1 : Track to start importing from. Useful for resuming an interrupted import.}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Imports the MLP Music Archive';
|
||||
|
||||
/**
|
||||
* File extensions to ignore when importing the archive.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $ignoredExtensions = ['db', 'jpg', 'png', 'txt', 'rtf', 'wma'];
|
||||
|
||||
/**
|
||||
* Used to stop the import process when a SIGINT is received.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $isInterrupted = false;
|
||||
|
||||
/**
|
||||
* A counter for the number of processed tracks.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $currentFile;
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function handleInterrupt($signo)
|
||||
{
|
||||
$this->error('Import aborted!');
|
||||
$this->error('Resume it from here using: --startAt=' . $this->currentFile);
|
||||
$this->isInterrupted = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
pcntl_signal(SIGINT, [$this, 'handleInterrupt']);
|
||||
|
||||
$mlpmaPath = Config::get('ponyfm.files_directory') . 'mlpma';
|
||||
$tmpPath = Config::get('ponyfm.files_directory') . 'tmp';
|
||||
|
||||
if (!File::exists($tmpPath)) {
|
||||
File::makeDirectory($tmpPath);
|
||||
}
|
||||
|
||||
$UNKNOWN_GENRE = Genre::firstOrCreate([
|
||||
'name' => 'Unknown',
|
||||
'slug' => 'unknown'
|
||||
]);
|
||||
|
||||
$this->comment('Enumerating MLP Music Archive source files...');
|
||||
$files = File::allFiles($mlpmaPath);
|
||||
$this->info(sizeof($files) . ' files found!');
|
||||
|
||||
$this->comment('Enumerating artists...');
|
||||
$artists = File::directories($mlpmaPath);
|
||||
$this->info(sizeof($artists) . ' artists found!');
|
||||
|
||||
$this->comment('Importing tracks...');
|
||||
|
||||
$totalFiles = sizeof($files);
|
||||
|
||||
$fileToStartAt = (int)$this->option('startAt') - 1;
|
||||
$this->comment("Skipping $fileToStartAt files..." . PHP_EOL);
|
||||
|
||||
$files = array_slice($files, $fileToStartAt);
|
||||
$this->currentFile = $fileToStartAt;
|
||||
|
||||
foreach ($files as $file) {
|
||||
$this->currentFile++;
|
||||
|
||||
pcntl_signal_dispatch();
|
||||
if ($this->isInterrupted) {
|
||||
break;
|
||||
}
|
||||
|
||||
$this->comment('[' . $this->currentFile . '/' . $totalFiles . '] Importing track [' . $file->getFilename() . ']...');
|
||||
|
||||
if (in_array($file->getExtension(), $this->ignoredExtensions)) {
|
||||
$this->comment('This is not an audio file! Skipping...' . PHP_EOL);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Has this track already been imported?
|
||||
$importedTrack = DB::table('mlpma_tracks')
|
||||
->where('filename', '=', $file->getFilename())
|
||||
->first();
|
||||
|
||||
if ($importedTrack) {
|
||||
$this->comment('This track has already been imported! Skipping...' . PHP_EOL);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================================================
|
||||
// Extract the original tags.
|
||||
//==========================================================================================================
|
||||
$getId3 = new getID3;
|
||||
|
||||
// all tags read by getID3, including the cover art
|
||||
$allTags = $getId3->analyze($file->getPathname());
|
||||
|
||||
// tags specific to a file format (ID3 or Atom), pre-normalization but with cover art removed
|
||||
$rawTags = [];
|
||||
|
||||
// normalized tags used by Pony.fm
|
||||
$parsedTags = [];
|
||||
|
||||
if (Str::lower($file->getExtension()) === 'mp3') {
|
||||
list($parsedTags, $rawTags) = $this->getId3Tags($allTags);
|
||||
|
||||
} elseif (Str::lower($file->getExtension()) === 'm4a') {
|
||||
list($parsedTags, $rawTags) = $this->getAtomTags($allTags);
|
||||
|
||||
} elseif (Str::lower($file->getExtension()) === 'ogg') {
|
||||
list($parsedTags, $rawTags) = $this->getVorbisTags($allTags);
|
||||
|
||||
} elseif (Str::lower($file->getExtension()) === 'flac') {
|
||||
list($parsedTags, $rawTags) = $this->getVorbisTags($allTags);
|
||||
|
||||
}
|
||||
|
||||
//==========================================================================================================
|
||||
// Determine the release date.
|
||||
//==========================================================================================================
|
||||
$modifiedDate = Carbon::createFromTimeStampUTC(File::lastModified($file->getPathname()));
|
||||
$taggedYear = $parsedTags['year'];
|
||||
|
||||
$this->info('Modification year: ' . $modifiedDate->year);
|
||||
$this->info('Tagged year: ' . $taggedYear);
|
||||
|
||||
if ($taggedYear !== null && $modifiedDate->year === $taggedYear) {
|
||||
$releasedAt = $modifiedDate;
|
||||
} elseif ($taggedYear !== null && Str::length((string)$taggedYear) !== 4) {
|
||||
$this->error('This track\'s tagged year makes no sense! Using the track\'s last modified date...');
|
||||
$releasedAt = $modifiedDate;
|
||||
} elseif ($taggedYear !== null && $modifiedDate->year !== $taggedYear) {
|
||||
$this->error('Release years don\'t match! Using the tagged year...');
|
||||
$releasedAt = Carbon::create($taggedYear);
|
||||
|
||||
} else {
|
||||
// $taggedYear is null
|
||||
$this->error('This track isn\'t tagged with its release year! Using the track\'s last modified date...');
|
||||
$releasedAt = $modifiedDate;
|
||||
}
|
||||
|
||||
// This is later used by the classification/publishing script to determine the publication date.
|
||||
$parsedTags['released_at'] = $releasedAt->toDateTimeString();
|
||||
|
||||
//==========================================================================================================
|
||||
// Does this track have vocals?
|
||||
//==========================================================================================================
|
||||
$isVocal = $parsedTags['lyrics'] !== null;
|
||||
|
||||
|
||||
//==========================================================================================================
|
||||
// Fill in the title tag if it's missing.
|
||||
//==========================================================================================================
|
||||
if (!$parsedTags['title']) {
|
||||
$parsedTags['title'] = $file->getBasename('.' . $file->getExtension());
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================================================
|
||||
// Determine the genre.
|
||||
//==========================================================================================================
|
||||
$genreName = $parsedTags['genre'];
|
||||
$genreSlug = Str::slug($genreName);
|
||||
$this->info('Genre: ' . $genreName);
|
||||
|
||||
if ($genreName && $genreSlug !== '') {
|
||||
$genre = Genre::where('name', '=', $genreName)->first();
|
||||
if ($genre) {
|
||||
$genreId = $genre->id;
|
||||
|
||||
} else {
|
||||
$genre = new Genre();
|
||||
$genre->name = $genreName;
|
||||
$genre->slug = $genreSlug;
|
||||
$genre->save();
|
||||
$genreId = $genre->id;
|
||||
$this->comment('Created a new genre!');
|
||||
}
|
||||
|
||||
} else {
|
||||
$genreId = $UNKNOWN_GENRE->id; // "Unknown" genre ID
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================================================
|
||||
// Determine which artist account this file belongs to using the containing directory.
|
||||
//==========================================================================================================
|
||||
$this->info('Path to file: ' . $file->getRelativePath());
|
||||
$path_components = explode(DIRECTORY_SEPARATOR, $file->getRelativePath());
|
||||
$artist_name = $path_components[0];
|
||||
$album_name = array_key_exists(1, $path_components) ? $path_components[1] : null;
|
||||
|
||||
$this->info('Artist: ' . $artist_name);
|
||||
$this->info('Album: ' . $album_name);
|
||||
|
||||
$artist = User::where('display_name', '=', $artist_name)->first();
|
||||
|
||||
if (!$artist) {
|
||||
$artist = new User;
|
||||
$artist->display_name = $artist_name;
|
||||
$artist->email = null;
|
||||
$artist->is_archived = true;
|
||||
|
||||
$artist->slug = Str::slug($artist_name);
|
||||
|
||||
$slugExists = User::where('slug', '=', $artist->slug)->first();
|
||||
if ($slugExists) {
|
||||
$this->error('Horsefeathers! The slug ' . $artist->slug . ' is already taken!');
|
||||
$artist->slug = $artist->slug . '-' . Str::random(4);
|
||||
}
|
||||
|
||||
$artist->save();
|
||||
}
|
||||
|
||||
//==========================================================================================================
|
||||
// Extract the cover art, if any exists.
|
||||
//==========================================================================================================
|
||||
|
||||
$this->comment('Extracting cover art!');
|
||||
$coverId = null;
|
||||
if (array_key_exists('comments', $allTags) && array_key_exists('picture', $allTags['comments'])) {
|
||||
$image = $allTags['comments']['picture'][0];
|
||||
|
||||
if ($image['image_mime'] === 'image/png') {
|
||||
$extension = 'png';
|
||||
|
||||
} elseif ($image['image_mime'] === 'image/jpeg') {
|
||||
$extension = 'jpg';
|
||||
|
||||
} elseif ($image['image_mime'] === 'image/gif') {
|
||||
$extension = 'gif';
|
||||
|
||||
} else {
|
||||
$this->error('Unknown cover art format!');
|
||||
}
|
||||
|
||||
// write temporary image file
|
||||
$imageFilename = $file->getFilename() . ".cover.$extension";
|
||||
$imageFilePath = "$tmpPath/" . $imageFilename;
|
||||
File::put($imageFilePath, $image['data']);
|
||||
|
||||
|
||||
$imageFile = new UploadedFile($imageFilePath, $imageFilename, $image['image_mime']);
|
||||
|
||||
$cover = Image::upload($imageFile, $artist);
|
||||
$coverId = $cover->id;
|
||||
|
||||
} else {
|
||||
$this->comment('No cover art found!');
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================================================
|
||||
// Is this part of an album?
|
||||
//==========================================================================================================
|
||||
|
||||
$albumId = null;
|
||||
$albumName = $parsedTags['album'];
|
||||
|
||||
if ($albumName !== null) {
|
||||
$album = Album::where('user_id', '=', $artist->id)
|
||||
->where('title', '=', $albumName)
|
||||
->first();
|
||||
|
||||
if (!$album) {
|
||||
$album = new Album;
|
||||
|
||||
$album->title = $albumName;
|
||||
$album->user_id = $artist->id;
|
||||
$album->cover_id = $coverId;
|
||||
|
||||
$album->save();
|
||||
}
|
||||
|
||||
$albumId = $album->id;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================================================
|
||||
// Save this track.
|
||||
//==========================================================================================================
|
||||
// "Upload" the track to Pony.fm
|
||||
$this->comment('Transcoding the track!');
|
||||
Auth::loginUsingId($artist->id);
|
||||
|
||||
$trackFile = new UploadedFile($file->getPathname(), $file->getFilename(), $allTags['mime_type']);
|
||||
Input::instance()->files->add(['track' => $trackFile]);
|
||||
|
||||
$upload = new UploadTrackCommand(true, true);
|
||||
$result = $upload->execute();
|
||||
|
||||
if ($result->didFail()) {
|
||||
$this->error(json_encode($result->getValidator()->messages()->getMessages(), JSON_PRETTY_PRINT));
|
||||
|
||||
} else {
|
||||
// Save metadata.
|
||||
$track = Track::find($result->getResponse()['id']);
|
||||
|
||||
$track->title = $parsedTags['title'];
|
||||
$track->cover_id = $coverId;
|
||||
$track->album_id = $albumId;
|
||||
$track->genre_id = $genreId;
|
||||
$track->track_number = $parsedTags['track_number'];
|
||||
$track->released_at = $releasedAt;
|
||||
$track->description = $parsedTags['comments'];
|
||||
$track->is_downloadable = true;
|
||||
$track->lyrics = $parsedTags['lyrics'];
|
||||
$track->is_vocal = $isVocal;
|
||||
$track->license_id = 2;
|
||||
$track->save();
|
||||
|
||||
// If we made it to here, the track is intact! Log the import.
|
||||
DB::table('mlpma_tracks')
|
||||
->insert([
|
||||
'track_id' => $result->getResponse()['id'],
|
||||
'path' => $file->getRelativePath(),
|
||||
'filename' => $file->getFilename(),
|
||||
'extension' => $file->getExtension(),
|
||||
'imported_at' => Carbon::now(),
|
||||
'parsed_tags' => json_encode($parsedTags),
|
||||
'raw_tags' => json_encode($rawTags),
|
||||
]);
|
||||
}
|
||||
|
||||
echo PHP_EOL . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $rawTags
|
||||
* @return array
|
||||
*/
|
||||
protected function getId3Tags($rawTags)
|
||||
{
|
||||
if (array_key_exists('tags', $rawTags) && array_key_exists('id3v2', $rawTags['tags'])) {
|
||||
$tags = $rawTags['tags']['id3v2'];
|
||||
} elseif (array_key_exists('tags', $rawTags) && array_key_exists('id3v1', $rawTags['tags'])) {
|
||||
$tags = $rawTags['tags']['id3v1'];
|
||||
} else {
|
||||
$tags = [];
|
||||
}
|
||||
|
||||
|
||||
$comment = null;
|
||||
|
||||
if (isset($tags['comment'])) {
|
||||
// The "comment" tag comes in with a badly encoded string index
|
||||
// so its array key has to be used implicitly.
|
||||
$key = array_keys($tags['comment'])[0];
|
||||
|
||||
// The comment may have a null byte at the end. trim() removes it.
|
||||
$comment = trim($tags['comment'][$key]);
|
||||
|
||||
// Replace the malformed comment with the "fixed" one.
|
||||
unset($tags['comment'][$key]);
|
||||
$tags['comment'][0] = $comment;
|
||||
}
|
||||
|
||||
return [
|
||||
[
|
||||
'title' => isset($tags['title']) ? $tags['title'][0] : null,
|
||||
'artist' => isset($tags['artist']) ? $tags['artist'][0] : null,
|
||||
'band' => isset($tags['band']) ? $tags['band'][0] : null,
|
||||
'genre' => isset($tags['genre']) ? $tags['genre'][0] : null,
|
||||
'track_number' => isset($tags['track_number']) ? $tags['track_number'][0] : null,
|
||||
'album' => isset($tags['album']) ? $tags['album'][0] : null,
|
||||
'year' => isset($tags['year']) ? (int)$tags['year'][0] : null,
|
||||
'comments' => $comment,
|
||||
'lyrics' => isset($tags['unsynchronised_lyric']) ? $tags['unsynchronised_lyric'][0] : null,
|
||||
],
|
||||
$tags
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $rawTags
|
||||
* @return array
|
||||
*/
|
||||
protected function getAtomTags($rawTags)
|
||||
{
|
||||
if (array_key_exists('tags', $rawTags) && array_key_exists('quicktime', $rawTags['tags'])) {
|
||||
$tags = $rawTags['tags']['quicktime'];
|
||||
} else {
|
||||
$tags = [];
|
||||
}
|
||||
|
||||
$trackNumber = null;
|
||||
if (isset($tags['track_number'])) {
|
||||
$trackNumberComponents = explode('/', $tags['track_number'][0]);
|
||||
$trackNumber = $trackNumberComponents[0];
|
||||
}
|
||||
|
||||
return [
|
||||
[
|
||||
'title' => isset($tags['title']) ? $tags['title'][0] : null,
|
||||
'artist' => isset($tags['artist']) ? $tags['artist'][0] : null,
|
||||
'band' => isset($tags['band']) ? $tags['band'][0] : null,
|
||||
'album_artist' => isset($tags['album_artist']) ? $tags['album_artist'][0] : null,
|
||||
'genre' => isset($tags['genre']) ? $tags['genre'][0] : null,
|
||||
'track_number' => $trackNumber,
|
||||
'album' => isset($tags['album']) ? $tags['album'][0] : null,
|
||||
'year' => isset($tags['year']) ? (int)$tags['year'][0] : null,
|
||||
'comments' => isset($tags['comments']) ? $tags['comments'][0] : null,
|
||||
'lyrics' => isset($tags['lyrics']) ? $tags['lyrics'][0] : null,
|
||||
],
|
||||
$tags
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $rawTags
|
||||
* @return array
|
||||
*/
|
||||
protected function getVorbisTags($rawTags)
|
||||
{
|
||||
if (array_key_exists('tags', $rawTags) && array_key_exists('vorbiscomment', $rawTags['tags'])) {
|
||||
$tags = $rawTags['tags']['vorbiscomment'];
|
||||
} else {
|
||||
$tags = [];
|
||||
}
|
||||
|
||||
$trackNumber = null;
|
||||
if (isset($tags['track_number'])) {
|
||||
$trackNumberComponents = explode('/', $tags['track_number'][0]);
|
||||
$trackNumber = $trackNumberComponents[0];
|
||||
}
|
||||
|
||||
return [
|
||||
[
|
||||
'title' => isset($tags['title']) ? $tags['title'][0] : null,
|
||||
'artist' => isset($tags['artist']) ? $tags['artist'][0] : null,
|
||||
'band' => isset($tags['band']) ? $tags['band'][0] : null,
|
||||
'album_artist' => isset($tags['album_artist']) ? $tags['album_artist'][0] : null,
|
||||
'genre' => isset($tags['genre']) ? $tags['genre'][0] : null,
|
||||
'track_number' => $trackNumber,
|
||||
'album' => isset($tags['album']) ? $tags['album'][0] : null,
|
||||
'year' => isset($tags['year']) ? (int)$tags['year'][0] : null,
|
||||
'comments' => isset($tags['comments']) ? $tags['comments'][0] : null,
|
||||
'lyrics' => isset($tags['lyrics']) ? $tags['lyrics'][0] : null,
|
||||
],
|
||||
$tags
|
||||
];
|
||||
}
|
||||
|
||||
}
|
33
app/Console/Commands/Inspire.php
Normal file
33
app/Console/Commands/Inspire.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Foundation\Inspiring;
|
||||
|
||||
class Inspire extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'inspire';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Display an inspiring quote';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->comment(PHP_EOL.Inspiring::quote().PHP_EOL);
|
||||
}
|
||||
}
|
382
app/Console/Commands/MigrateOldData.php
Normal file
382
app/Console/Commands/MigrateOldData.php
Normal file
|
@ -0,0 +1,382 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Image;
|
||||
use App\ResourceLogItem;
|
||||
use DB;
|
||||
use Exception;
|
||||
use Illuminate\Console\Command;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
|
||||
class MigrateOldData extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'migrate-old-data';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Migrates data from the old pfm site.';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
DB::connection()->disableQueryLog();
|
||||
|
||||
$oldDb = DB::connection('old');
|
||||
|
||||
$this->call('migrate:refresh');
|
||||
|
||||
$oldUsers = $oldDb->table('users')->get();
|
||||
$this->info('Syncing Users');
|
||||
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,
|
||||
'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,
|
||||
'avatar_id' => null
|
||||
]);
|
||||
|
||||
$coverId = null;
|
||||
if (!$user->uses_gravatar) {
|
||||
try {
|
||||
$coverFile = $this->getIdDirectory('users', $user->id) . '/' . $user->id . '_.png';
|
||||
$coverId = Image::upload(new UploadedFile($coverFile,
|
||||
$user->id . '_.png'), $user->id)->id;
|
||||
DB::table('users')->where('id', $user->id)->update(['avatar_id' => $coverId]);
|
||||
} catch (\Exception $e) {
|
||||
$this->error('Could copy user avatar ' . $user->id . ' because ' . $e->getMessage());
|
||||
DB::table('users')->where('id', $user->id)->update(['uses_gravatar' => true]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->info('Syncing Genres');
|
||||
$oldGenres = $oldDb->table('genres')->get();
|
||||
foreach ($oldGenres as $genre) {
|
||||
DB::table('genres')->insert([
|
||||
'id' => $genre->id,
|
||||
'name' => $genre->title,
|
||||
'slug' => $genre->slug
|
||||
]);
|
||||
}
|
||||
|
||||
$this->info('Syncing Albums');
|
||||
$oldAlbums = $oldDb->table('albums')->get();
|
||||
foreach ($oldAlbums as $playlist) {
|
||||
$logViews = $oldDb->table('album_log_views')->whereAlbumId($playlist->id)->get();
|
||||
$logDownload = $oldDb->table('album_log_downloads')->whereAlbumId($playlist->id)->get();
|
||||
|
||||
DB::table('albums')->insert([
|
||||
'title' => $playlist->title,
|
||||
'description' => $playlist->description,
|
||||
'created_at' => $playlist->created_at,
|
||||
'updated_at' => $playlist->updated_at,
|
||||
'deleted_at' => $playlist->deleted_at,
|
||||
'slug' => $playlist->slug,
|
||||
'id' => $playlist->id,
|
||||
'user_id' => $playlist->user_id,
|
||||
'view_count' => 0,
|
||||
'download_count' => 0
|
||||
]);
|
||||
|
||||
foreach ($logViews as $logItem) {
|
||||
try {
|
||||
DB::table('resource_log_items')->insert([
|
||||
'user_id' => $logItem->user_id,
|
||||
'log_type' => ResourceLogItem::VIEW,
|
||||
'album_id' => $logItem->album_id,
|
||||
'created_at' => $logItem->created_at,
|
||||
'ip_address' => $logItem->ip_address,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
$this->error('Could insert log item for album ' . $playlist->id . ' because ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($logDownload as $logItem) {
|
||||
try {
|
||||
DB::table('resource_log_items')->insert([
|
||||
'user_id' => $logItem->user_id,
|
||||
'log_type' => ResourceLogItem::DOWNLOAD,
|
||||
'album_id' => $logItem->album_id,
|
||||
'created_at' => $logItem->created_at,
|
||||
'ip_address' => $logItem->ip_address,
|
||||
'track_format_id' => $logItem->track_file_format_id - 1
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
$this->error('Could insert log item for album ' . $playlist->id . ' because ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->info('Syncing Tracks');
|
||||
$oldTracks = $oldDb->table('tracks')->get();
|
||||
foreach ($oldTracks as $track) {
|
||||
$coverId = null;
|
||||
if ($track->cover) {
|
||||
try {
|
||||
$coverFile = $this->getIdDirectory('tracks',
|
||||
$track->id) . '/' . $track->id . '_' . $track->cover . '.png';
|
||||
$coverId = Image::upload(new UploadedFile($coverFile,
|
||||
$track->id . '_' . $track->cover . '.png'), $track->user_id)->id;
|
||||
} catch (\Exception $e) {
|
||||
$this->error('Could copy track cover ' . $track->id . ' because ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$trackLogViews = $oldDb->table('track_log_views')->whereTrackId($track->id)->get();
|
||||
$trackLogPlays = $oldDb->table('track_log_plays')->whereTrackId($track->id)->get();
|
||||
$trackLogDownload = $oldDb->table('track_log_downloads')->whereTrackId($track->id)->get();
|
||||
|
||||
DB::table('tracks')->insert([
|
||||
'id' => $track->id,
|
||||
'title' => $track->title,
|
||||
'slug' => $track->slug,
|
||||
'description' => $track->description,
|
||||
'lyrics' => $track->lyrics,
|
||||
'created_at' => $track->created_at,
|
||||
'deleted_at' => $track->deleted_at,
|
||||
'updated_at' => $track->updated_at,
|
||||
'released_at' => $track->released_at,
|
||||
'published_at' => $track->published_at,
|
||||
'genre_id' => $track->genre_id,
|
||||
'is_explicit' => $track->explicit,
|
||||
'is_downloadable' => $track->downloadable,
|
||||
'is_vocal' => $track->is_vocal,
|
||||
'track_type_id' => $track->track_type_id,
|
||||
'track_number' => $track->track_number,
|
||||
'user_id' => $track->user_id,
|
||||
'album_id' => $track->album_id,
|
||||
'cover_id' => $coverId,
|
||||
'license_id' => $track->license_id,
|
||||
'duration' => $track->duration,
|
||||
'view_count' => 0,
|
||||
'play_count' => 0,
|
||||
'download_count' => 0
|
||||
]);
|
||||
|
||||
foreach ($trackLogViews as $logItem) {
|
||||
try {
|
||||
DB::table('resource_log_items')->insert([
|
||||
'user_id' => $logItem->user_id,
|
||||
'log_type' => ResourceLogItem::VIEW,
|
||||
'track_id' => $logItem->track_id,
|
||||
'created_at' => $logItem->created_at,
|
||||
'ip_address' => $logItem->ip_address
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
$this->error('Could insert log item for track ' . $track->id . ' because ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($trackLogPlays as $logItem) {
|
||||
try {
|
||||
DB::table('resource_log_items')->insert([
|
||||
'user_id' => $logItem->user_id,
|
||||
'log_type' => ResourceLogItem::PLAY,
|
||||
'track_id' => $logItem->track_id,
|
||||
'created_at' => $logItem->created_at,
|
||||
'ip_address' => $logItem->ip_address
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
$this->error('Could insert log item for track ' . $track->id . ' because ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($trackLogDownload as $logItem) {
|
||||
try {
|
||||
DB::table('resource_log_items')->insert([
|
||||
'user_id' => $logItem->user_id,
|
||||
'log_type' => ResourceLogItem::DOWNLOAD,
|
||||
'track_id' => $logItem->track_id,
|
||||
'created_at' => $logItem->created_at,
|
||||
'ip_address' => $logItem->ip_address,
|
||||
'track_format_id' => $logItem->track_file_format_id - 1
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
$this->error('Could insert log item for track ' . $track->id . ' because ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$oldShowSongs = $oldDb->table('song_track')->get();
|
||||
foreach ($oldShowSongs as $song) {
|
||||
try {
|
||||
DB::table('show_song_track')->insert([
|
||||
'id' => $song->id,
|
||||
'show_song_id' => $song->song_id,
|
||||
'track_id' => $song->track_id
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
$this->error('Could insert show track item for ' . $song->track_id . ' because ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$this->info('Syncing Playlists');
|
||||
$oldPlaylists = $oldDb->table('playlists')->get();
|
||||
foreach ($oldPlaylists as $playlist) {
|
||||
$logViews = $oldDb->table('playlist_log_views')->wherePlaylistId($playlist->id)->get();
|
||||
$logDownload = $oldDb->table('playlist_log_downloads')->wherePlaylistId($playlist->id)->get();
|
||||
|
||||
DB::table('playlists')->insert([
|
||||
'title' => $playlist->title,
|
||||
'description' => $playlist->description,
|
||||
'created_at' => $playlist->created_at,
|
||||
'updated_at' => $playlist->updated_at,
|
||||
'deleted_at' => $playlist->deleted_at,
|
||||
'slug' => $playlist->slug,
|
||||
'id' => $playlist->id,
|
||||
'user_id' => $playlist->user_id,
|
||||
'is_public' => true,
|
||||
'view_count' => 0,
|
||||
'download_count' => 0,
|
||||
]);
|
||||
|
||||
foreach ($logViews as $logItem) {
|
||||
try {
|
||||
DB::table('resource_log_items')->insert([
|
||||
'user_id' => $logItem->user_id,
|
||||
'log_type' => ResourceLogItem::VIEW,
|
||||
'playlist_id' => $logItem->playlist_id,
|
||||
'created_at' => $logItem->created_at,
|
||||
'ip_address' => $logItem->ip_address,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
$this->error('Could insert log item for playlist ' . $playlist->id . ' because ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($logDownload as $logItem) {
|
||||
try {
|
||||
DB::table('resource_log_items')->insert([
|
||||
'user_id' => $logItem->user_id,
|
||||
'log_type' => ResourceLogItem::DOWNLOAD,
|
||||
'playlist_id' => $logItem->playlist_id,
|
||||
'created_at' => $logItem->created_at,
|
||||
'ip_address' => $logItem->ip_address,
|
||||
'track_format_id' => $logItem->track_file_format_id - 1
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
$this->error('Could insert log item for playlist ' . $playlist->id . ' because ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->info('Syncing Playlist Tracks');
|
||||
$oldPlaylistTracks = $oldDb->table('playlist_track')->get();
|
||||
foreach ($oldPlaylistTracks as $playlistTrack) {
|
||||
DB::table('playlist_track')->insert([
|
||||
'id' => $playlistTrack->id,
|
||||
'created_at' => $playlistTrack->created_at,
|
||||
'updated_at' => $playlistTrack->updated_at,
|
||||
'position' => $playlistTrack->position,
|
||||
'playlist_id' => $playlistTrack->playlist_id,
|
||||
'track_id' => $playlistTrack->track_id
|
||||
]);
|
||||
}
|
||||
|
||||
$this->info('Syncing Comments');
|
||||
$oldComments = $oldDb->table('comments')->get();
|
||||
foreach ($oldComments as $comment) {
|
||||
try {
|
||||
DB::table('comments')->insert([
|
||||
'id' => $comment->id,
|
||||
'user_id' => $comment->user_id,
|
||||
'created_at' => $comment->created_at,
|
||||
'deleted_at' => $comment->deleted_at,
|
||||
'updated_at' => $comment->updated_at,
|
||||
'content' => $comment->content,
|
||||
'track_id' => $comment->track_id,
|
||||
'album_id' => $comment->album_id,
|
||||
'playlist_id' => $comment->playlist_id,
|
||||
'profile_id' => $comment->profile_id
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
$this->error('Could not sync comment ' . $comment->id . ' because ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$this->info('Syncing Favourites');
|
||||
$oldFavs = $oldDb->table('favourites')->get();
|
||||
foreach ($oldFavs as $fav) {
|
||||
try {
|
||||
DB::table('favourites')->insert([
|
||||
'id' => $fav->id,
|
||||
'user_id' => $fav->user_id,
|
||||
'created_at' => $fav->created_at,
|
||||
'track_id' => $fav->track_id,
|
||||
'album_id' => $fav->album_id,
|
||||
'playlist_id' => $fav->playlist_id,
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
$this->error('Could not sync favourite ' . $fav->id . ' because ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$this->info('Syncing Followers');
|
||||
$oldFollowers = $oldDb->table('user_follower')->get();
|
||||
foreach ($oldFollowers as $follower) {
|
||||
try {
|
||||
DB::table('followers')->insert([
|
||||
'id' => $follower->id,
|
||||
'user_id' => $follower->follower_id,
|
||||
'artist_id' => $follower->user_id,
|
||||
'created_at' => $follower->created_at,
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
$this->error('Could not sync follower ' . $follower->id . ' because ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getIdDirectory($type, $id)
|
||||
{
|
||||
$dir = (string)(floor($id / 100) * 100);
|
||||
|
||||
return \Config::get('ponyfm.files_directory') . '/' . $type . '/' . $dir;
|
||||
}
|
||||
|
||||
}
|
53
app/Console/Commands/RebuildTags.php
Normal file
53
app/Console/Commands/RebuildTags.php
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Track;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class RebuildTags extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'rebuild:tags
|
||||
{trackId? : ID of the track to rebuild tags for}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Rewrites tags in track files, ensuring they\'re up to date.';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if ($this->argument('trackId')) {
|
||||
$track = Track::findOrFail($this->argument('trackId'));
|
||||
$tracks = [$track];
|
||||
} else {
|
||||
$tracks = Track::whereNotNull('published_at')->get();
|
||||
}
|
||||
|
||||
foreach($tracks as $track) {
|
||||
$this->comment('Rewriting tags for track #'.$track->id.'...');
|
||||
$track->updateTags();
|
||||
}
|
||||
}
|
||||
}
|
232
app/Console/Commands/RefreshCache.php
Normal file
232
app/Console/Commands/RefreshCache.php
Normal file
|
@ -0,0 +1,232 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\ResourceLogItem;
|
||||
use DB;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class RefreshCache extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'refresh-cache';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Refreshes cache tables for views and downloads';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
DB::connection()->disableQueryLog();
|
||||
|
||||
DB::table('tracks')->update(['comment_count' => DB::raw('(SELECT COUNT(id) FROM comments WHERE comments.track_id = tracks.id AND deleted_at IS NULL)')]);
|
||||
|
||||
DB::table('albums')->update([
|
||||
'comment_count' => DB::raw('(SELECT COUNT(id) FROM comments WHERE comments.album_id = albums.id AND deleted_at IS NULL)'),
|
||||
'track_count' => DB::raw('(SELECT COUNT(id) FROM tracks WHERE album_id = albums.id)')
|
||||
]);
|
||||
|
||||
DB::table('playlists')->update([
|
||||
'comment_count' => DB::raw('(SELECT COUNT(id) FROM comments WHERE comments.playlist_id = playlists.id AND deleted_at IS NULL)'),
|
||||
'track_count' => DB::raw('(SELECT COUNT(id) FROM playlist_track WHERE playlist_id = playlists.id)')
|
||||
]);
|
||||
|
||||
DB::table('users')->update([
|
||||
'comment_count' => DB::raw('(SELECT COUNT(id) FROM comments WHERE comments.profile_id = users.id AND deleted_at IS NULL)'),
|
||||
'track_count' => DB::raw('(SELECT COUNT(id) FROM tracks WHERE deleted_at IS NULL AND published_at IS NOT NULL AND user_id = users.id)')
|
||||
]);
|
||||
|
||||
$users = DB::table('users')->get();
|
||||
$cacheItems = [];
|
||||
$resources = [
|
||||
'album' => [],
|
||||
'playlist' => [],
|
||||
'track' => []
|
||||
];
|
||||
|
||||
foreach ($users as $user) {
|
||||
$cacheItems[$user->id] = [
|
||||
'album' => [],
|
||||
'playlist' => [],
|
||||
'track' => [],
|
||||
];
|
||||
}
|
||||
|
||||
$logItems = DB::table('resource_log_items')->get();
|
||||
foreach ($logItems as $item) {
|
||||
$type = '';
|
||||
$id = 0;
|
||||
|
||||
if ($item->album_id) {
|
||||
$type = 'album';
|
||||
$id = $item->album_id;
|
||||
} else {
|
||||
if ($item->playlist_id) {
|
||||
$type = 'playlist';
|
||||
$id = $item->playlist_id;
|
||||
} else {
|
||||
if ($item->track_id) {
|
||||
$type = 'track';
|
||||
$id = $item->track_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$resource = $this->getCacheItem($resources, $type, $id);
|
||||
|
||||
if ($item->user_id != null) {
|
||||
$userResource = $this->getUserCacheItem($cacheItems, $item->user_id, $type, $id);
|
||||
|
||||
if ($item->log_type == ResourceLogItem::DOWNLOAD) {
|
||||
$userResource['download_count']++;
|
||||
} else {
|
||||
if ($item->log_type == ResourceLogItem::VIEW) {
|
||||
$userResource['view_count']++;
|
||||
} else {
|
||||
if ($item->log_type == ResourceLogItem::PLAY) {
|
||||
$userResource['play_count']++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$cacheItems[$item->user_id][$type][$id] = $userResource;
|
||||
}
|
||||
|
||||
if ($item->log_type == ResourceLogItem::DOWNLOAD) {
|
||||
$resource['download_count']++;
|
||||
} else {
|
||||
if ($item->log_type == ResourceLogItem::VIEW) {
|
||||
$resource['view_count']++;
|
||||
} else {
|
||||
if ($item->log_type == ResourceLogItem::PLAY) {
|
||||
$resource['play_count']++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$resources[$type][$id] = $resource;
|
||||
}
|
||||
|
||||
$pins = DB::table('pinned_playlists')->get();
|
||||
foreach ($pins as $pin) {
|
||||
$userResource = $this->getUserCacheItem($cacheItems, $pin->user_id, 'playlist', $pin->playlist_id);
|
||||
$userResource['is_pinned'] = true;
|
||||
$cacheItems[$pin->user_id]['playlist'][$pin->playlist_id] = $userResource;
|
||||
}
|
||||
|
||||
$favs = DB::table('favourites')->get();
|
||||
foreach ($favs as $fav) {
|
||||
$type = '';
|
||||
$id = 0;
|
||||
|
||||
if ($fav->album_id) {
|
||||
$type = 'album';
|
||||
$id = $fav->album_id;
|
||||
} else {
|
||||
if ($fav->playlist_id) {
|
||||
$type = 'playlist';
|
||||
$id = $fav->playlist_id;
|
||||
} else {
|
||||
if ($fav->track_id) {
|
||||
$type = 'track';
|
||||
$id = $fav->track_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$userResource = $this->getUserCacheItem($cacheItems, $fav->user_id, $type, $id);
|
||||
$userResource['is_favourited'] = true;
|
||||
$cacheItems[$fav->user_id][$type][$id] = $userResource;
|
||||
|
||||
$resource = $this->getCacheItem($resources, $type, $id);
|
||||
$resource['favourite_count']++;
|
||||
$resources[$type][$id] = $resource;
|
||||
}
|
||||
|
||||
foreach (DB::table('followers')->get() as $follower) {
|
||||
$userResource = $this->getUserCacheItem($cacheItems, $follower->user_id, 'artist', $follower->artist_id);
|
||||
$userResource['is_followed'] = true;
|
||||
$cacheItems[$follower->user_id]['artist'][$follower->artist_id] = $userResource;
|
||||
}
|
||||
|
||||
foreach ($resources as $name => $resourceArray) {
|
||||
foreach ($resourceArray as $id => $resource) {
|
||||
DB::table($name . 's')->whereId($id)->update($resource);
|
||||
}
|
||||
}
|
||||
|
||||
DB::table('resource_users')->delete();
|
||||
foreach ($cacheItems as $cacheItem) {
|
||||
foreach ($cacheItem as $resources) {
|
||||
foreach ($resources as $resource) {
|
||||
DB::table('resource_users')->insert($resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getCacheItem(&$resources, $type, $id)
|
||||
{
|
||||
if (!isset($resources[$type][$id])) {
|
||||
$item = [
|
||||
'view_count' => 0,
|
||||
'download_count' => 0,
|
||||
'favourite_count' => 0,
|
||||
];
|
||||
|
||||
if ($type == 'track') {
|
||||
$item['play_count'] = 0;
|
||||
}
|
||||
|
||||
$resources[$type][$id] = $item;
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
return $resources[$type][$id];
|
||||
}
|
||||
|
||||
private function getUserCacheItem(&$items, $userId, $type, $id)
|
||||
{
|
||||
if (!isset($items[$userId][$type][$id])) {
|
||||
$item = [
|
||||
'is_followed' => false,
|
||||
'is_favourited' => false,
|
||||
'is_pinned' => false,
|
||||
'view_count' => 0,
|
||||
'play_count' => 0,
|
||||
'download_count' => 0,
|
||||
'user_id' => $userId
|
||||
];
|
||||
|
||||
$item[$type . '_id'] = $id;
|
||||
|
||||
$items[$userId][$type][$id] = $item;
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
return $items[$userId][$type][$id];
|
||||
}
|
||||
}
|
32
app/Console/Kernel.php
Normal file
32
app/Console/Kernel.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console;
|
||||
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
|
||||
class Kernel extends ConsoleKernel
|
||||
{
|
||||
/**
|
||||
* The Artisan commands provided by your application.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $commands = [
|
||||
\App\Console\Commands\MigrateOldData::class,
|
||||
\App\Console\Commands\RefreshCache::class,
|
||||
\App\Console\Commands\ImportMLPMA::class,
|
||||
\App\Console\Commands\ClassifyMLPMA::class,
|
||||
\App\Console\Commands\RebuildTags::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Define the application's command schedule.
|
||||
*
|
||||
* @param \Illuminate\Console\Scheduling\Schedule $schedule
|
||||
* @return void
|
||||
*/
|
||||
protected function schedule(Schedule $schedule)
|
||||
{
|
||||
}
|
||||
}
|
8
app/Events/Event.php
Normal file
8
app/Events/Event.php
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
abstract class Event
|
||||
{
|
||||
//
|
||||
}
|
44
app/Exceptions/Handler.php
Normal file
44
app/Exceptions/Handler.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
|
||||
|
||||
class Handler extends ExceptionHandler
|
||||
{
|
||||
/**
|
||||
* A list of the exception types that should not be reported.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $dontReport = [
|
||||
HttpException::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* Report or log an exception.
|
||||
*
|
||||
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
|
||||
*
|
||||
* @param \Exception $e
|
||||
* @return void
|
||||
*/
|
||||
public function report(Exception $e)
|
||||
{
|
||||
return parent::report($e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an exception into an HTTP response.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Exception $e
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function render($request, Exception $e)
|
||||
{
|
||||
return parent::render($request, $e);
|
||||
}
|
||||
}
|
65
app/Favourite.php
Normal file
65
app/Favourite.php
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Favourite extends Model
|
||||
{
|
||||
protected $table = 'favourites';
|
||||
public $timestamps = false;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Relationships
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('App\User');
|
||||
}
|
||||
|
||||
public function track()
|
||||
{
|
||||
return $this->belongsTo('App\Track');
|
||||
}
|
||||
|
||||
public function album()
|
||||
{
|
||||
return $this->belongsTo('App\Album');
|
||||
}
|
||||
|
||||
public function playlist()
|
||||
{
|
||||
return $this->belongsTo('App\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);
|
||||
}
|
||||
}
|
12
app/Follower.php
Normal file
12
app/Follower.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Follower extends Model
|
||||
{
|
||||
protected $table = 'followers';
|
||||
|
||||
public $timestamps = false;
|
||||
}
|
15
app/Genre.php
Normal file
15
app/Genre.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use App\Traits\SlugTrait;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Genre extends Model
|
||||
{
|
||||
protected $table = 'genres';
|
||||
protected $fillable = ['name', 'slug'];
|
||||
public $timestamps = false;
|
||||
|
||||
use SlugTrait;
|
||||
}
|
20
app/Http/Controllers/AccountController.php
Normal file
20
app/Http/Controllers/AccountController.php
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
use View;
|
||||
|
||||
class AccountController extends Controller
|
||||
{
|
||||
public function getIndex()
|
||||
{
|
||||
return View::make('shared.null');
|
||||
}
|
||||
|
||||
public function getRegister()
|
||||
{
|
||||
return Redirect::to(Config::get('poniverse.urls')['register']);
|
||||
}
|
||||
}
|
70
app/Http/Controllers/AlbumsController.php
Normal file
70
app/Http/Controllers/AlbumsController.php
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use AlbumDownloader;
|
||||
use App;
|
||||
use App\Album;
|
||||
use App\ResourceLogItem;
|
||||
use App\Track;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
use View;
|
||||
|
||||
class AlbumsController extends Controller
|
||||
{
|
||||
public function getIndex()
|
||||
{
|
||||
return View::make('albums.index');
|
||||
}
|
||||
|
||||
public function getShow($id, $slug)
|
||||
{
|
||||
$album = Album::find($id);
|
||||
if (!$album) {
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
if ($album->slug != $slug) {
|
||||
return Redirect::action('AlbumsController@getAlbum', [$id, $album->slug]);
|
||||
}
|
||||
|
||||
return View::make('albums.show');
|
||||
}
|
||||
|
||||
public function getShortlink($id)
|
||||
{
|
||||
$album = Album::find($id);
|
||||
if (!$album) {
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
return Redirect::action('AlbumsController@getTrack', [$id, $album->slug]);
|
||||
}
|
||||
|
||||
public function getDownload($id, $extension)
|
||||
{
|
||||
$album = Album::with('tracks', 'user')->find($id);
|
||||
if (!$album) {
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
$format = null;
|
||||
$formatName = null;
|
||||
|
||||
foreach (Track::$Formats as $name => $item) {
|
||||
if ($item['extension'] == $extension) {
|
||||
$format = $item;
|
||||
$formatName = $name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($format == null) {
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
ResourceLogItem::logItem('album', $id, ResourceLogItem::DOWNLOAD, $format['index']);
|
||||
$downloader = new AlbumDownloader($album, $formatName);
|
||||
$downloader->download();
|
||||
}
|
||||
}
|
|
@ -1,6 +1,10 @@
|
|||
<?php namespace Api\Mobile;
|
||||
<?php
|
||||
|
||||
use Entities\Track;
|
||||
namespace App\Http\Controllers\Api\Mobile;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Track;
|
||||
use Response;
|
||||
|
||||
class TracksController extends Controller
|
||||
{
|
88
app/Http/Controllers/Api/V1/TracksController.php
Normal file
88
app/Http/Controllers/Api/V1/TracksController.php
Normal file
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\V1;
|
||||
|
||||
use App\Image;
|
||||
use App\Track;
|
||||
use Cover;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
|
||||
class TracksController extends \ApiControllerBase
|
||||
{
|
||||
public function getTrackRadioDetails($hash)
|
||||
{
|
||||
$track = Track
|
||||
::with('user', 'album', 'user.avatar', 'cover', 'comments', 'genre')
|
||||
->published()
|
||||
->whereHash($hash)->first();
|
||||
|
||||
if (!$track) {
|
||||
return Response::json(['message' => 'Track not found.'], 403);
|
||||
}
|
||||
|
||||
$comments = [];
|
||||
foreach ($track->comments as $comment) {
|
||||
$comments[] = [
|
||||
'id' => $comment->id,
|
||||
'created_at' => $comment->created_at,
|
||||
'content' => $comment->content,
|
||||
'user' => [
|
||||
'name' => $comment->user->display_name,
|
||||
'id' => $comment->user->id,
|
||||
'url' => $comment->user->url,
|
||||
'avatars' => [
|
||||
'normal' => $comment->user->getAvatarUrl(Image::NORMAL),
|
||||
'thumbnail' => $comment->user->getAvatarUrl(Image::THUMBNAIL),
|
||||
'small' => $comment->user->getAvatarUrl(Image::SMALL),
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
return Response::json([
|
||||
'id' => $track->id,
|
||||
'title' => $track->title,
|
||||
'description' => $track->description,
|
||||
'lyrics' => $track->lyrics,
|
||||
'user' => [
|
||||
'id' => $track->user->id,
|
||||
'name' => $track->user->display_name,
|
||||
'url' => $track->user->url,
|
||||
'avatars' => [
|
||||
'thumbnail' => $track->user->getAvatarUrl(Image::THUMBNAIL),
|
||||
'small' => $track->user->getAvatarUrl(Image::SMALL),
|
||||
'normal' => $track->user->getAvatarUrl(Image::NORMAL)
|
||||
]
|
||||
],
|
||||
'stats' => [
|
||||
'views' => $track->view_count,
|
||||
'plays' => $track->play_count,
|
||||
'downloads' => $track->download_count,
|
||||
'comments' => $track->comment_count,
|
||||
'favourites' => $track->favourite_count
|
||||
],
|
||||
'url' => $track->url,
|
||||
'is_vocal' => !!$track->is_vocal,
|
||||
'is_explicit' => !!$track->is_explicit,
|
||||
'is_downloadable' => !!$track->is_downloadable,
|
||||
'published_at' => $track->published_at,
|
||||
'duration' => $track->duration,
|
||||
'genre' => $track->genre != null
|
||||
?
|
||||
[
|
||||
'id' => $track->genre->id,
|
||||
'name' => $track->genre->name
|
||||
] : null,
|
||||
'type' => [
|
||||
'id' => $track->track_type->id,
|
||||
'name' => $track->track_type->title
|
||||
],
|
||||
'covers' => [
|
||||
'thumbnail' => $track->getCoverUrl(Image::THUMBNAIL),
|
||||
'small' => $track->getCoverUrl(Image::SMALL),
|
||||
'normal' => $track->getCoverUrl(Image::NORMAL)
|
||||
],
|
||||
'comments' => $comments
|
||||
], 200);
|
||||
}
|
||||
}
|
34
app/Http/Controllers/Api/Web/AccountController.php
Normal file
34
app/Http/Controllers/Api/Web/AccountController.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Web;
|
||||
|
||||
use App\Http\Controllers\ApiControllerBase;
|
||||
use App\Commands\SaveAccountSettingsCommand;
|
||||
use Cover;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
|
||||
class AccountController extends ApiControllerBase
|
||||
{
|
||||
public function getSettings()
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
return Response::json([
|
||||
'bio' => $user->bio,
|
||||
'can_see_explicit_content' => $user->can_see_explicit_content == 1,
|
||||
'display_name' => $user->display_name,
|
||||
'sync_names' => $user->sync_names == 1,
|
||||
'mlpforums_name' => $user->mlpforums_name,
|
||||
'gravatar' => $user->gravatar ? $user->gravatar : $user->email,
|
||||
'avatar_url' => !$user->uses_gravatar ? $user->getAvatarUrl() : null,
|
||||
'uses_gravatar' => $user->uses_gravatar == 1
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function postSave()
|
||||
{
|
||||
return $this->execute(new SaveAccountSettingsCommand(Input::all()));
|
||||
}
|
||||
}
|
147
app/Http/Controllers/Api/Web/AlbumsController.php
Normal file
147
app/Http/Controllers/Api/Web/AlbumsController.php
Normal file
|
@ -0,0 +1,147 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Web;
|
||||
|
||||
use App\Album;
|
||||
use App\Commands\CreateAlbumCommand;
|
||||
use App\Commands\DeleteAlbumCommand;
|
||||
use App\Commands\EditAlbumCommand;
|
||||
use App\Http\Controllers\ApiControllerBase;
|
||||
use App\Image;
|
||||
use App\ResourceLogItem;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
|
||||
class AlbumsController extends ApiControllerBase
|
||||
{
|
||||
public function postCreate()
|
||||
{
|
||||
return $this->execute(new CreateAlbumCommand(Input::all()));
|
||||
}
|
||||
|
||||
public function postEdit($id)
|
||||
{
|
||||
return $this->execute(new EditAlbumCommand($id, Input::all()));
|
||||
}
|
||||
|
||||
public function postDelete($id)
|
||||
{
|
||||
return $this->execute(new DeleteAlbumCommand($id));
|
||||
}
|
||||
|
||||
public function getShow($id)
|
||||
{
|
||||
$album = Album::with([
|
||||
'tracks' => function ($query) {
|
||||
$query->userDetails();
|
||||
},
|
||||
'tracks.cover',
|
||||
'tracks.genre',
|
||||
'tracks.user',
|
||||
'user',
|
||||
'comments',
|
||||
'comments.user'
|
||||
])
|
||||
->userDetails()
|
||||
->find($id);
|
||||
|
||||
if (!$album) {
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
if (Input::get('log')) {
|
||||
ResourceLogItem::logItem('album', $id, ResourceLogItem::VIEW);
|
||||
$album->view_count++;
|
||||
}
|
||||
|
||||
$returned_album = Album::mapPublicAlbumShow($album);
|
||||
if ($returned_album['is_downloadable'] == 0) {
|
||||
unset($returned_album['formats']);
|
||||
}
|
||||
|
||||
return Response::json([
|
||||
'album' => $returned_album
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function getIndex()
|
||||
{
|
||||
$page = 1;
|
||||
if (Input::has('page')) {
|
||||
$page = Input::get('page');
|
||||
}
|
||||
|
||||
$query = Album::summary()
|
||||
->with('user', 'user.avatar', 'cover')
|
||||
->userDetails()
|
||||
->orderBy('created_at', 'desc')
|
||||
->where('track_count', '>', 0);
|
||||
|
||||
$count = $query->count();
|
||||
$perPage = 40;
|
||||
|
||||
$query->skip(($page - 1) * $perPage)->take($perPage);
|
||||
$albums = [];
|
||||
|
||||
foreach ($query->get() as $album) {
|
||||
$albums[] = Album::mapPublicAlbumSummary($album);
|
||||
}
|
||||
|
||||
return Response::json(["albums" => $albums, "current_page" => $page, "total_pages" => ceil($count / $perPage)],
|
||||
200);
|
||||
}
|
||||
|
||||
public function getOwned()
|
||||
{
|
||||
$query = Album::summary()->where('user_id', \Auth::user()->id)->orderBy('created_at', 'desc')->get();
|
||||
$albums = [];
|
||||
foreach ($query as $album) {
|
||||
$albums[] = [
|
||||
'id' => $album->id,
|
||||
'title' => $album->title,
|
||||
'slug' => $album->slug,
|
||||
'created_at' => $album->created_at,
|
||||
'covers' => [
|
||||
'small' => $album->getCoverUrl(Image::SMALL),
|
||||
'normal' => $album->getCoverUrl(Image::NORMAL)
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
return Response::json($albums, 200);
|
||||
}
|
||||
|
||||
public function getEdit($id)
|
||||
{
|
||||
$album = Album::with('tracks')->find($id);
|
||||
if (!$album) {
|
||||
return $this->notFound('Album ' . $id . ' not found!');
|
||||
}
|
||||
|
||||
if ($album->user_id != Auth::user()->id) {
|
||||
return $this->notAuthorized();
|
||||
}
|
||||
|
||||
$tracks = [];
|
||||
foreach ($album->tracks as $track) {
|
||||
$tracks[] = [
|
||||
'id' => $track->id,
|
||||
'title' => $track->title
|
||||
];
|
||||
}
|
||||
|
||||
return Response::json([
|
||||
'id' => $album->id,
|
||||
'title' => $album->title,
|
||||
'user_id' => $album->user_id,
|
||||
'slug' => $album->slug,
|
||||
'created_at' => $album->created_at,
|
||||
'published_at' => $album->published_at,
|
||||
'description' => $album->description,
|
||||
'cover_url' => $album->hasCover() ? $album->getCoverUrl(Image::NORMAL) : null,
|
||||
'real_cover_url' => $album->getCoverUrl(Image::NORMAL),
|
||||
'tracks' => $tracks
|
||||
], 200);
|
||||
}
|
||||
}
|
197
app/Http/Controllers/Api/Web/ArtistsController.php
Normal file
197
app/Http/Controllers/Api/Web/ArtistsController.php
Normal file
|
@ -0,0 +1,197 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Web;
|
||||
|
||||
use App\Album;
|
||||
use App\Comment;
|
||||
use App\Favourite;
|
||||
use App\Http\Controllers\ApiControllerBase;
|
||||
use App\Image;
|
||||
use App\Track;
|
||||
use App\User;
|
||||
use Cover;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
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.genre',
|
||||
'track.cover',
|
||||
'track.user',
|
||||
'album.cover',
|
||||
'album.user',
|
||||
'track' => function ($query) {
|
||||
$query->userDetails();
|
||||
},
|
||||
'album' => function ($query) {
|
||||
$query->userDetails();
|
||||
}
|
||||
])->get();
|
||||
|
||||
$tracks = [];
|
||||
$albums = [];
|
||||
|
||||
foreach ($favs as $fav) {
|
||||
if ($fav->type == 'App\Track') {
|
||||
$tracks[] = Track::mapPublicTrackSummary($fav->track);
|
||||
} else {
|
||||
if ($fav->type == 'App\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) {
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
$query = Track::summary()->published()->listed()->explicitFilter()->with('genre', 'cover',
|
||||
'user')->userDetails()->whereUserId($user->id)->whereNotNull('published_at');
|
||||
$tracks = [];
|
||||
$singles = [];
|
||||
|
||||
foreach ($query->get() as $track) {
|
||||
if ($track->album_id != null) {
|
||||
$tracks[] = Track::mapPublicTrackSummary($track);
|
||||
} else {
|
||||
$singles[] = Track::mapPublicTrackSummary($track);
|
||||
}
|
||||
}
|
||||
|
||||
$query = Album::summary()
|
||||
->with('user')
|
||||
->orderBy('created_at', 'desc')
|
||||
->where('track_count', '>', 0)
|
||||
->whereUserId($user->id);
|
||||
|
||||
$albums = [];
|
||||
|
||||
foreach ($query->get() as $album) {
|
||||
$albums[] = Album::mapPublicAlbumSummary($album);
|
||||
}
|
||||
|
||||
return Response::json(['singles' => $singles, 'albumTracks' => $tracks, 'albums' => $albums], 200);
|
||||
}
|
||||
|
||||
public function getShow($slug)
|
||||
{
|
||||
$user = User::whereSlug($slug)
|
||||
->userDetails()
|
||||
->with([
|
||||
'comments' => function ($query) {
|
||||
$query->with('user');
|
||||
}
|
||||
])
|
||||
->first();
|
||||
if (!$user) {
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
$trackQuery = Track::summary()
|
||||
->published()
|
||||
->explicitFilter()
|
||||
->listed()
|
||||
->with('genre', 'cover', 'user')
|
||||
->userDetails()
|
||||
->whereUserId($user->id)
|
||||
->whereNotNull('published_at')
|
||||
->orderBy('created_at', 'desc')
|
||||
->take(20);
|
||||
|
||||
$latestTracks = [];
|
||||
foreach ($trackQuery->get() as $track) {
|
||||
$latestTracks[] = Track::mapPublicTrackSummary($track);
|
||||
}
|
||||
|
||||
$comments = [];
|
||||
foreach ($user->comments as $comment) {
|
||||
$comments[] = Comment::mapPublic($comment);
|
||||
}
|
||||
|
||||
$userData = [
|
||||
'is_following' => false
|
||||
];
|
||||
|
||||
if ($user->users->count()) {
|
||||
$userRow = $user->users[0];
|
||||
$userData = [
|
||||
'is_following' => (bool)$userRow->is_followed
|
||||
];
|
||||
}
|
||||
|
||||
return Response::json([
|
||||
'artist' => [
|
||||
'id' => (int)$user->id,
|
||||
'name' => $user->display_name,
|
||||
'slug' => $user->slug,
|
||||
'is_archived' => (bool)$user->is_archived,
|
||||
'avatars' => [
|
||||
'small' => $user->getAvatarUrl(Image::SMALL),
|
||||
'normal' => $user->getAvatarUrl(Image::NORMAL)
|
||||
],
|
||||
'created_at' => $user->created_at,
|
||||
'followers' => [],
|
||||
'following' => [],
|
||||
'latest_tracks' => $latestTracks,
|
||||
'comments' => $comments,
|
||||
'bio' => $user->bio,
|
||||
'mlpforums_username' => $user->mlpforums_name,
|
||||
'message_url' => $user->message_url,
|
||||
'user_data' => $userData
|
||||
]
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function getIndex()
|
||||
{
|
||||
$page = 1;
|
||||
if (Input::has('page')) {
|
||||
$page = Input::get('page');
|
||||
}
|
||||
|
||||
$query = User::orderBy('created_at', 'desc')
|
||||
->where('track_count', '>', 0);
|
||||
|
||||
$count = $query->count();
|
||||
$perPage = 40;
|
||||
|
||||
$query->skip(($page - 1) * $perPage)->take($perPage);
|
||||
$users = [];
|
||||
|
||||
foreach ($query->get() as $user) {
|
||||
$users[] = [
|
||||
'id' => $user->id,
|
||||
'name' => $user->display_name,
|
||||
'slug' => $user->slug,
|
||||
'url' => $user->url,
|
||||
'is_archived' => $user->is_archived,
|
||||
'avatars' => [
|
||||
'small' => $user->getAvatarUrl(Image::SMALL),
|
||||
'normal' => $user->getAvatarUrl(Image::NORMAL)
|
||||
],
|
||||
'created_at' => $user->created_at
|
||||
];
|
||||
}
|
||||
|
||||
return Response::json(["artists" => $users, "current_page" => $page, "total_pages" => ceil($count / $perPage)],
|
||||
200);
|
||||
}
|
||||
}
|
13
app/Http/Controllers/Api/Web/AuthController.php
Normal file
13
app/Http/Controllers/Api/Web/AuthController.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Web;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
public function postLogout()
|
||||
{
|
||||
\Auth::logout();
|
||||
}
|
||||
}
|
50
app/Http/Controllers/Api/Web/CommentsController.php
Normal file
50
app/Http/Controllers/Api/Web/CommentsController.php
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Web;
|
||||
|
||||
use App;
|
||||
use App\Commands\CreateCommentCommand;
|
||||
use App\Comment;
|
||||
use App\Http\Controllers\ApiControllerBase;
|
||||
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)]);
|
||||
}
|
||||
}
|
47
app/Http/Controllers/Api/Web/DashboardController.php
Normal file
47
app/Http/Controllers/Api/Web/DashboardController.php
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Web;
|
||||
|
||||
use App\Http\Controllers\ApiControllerBase;
|
||||
use App\News;
|
||||
use App\Track;
|
||||
use Cover;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
|
||||
class DashboardController extends ApiControllerBase
|
||||
{
|
||||
public function getIndex()
|
||||
{
|
||||
$recentQuery = Track::summary()
|
||||
->with(['genre', 'user', 'cover', 'user.avatar'])
|
||||
->whereIsLatest(true)
|
||||
->listed()
|
||||
->userDetails()
|
||||
->explicitFilter()
|
||||
->published()
|
||||
->orderBy('published_at', 'desc')
|
||||
->take(30);
|
||||
|
||||
$recentTracks = [];
|
||||
|
||||
foreach ($recentQuery->get() as $track) {
|
||||
$recentTracks[] = Track::mapPublicTrackSummary($track);
|
||||
}
|
||||
|
||||
return Response::json([
|
||||
'recent_tracks' => $recentTracks,
|
||||
'popular_tracks' => Track::popular(30, Auth::check() && Auth::user()->can_see_explicit_content),
|
||||
'news' => News::getNews(0, 10)
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function postReadNews()
|
||||
{
|
||||
News::markPostAsRead(Input::get('url'));
|
||||
|
||||
return Response::json([
|
||||
]);
|
||||
}
|
||||
}
|
110
app/Http/Controllers/Api/Web/FavouritesController.php
Normal file
110
app/Http/Controllers/Api/Web/FavouritesController.php
Normal file
|
@ -0,0 +1,110 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Web;
|
||||
|
||||
use App\Album;
|
||||
use App\Commands\ToggleFavouriteCommand;
|
||||
use App\Favourite;
|
||||
use App\Http\Controllers\ApiControllerBase;
|
||||
use App\Playlist;
|
||||
use App\Track;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
|
||||
class FavouritesController extends ApiControllerBase
|
||||
{
|
||||
public function postToggle()
|
||||
{
|
||||
return $this->execute(new ToggleFavouriteCommand(Input::get('type'), Input::get('id')));
|
||||
}
|
||||
|
||||
public function getTracks()
|
||||
{
|
||||
$query = Favourite
|
||||
::whereUserId(Auth::user()->id)
|
||||
->whereNotNull('track_id')
|
||||
->with([
|
||||
'track' => function ($query) {
|
||||
$query
|
||||
->userDetails()
|
||||
->published();
|
||||
},
|
||||
'track.user',
|
||||
'track.genre',
|
||||
'track.cover',
|
||||
'track.album',
|
||||
'track.album.user'
|
||||
]);
|
||||
|
||||
$tracks = [];
|
||||
|
||||
foreach ($query->get() as $fav) {
|
||||
if ($fav->track == null) // deleted track
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$tracks[] = Track::mapPublicTrackSummary($fav->track);
|
||||
}
|
||||
|
||||
return Response::json(["tracks" => $tracks], 200);
|
||||
}
|
||||
|
||||
public function getAlbums()
|
||||
{
|
||||
$query = Favourite
|
||||
::whereUserId(Auth::user()->id)
|
||||
->whereNotNull('album_id')
|
||||
->with([
|
||||
'album' => function ($query) {
|
||||
$query->userDetails();
|
||||
},
|
||||
'album.user',
|
||||
'album.user.avatar',
|
||||
'album.cover'
|
||||
]);
|
||||
|
||||
$albums = [];
|
||||
|
||||
foreach ($query->get() as $fav) {
|
||||
if ($fav->album == null) // deleted album
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$albums[] = Album::mapPublicAlbumSummary($fav->album);
|
||||
}
|
||||
|
||||
return Response::json(["albums" => $albums], 200);
|
||||
}
|
||||
|
||||
public function getPlaylists()
|
||||
{
|
||||
$query = Favourite
|
||||
::whereUserId(Auth::user()->id)
|
||||
->whereNotNull('playlist_id')
|
||||
->with([
|
||||
'playlist' => function ($query) {
|
||||
$query->userDetails();
|
||||
},
|
||||
'playlist.user',
|
||||
'playlist.user.avatar',
|
||||
'playlist.tracks',
|
||||
'playlist.tracks.cover'
|
||||
]);
|
||||
|
||||
$playlists = [];
|
||||
|
||||
foreach ($query->get() as $fav) {
|
||||
if ($fav->playlist == null) // deleted playlist
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$playlists[] = Playlist::mapPublicPlaylistSummary($fav->playlist);
|
||||
}
|
||||
|
||||
return Response::json(["playlists" => $playlists], 200);
|
||||
}
|
||||
}
|
15
app/Http/Controllers/Api/Web/FollowController.php
Normal file
15
app/Http/Controllers/Api/Web/FollowController.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Web;
|
||||
|
||||
use App\Commands\ToggleFollowingCommand;
|
||||
use App\Http\Controllers\ApiControllerBase;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
|
||||
class FollowController extends ApiControllerBase
|
||||
{
|
||||
public function postToggle()
|
||||
{
|
||||
return $this->execute(new ToggleFollowingCommand(Input::get('type'), Input::get('id')));
|
||||
}
|
||||
}
|
31
app/Http/Controllers/Api/Web/ImagesController.php
Normal file
31
app/Http/Controllers/Api/Web/ImagesController.php
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Web;
|
||||
|
||||
use App\Http\Controllers\ApiControllerBase;
|
||||
use App\Image;
|
||||
use Cover;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
|
||||
class ImagesController extends ApiControllerBase
|
||||
{
|
||||
public function getOwned()
|
||||
{
|
||||
$query = Image::where('uploaded_by', \Auth::user()->id);
|
||||
$images = [];
|
||||
foreach ($query->get() as $image) {
|
||||
$images[] = [
|
||||
'id' => $image->id,
|
||||
'urls' => [
|
||||
'small' => $image->getUrl(Image::SMALL),
|
||||
'normal' => $image->getUrl(Image::NORMAL),
|
||||
'thumbnail' => $image->getUrl(Image::THUMBNAIL),
|
||||
'original' => $image->getUrl(Image::ORIGINAL)
|
||||
],
|
||||
'filename' => $image->filename
|
||||
];
|
||||
}
|
||||
|
||||
return Response::json($images, 200);
|
||||
}
|
||||
}
|
143
app/Http/Controllers/Api/Web/PlaylistsController.php
Normal file
143
app/Http/Controllers/Api/Web/PlaylistsController.php
Normal file
|
@ -0,0 +1,143 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Web;
|
||||
|
||||
use App\Commands\AddTrackToPlaylistCommand;
|
||||
use App\Commands\CreatePlaylistCommand;
|
||||
use App\Commands\DeletePlaylistCommand;
|
||||
use App\Commands\EditPlaylistCommand;
|
||||
use App\Http\Controllers\ApiControllerBase;
|
||||
use App\Image;
|
||||
use App\Playlist;
|
||||
use App\ResourceLogItem;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
|
||||
class PlaylistsController extends ApiControllerBase
|
||||
{
|
||||
public function postCreate()
|
||||
{
|
||||
return $this->execute(new CreatePlaylistCommand(Input::all()));
|
||||
}
|
||||
|
||||
public function postEdit($id)
|
||||
{
|
||||
return $this->execute(new EditPlaylistCommand($id, Input::all()));
|
||||
}
|
||||
|
||||
public function postDelete($id)
|
||||
{
|
||||
return $this->execute(new DeletePlaylistCommand($id, Input::all()));
|
||||
}
|
||||
|
||||
public function postAddTrack($id)
|
||||
{
|
||||
return $this->execute(new AddTrackToPlaylistCommand($id, Input::get('track_id')));
|
||||
}
|
||||
|
||||
public function getIndex()
|
||||
{
|
||||
$page = 1;
|
||||
if (Input::has('page')) {
|
||||
$page = Input::get('page');
|
||||
}
|
||||
|
||||
$query = Playlist::summary()
|
||||
->with('user', 'user.avatar', 'tracks', 'tracks.cover', 'tracks.user', 'tracks.album', 'tracks.album.user')
|
||||
->userDetails()
|
||||
->orderBy('created_at', 'desc')
|
||||
->where('track_count', '>', 0)
|
||||
->whereIsPublic(true);
|
||||
|
||||
$count = $query->count();
|
||||
$perPage = 40;
|
||||
|
||||
$query->skip(($page - 1) * $perPage)->take($perPage);
|
||||
$playlists = [];
|
||||
|
||||
foreach ($query->get() as $playlist) {
|
||||
$playlists[] = Playlist::mapPublicPlaylistSummary($playlist);
|
||||
}
|
||||
|
||||
return Response::json([
|
||||
"playlists" => $playlists,
|
||||
"current_page" => $page,
|
||||
"total_pages" => ceil($count / $perPage)
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function getShow($id)
|
||||
{
|
||||
$playlist = Playlist::with([
|
||||
'tracks.user',
|
||||
'tracks.genre',
|
||||
'tracks.cover',
|
||||
'tracks.album',
|
||||
'tracks' => function ($query) {
|
||||
$query->userDetails();
|
||||
},
|
||||
'comments',
|
||||
'comments.user'
|
||||
])->userDetails()->find($id);
|
||||
if (!$playlist || !$playlist->canView(Auth::user())) {
|
||||
App::abort('404');
|
||||
}
|
||||
|
||||
if (Input::get('log')) {
|
||||
ResourceLogItem::logItem('playlist', $id, ResourceLogItem::VIEW);
|
||||
$playlist->view_count++;
|
||||
}
|
||||
|
||||
return Response::json(Playlist::mapPublicPlaylistShow($playlist), 200);
|
||||
}
|
||||
|
||||
public function getPinned()
|
||||
{
|
||||
$query = Playlist
|
||||
::userDetails()
|
||||
->with('tracks', 'tracks.cover', 'tracks.user', 'user')
|
||||
->join('pinned_playlists', function ($join) {
|
||||
$join->on('playlist_id', '=', 'playlists.id');
|
||||
})
|
||||
->where('pinned_playlists.user_id', '=', Auth::user()->id)
|
||||
->orderBy('title', 'asc')
|
||||
->select('playlists.*')
|
||||
->get();
|
||||
|
||||
$playlists = [];
|
||||
foreach ($query as $playlist) {
|
||||
$mapped = Playlist::mapPublicPlaylistSummary($playlist);
|
||||
$mapped['description'] = $playlist->description;
|
||||
$mapped['is_pinned'] = true;
|
||||
$playlists[] = $mapped;
|
||||
}
|
||||
|
||||
return Response::json($playlists, 200);
|
||||
}
|
||||
|
||||
public function getOwned()
|
||||
{
|
||||
$query = Playlist::summary()->with('pins', 'tracks', 'tracks.cover')->where('user_id',
|
||||
\Auth::user()->id)->orderBy('title', 'asc')->get();
|
||||
$playlists = [];
|
||||
foreach ($query as $playlist) {
|
||||
$playlists[] = [
|
||||
'id' => $playlist->id,
|
||||
'title' => $playlist->title,
|
||||
'slug' => $playlist->slug,
|
||||
'created_at' => $playlist->created_at,
|
||||
'description' => $playlist->description,
|
||||
'url' => $playlist->url,
|
||||
'covers' => [
|
||||
'small' => $playlist->getCoverUrl(Image::SMALL),
|
||||
'normal' => $playlist->getCoverUrl(Image::NORMAL)
|
||||
],
|
||||
'is_pinned' => $playlist->hasPinFor(Auth::user()->id),
|
||||
'is_public' => $playlist->is_public == 1
|
||||
];
|
||||
}
|
||||
|
||||
return Response::json($playlists, 200);
|
||||
}
|
||||
}
|
29
app/Http/Controllers/Api/Web/ProfilerController.php
Normal file
29
app/Http/Controllers/Api/Web/ProfilerController.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Web;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\ProfileRequest;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
|
||||
class ProfilerController extends Controller
|
||||
{
|
||||
public function getRequest($id)
|
||||
{
|
||||
if (!Config::get('app.debug')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$key = 'profiler-request-' . $id;
|
||||
$request = Cache::get($key);
|
||||
if (!$request) {
|
||||
exit();
|
||||
}
|
||||
|
||||
Cache::forget($key);
|
||||
|
||||
return Response::json(['request' => ProfileRequest::load($request)->toArray()], 200);
|
||||
}
|
||||
}
|
26
app/Http/Controllers/Api/Web/TaxonomiesController.php
Normal file
26
app/Http/Controllers/Api/Web/TaxonomiesController.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Web;
|
||||
|
||||
use App\Genre;
|
||||
use App\Http\Controllers\ApiControllerBase;
|
||||
use App\License;
|
||||
use App\ShowSong;
|
||||
use App\TrackType;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class TaxonomiesController extends ApiControllerBase
|
||||
{
|
||||
public function getAll()
|
||||
{
|
||||
return \Response::json([
|
||||
'licenses' => License::all()->toArray(),
|
||||
'genres' => Genre::select('genres.*',
|
||||
DB::raw('(SELECT COUNT(id) FROM tracks WHERE tracks.genre_id = genres.id AND tracks.published_at IS NOT NULL) AS track_count'))->orderBy('name')->get()->toArray(),
|
||||
'track_types' => TrackType::select('track_types.*',
|
||||
DB::raw('(SELECT COUNT(id) FROM tracks WHERE tracks.track_type_id = track_types.id AND tracks.published_at IS NOT NULL) AS track_count'))->get()->toArray(),
|
||||
'show_songs' => ShowSong::select('title', 'id', 'slug',
|
||||
DB::raw('(SELECT COUNT(tracks.id) FROM show_song_track INNER JOIN tracks ON tracks.id = show_song_track.track_id WHERE show_song_track.show_song_id = show_songs.id AND tracks.published_at IS NOT NULL) AS track_count'))->get()->toArray()
|
||||
], 200);
|
||||
}
|
||||
}
|
159
app/Http/Controllers/Api/Web/TracksController.php
Normal file
159
app/Http/Controllers/Api/Web/TracksController.php
Normal file
|
@ -0,0 +1,159 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api\Web;
|
||||
|
||||
use App\Commands\DeleteTrackCommand;
|
||||
use App\Commands\EditTrackCommand;
|
||||
use App\Commands\UploadTrackCommand;
|
||||
use App\Http\Controllers\ApiControllerBase;
|
||||
use App\ResourceLogItem;
|
||||
use App\Track;
|
||||
use Cover;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
|
||||
class TracksController extends ApiControllerBase
|
||||
{
|
||||
public function postUpload()
|
||||
{
|
||||
session_write_close();
|
||||
|
||||
return $this->execute(new UploadTrackCommand());
|
||||
}
|
||||
|
||||
public function postDelete($id)
|
||||
{
|
||||
return $this->execute(new DeleteTrackCommand($id));
|
||||
}
|
||||
|
||||
public function postEdit($id)
|
||||
{
|
||||
return $this->execute(new EditTrackCommand($id, Input::all()));
|
||||
}
|
||||
|
||||
public function getShow($id)
|
||||
{
|
||||
$track = Track::userDetails()->withComments()->find($id);
|
||||
if (!$track || !$track->canView(Auth::user())) {
|
||||
return $this->notFound('Track not found!');
|
||||
}
|
||||
|
||||
if (Input::get('log')) {
|
||||
ResourceLogItem::logItem('track', $id, ResourceLogItem::VIEW);
|
||||
$track->view_count++;
|
||||
}
|
||||
|
||||
$returned_track = Track::mapPublicTrackShow($track);
|
||||
if ($returned_track['is_downloadable'] != 1) {
|
||||
unset($returned_track['formats']);
|
||||
}
|
||||
|
||||
return Response::json(['track' => $returned_track], 200);
|
||||
}
|
||||
|
||||
public function getIndex()
|
||||
{
|
||||
$page = 1;
|
||||
$perPage = 45;
|
||||
|
||||
if (Input::has('page')) {
|
||||
$page = Input::get('page');
|
||||
}
|
||||
|
||||
$query = Track::summary()
|
||||
->userDetails()
|
||||
->listed()
|
||||
->explicitFilter()
|
||||
->published()
|
||||
->with('user', 'genre', 'cover', 'album', 'album.user');
|
||||
|
||||
$this->applyFilters($query);
|
||||
|
||||
$totalCount = $query->count();
|
||||
$query->take($perPage)->skip($perPage * ($page - 1));
|
||||
|
||||
$tracks = [];
|
||||
$ids = [];
|
||||
|
||||
foreach ($query->get(['tracks.*']) as $track) {
|
||||
$tracks[] = Track::mapPublicTrackSummary($track);
|
||||
$ids[] = $track->id;
|
||||
}
|
||||
|
||||
return Response::json([
|
||||
"tracks" => $tracks,
|
||||
"current_page" => $page,
|
||||
"total_pages" => ceil($totalCount / $perPage)
|
||||
], 200);
|
||||
}
|
||||
|
||||
public function getOwned()
|
||||
{
|
||||
$query = Track::summary()->where('user_id', \Auth::user()->id)->orderBy('created_at', 'desc');
|
||||
|
||||
$tracks = [];
|
||||
foreach ($query->get() as $track) {
|
||||
$tracks[] = Track::mapPrivateTrackSummary($track);
|
||||
}
|
||||
|
||||
return Response::json($tracks, 200);
|
||||
}
|
||||
|
||||
public function getEdit($id)
|
||||
{
|
||||
$track = Track::with('showSongs')->find($id);
|
||||
if (!$track) {
|
||||
return $this->notFound('Track ' . $id . ' not found!');
|
||||
}
|
||||
|
||||
if ($track->user_id != Auth::user()->id) {
|
||||
return $this->notAuthorized();
|
||||
}
|
||||
|
||||
return Response::json(Track::mapPrivateTrackShow($track), 200);
|
||||
}
|
||||
|
||||
private function applyFilters($query)
|
||||
{
|
||||
if (Input::has('order')) {
|
||||
$order = \Input::get('order');
|
||||
$parts = explode(',', $order);
|
||||
$query->orderBy($parts[0], $parts[1]);
|
||||
}
|
||||
|
||||
if (Input::has('is_vocal')) {
|
||||
$isVocal = \Input::get('is_vocal');
|
||||
if ($isVocal == 'true') {
|
||||
$query->whereIsVocal(true);
|
||||
} else {
|
||||
$query->whereIsVocal(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (Input::has('in_album')) {
|
||||
if (Input::get('in_album') == 'true') {
|
||||
$query->whereNotNull('album_id');
|
||||
} else {
|
||||
$query->whereNull('album_id');
|
||||
}
|
||||
}
|
||||
|
||||
if (Input::has('genres')) {
|
||||
$query->whereIn('genre_id', Input::get('genres'));
|
||||
}
|
||||
|
||||
if (Input::has('types')) {
|
||||
$query->whereIn('track_type_id', Input::get('types'));
|
||||
}
|
||||
|
||||
if (Input::has('songs')) {
|
||||
$query->join('show_song_track', function ($join) {
|
||||
$join->on('tracks.id', '=', 'show_song_track.track_id');
|
||||
});
|
||||
$query->whereIn('show_song_track.show_song_id', Input::get('songs'));
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
}
|
35
app/Http/Controllers/ApiControllerBase.php
Normal file
35
app/Http/Controllers/ApiControllerBase.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Response;
|
||||
|
||||
abstract class ApiControllerBase extends Controller
|
||||
{
|
||||
protected function execute($command)
|
||||
{
|
||||
if (!$command->authorize()) {
|
||||
return $this->notAuthorized();
|
||||
}
|
||||
|
||||
$result = $command->execute();
|
||||
if ($result->didFail()) {
|
||||
return Response::json([
|
||||
'message' => 'Validation failed',
|
||||
'errors' => $result->getValidator()->messages()->getMessages()
|
||||
], 400);
|
||||
}
|
||||
|
||||
return Response::json($result->getResponse(), 200);
|
||||
}
|
||||
|
||||
public function notAuthorized()
|
||||
{
|
||||
return Response::json(['message' => 'You may not do this!'], 403);
|
||||
}
|
||||
|
||||
public function notFound($message)
|
||||
{
|
||||
return Response::json(['message' => $message], 403);
|
||||
}
|
||||
}
|
35
app/Http/Controllers/ArtistsController.php
Normal file
35
app/Http/Controllers/ArtistsController.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App;
|
||||
use App\User;
|
||||
use Illuminate\Contracts\View\View;
|
||||
|
||||
class ArtistsController extends Controller
|
||||
{
|
||||
public function getIndex()
|
||||
{
|
||||
return View::make('artists.index');
|
||||
}
|
||||
|
||||
public function getProfile($slug)
|
||||
{
|
||||
$user = User::whereSlug($slug)->first();
|
||||
if (!$user) {
|
||||
App::abort('404');
|
||||
}
|
||||
|
||||
return View::make('artists.profile');
|
||||
}
|
||||
|
||||
public function getShortlink($id)
|
||||
{
|
||||
$user = User::find($id);
|
||||
if (!$user) {
|
||||
App::abort('404');
|
||||
}
|
||||
|
||||
return Redirect::action('ArtistsController@getProfile', [$id]);
|
||||
}
|
||||
}
|
115
app/Http/Controllers/AuthController.php
Normal file
115
app/Http/Controllers/AuthController.php
Normal file
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\User;
|
||||
use Auth;
|
||||
use Config;
|
||||
use DB;
|
||||
use Input;
|
||||
use Poniverse;
|
||||
use Redirect;
|
||||
use URL;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
protected $poniverse;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->poniverse = new Poniverse(Config::get('poniverse.client_id'), Config::get('poniverse.secret'));
|
||||
$this->poniverse->setRedirectUri(URL::to('/auth/oauth'));
|
||||
}
|
||||
|
||||
public function getLogin()
|
||||
{
|
||||
if (Auth::guest()) {
|
||||
return Redirect::to($this->poniverse->getAuthenticationUrl('login'));
|
||||
}
|
||||
|
||||
return Redirect::to('/');
|
||||
}
|
||||
|
||||
public function postLogout()
|
||||
{
|
||||
Auth::logout();
|
||||
|
||||
return Redirect::to('/');
|
||||
}
|
||||
|
||||
public function getOAuth()
|
||||
{
|
||||
$code = $this->poniverse->getClient()->getAccessToken(
|
||||
Config::get('poniverse.urls')['token'],
|
||||
'authorization_code',
|
||||
[
|
||||
'code' => Input::query('code'),
|
||||
'redirect_uri' => URL::to('/auth/oauth')
|
||||
]);
|
||||
|
||||
if ($code['code'] != 200) {
|
||||
if ($code['code'] == 400 && $code['result']['error_description'] == 'The authorization code has expired' && !isset($this->request['login_attempt'])) {
|
||||
return Redirect::to($this->poniverse->getAuthenticationUrl('login_attempt'));
|
||||
}
|
||||
|
||||
return Redirect::to('/')->with('message',
|
||||
'Unfortunately we are having problems attempting to log you in at the moment. Please try again at a later time.');
|
||||
}
|
||||
|
||||
$this->poniverse->setAccessToken($code['result']['access_token']);
|
||||
$poniverseUser = $this->poniverse->getUser();
|
||||
$token = DB::table('oauth2_tokens')->where('external_user_id', '=', $poniverseUser['id'])->where('service', '=',
|
||||
'poniverse')->first();
|
||||
|
||||
$setData = [
|
||||
'access_token' => $code['result']['access_token'],
|
||||
'expires' => date('Y-m-d H:i:s', strtotime("+" . $code['result']['expires_in'] . " Seconds", time())),
|
||||
'type' => $code['result']['token_type'],
|
||||
];
|
||||
|
||||
if (isset($code['result']['refresh_token']) && !empty($code['result']['refresh_token'])) {
|
||||
$setData['refresh_token'] = $code['result']['refresh_token'];
|
||||
}
|
||||
|
||||
if ($token) {
|
||||
//User already exists, update access token and refresh token if provided.
|
||||
DB::table('oauth2_tokens')->where('id', '=', $token->id)->update($setData);
|
||||
|
||||
return $this->loginRedirect(User::find($token->user_id));
|
||||
}
|
||||
|
||||
//Check by email to see if they already have an account
|
||||
$localMember = User::where('email', '=', $poniverseUser['email'])->first();
|
||||
|
||||
if ($localMember) {
|
||||
return $this->loginRedirect($localMember);
|
||||
}
|
||||
|
||||
$user = new User;
|
||||
|
||||
$user->mlpforums_name = $poniverseUser['username'];
|
||||
$user->display_name = $poniverseUser['display_name'];
|
||||
$user->email = $poniverseUser['email'];
|
||||
$user->created_at = gmdate("Y-m-d H:i:s", time());
|
||||
$user->uses_gravatar = 1;
|
||||
|
||||
$user->save();
|
||||
|
||||
//We need to insert a new token row :O
|
||||
|
||||
$setData['user_id'] = $user->id;
|
||||
$setData['external_user_id'] = $poniverseUser['id'];
|
||||
$setData['service'] = 'poniverse';
|
||||
|
||||
DB::table('oauth2_tokens')->insert($setData);
|
||||
|
||||
return $this->loginRedirect($user);
|
||||
}
|
||||
|
||||
protected function loginRedirect($user, $rememberMe = true)
|
||||
{
|
||||
Auth::login($user, $rememberMe);
|
||||
|
||||
return Redirect::to('/');
|
||||
}
|
||||
}
|
23
app/Http/Controllers/ContentController.php
Normal file
23
app/Http/Controllers/ContentController.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use View;
|
||||
|
||||
class ContentController extends Controller
|
||||
{
|
||||
public function getTracks()
|
||||
{
|
||||
return View::make('shared.null');
|
||||
}
|
||||
|
||||
public function getAlbums()
|
||||
{
|
||||
return View::make('shared.null');
|
||||
}
|
||||
|
||||
public function getPlaylists()
|
||||
{
|
||||
return View::make('shared.null');
|
||||
}
|
||||
}
|
12
app/Http/Controllers/Controller.php
Normal file
12
app/Http/Controllers/Controller.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
|
||||
abstract class Controller extends BaseController
|
||||
{
|
||||
use DispatchesJobs, ValidatesRequests;
|
||||
}
|
23
app/Http/Controllers/FavouritesController.php
Normal file
23
app/Http/Controllers/FavouritesController.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use View;
|
||||
|
||||
class FavouritesController extends Controller
|
||||
{
|
||||
public function getTracks()
|
||||
{
|
||||
return View::make('shared.null');
|
||||
}
|
||||
|
||||
public function getAlbums()
|
||||
{
|
||||
return View::make('shared.null');
|
||||
}
|
||||
|
||||
public function getPlaylists()
|
||||
{
|
||||
return View::make('shared.null');
|
||||
}
|
||||
}
|
13
app/Http/Controllers/HomeController.php
Normal file
13
app/Http/Controllers/HomeController.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use View;
|
||||
|
||||
class HomeController extends Controller
|
||||
{
|
||||
public function getIndex()
|
||||
{
|
||||
return View::make('home.index');
|
||||
}
|
||||
}
|
52
app/Http/Controllers/ImagesController.php
Normal file
52
app/Http/Controllers/ImagesController.php
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Image;
|
||||
use Config;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
use Response;
|
||||
use URL;
|
||||
|
||||
class ImagesController extends Controller
|
||||
{
|
||||
public function getImage($id, $type)
|
||||
{
|
||||
$coverType = Image::getImageTypeFromName($type);
|
||||
|
||||
if ($coverType == null) {
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
$image = Image::find($id);
|
||||
if (!$image) {
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
$response = Response::make('', 200);
|
||||
$filename = $image->getFile($coverType['id']);
|
||||
|
||||
if (!is_file($filename)) {
|
||||
$redirect = URL::to('/images/icons/profile_' . Image::$ImageTypes[$coverType['id']]['name'] . '.png');
|
||||
|
||||
return Redirect::to($redirect);
|
||||
}
|
||||
|
||||
if (Config::get('app.sendfile')) {
|
||||
$response->header('X-Sendfile', $filename);
|
||||
} else {
|
||||
$response->header('X-Accel-Redirect', $filename);
|
||||
}
|
||||
|
||||
$response->header('Content-Disposition', 'filename="' . $filename . '"');
|
||||
$response->header('Content-Type', 'image/png');
|
||||
|
||||
$lastModified = filemtime($filename);
|
||||
|
||||
$response->header('Last-Modified', $lastModified);
|
||||
$response->header('Cache-Control', 'max-age=' . (60 * 60 * 24 * 7));
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
70
app/Http/Controllers/PlaylistsController.php
Normal file
70
app/Http/Controllers/PlaylistsController.php
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App;
|
||||
use App\Playlist;
|
||||
use App\ResourceLogItem;
|
||||
use App\Track;
|
||||
use Auth;
|
||||
use Illuminate\Support\Facades\Redirect;
|
||||
use View;
|
||||
|
||||
class PlaylistsController extends Controller
|
||||
{
|
||||
public function getIndex()
|
||||
{
|
||||
return View::make('playlists.index');
|
||||
}
|
||||
|
||||
public function getPlaylist($id, $slug)
|
||||
{
|
||||
$playlist = Playlist::find($id);
|
||||
if (!$playlist || !$playlist->canView(Auth::user())) {
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
if ($playlist->slug != $slug) {
|
||||
return Redirect::action('PlaylistsController@getPlaylist', [$id, $playlist->slug]);
|
||||
}
|
||||
|
||||
return View::make('playlists.show');
|
||||
}
|
||||
|
||||
public function getShortlink($id)
|
||||
{
|
||||
$playlist = Playlist::find($id);
|
||||
if (!$playlist || !$playlist->canView(Auth::user())) {
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
return Redirect::action('PlaylistsController@getPlaylist', [$id, $playlist->slug]);
|
||||
}
|
||||
|
||||
public function getDownload($id, $extension)
|
||||
{
|
||||
$playlist = Playlist::with('tracks', 'user', 'tracks.album')->find($id);
|
||||
if (!$playlist || !$playlist->is_public) {
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
$format = null;
|
||||
$formatName = null;
|
||||
|
||||
foreach (Track::$Formats as $name => $item) {
|
||||
if ($item['extension'] == $extension) {
|
||||
$format = $item;
|
||||
$formatName = $name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($format == null) {
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
ResourceLogItem::logItem('playlist', $id, ResourceLogItem::DOWNLOAD, $format['index']);
|
||||
$downloader = new PlaylistDownloader($playlist, $formatName);
|
||||
$downloader->download();
|
||||
}
|
||||
}
|
153
app/Http/Controllers/TracksController.php
Normal file
153
app/Http/Controllers/TracksController.php
Normal file
|
@ -0,0 +1,153 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\ResourceLogItem;
|
||||
use App\Track;
|
||||
use App\TrackFile;
|
||||
use Auth;
|
||||
use Config;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Redirect;
|
||||
use Response;
|
||||
use View;
|
||||
|
||||
class TracksController extends Controller
|
||||
{
|
||||
public function getIndex()
|
||||
{
|
||||
return View::make('tracks.index');
|
||||
}
|
||||
|
||||
public function getEmbed($id)
|
||||
{
|
||||
$track = Track
|
||||
::whereId($id)
|
||||
->published()
|
||||
->userDetails()
|
||||
->with(
|
||||
'user',
|
||||
'user.avatar',
|
||||
'genre'
|
||||
)->first();
|
||||
|
||||
if (!$track || !$track->canView(Auth::user())) {
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
$userData = [
|
||||
'stats' => [
|
||||
'views' => 0,
|
||||
'plays' => 0,
|
||||
'downloads' => 0
|
||||
],
|
||||
'is_favourited' => false
|
||||
];
|
||||
|
||||
if ($track->users->count()) {
|
||||
$userRow = $track->users[0];
|
||||
$userData = [
|
||||
'stats' => [
|
||||
'views' => $userRow->view_count,
|
||||
'plays' => $userRow->play_count,
|
||||
'downloads' => $userRow->download_count,
|
||||
],
|
||||
'is_favourited' => $userRow->is_favourited
|
||||
];
|
||||
}
|
||||
|
||||
return View::make('tracks.embed', ['track' => $track, 'user' => $userData]);
|
||||
}
|
||||
|
||||
public function getTrack($id, $slug)
|
||||
{
|
||||
$track = Track::find($id);
|
||||
if (!$track || !$track->canView(Auth::user())) {
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
if ($track->slug != $slug) {
|
||||
return Redirect::action('TracksController@getTrack', [$id, $track->slug]);
|
||||
}
|
||||
|
||||
return View::make('tracks.show');
|
||||
}
|
||||
|
||||
public function getShortlink($id)
|
||||
{
|
||||
$track = Track::find($id);
|
||||
if (!$track || !$track->canView(Auth::user())) {
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
return Redirect::action('TracksController@getTrack', [$id, $track->slug]);
|
||||
}
|
||||
|
||||
public function getStream($id, $extension)
|
||||
{
|
||||
$track = Track::find($id);
|
||||
if (!$track || !$track->canView(Auth::user())) {
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
$trackFile = TrackFile::findOrFailByExtension($track->id, $extension);
|
||||
ResourceLogItem::logItem('track', $id, ResourceLogItem::PLAY, $trackFile->getFormat()['index']);
|
||||
|
||||
$response = Response::make('', 200);
|
||||
$filename = $trackFile->getFile();
|
||||
|
||||
if (Config::get('app.sendfile')) {
|
||||
$response->header('X-Sendfile', $filename);
|
||||
} else {
|
||||
$response->header('X-Accel-Redirect', $filename);
|
||||
}
|
||||
|
||||
$time = gmdate(filemtime($filename));
|
||||
|
||||
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $time == $_SERVER['HTTP_IF_MODIFIED_SINCE']) {
|
||||
header('HTTP/1.0 304 Not Modified');
|
||||
exit();
|
||||
}
|
||||
|
||||
$response->header('Last-Modified', $time);
|
||||
$response->header('Content-Type', $trackFile->getFormat()['mime_type']);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function getDownload($id, $extension)
|
||||
{
|
||||
$track = Track::find($id);
|
||||
if (!$track || !$track->canView(Auth::user())) {
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
$trackFile = TrackFile::findOrFailByExtension($track->id, $extension);
|
||||
ResourceLogItem::logItem('track', $id, ResourceLogItem::DOWNLOAD, $trackFile->getFormat()['index']);
|
||||
|
||||
$response = Response::make('', 200);
|
||||
$filename = $trackFile->getFile();
|
||||
|
||||
if (Config::get('app.sendfile')) {
|
||||
$response->header('X-Sendfile', $filename);
|
||||
$response->header('Content-Disposition',
|
||||
'attachment; filename="' . $trackFile->getDownloadFilename() . '"');
|
||||
} else {
|
||||
$response->header('X-Accel-Redirect', $filename);
|
||||
$response->header('Content-Disposition',
|
||||
'attachment; filename="' . $trackFile->getDownloadFilename() . '"');
|
||||
}
|
||||
|
||||
$time = gmdate(filemtime($filename));
|
||||
|
||||
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $time == $_SERVER['HTTP_IF_MODIFIED_SINCE']) {
|
||||
header('HTTP/1.0 304 Not Modified');
|
||||
exit();
|
||||
}
|
||||
|
||||
$response->header('Last-Modified', $time);
|
||||
$response->header('Content-Type', $trackFile->getFormat()['mime_type']);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
13
app/Http/Controllers/UploaderController.php
Normal file
13
app/Http/Controllers/UploaderController.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use View;
|
||||
|
||||
class UploaderController extends Controller
|
||||
{
|
||||
public function getIndex()
|
||||
{
|
||||
return View::make('shared.null');
|
||||
}
|
||||
}
|
26
app/Http/Controllers/UsersController.php
Normal file
26
app/Http/Controllers/UsersController.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\User;
|
||||
use File;
|
||||
use Illuminate\Support\Facades\App;
|
||||
|
||||
class UsersController extends Controller
|
||||
{
|
||||
public function getAvatar($id, $type)
|
||||
{
|
||||
$coverType = Cover::getCoverFromName($type);
|
||||
|
||||
if ($coverType == null) {
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
$user = User::find($id);
|
||||
if (!$user) {
|
||||
App::abort(404);
|
||||
}
|
||||
|
||||
return File::inline($user->getAvatarFile($coverType['id']), 'image/png', 'cover.png');
|
||||
}
|
||||
}
|
34
app/Http/Kernel.php
Normal file
34
app/Http/Kernel.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http;
|
||||
|
||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||
|
||||
class Kernel extends HttpKernel
|
||||
{
|
||||
/**
|
||||
* The application's global HTTP middleware stack.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $middleware = [
|
||||
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
|
||||
\App\Http\Middleware\EncryptCookies::class,
|
||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||
\Illuminate\Session\Middleware\StartSession::class,
|
||||
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
|
||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* The application's route middleware.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $routeMiddleware = [
|
||||
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
|
||||
'csrf' => \App\Http\Middleware\VerifyCsrfHeader::class,
|
||||
];
|
||||
}
|
42
app/Http/Middleware/Authenticate.php
Normal file
42
app/Http/Middleware/Authenticate.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Auth\Guard;
|
||||
|
||||
class Authenticate
|
||||
{
|
||||
/**
|
||||
* The Guard implementation.
|
||||
*
|
||||
* @var Guard
|
||||
*/
|
||||
protected $auth;
|
||||
|
||||
/**
|
||||
* Create a new filter instance.
|
||||
*
|
||||
* @param Guard $auth
|
||||
*/
|
||||
public function __construct(Guard $auth)
|
||||
{
|
||||
$this->auth = $auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
if ($this->auth->guest()) {
|
||||
return redirect()->guest('login');
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
17
app/Http/Middleware/EncryptCookies.php
Normal file
17
app/Http/Middleware/EncryptCookies.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Cookie\Middleware\EncryptCookies as BaseEncrypter;
|
||||
|
||||
class EncryptCookies extends BaseEncrypter
|
||||
{
|
||||
/**
|
||||
* The names of the cookies that should not be encrypted.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $except = [
|
||||
//
|
||||
];
|
||||
}
|
43
app/Http/Middleware/RedirectIfAuthenticated.php
Normal file
43
app/Http/Middleware/RedirectIfAuthenticated.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Auth\Guard;
|
||||
|
||||
class RedirectIfAuthenticated
|
||||
{
|
||||
/**
|
||||
* The Guard implementation.
|
||||
*
|
||||
* @var Guard
|
||||
*/
|
||||
protected $auth;
|
||||
|
||||
/**
|
||||
* Create a new filter instance.
|
||||
*
|
||||
* @param Guard $auth
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Guard $auth)
|
||||
{
|
||||
$this->auth = $auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
if ($this->auth->check()) {
|
||||
return redirect('/home');
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
28
app/Http/Middleware/VerifyCsrfHeader.php
Normal file
28
app/Http/Middleware/VerifyCsrfHeader.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Session\TokenMismatchException;
|
||||
use Session;
|
||||
|
||||
class VerifyCsrfHeader
|
||||
{
|
||||
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
* @throws TokenMismatchException
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
if (Session::token() != $request->input('_token') && Session::token() != $request->header('X-Token')) {
|
||||
throw new TokenMismatchException;
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
17
app/Http/Middleware/VerifyCsrfToken.php
Normal file
17
app/Http/Middleware/VerifyCsrfToken.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
|
||||
|
||||
class VerifyCsrfToken extends BaseVerifier
|
||||
{
|
||||
/**
|
||||
* The URIs that should be excluded from CSRF verification.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $except = [
|
||||
//
|
||||
];
|
||||
}
|
10
app/Http/Requests/Request.php
Normal file
10
app/Http/Requests/Request.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
abstract class Request extends FormRequest
|
||||
{
|
||||
//
|
||||
}
|
161
app/Http/routes.php
Normal file
161
app/Http/routes.php
Normal file
|
@ -0,0 +1,161 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Routes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Here is where you can register all of the routes for an application.
|
||||
| It's a breeze. Simply tell Laravel the URIs it should respond to
|
||||
| and give it the controller to call when that URI is requested.
|
||||
|
|
||||
*/
|
||||
|
||||
if (Config::get('app.debug')) {
|
||||
Route::get('/api/web/profiler/{id}', 'Api\Web\ProfilerController@getRequest');
|
||||
}
|
||||
|
||||
Route::get('/dashboard', 'TracksController@getIndex');
|
||||
Route::get('/tracks', 'TracksController@getIndex');
|
||||
Route::get('/tracks/popular', 'TracksController@getIndex');
|
||||
Route::get('/tracks/random', 'TracksController@getIndex');
|
||||
|
||||
Route::get('tracks/{id}-{slug}', 'TracksController@getTrack');
|
||||
Route::get('t{id}', 'TracksController@getShortlink' );
|
||||
Route::get('t{id}/embed', 'TracksController@getEmbed' );
|
||||
Route::get('t{id}/stream.{extension}', 'TracksController@getStream' );
|
||||
Route::get('t{id}/dl.{extension}', 'TracksController@getDownload' );
|
||||
|
||||
Route::get('albums', 'AlbumsController@getIndex');
|
||||
Route::get('albums/{id}-{slug}', 'AlbumsController@getShow');
|
||||
Route::get('a{id}', 'AlbumsController@getShortlink')->where('id', '\d+');
|
||||
Route::get('a{id}/dl.{extension}', 'AlbumsController@getDownload' );
|
||||
|
||||
Route::get('artists', 'ArtistsController@getIndex');
|
||||
Route::get('playlists', 'PlaylistsController@getIndex');
|
||||
|
||||
Route::get('/register', 'AccountController@getRegister');
|
||||
Route::get('/login', 'AuthController@getLogin');
|
||||
Route::get('/auth/oauth', 'AuthController@getOAuth');
|
||||
|
||||
Route::get('/about', function() { return View::make('pages.about'); });
|
||||
Route::get('/faq', function() { return View::make('pages.faq'); });
|
||||
|
||||
Route::get('i{id}/{type}.png', 'ImagesController@getImage')->where('id', '\d+');
|
||||
|
||||
Route::get('u{id}/avatar_{type}.png', 'UsersController@getAvatar')->where('id', '\d+');
|
||||
|
||||
Route::get('playlist/{id}-{slug}', 'PlaylistsController@getPlaylist');
|
||||
Route::get('p{id}', 'PlaylistsController@getShortlink')->where('id', '\d+');
|
||||
Route::get('p{id}/dl.{extension}', 'PlaylistsController@getDownload' );
|
||||
|
||||
Route::group(['prefix' => 'api/v1'], function() {
|
||||
Route::get('/tracks/radio-details/{hash}', 'Api\V1\TracksController@getTrackRadioDetails');
|
||||
Route::post('/tracks/radio-details/{hash}', 'Api\V1\TracksController@getTrackRadioDetails');
|
||||
});
|
||||
|
||||
Route::group(['prefix' => 'api/web'], function() {
|
||||
Route::get('/taxonomies/all', 'Api\Web\TaxonomiesController@getAll');
|
||||
|
||||
Route::get('/playlists/show/{id}', 'Api\Web\PlaylistsController@getShow');
|
||||
|
||||
Route::get('/tracks', 'Api\Web\TracksController@getIndex');
|
||||
Route::get('/tracks/{id}', 'Api\Web\TracksController@getShow')->where('id', '\d+');
|
||||
|
||||
Route::get('/albums', 'Api\Web\AlbumsController@getIndex');
|
||||
Route::get('/albums/{id}', 'Api\Web\AlbumsController@getShow')->where('id', '\d+');
|
||||
|
||||
Route::get('/playlists', 'Api\Web\PlaylistsController@getIndex');
|
||||
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');
|
||||
Route::get('/artists/{slug}/favourites', 'Api\Web\ArtistsController@getFavourites');
|
||||
|
||||
Route::get('/dashboard', 'Api\Web\DashboardController@getIndex');
|
||||
|
||||
Route::group(['before' => 'auth|csrf'], function() {
|
||||
Route::post('/tracks/upload', 'Api\Web\TracksController@postUpload');
|
||||
Route::post('/tracks/delete/{id}', 'Api\Web\TracksController@postDelete');
|
||||
Route::post('/tracks/edit/{id}', 'Api\Web\TracksController@postEdit');
|
||||
|
||||
Route::post('/albums/create', 'Api\Web\AlbumsController@postCreate');
|
||||
Route::post('/albums/delete/{id}', 'Api\Web\AlbumsController@postDelete');
|
||||
Route::post('/albums/edit/{id}', 'Api\Web\AlbumsController@postEdit');
|
||||
|
||||
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::post('/follow/toggle', 'Api\Web\FollowController@postToggle');
|
||||
|
||||
Route::post('/dashboard/read-news', 'Api\Web\DashboardController@postReadNews');
|
||||
});
|
||||
|
||||
Route::group(['before' => 'auth'], function() {
|
||||
Route::get('/account/settings', 'Api\Web\AccountController@getSettings');
|
||||
|
||||
Route::get('/images/owned', 'Api\Web\ImagesController@getOwned');
|
||||
|
||||
Route::get('/tracks/owned', 'Api\Web\TracksController@getOwned');
|
||||
Route::get('/tracks/edit/{id}', 'Api\Web\TracksController@getEdit');
|
||||
|
||||
Route::get('/albums/owned', 'Api\Web\AlbumsController@getOwned');
|
||||
Route::get('/albums/edit/{id}', 'Api\Web\AlbumsController@getEdit');
|
||||
|
||||
Route::get('/playlists/owned', 'Api\Web\PlaylistsController@getOwned');
|
||||
Route::get('/playlists/pinned', 'Api\Web\PlaylistsController@getPinned');
|
||||
|
||||
Route::get('/favourites/tracks', 'Api\Web\FavouritesController@getTracks');
|
||||
Route::get('/favourites/albums', 'Api\Web\FavouritesController@getAlbums');
|
||||
Route::get('/favourites/playlists', 'Api\Web\FavouritesController@getPlaylists');
|
||||
});
|
||||
|
||||
Route::group(['before' => 'csrf'], function(){
|
||||
Route::post('/auth/logout', 'Api\Web\AuthController@postLogout');
|
||||
});
|
||||
});
|
||||
|
||||
Route::group(['prefix' => 'account'], function() {
|
||||
Route::group(['before' => 'auth'], function(){
|
||||
Route::get('/favourites/tracks', 'FavouritesController@getTracks');
|
||||
Route::get('/favourites/albums', 'FavouritesController@getAlbums');
|
||||
Route::get('/favourites/playlists', 'FavouritesController@getPlaylists');
|
||||
|
||||
Route::get('/tracks', 'ContentController@getTracks');
|
||||
Route::get('/tracks/edit/{id}', 'ContentController@getTracks');
|
||||
Route::get('/albums', 'ContentController@getAlbums');
|
||||
Route::get('/albums/edit/{id}', 'ContentController@getAlbums');
|
||||
Route::get('/albums/create', 'ContentController@getAlbums');
|
||||
Route::get('/playlists', 'ContentController@getPlaylists');
|
||||
|
||||
Route::get('/uploader', 'UploaderController@getIndex');
|
||||
|
||||
Route::get('/', 'AccountController@getIndex');
|
||||
});
|
||||
});
|
||||
|
||||
Route::get('u{id}', 'ArtistsController@getShortlink')->where('id', '\d+');
|
||||
Route::get('users/{id}-{slug}', 'ArtistsController@getShortlink')->where('id', '\d+');
|
||||
Route::get('{slug}', 'ArtistsController@getProfile');
|
||||
Route::get('{slug}/content', 'ArtistsController@getProfile');
|
||||
Route::get('{slug}/favourites', 'ArtistsController@getProfile');
|
||||
|
||||
Route::get('/', 'HomeController@getIndex');
|
||||
|
||||
Route::group(['domain' => 'api.pony.fm'], function() {
|
||||
Route::get('tracks/latest', ['uses' => 'Api\Mobile\TracksController@latest']);
|
||||
Route::get('tracks/popular', [ 'uses' => 'Api\Mobile\TracksController@popular']);
|
||||
/* Route::get('tracks/id', [ 'uses' => 'Api\Mobile\TracksController@track']);
|
||||
Route::get('user', ['uses' => 'Api\Mobile\UserController@user']);*/
|
||||
});
|
117
app/Image.php
Normal file
117
app/Image.php
Normal file
|
@ -0,0 +1,117 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use External;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\URL;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
|
||||
class Image extends Model
|
||||
{
|
||||
const NORMAL = 1;
|
||||
const ORIGINAL = 2;
|
||||
const THUMBNAIL = 3;
|
||||
const SMALL = 4;
|
||||
|
||||
public static $ImageTypes = [
|
||||
self::NORMAL => ['id' => self::NORMAL, 'name' => 'normal', 'width' => 350, 'height' => 350],
|
||||
self::ORIGINAL => ['id' => self::ORIGINAL, 'name' => 'original', 'width' => null, 'height' => null],
|
||||
self::SMALL => ['id' => self::SMALL, 'name' => 'small', 'width' => 100, 'height' => 100],
|
||||
self::THUMBNAIL => ['id' => self::THUMBNAIL, 'name' => 'thumbnail', 'width' => 50, 'height' => 50]
|
||||
];
|
||||
|
||||
public static function getImageTypeFromName($name)
|
||||
{
|
||||
foreach (self::$ImageTypes as $cover) {
|
||||
if ($cover['name'] != $name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $cover;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function upload(UploadedFile $file, $user)
|
||||
{
|
||||
$userId = $user;
|
||||
if ($user instanceof User) {
|
||||
$userId = $user->id;
|
||||
}
|
||||
|
||||
$hash = md5_file($file->getPathname());
|
||||
$image = Image::whereHash($hash)->whereUploadedBy($userId)->first();
|
||||
|
||||
if ($image) {
|
||||
return $image;
|
||||
}
|
||||
|
||||
$image = new Image();
|
||||
try {
|
||||
$image->uploaded_by = $userId;
|
||||
$image->size = $file->getSize();
|
||||
$image->filename = $file->getClientOriginalName();
|
||||
$image->extension = $file->getClientOriginalExtension();
|
||||
$image->mime = $file->getMimeType();
|
||||
$image->hash = $hash;
|
||||
$image->save();
|
||||
|
||||
$image->ensureDirectoryExists();
|
||||
foreach (self::$ImageTypes as $coverType) {
|
||||
$command = 'convert 2>&1 "' . $file->getPathname() . '" -background transparent -flatten +matte -strip -quality 95 -format png ';
|
||||
if (isset($coverType['width']) && isset($coverType['height'])) {
|
||||
$command .= '-thumbnail ' . $coverType['width'] . 'x' . $coverType['height'] . '^ -gravity center -extent ' . $coverType['width'] . 'x' . $coverType['height'] . ' ';
|
||||
}
|
||||
|
||||
$command .= '"' . $image->getFile($coverType['id']) . '"';
|
||||
External::execute($command);
|
||||
}
|
||||
|
||||
return $image;
|
||||
} catch (\Exception $e) {
|
||||
$image->delete();
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
protected $table = 'images';
|
||||
|
||||
public function getUrl($type = self::NORMAL)
|
||||
{
|
||||
$type = self::$ImageTypes[$type];
|
||||
|
||||
return URL::to('i' . $this->id . '/' . $type['name'] . '.png');
|
||||
}
|
||||
|
||||
public function getFile($type = self::NORMAL)
|
||||
{
|
||||
return $this->getDirectory() . '/' . $this->getFilename($type);
|
||||
}
|
||||
|
||||
public function getFilename($type = self::NORMAL)
|
||||
{
|
||||
$typeInfo = self::$ImageTypes[$type];
|
||||
|
||||
return $this->id . '_' . $typeInfo['name'] . '.png';
|
||||
}
|
||||
|
||||
public function getDirectory()
|
||||
{
|
||||
$dir = (string)(floor($this->id / 100) * 100);
|
||||
|
||||
return Config::get('ponyfm.files_directory') . '/images/' . $dir;
|
||||
}
|
||||
|
||||
public function ensureDirectoryExists()
|
||||
{
|
||||
$destination = $this->getDirectory();
|
||||
umask(0);
|
||||
|
||||
if (!is_dir($destination)) {
|
||||
mkdir($destination, 0777, true);
|
||||
}
|
||||
}
|
||||
}
|
21
app/Jobs/Job.php
Normal file
21
app/Jobs/Job.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace App\Jobs;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
|
||||
abstract class Job
|
||||
{
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Queueable Jobs
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This job base class provides a central location to place any logic that
|
||||
| is shared across all of your jobs. The trait included with the class
|
||||
| provides access to the "queueOn" and "delay" queue helper methods.
|
||||
|
|
||||
*/
|
||||
|
||||
use Queueable;
|
||||
}
|
118
app/Library/Assets.php
Normal file
118
app/Library/Assets.php
Normal file
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
|
||||
class Assets
|
||||
{
|
||||
public static function scriptIncludes($area = 'app')
|
||||
{
|
||||
if (!Config::get("app.debug")) {
|
||||
return '<script src="/build/scripts/' . $area . '.js?' . filemtime("./build/scripts/" . $area . ".js") . '"></script>';
|
||||
}
|
||||
|
||||
$scripts = self::mergeGlobs(self::getScriptsForArea($area));
|
||||
$retVal = "";
|
||||
|
||||
foreach ($scripts as $script) {
|
||||
$filename = self::replaceExtensionWith($script, ".coffee", ".js");
|
||||
$retVal .= "<script src='/build/$filename?" . filemtime('./build/' . $filename) . "'></script>";
|
||||
}
|
||||
|
||||
return $retVal;
|
||||
}
|
||||
|
||||
public static function styleIncludes($area = 'app')
|
||||
{
|
||||
if (!Config::get("app.debug")) {
|
||||
return '<script>document.write(\'<link rel="stylesheet" href="build/styles/' . $area . '.css?' . filemtime("build/styles/" . $area . ".css") . '" />\');</script>';
|
||||
}
|
||||
|
||||
$styles = self::mergeGlobs(self::getStylesForArea($area));
|
||||
$retVal = "";
|
||||
|
||||
foreach ($styles as $style) {
|
||||
$filename = self::replaceExtensionWith($style, ".less", ".css");
|
||||
$retVal .= "<link rel='stylesheet' href='/build/$filename?" . filemtime('./build/' . $filename) . "' />";
|
||||
}
|
||||
|
||||
return $retVal;
|
||||
}
|
||||
|
||||
private static function replaceExtensionWith($filename, $fromExtension, $toExtension)
|
||||
{
|
||||
$fromLength = strlen($fromExtension);
|
||||
|
||||
return substr($filename, -$fromLength) == $fromExtension
|
||||
? substr($filename, 0, strlen($filename) - $fromLength) . $toExtension
|
||||
: $filename;
|
||||
}
|
||||
|
||||
/** Merges an array of paths that are passed into "glob" into a list of unique filenames.
|
||||
* Note that this method assumes the globs should be relative to the "app" folder of this project */
|
||||
private static function mergeGlobs($globs)
|
||||
{
|
||||
$files = [];
|
||||
$filesFound = [];
|
||||
foreach ($globs as $glob) {
|
||||
foreach (glob("../resources/assets/" . $glob, GLOB_BRACE) as $file) {
|
||||
if (isset($filesFound[$file])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$filesFound[$file] = true;
|
||||
$files[] = substr($file, 20); // chop off ../app/
|
||||
}
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
|
||||
private static function getScriptsForArea($area)
|
||||
{
|
||||
if ($area == 'app') {
|
||||
return [
|
||||
"scripts/base/jquery-2.0.2.js",
|
||||
"scripts/base/angular.js",
|
||||
"scripts/base/*.{coffee,js}",
|
||||
"scripts/shared/*.{coffee,js}",
|
||||
"scripts/app/*.{coffee,js}",
|
||||
"scripts/app/services/*.{coffee,js}",
|
||||
"scripts/app/filters/*.{coffee,js}",
|
||||
"scripts/app/directives/*.{coffee,js}",
|
||||
"scripts/app/controllers/*.{coffee,js}",
|
||||
"scripts/**/*.{coffee,js}"
|
||||
];
|
||||
} else {
|
||||
if ($area == 'embed') {
|
||||
return [
|
||||
"scripts/base/jquery-2.0.2.js",
|
||||
"scripts/base/jquery.viewport.js",
|
||||
"scripts/base/underscore.js",
|
||||
"scripts/base/moment.js",
|
||||
"scripts/base/jquery.timeago.js",
|
||||
"scripts/base/soundmanager2-nodebug.js",
|
||||
"scripts/embed/*.coffee"
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
private static function getStylesForArea($area)
|
||||
{
|
||||
if ($area == 'app') {
|
||||
return [
|
||||
"styles/base/jquery-ui.css",
|
||||
"styles/base/colorbox.css",
|
||||
"styles/app.less",
|
||||
"styles/profiler.less"
|
||||
];
|
||||
} else {
|
||||
if ($area == 'embed') {
|
||||
return [
|
||||
"styles/embed.less"
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
19
app/Library/AudioCache.php
Normal file
19
app/Library/AudioCache.php
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
class AudioCache
|
||||
{
|
||||
private static $_movieCache = array();
|
||||
|
||||
/**
|
||||
* @param $filename
|
||||
* @return FFmpegMovie
|
||||
*/
|
||||
public static function get($filename)
|
||||
{
|
||||
if (isset(self::$_movieCache[$filename])) {
|
||||
return self::$_movieCache[$filename];
|
||||
}
|
||||
|
||||
return self::$_movieCache[$filename] = new FFmpegMovie($filename);
|
||||
}
|
||||
}
|
36
app/Library/CacheBusterAsset.php
Normal file
36
app/Library/CacheBusterAsset.php
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
use Assetic\Asset\BaseAsset;
|
||||
use Assetic\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* Class CacheBusterAsset
|
||||
* OH GOD IT BUUUUUUURNS
|
||||
*
|
||||
* Well, I may as well tell you why this awful class exists. So... Assetic doesn't quite support less's import
|
||||
* directive. I mean; it supports it insofar as Less itself supports it - but it doesn't take into account the
|
||||
* last modified time for imported assets. Since we only have one less file that imports everything else... well
|
||||
* you can see where this is going. This asset will let us override the last modified time for an entire collection
|
||||
* which allows me to write a custom mechanism for cache busting.
|
||||
*/
|
||||
class CacheBusterAsset extends BaseAsset
|
||||
{
|
||||
private $_lastModified;
|
||||
|
||||
/**
|
||||
* @param int $lastModified
|
||||
*/
|
||||
public function __construct($lastModified)
|
||||
{
|
||||
$this->_lastModified = $lastModified;
|
||||
parent::__construct([], '', '', []);
|
||||
}
|
||||
|
||||
public function load(FilterInterface $additionalFilter = null)
|
||||
{
|
||||
}
|
||||
|
||||
public function getLastModified()
|
||||
{
|
||||
return $this->_lastModified;
|
||||
}
|
||||
}
|
16
app/Library/External.php
Normal file
16
app/Library/External.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class External
|
||||
{
|
||||
public static function execute($command)
|
||||
{
|
||||
$output = [];
|
||||
$error = exec($command, $output);
|
||||
|
||||
if ($error != null) {
|
||||
Log::error('"' . $command . '" failed with "' . $error . '"');
|
||||
}
|
||||
}
|
||||
}
|
32
app/Library/File.php
Normal file
32
app/Library/File.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* File
|
||||
*
|
||||
* Note: Remember to remove the "File" alias in APP_DIR/config/application.php
|
||||
*
|
||||
* @author Phill Sparks <me@phills.me.uk>
|
||||
*/
|
||||
class File extends \Illuminate\Support\Facades\File
|
||||
{
|
||||
|
||||
public static function inline($path, $mime, $name = null)
|
||||
{
|
||||
if (is_null($name)) {
|
||||
$name = basename($path);
|
||||
}
|
||||
|
||||
$response = Response::make(static::get($path));
|
||||
|
||||
$response->header('Content-Type', $mime);
|
||||
$response->header('Content-Disposition', 'inline; filename="' . $name . '"');
|
||||
$response->header('Content-Transfer-Encoding', 'binary');
|
||||
$response->header('Expires', 0);
|
||||
$response->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0');
|
||||
$response->header('Pragma', 'public');
|
||||
$response->header('Content-Length', filesize($path));
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
}
|
30
app/Library/Gravatar.php
Normal file
30
app/Library/Gravatar.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\URL;
|
||||
|
||||
class Gravatar
|
||||
{
|
||||
public static function getUrl($email, $size = 80, $default = null, $rating = 'g')
|
||||
{
|
||||
$url = 'https://www.gravatar.com/avatar/';
|
||||
$url .= md5(strtolower(trim($email)));
|
||||
$url .= "?s=$size&r=$rating";
|
||||
|
||||
if ($default != null) {
|
||||
$url .= "&d=" . $default;
|
||||
} else {
|
||||
$size = 'normal';
|
||||
if ($size == 50) {
|
||||
$size = 'thumbnail';
|
||||
} else {
|
||||
if ($size == 100) {
|
||||
$size = 'small';
|
||||
}
|
||||
}
|
||||
|
||||
$url .= "&d=" . urlencode(URL::to('/images/icons/profile_' . $size . '.png'));
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
}
|
60
app/Library/Helpers.php
Normal file
60
app/Library/Helpers.php
Normal file
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
class Helpers
|
||||
{
|
||||
/**
|
||||
* Removes whitespace and special characters from a string
|
||||
* and sets all characters to lower case.
|
||||
*/
|
||||
public static function sanitizeInputForHashing($value)
|
||||
{
|
||||
$value = preg_replace('/[^A-Za-z0-9]/', '', $value);
|
||||
|
||||
return strtolower($value);
|
||||
}
|
||||
|
||||
public static function template($template)
|
||||
{
|
||||
echo file_get_contents('templates/' . $template);
|
||||
}
|
||||
|
||||
public static function angular($expression)
|
||||
{
|
||||
return '{{' . $expression . '}}';
|
||||
}
|
||||
|
||||
public static function formatBytes($bytes, $precision = 2)
|
||||
{
|
||||
if ($bytes == 0) {
|
||||
return '0 MB';
|
||||
}
|
||||
|
||||
$units = array('B', 'KB', 'MB', 'GB', 'TB');
|
||||
|
||||
$bytes = max($bytes, 0);
|
||||
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
|
||||
$pow = min($pow, count($units) - 1);
|
||||
|
||||
$bytes /= pow(1024, $pow);
|
||||
|
||||
return round($bytes, $precision) . ' ' . $units[$pow];
|
||||
}
|
||||
|
||||
/**
|
||||
* timeago-style timestamp generator macro.
|
||||
*
|
||||
* @param string $timestamp A timestamp in SQL DATETIME syntax
|
||||
* @return string
|
||||
*/
|
||||
public static function timestamp($timestamp)
|
||||
{
|
||||
if (gettype($timestamp) !== 'string' && get_class($timestamp) === 'DateTime') {
|
||||
$timestamp = $timestamp->format('c');
|
||||
}
|
||||
|
||||
$title = date('c', strtotime($timestamp));
|
||||
$content = date('F d, o \@ g:i:s a', strtotime($timestamp));
|
||||
|
||||
return '<abbr class="timeago" title="' . $title . '">' . $content . '</abbr>';
|
||||
}
|
||||
}
|
35
app/Library/IpsHasher.php
Normal file
35
app/Library/IpsHasher.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Contracts\Hashing\Hasher;
|
||||
|
||||
class IpsHasher implements Hasher
|
||||
{
|
||||
public function make($value, array $options = array())
|
||||
{
|
||||
return md5(md5($options['salt']) . md5(static::ips_sanitize($value)));
|
||||
}
|
||||
|
||||
public function check($value, $hashedValue, array $options = array())
|
||||
{
|
||||
return static::make($value, ['salt' => $options['salt']]) === $hashedValue;
|
||||
}
|
||||
|
||||
public function needsRehash($hashedValue, array $options = array())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static public function ips_sanitize($value)
|
||||
{
|
||||
$value = str_replace('&', '&', $value);
|
||||
$value = str_replace('\\', '\', $value);
|
||||
$value = str_replace('!', '!', $value);
|
||||
$value = str_replace('$', '$', $value);
|
||||
$value = str_replace('"', '"', $value);
|
||||
$value = str_replace('<', '<', $value);
|
||||
$value = str_replace('>', '>', $value);
|
||||
$value = str_replace('\'', ''', $value);
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
26
app/Library/PFMAuth.php
Normal file
26
app/Library/PFMAuth.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
use Illuminate\Auth\EloquentUserProvider;
|
||||
use Illuminate\Contracts\Hashing\Hasher;
|
||||
|
||||
class NullHasher implements Hasher
|
||||
{
|
||||
public function make($value, array $options = array())
|
||||
{
|
||||
}
|
||||
|
||||
public function check($value, $hashedValue, array $options = array())
|
||||
{
|
||||
}
|
||||
|
||||
public function needsRehash($hashedValue, array $options = array())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class PFMAuth extends EloquentUserProvider
|
||||
{
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct(new NullHasher(), 'App\User');
|
||||
}
|
||||
}
|
158
app/Library/PfmValidator.php
Normal file
158
app/Library/PfmValidator.php
Normal file
|
@ -0,0 +1,158 @@
|
|||
<?php
|
||||
|
||||
class PfmValidator extends Illuminate\Validation\Validator
|
||||
{
|
||||
/**
|
||||
* Determine if a given rule implies that the attribute is required.
|
||||
*
|
||||
* @param string $rule
|
||||
* @return bool
|
||||
*/
|
||||
protected function implicit($rule)
|
||||
{
|
||||
return $rule == 'required' or $rule == 'accepted' or $rule == 'required_with' or $rule == 'required_when';
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the audio format of the file.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param array $value
|
||||
* @param array $parameters
|
||||
* @return bool
|
||||
*/
|
||||
public function validateAudioFormat($attribute, $value, $parameters)
|
||||
{
|
||||
// attribute is the file field
|
||||
// value is the file array itself
|
||||
// parameters is a list of formats the file can be, verified via ffmpeg
|
||||
$file = AudioCache::get($value->getPathname());
|
||||
|
||||
return in_array($file->getAudioCodec(), $parameters);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate the sample rate of the audio file.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param array $value
|
||||
* @param array $parameters
|
||||
* @return bool
|
||||
*/
|
||||
public function validateSampleRate($attribute, $value, $parameters)
|
||||
{
|
||||
// attribute is the file field
|
||||
// value is the file array itself
|
||||
// parameters is a list of sample rates the file can be, verified via ffmpeg
|
||||
$file = AudioCache::get($value->getPathname());
|
||||
|
||||
return in_array($file->getAudioSampleRate(), $parameters);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate the number of channels in the audio file.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param array $value
|
||||
* @param array $parameters
|
||||
* @return bool
|
||||
*/
|
||||
public function validateAudioChannels($attribute, $value, $parameters)
|
||||
{
|
||||
// attribute is the file field
|
||||
// value is the file array itself
|
||||
// parameters is a list of sample rates the file can be, verified via ffmpeg
|
||||
$file = AudioCache::get($value->getPathname());
|
||||
|
||||
return in_array($file->getAudioChannels(), $parameters);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate the bit rate of the audio file.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param array $value
|
||||
* @param array $parameters
|
||||
* @return bool
|
||||
*/
|
||||
public function validateAudioBitrate($attribute, $value, $parameters)
|
||||
{
|
||||
// attribute is the file field
|
||||
// value is the file array itself
|
||||
// parameters is a list of sample rates the file can be, verified via ffmpeg
|
||||
$file = AudioCache::get($value->getPathname());
|
||||
|
||||
return in_array($file->getAudioBitRate(), $parameters);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate the duration of the audio file, in seconds.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param array $value
|
||||
* @param array $parameters
|
||||
* @return bool
|
||||
*/
|
||||
public function validateMinDuration($attribute, $value, $parameters)
|
||||
{
|
||||
// attribute is the file field
|
||||
// value is the file array itself
|
||||
// parameters is an array containing one value: the minimum duration
|
||||
$file = AudioCache::get($value->getPathname());
|
||||
|
||||
return $file->getDuration() >= (float)$parameters[0];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Require a field when the value of another field matches a certain value.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param array $value
|
||||
* @param array $parameters
|
||||
* @return bool
|
||||
*/
|
||||
/** OLD CODE
|
||||
* public function validate_required_when($attribute, $value, $parameters)
|
||||
* {
|
||||
* if ( Input::get($parameters[0]) === $parameters[1] && static::required($attribute, $value) ){
|
||||
* return true;
|
||||
*
|
||||
* } else {
|
||||
* return false;
|
||||
* }
|
||||
* }
|
||||
**/
|
||||
|
||||
// custom required_when validator
|
||||
public function validateRequiredWhen($attribute, $value, $parameters)
|
||||
{
|
||||
if (Input::get($parameters[0]) == $parameters[1]) {
|
||||
return $this->validate_required($attribute, $value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// custom image width validator
|
||||
public function validateMinWidth($attribute, $value, $parameters)
|
||||
{
|
||||
return getimagesize($value->getPathname())[0] >= $parameters[0];
|
||||
}
|
||||
|
||||
// custom image height validator
|
||||
public function validateMinHeight($attribute, $value, $parameters)
|
||||
{
|
||||
return getimagesize($value->getPathname())[1] >= $parameters[0];
|
||||
}
|
||||
|
||||
public function validateTextareaLength($attribute, $value, $parameters)
|
||||
{
|
||||
return strlen(str_replace("\r\n", "\n", $value)) <= $parameters[0];
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue