diff --git a/app/Facades/ITunes.php b/app/Facades/ITunes.php index 4ddca683..8240fb49 100644 --- a/app/Facades/ITunes.php +++ b/app/Facades/ITunes.php @@ -4,6 +4,9 @@ namespace App\Facades; use Illuminate\Support\Facades\Facade; +/** + * @method static bool used() + */ class ITunes extends Facade { protected static function getFacadeAccessor(): string diff --git a/app/Http/Controllers/API/DataController.php b/app/Http/Controllers/API/DataController.php index 7d71788c..e75c2499 100644 --- a/app/Http/Controllers/API/DataController.php +++ b/app/Http/Controllers/API/DataController.php @@ -41,7 +41,7 @@ class DataController extends Controller InteractionRepository $interactionRepository, UserRepository $userRepository, ApplicationInformationService $applicationInformationService, - Authenticatable $currentUser + ?Authenticatable $currentUser ) { $this->lastfmService = $lastfmService; $this->youTubeService = $youTubeService; diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 8957ed61..c311d011 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -7,58 +7,21 @@ use Illuminate\Support\Facades\Route; class RouteServiceProvider extends ServiceProvider { - /** - * This namespace is applied to the controller routes in your routes file. - * - * In addition, it is set as the URL generator's root namespace. - * - * @var string - */ protected $namespace = 'App\Http\Controllers'; - /** - * Define your route model bindings, pattern filters, etc. - * - */ - public function boot(): void - { - parent::boot(); - } - - /** - * Define the routes for the application. - * - */ public function map(): void { $this->mapApiRoutes(); $this->mapWebRoutes(); } - /** - * Define the "web" routes for the application. - * - * These routes all receive session state, CSRF protection, etc. - * - */ protected function mapWebRoutes(): void { - Route::middleware('web') - ->namespace($this->namespace) - ->group(base_path('routes/web.php')); + Route::middleware('web')->group(base_path('routes/web.php')); } - /** - * Define the "api" routes for the application. - * - * These routes are typically stateless. - * - */ protected function mapApiRoutes(): void { - Route::prefix('api') - ->middleware('api') - ->namespace($this->namespace) - ->group(base_path('routes/api.php')); + Route::prefix('api')->middleware('api')->group(base_path('routes/api.php')); } } diff --git a/routes/api.php b/routes/api.php index 6467a00a..9a84c7f5 100644 --- a/routes/api.php +++ b/routes/api.php @@ -1,101 +1,113 @@ 'API'], static function (): void { - Route::post('me', 'AuthController@login')->name('auth.login'); - Route::delete('me', 'AuthController@logout'); +Route::post('me', [AuthController::class, 'login'])->name('auth.login'); +Route::delete('me', [AuthController::class, 'logout']); - Route::group(['middleware' => 'auth'], static function (): void { - Route::get('/ping', static function (): void { - // Only acting as a ping service. - }); +Route::middleware('auth')->group(static function (): void { + Route::get('ping', static fn () => null); - Route::post('broadcasting/auth', static function (Request $request) { - $pusher = new Pusher\Pusher( - config('broadcasting.connections.pusher.key'), - config('broadcasting.connections.pusher.secret'), - config('broadcasting.connections.pusher.app_id'), - [ - 'cluster' => config('broadcasting.connections.pusher.options.cluster'), - 'encrypted' => true, - ] - ); + Route::post('broadcasting/auth', static function (Request $request) { + $pusher = new Pusher( + config('broadcasting.connections.pusher.key'), + config('broadcasting.connections.pusher.secret'), + config('broadcasting.connections.pusher.app_id'), + [ + 'cluster' => config('broadcasting.connections.pusher.options.cluster'), + 'encrypted' => true, + ] + ); - return $pusher->socket_auth($request->channel_name, $request->socket_id); - })->name('broadcasting.auth'); + return $pusher->socket_auth($request->channel_name, $request->socket_id); + })->name('broadcasting.auth'); - Route::get('data', 'DataController@index'); + Route::get('data', [DataController::class, 'index']); - Route::post('settings', 'SettingController@store'); + Route::post('settings', [SettingController::class, 'store']); - Route::post('{song}/scrobble', 'ScrobbleController@store'); - Route::put('songs', 'SongController@update'); + Route::post('{song}/scrobble', [ScrobbleController::class, 'store']); + Route::put('songs', [SongController::class, 'update']); - Route::resource('upload', 'UploadController'); + Route::apiResource('upload', UploadController::class)->only('store'); - // Interaction routes - Route::post('interaction/play', 'Interaction\PlayCountController@store'); - Route::post('interaction/like', 'Interaction\LikeController@store'); - Route::post('interaction/batch/like', 'Interaction\BatchLikeController@store'); - Route::post('interaction/batch/unlike', 'Interaction\BatchLikeController@destroy'); - Route::get('interaction/recently-played/{count?}', 'Interaction\RecentlyPlayedController@index')->where([ - 'count' => '\d+', - ]); + // Interaction routes + Route::post('interaction/play', [PlayCountController::class, 'store']); + Route::post('interaction/like', [LikeController::class, 'store']); + Route::post('interaction/batch/like', [BatchLikeController::class, 'store']); + Route::post('interaction/batch/unlike', [BatchLikeController::class, 'destroy']); + Route::get('interaction/recently-played/{count?}', [RecentlyPlayedController::class, 'index'])->where([ + 'count' => '\d+', + ]); - // Playlist routes - Route::apiResource('playlist', 'PlaylistController'); + // Playlist routes + Route::apiResource('playlist', PlaylistController::class); - Route::put('playlist/{playlist}/sync', 'PlaylistSongController@update'); + Route::put('playlist/{playlist}/sync', [PlaylistSongController::class, 'update']); // @deprecated + Route::put('playlist/{playlist}/songs', [PlaylistSongController::class, 'update']); + Route::get('playlist/{playlist}/songs', [PlaylistSongController::class, 'index']); - Route::apiResource('playlist.songs', 'PlaylistSongController')->only('index', 'update'); - Route::put('playlist/{playlist}/songs', 'PlaylistSongController@update'); - Route::get('playlist/{playlist}/songs', 'PlaylistSongController@index'); + // User and user profile routes + Route::apiResource('user', UserController::class)->only('store', 'update', 'destroy'); + Route::get('me', [ProfileController::class, 'show']); + Route::put('me', [ProfileController::class, 'update']); - // User and user profile routes - Route::resource('user', 'UserController', ['only' => ['store', 'update', 'destroy']]); - Route::get('me', 'ProfileController@show'); - Route::put('me', 'ProfileController@update'); + // Last.fm-related routes + Route::post('lastfm/session-key', [LastfmController::class, 'setSessionKey']); + Route::delete('lastfm/disconnect', [LastfmController::class, 'disconnect'])->name('lastfm.disconnect'); - // Last.fm-related routes - Route::post('lastfm/session-key', 'LastfmController@setSessionKey'); - Route::delete('lastfm/disconnect', 'LastfmController@disconnect')->name('lastfm.disconnect'); + // YouTube-related routes + if (YouTube::enabled()) { + Route::get('youtube/search/song/{song}', [YouTubeController::class, 'searchVideosRelatedToSong']); + } - // YouTube-related routes - if (YouTube::enabled()) { - Route::get('youtube/search/song/{song}', 'YouTubeController@searchVideosRelatedToSong'); - } + // Media information routes + Route::get('album/{album}/info', [AlbumInformationController::class, 'show']); + Route::get('artist/{artist}/info', [ArtistInformationController::class, 'show']); + Route::get('song/{song}/info', [SongInformationController::class, 'show']); - // Info routes - Route::group(['namespace' => 'MediaInformation'], static function (): void { - Route::get('album/{album}/info', 'AlbumController@show'); - Route::get('artist/{artist}/info', 'ArtistController@show'); - Route::get('{song}/info', 'SongController@show')->name('song.show.deprecated'); // backward compat - Route::get('song/{song}/info', 'SongController@show'); - }); + // Cover/image upload routes + Route::put('album/{album}/cover', [AlbumCoverController::class, 'update']); + Route::put('artist/{artist}/image', [ArtistImageController::class, 'update']); + Route::get('album/{album}/thumbnail', [AlbumThumbnailController::class, 'show']); - // Cover/image upload routes - Route::put('album/{album}/cover', 'AlbumCoverController@update'); - Route::put('artist/{artist}/image', 'ArtistImageController@update'); - - Route::get('album/{album}/thumbnail', 'AlbumThumbnailController@show'); - - Route::group(['namespace' => 'Search', 'prefix' => 'search'], static function (): void { - Route::get('/', 'ExcerptSearchController@index'); - Route::get('songs', 'SongSearchController@index'); - }); - }); - - Route::group([ - 'middleware' => 'os.auth', - 'prefix' => 'os', - 'namespace' => 'ObjectStorage', - ], static function (): void { - Route::group(['prefix' => 's3', 'namespace' => 'S3'], static function (): void { - Route::post('song', 'SongController@put')->name('s3.song.put'); // we follow AWS's convention here. - Route::delete('song', 'SongController@remove')->name('s3.song.remove'); // and here. - }); + // Search routes + Route::prefix('search')->group(static function (): void { + Route::get('/', [ExcerptSearchController::class, 'index']); + Route::get('songs', [SongSearchController::class, 'index']); }); }); + +// Object-storage (S3) routes +Route::middleware('os.auth')->prefix('os/s3')->group(static function (): void { + Route::post('song', [S3SongController::class, 'put'])->name('s3.song.put'); // we follow AWS's convention here. + Route::delete('song', [S3SongController::class, 'remove'])->name('s3.song.remove'); // and here. +}); diff --git a/routes/web.php b/routes/web.php index ec4f4464..e82d8dad 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,30 +1,37 @@ view('index')); -Route::get('/remote', static fn () => view('remote')); +Route::get('remote', static fn () => view('remote')); -Route::group(['middleware' => 'auth'], static function (): void { - Route::get('play/{song}/{transcode?}/{bitrate?}', 'PlayController@show') - ->name('song.play'); +Route::middleware('auth')->group(static function (): void { + Route::get('play/{song}/{transcode?}/{bitrate?}', [PlayController::class, 'show'])->name('song.play'); - Route::group(['prefix' => 'lastfm'], static function (): void { - Route::get('connect', 'LastfmController@connect')->name('lastfm.connect'); - Route::get('callback', 'LastfmController@callback')->name('lastfm.callback'); + Route::prefix('lastfm')->group(static function (): void { + Route::get('connect', [LastfmController::class, 'connect'])->name('lastfm.connect'); + Route::get('callback', [LastfmController::class, 'callback'])->name('lastfm.callback'); }); if (ITunes::used()) { - Route::get('itunes/song/{album}', 'ITunesController@viewSong')->name('iTunes.viewSong'); + Route::get('itunes/song/{album}', [ITunesController::class, 'viewSong'])->name('iTunes.viewSong'); } - Route::group(['prefix' => 'download', 'namespace' => 'Download'], static function (): void { - Route::get('songs', 'SongController@show'); - Route::get('album/{album}', 'AlbumController@show'); - Route::get('artist/{artist}', 'ArtistController@show'); - Route::get('playlist/{playlist}', 'PlaylistController@show'); - Route::get('favorites', 'FavoritesController@show'); + Route::prefix('download')->group(static function (): void { + Route::get('songs', [SongDownloadController::class, 'show']); + Route::get('album/{album}', [AlbumDownloadController::class, 'show']); + Route::get('artist/{artist}', [ArtistDownloadController::class, 'show']); + Route::get('playlist/{playlist}', [PlaylistDownloadController::class, 'show']); + Route::get('favorites', [FavoritesDownloadController::class, 'show']); }); }); diff --git a/tests/Feature/PlaylistSongTest.php b/tests/Feature/PlaylistSongTest.php index b5645b33..72a7244d 100644 --- a/tests/Feature/PlaylistSongTest.php +++ b/tests/Feature/PlaylistSongTest.php @@ -48,7 +48,7 @@ class PlaylistSongTest extends TestCase $this->putAsUser($path, [ 'songs' => $songs->pluck('id')->all(), - ], $user); + ], $user)->assertOk(); // We should still see the first 3 songs, but not the removed one foreach ($songs as $song) {