mirror of
https://github.com/koel/koel
synced 2024-11-24 05:03:05 +00:00
chore: some cleanups
This commit is contained in:
parent
2240fc0b80
commit
e3bbf4ab4b
10 changed files with 60 additions and 70 deletions
|
@ -14,7 +14,7 @@ class ScrobbleController extends Controller
|
|||
/** @param User $user */
|
||||
public function __invoke(ScrobbleRequest $request, Song $song, Authenticatable $user)
|
||||
{
|
||||
if (!$song->artist->is_unknown && $user->connectedToLastfm()) {
|
||||
if (!$song->artist->is_unknown && $user->connected_to_lastfm) {
|
||||
ScrobbleJob::dispatch($user, $song, $request->timestamp);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ namespace App\Models;
|
|||
|
||||
use App\Casts\SmartPlaylistRulesCast;
|
||||
use App\Facades\License as LicenseFacade;
|
||||
use App\Models\Song as Playable;
|
||||
use App\Values\SmartPlaylistRuleGroupCollection;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
|
@ -16,7 +17,6 @@ use Illuminate\Support\Arr;
|
|||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Scout\Searchable;
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* @property string $id
|
||||
|
@ -24,8 +24,7 @@ use LogicException;
|
|||
* @property bool $is_smart
|
||||
* @property int $user_id
|
||||
* @property User $user
|
||||
* @property Collection<array-key, Song> $songs
|
||||
* @property array<string> $song_ids
|
||||
* @property Collection<array-key, Playable> $playables
|
||||
* @property ?SmartPlaylistRuleGroupCollection $rule_groups
|
||||
* @property ?SmartPlaylistRuleGroupCollection $rules
|
||||
* @property Carbon $created_at
|
||||
|
@ -61,9 +60,9 @@ class Playlist extends Model
|
|||
});
|
||||
}
|
||||
|
||||
public function songs(): BelongsToMany
|
||||
public function playables(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Song::class)
|
||||
return $this->belongsToMany(Playable::class)
|
||||
->withTimestamps()
|
||||
->withPivot('position')
|
||||
->orderByPivot('position');
|
||||
|
@ -100,13 +99,6 @@ class Playlist extends Model
|
|||
return Attribute::get(fn () => $this->rules);
|
||||
}
|
||||
|
||||
public function songIds(): Attribute
|
||||
{
|
||||
throw_if($this->is_smart, new LogicException('Smart playlist contents are generated dynamically.'));
|
||||
|
||||
return Attribute::get(fn () => $this->songs->pluck('id')->all());
|
||||
}
|
||||
|
||||
protected function cover(): Attribute
|
||||
{
|
||||
return Attribute::get(static fn (?string $value): ?string => playlist_cover_url($value));
|
||||
|
@ -156,39 +148,39 @@ class Playlist extends Model
|
|||
}
|
||||
|
||||
/**
|
||||
* @param Collection|array<array-key, Song>|Song|array<string> $songs
|
||||
* @param Collection|array<array-key, Playable>|Playable|array<string> $playables
|
||||
*/
|
||||
public function addPlayables(Collection|Song|array $songs, ?User $collaborator = null): void
|
||||
public function addPlayables(Collection|Playable|array $playables, ?User $collaborator = null): void
|
||||
{
|
||||
$collaborator ??= $this->user;
|
||||
$maxPosition = $this->songs()->getQuery()->max('position') ?? 0;
|
||||
$maxPosition = $this->playables()->getQuery()->max('position') ?? 0;
|
||||
|
||||
if (!is_array($songs)) {
|
||||
$songs = Collection::wrap($songs)->pluck('id')->all();
|
||||
if (!is_array($playables)) {
|
||||
$playables = Collection::wrap($playables)->pluck('id')->all();
|
||||
}
|
||||
|
||||
$data = [];
|
||||
|
||||
foreach ($songs as $song) {
|
||||
$data[$song] = [
|
||||
foreach ($playables as $playable) {
|
||||
$data[$playable] = [
|
||||
'position' => ++$maxPosition,
|
||||
'user_id' => $collaborator->id,
|
||||
];
|
||||
}
|
||||
|
||||
$this->songs()->attach($data);
|
||||
$this->playables()->attach($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection<array-key, Song>|Song|array<string> $songs
|
||||
* @param Collection<array-key, Playable>|Playable|array<string> $playables
|
||||
*/
|
||||
public function removePlayables(Collection|Song|array $songs): void
|
||||
public function removePlayables(Collection|Playable|array $playables): void
|
||||
{
|
||||
if (!is_array($songs)) {
|
||||
$songs = Collection::wrap($songs)->pluck('id')->all();
|
||||
if (!is_array($playables)) {
|
||||
$playables = Collection::wrap($playables)->pluck('id')->all();
|
||||
}
|
||||
|
||||
$this->songs()->detach($songs);
|
||||
$this->playables()->detach($playables);
|
||||
}
|
||||
|
||||
protected function isCollaborative(): Attribute
|
||||
|
|
|
@ -20,27 +20,28 @@ use Laravel\Sanctum\HasApiTokens;
|
|||
use Laravel\Sanctum\PersonalAccessToken;
|
||||
|
||||
/**
|
||||
* @property UserPreferences $preferences
|
||||
* @property int $id
|
||||
* @property bool $is_admin
|
||||
* @property string $name
|
||||
* @property string $email
|
||||
* @property string $password
|
||||
* @property-read bool $has_custom_avatar
|
||||
* @property-read string $avatar
|
||||
* @property Collection<array-key, Playlist> $playlists
|
||||
* @property Collection<array-key, PlaylistFolder> $playlist_folders
|
||||
* @property PersonalAccessToken $currentAccessToken
|
||||
* @property ?Carbon $invitation_accepted_at
|
||||
* @property ?Carbon $invited_at
|
||||
* @property ?User $invitedBy
|
||||
* @property ?string $invitation_token
|
||||
* @property ?Carbon $invited_at
|
||||
* @property-read bool $is_prospect
|
||||
* @property Collection<array-key, Playlist> $collaboratedPlaylists
|
||||
* @property ?string $sso_provider
|
||||
* @property ?string $sso_id
|
||||
* @property bool $is_sso
|
||||
* @property Collection<array-key, Playlist> $playlists
|
||||
* @property Collection<array-key, PlaylistFolder> $playlist_folders
|
||||
* @property Collection<array-key, Podcast> $podcasts
|
||||
* @property PersonalAccessToken $currentAccessToken
|
||||
* @property UserPreferences $preferences
|
||||
* @property bool $is_admin
|
||||
* @property int $id
|
||||
* @property string $email
|
||||
* @property string $name
|
||||
* @property string $password
|
||||
* @property-read ?string $sso_id
|
||||
* @property-read ?string $sso_provider
|
||||
* @property-read bool $connected_to_lastfm Whether the user is connected to Last.fm
|
||||
* @property-read bool $has_custom_avatar
|
||||
* @property-read bool $is_prospect
|
||||
* @property-read bool $is_sso
|
||||
* @property-read string $avatar
|
||||
*/
|
||||
class User extends Authenticatable
|
||||
{
|
||||
|
@ -126,11 +127,8 @@ class User extends Authenticatable
|
|||
return Attribute::get(fn (): bool => License::isPlus() && $this->sso_provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the user is connected to Last.fm.
|
||||
*/
|
||||
public function connectedToLastfm(): bool
|
||||
protected function connectedToLastfm(): Attribute
|
||||
{
|
||||
return (bool) $this->preferences->lastFmSessionKey;
|
||||
return Attribute::get(fn (): bool => (bool) $this->preferences->lastFmSessionKey);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ class PlaylistCollaborationService
|
|||
|
||||
DB::transaction(static function () use ($playlist, $user): void {
|
||||
$playlist->collaborators()->detach($user);
|
||||
$playlist->songs()->wherePivot('user_id', $user->id)->detach();
|
||||
$playlist->playables()->wherePivot('user_id', $user->id)->detach();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,7 +95,7 @@ class PlaylistService
|
|||
$playables = Collection::wrap($playables);
|
||||
|
||||
$playlist->addPlayables(
|
||||
$playables->filter(static fn ($song): bool => !$playlist->songs->contains($song)),
|
||||
$playables->filter(static fn ($song): bool => !$playlist->playables->contains($song)),
|
||||
$user
|
||||
);
|
||||
|
||||
|
@ -119,7 +119,7 @@ class PlaylistService
|
|||
|
||||
public function makePlaylistContentPublic(Playlist $playlist): void
|
||||
{
|
||||
$playlist->songs()->where('is_public', false)->update(['is_public' => true]);
|
||||
$playlist->playables()->where('is_public', false)->update(['is_public' => true]);
|
||||
}
|
||||
|
||||
public function movePlayablesInPlaylist(Playlist $playlist, array $movingIds, string $target, string $type): void
|
||||
|
@ -128,11 +128,11 @@ class PlaylistService
|
|||
throw_if($playlist->is_smart, OperationNotApplicableForSmartPlaylistException::class);
|
||||
|
||||
DB::transaction(static function () use ($playlist, $movingIds, $target, $type): void {
|
||||
$targetPosition = $playlist->songs()->wherePivot('song_id', $target)->value('position');
|
||||
$targetPosition = $playlist->playables()->wherePivot('song_id', $target)->value('position');
|
||||
$insertPosition = $type === 'before' ? $targetPosition : $targetPosition + 1;
|
||||
|
||||
// create a "gap" for the moving songs by incrementing the position of the songs after the target
|
||||
$playlist->songs()
|
||||
$playlist->playables()
|
||||
->newPivotQuery()
|
||||
->where('position', $type === 'before' ? '>=' : '>', $targetPosition)
|
||||
->whereNotIn('song_id', $movingIds)
|
||||
|
@ -144,7 +144,7 @@ class PlaylistService
|
|||
$values[$id] = ['position' => $insertPosition++];
|
||||
}
|
||||
|
||||
$playlist->songs()->syncWithoutDetaching($values);
|
||||
$playlist->playables()->syncWithoutDetaching($values);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ class PlaylistSongTest extends PlusTestCase
|
|||
->assertSuccessful();
|
||||
|
||||
$playlist->refresh();
|
||||
$songs->each(static fn (Song $song) => self::assertTrue($playlist->songs->contains($song)));
|
||||
$songs->each(static fn (Song $song) => self::assertTrue($playlist->playables->contains($song)));
|
||||
}
|
||||
|
||||
public function testCollaboratorCanRemoveSongs(): void
|
||||
|
@ -74,6 +74,6 @@ class PlaylistSongTest extends PlusTestCase
|
|||
->assertSuccessful();
|
||||
|
||||
$playlist->refresh();
|
||||
$songs->each(static fn (Song $song) => self::assertFalse($playlist->songs->contains($song)));
|
||||
$songs->each(static fn (Song $song) => self::assertFalse($playlist->playables->contains($song)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ class PlaylistSongTest extends TestCase
|
|||
$this->postAs("api/playlists/$playlist->id/songs", ['songs' => $songs->pluck('id')->all()], $playlist->user)
|
||||
->assertSuccessful();
|
||||
|
||||
self::assertEqualsCanonicalizing($songs->pluck('id')->all(), $playlist->songs->pluck('id')->all());
|
||||
self::assertEqualsCanonicalizing($songs->pluck('id')->all(), $playlist->playables->pluck('id')->all());
|
||||
}
|
||||
|
||||
public function testRemoveSongsFromPlaylist(): void
|
||||
|
@ -83,7 +83,7 @@ class PlaylistSongTest extends TestCase
|
|||
|
||||
$playlist->addPlayables($toRemainSongs->merge($toBeRemovedSongs));
|
||||
|
||||
self::assertCount(7, $playlist->songs);
|
||||
self::assertCount(7, $playlist->playables);
|
||||
|
||||
$this->deleteAs(
|
||||
"api/playlists/$playlist->id/songs",
|
||||
|
@ -94,7 +94,7 @@ class PlaylistSongTest extends TestCase
|
|||
|
||||
$playlist->refresh();
|
||||
|
||||
self::assertEqualsCanonicalizing($toRemainSongs->pluck('id')->all(), $playlist->songs->pluck('id')->all());
|
||||
self::assertEqualsCanonicalizing($toRemainSongs->pluck('id')->all(), $playlist->playables->pluck('id')->all());
|
||||
}
|
||||
|
||||
public function testNonOwnerCannotModifyPlaylist(): void
|
||||
|
|
|
@ -43,7 +43,7 @@ class PlaylistTest extends TestCase
|
|||
self::assertSame('Foo Bar', $playlist->name);
|
||||
self::assertTrue($playlist->ownedBy($user));
|
||||
self::assertNull($playlist->getFolder());
|
||||
self::assertEqualsCanonicalizing($songs->pluck('id')->all(), $playlist->songs->pluck('id')->all());
|
||||
self::assertEqualsCanonicalizing($songs->pluck('id')->all(), $playlist->playables->pluck('id')->all());
|
||||
}
|
||||
|
||||
public function testCreatingSmartPlaylist(): void
|
||||
|
|
|
@ -75,7 +75,7 @@ class SongPlayTest extends TestCase
|
|||
->shouldReceive('stream')
|
||||
->once();
|
||||
|
||||
$this->get("play/$song->id/1/128?t=$token->audioToken")
|
||||
$this->get("play/$song->id/1?t=$token->audioToken")
|
||||
->assertOk();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ class PlaylistServiceTest extends TestCase
|
|||
self::assertSame('foo', $playlist->name);
|
||||
self::assertTrue($user->is($playlist->user));
|
||||
self::assertFalse($playlist->is_smart);
|
||||
self::assertEqualsCanonicalizing($playlist->songs->pluck('id')->all(), $songs->pluck('id')->all());
|
||||
self::assertEqualsCanonicalizing($playlist->playables->pluck('id')->all(), $songs->pluck('id')->all());
|
||||
}
|
||||
|
||||
public function testCreateSmartPlaylist(): void
|
||||
|
@ -201,9 +201,9 @@ class PlaylistServiceTest extends TestCase
|
|||
$playlist->refresh();
|
||||
|
||||
self::assertCount(2, $addedSongs);
|
||||
self::assertCount(5, $playlist->songs);
|
||||
self::assertCount(5, $playlist->playables);
|
||||
self::assertEqualsCanonicalizing($addedSongs->pluck('id')->all(), $songs->pluck('id')->all());
|
||||
$songs->each(static fn (Song $song) => self::assertTrue($playlist->songs->contains($song)));
|
||||
$songs->each(static fn (Song $song) => self::assertTrue($playlist->playables->contains($song)));
|
||||
}
|
||||
|
||||
public function testAddEpisodesToPlaylist(): void
|
||||
|
@ -222,7 +222,7 @@ class PlaylistServiceTest extends TestCase
|
|||
$playlist->refresh();
|
||||
|
||||
self::assertCount(2, $addedEpisodes);
|
||||
self::assertCount(5, $playlist->songs);
|
||||
self::assertCount(5, $playlist->playables);
|
||||
self::assertEqualsCanonicalizing($addedEpisodes->pluck('id')->all(), $episodes->pluck('id')->all());
|
||||
}
|
||||
|
||||
|
@ -238,7 +238,7 @@ class PlaylistServiceTest extends TestCase
|
|||
$playlist->refresh();
|
||||
|
||||
self::assertCount(4, $addedEpisodes);
|
||||
self::assertCount(7, $playlist->songs);
|
||||
self::assertCount(7, $playlist->playables);
|
||||
self::assertEqualsCanonicalizing($addedEpisodes->pluck('id')->all(), $playables->pluck('id')->all());
|
||||
}
|
||||
|
||||
|
@ -268,7 +268,7 @@ class PlaylistServiceTest extends TestCase
|
|||
|
||||
$this->service->makePlaylistContentPublic($playlist);
|
||||
|
||||
$playlist->songs->each(static fn (Song $song) => self::assertTrue($song->is_public));
|
||||
$playlist->playables->each(static fn (Song $song) => self::assertTrue($song->is_public));
|
||||
}
|
||||
|
||||
public function testMoveSongsInPlaylist(): void
|
||||
|
@ -282,17 +282,17 @@ class PlaylistServiceTest extends TestCase
|
|||
$playlist->addPlayables($songs);
|
||||
|
||||
$this->service->movePlayablesInPlaylist($playlist, [$ids[2], $ids[3]], $ids[0], 'after');
|
||||
self::assertSame([$ids[0], $ids[2], $ids[3], $ids[1]], $playlist->refresh()->songs->pluck('id')->all());
|
||||
self::assertSame([$ids[0], $ids[2], $ids[3], $ids[1]], $playlist->refresh()->playables->pluck('id')->all());
|
||||
|
||||
$this->service->movePlayablesInPlaylist($playlist, [$ids[0]], $ids[3], 'before');
|
||||
self::assertSame([$ids[2], $ids[0], $ids[3], $ids[1]], $playlist->refresh()->songs->pluck('id')->all());
|
||||
self::assertSame([$ids[2], $ids[0], $ids[3], $ids[1]], $playlist->refresh()->playables->pluck('id')->all());
|
||||
|
||||
// move to the first position
|
||||
$this->service->movePlayablesInPlaylist($playlist, [$ids[0], $ids[1]], $ids[2], 'before');
|
||||
self::assertSame([$ids[0], $ids[1], $ids[2], $ids[3]], $playlist->refresh()->songs->pluck('id')->all());
|
||||
self::assertSame([$ids[0], $ids[1], $ids[2], $ids[3]], $playlist->refresh()->playables->pluck('id')->all());
|
||||
|
||||
// move to the last position
|
||||
$this->service->movePlayablesInPlaylist($playlist, [$ids[0], $ids[1]], $ids[3], 'after');
|
||||
self::assertSame([$ids[2], $ids[3], $ids[0], $ids[1]], $playlist->refresh()->songs->pluck('id')->all());
|
||||
self::assertSame([$ids[2], $ids[3], $ids[0], $ids[1]], $playlist->refresh()->playables->pluck('id')->all());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue