diff --git a/app/controllers/Api/V1/TracksController.php b/app/controllers/Api/V1/TracksController.php new file mode 100644 index 00000000..ae989272 --- /dev/null +++ b/app/controllers/Api/V1/TracksController.php @@ -0,0 +1,92 @@ +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, + 'user' => [ + 'id' => $track->user->id, + 'name' => $track->user->display_name, + 'url' => $track->user->url, + 'avatars' => [ + 'thumbnail' => $track->user->getAvatarUrl(Image::THUMBNAIL), + 'small' => $track->user->getAvatarUrl(Image::SMALL), + 'normal' => $track->user->getAvatarUrl(Image::NORMAL) + ] + ], + 'stats' => [ + 'views' => $track->view_count, + 'plays' => $track->play_count, + 'downloads' => $track->download_count, + 'comments' => $track->comment_count, + 'favourites' => $track->favourite_count + ], + 'url' => $track->url, + 'is_vocal' => !!$track->is_vocal, + 'is_explicit' => !!$track->is_explicit, + 'is_downloadable' => !!$track->is_downloadable, + 'published_at' => $track->published_at, + 'duration' => $track->duration, + 'genre' => $track->genre != null + ? + [ + 'id' => $track->genre->id, + 'name' => $track->genre->name + ] : null, + 'type' => [ + 'id' => $track->track_type->id, + 'name' => $track->track_type->title + ], + 'covers' => [ + 'thumbnail' => $track->getCoverUrl(Image::THUMBNAIL), + 'small' => $track->getCoverUrl(Image::SMALL), + 'normal' => $track->getCoverUrl(Image::NORMAL) + ], + 'comments' => $comments + ], 200); + } + } \ No newline at end of file diff --git a/app/database/migrations/2013_09_23_031316_create_track_hashes.php b/app/database/migrations/2013_09_23_031316_create_track_hashes.php new file mode 100644 index 00000000..88da6afa --- /dev/null +++ b/app/database/migrations/2013_09_23_031316_create_track_hashes.php @@ -0,0 +1,23 @@ +string('hash', 32)->notNullable()->indexed(); + }); + + foreach (Track::with('user')->get() as $track) { + $track->updateHash(); + $track->save(); + } + } + + public function down() { + Schema::table('tracks', function($table) { + $table->dropColumn('hash'); + }); + } +} \ No newline at end of file diff --git a/app/library/Helpers.php b/app/library/Helpers.php index 771cb787..cd2eee46 100644 --- a/app/library/Helpers.php +++ b/app/library/Helpers.php @@ -1,6 +1,15 @@ ['index' => 0, 'extension' => 'flac', 'tag_format' => 'metaflac', 'tag_method' => 'updateTagsWithGetId3', 'mime_type' => 'audio/flac', 'command' => 'ffmpeg 2>&1 -y -i {$source} -acodec flac -aq 8 -f flac {$target}'], @@ -257,6 +259,10 @@ return $this->belongsTo('Entities\Genre'); } + public function trackType() { + return $this->belongsTo('Entities\TrackType', 'track_type_id'); + } + public function comments(){ return $this->hasMany('Entities\Comment')->orderBy('created_at', 'desc'); } @@ -289,6 +295,11 @@ return date('Y', strtotime($this->release_date)); } + public function setTitleAttribute($value) { + $this->setTitleAttributeSlug($value);; + $this->updateHash(); + } + public function getFilesize($formatName) { return Cache::remember($this->getCacheKey('filesize-' . $formatName), 1440, function () use ($formatName) { $file = $this->getFileFor($formatName); @@ -401,6 +412,10 @@ return URL::to('/t' . $this->id . '/dl.' . $format['extension']); } + public function updateHash() { + $this->hash = md5(Helpers::sanitizeInputForHashing($this->user->display_name) . '-' . Helpers::sanitizeInputForHashing($this->title)); + } + public function updateTags() { foreach (self::$Formats as $format => $data) { $this->{$data['tag_method']}($format); diff --git a/app/routes.php b/app/routes.php index 203ac3f5..be0dc69c 100644 --- a/app/routes.php +++ b/app/routes.php @@ -49,6 +49,10 @@ 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::group(['prefix' => 'api/web'], function() { Route::get('/taxonomies/all', 'Api\Web\TaxonomiesController@getAll'); diff --git a/bootstrap/compiled.php b/bootstrap/compiled.php index cb73d68f..2079b47f 100644 --- a/bootstrap/compiled.php +++ b/bootstrap/compiled.php @@ -302,7 +302,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpFoundation\RedirectResponse as SymfonyRedirect; class Application extends Container implements HttpKernelInterface, ResponsePreparerInterface { - const VERSION = '4.0.6'; + const VERSION = '4.0.7'; protected $booted = false; protected $bootingCallbacks = array(); protected $bootedCallbacks = array(); @@ -949,11 +949,19 @@ class Request $query = $parameters; break; } + $queryString = ''; if (isset($components['query'])) { parse_str(html_entity_decode($components['query']), $qs); - $query = array_replace($qs, $query); + if ($query) { + $query = array_replace($qs, $query); + $queryString = http_build_query($query, '', '&'); + } else { + $query = $qs; + $queryString = $components['query']; + } + } elseif ($query) { + $queryString = http_build_query($query, '', '&'); } - $queryString = http_build_query($query, '', '&'); $server['REQUEST_URI'] = $components['path'] . ('' !== $queryString ? '?' . $queryString : ''); $server['QUERY_STRING'] = $queryString; return new static($query, $request, array(), $cookies, $files, $server, $content); @@ -989,8 +997,11 @@ class Request $dup->basePath = null; $dup->method = null; $dup->format = null; - if (!$dup->get('_format')) { - $dup->setRequestFormat($this->getRequestFormat()); + if (!$dup->get('_format') && $this->get('_format')) { + $dup->attributes->set('_format', $this->get('_format')); + } + if (!$dup->getRequestFormat(null)) { + $dup->setRequestFormat($format = $this->getRequestFormat(null)); } return $dup; } @@ -1176,6 +1187,12 @@ class Request return 443; } } + if ($host = $this->headers->get('HOST')) { + if (false !== ($pos = strrpos($host, ':'))) { + return intval(substr($host, $pos + 1)); + } + return 'https' === $this->getScheme() ? 443 : 80; + } return $this->server->get('SERVER_PORT'); } public function getUser() @@ -1509,14 +1526,14 @@ class Request return rtrim($prefix, '/'); } $truncatedRequestUri = $requestUri; - if (($pos = strpos($requestUri, '?')) !== false) { + if (false !== ($pos = strpos($requestUri, '?'))) { $truncatedRequestUri = substr($requestUri, 0, $pos); } $basename = basename($baseUrl); if (empty($basename) || !strpos(rawurldecode($truncatedRequestUri), $basename)) { return ''; } - if (strlen($requestUri) >= strlen($baseUrl) && (false !== ($pos = strpos($requestUri, $baseUrl)) && $pos !== 0)) { + if (strlen($requestUri) >= strlen($baseUrl) && false !== ($pos = strpos($requestUri, $baseUrl)) && $pos !== 0) { $baseUrl = substr($requestUri, 0, $pos + strlen($baseUrl)); } return rtrim($baseUrl, '/'); @@ -1787,15 +1804,22 @@ class ServerBag extends ParameterBag } elseif (isset($this->parameters['REDIRECT_HTTP_AUTHORIZATION'])) { $authorizationHeader = $this->parameters['REDIRECT_HTTP_AUTHORIZATION']; } - if (null !== $authorizationHeader && 0 === stripos($authorizationHeader, 'basic')) { - $exploded = explode(':', base64_decode(substr($authorizationHeader, 6))); - if (count($exploded) == 2) { - list($headers['PHP_AUTH_USER'], $headers['PHP_AUTH_PW']) = $exploded; + if (null !== $authorizationHeader) { + if (0 === stripos($authorizationHeader, 'basic')) { + $exploded = explode(':', base64_decode(substr($authorizationHeader, 6))); + if (count($exploded) == 2) { + list($headers['PHP_AUTH_USER'], $headers['PHP_AUTH_PW']) = $exploded; + } + } elseif (empty($this->parameters['PHP_AUTH_DIGEST']) && 0 === stripos($authorizationHeader, 'digest')) { + $headers['PHP_AUTH_DIGEST'] = $authorizationHeader; + $this->parameters['PHP_AUTH_DIGEST'] = $authorizationHeader; } } } if (isset($headers['PHP_AUTH_USER'])) { $headers['AUTHORIZATION'] = 'Basic ' . base64_encode($headers['PHP_AUTH_USER'] . ':' . $headers['PHP_AUTH_PW']); + } elseif (isset($headers['PHP_AUTH_DIGEST'])) { + $headers['AUTHORIZATION'] = $headers['PHP_AUTH_DIGEST']; } return $headers; } @@ -2225,6 +2249,7 @@ class NativeSessionStorage implements SessionStorageInterface } else { session_start(); } + $this->loadSession(); } return $ret; } @@ -3257,8 +3282,7 @@ class ExceptionServiceProvider extends ServiceProvider } protected function getResourcePath() { - $base = $this->app['path.base']; - return $base . '/vendor/laravel/framework/src/Illuminate/Exception/resources'; + return 'F:\\Nelson\\My Documents - Personal\\Visual Studio 2010\\Projects\\Poniverse\\spa.pony.fm\\vendor\\laravel\\framework\\src\\Illuminate\\Exception' . '/resources'; } } namespace Illuminate\Routing; @@ -3611,7 +3635,7 @@ class ErrorHandler if (null === ($error = error_get_last())) { return; } - unset($this->reservedMemory); + $this->reservedMemory = ''; $type = $error['type']; if (0 === $this->level || !in_array($type, array(E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE))) { return; @@ -4218,10 +4242,6 @@ class ProviderRepository $this->files->put($path, json_encode($manifest)); return $manifest; } - protected function getManifestPath($app) - { - return $this->manifestPath; - } protected function freshManifest(array $providers) { list($eager, $deferred) = array(array(), array()); @@ -5381,6 +5401,7 @@ abstract class Model implements ArrayAccess, ArrayableInterface, JsonableInterfa protected $appends = array(); protected $fillable = array(); protected $guarded = array('*'); + protected $dates = array(); protected $touches = array(); protected $with = array(); public $exists = false; @@ -5853,7 +5874,7 @@ abstract class Model implements ArrayAccess, ArrayableInterface, JsonableInterfa } public function freshTimestamp() { - return new DateTime(); + return new Carbon(); } public function freshTimestampString() { @@ -6153,7 +6174,8 @@ abstract class Model implements ArrayAccess, ArrayableInterface, JsonableInterfa } public function getDates() { - return array(static::CREATED_AT, static::UPDATED_AT, static::DELETED_AT); + $defaults = array(static::CREATED_AT, static::UPDATED_AT, static::DELETED_AT); + return array_merge($this->dates, $defaults); } public function fromDateTime($value) { @@ -6590,7 +6612,7 @@ class Store extends SymfonySession } protected function mergeNewFlashes(array $keys) { - $values = array_unique(array_merge($this->get('flash.new'), $keys)); + $values = array_unique(array_merge($this->get('flash.new', array()), $keys)); $this->put('flash.new', $values); } protected function removeFromOldFlashData(array $keys)