koel/app/Repositories/SongRepository.php

253 lines
7.9 KiB
PHP
Raw Normal View History

2018-08-29 06:15:11 +00:00
<?php
namespace App\Repositories;
2022-06-10 10:47:46 +00:00
use App\Models\Album;
use App\Models\Artist;
use App\Models\Playlist;
2018-08-29 06:15:11 +00:00
use App\Models\Song;
2022-06-10 10:47:46 +00:00
use App\Models\User;
2020-12-23 11:03:22 +00:00
use App\Repositories\Traits\Searchable;
2022-10-21 20:06:43 +00:00
use App\Values\Genre;
2022-06-10 10:47:46 +00:00
use Illuminate\Contracts\Database\Query\Builder;
use Illuminate\Contracts\Pagination\Paginator;
2022-07-27 15:32:36 +00:00
use Illuminate\Support\Collection;
2022-06-10 10:47:46 +00:00
use Webmozart\Assert\Assert;
2018-08-29 06:15:11 +00:00
2022-07-29 06:47:10 +00:00
class SongRepository extends Repository
2018-08-29 06:15:11 +00:00
{
2020-12-23 11:03:22 +00:00
use Searchable;
2022-07-27 09:30:04 +00:00
public const SORT_COLUMNS_NORMALIZE_MAP = [
2022-06-10 10:47:46 +00:00
'title' => 'songs.title',
'track' => 'songs.track',
'length' => 'songs.length',
'created_at' => 'songs.created_at',
2022-06-10 10:47:46 +00:00
'disc' => 'songs.disc',
2022-07-05 14:46:23 +00:00
'artist_name' => 'artists.name',
'album_name' => 'albums.name',
2022-06-10 10:47:46 +00:00
];
2018-08-29 06:15:11 +00:00
private const VALID_SORT_COLUMNS = [
'songs.title',
'songs.track',
'songs.length',
'songs.created_at',
'artists.name',
'albums.name',
];
2022-06-10 10:47:46 +00:00
private const DEFAULT_QUEUE_LIMIT = 500;
2018-08-29 06:15:11 +00:00
public function getOneByPath(string $path): ?Song
{
return Song::query()->where('path', $path)->first();
}
/** @return Collection|array<Song> */
public function getAllHostedOnS3(): Collection
{
return Song::query()->hostedOnS3()->get();
2018-08-29 06:15:11 +00:00
}
2022-06-10 10:47:46 +00:00
/** @return Collection|array<array-key, Song> */
public function getRecentlyAdded(int $count = 10, ?User $scopedUser = null): Collection
{
return Song::query()->withMeta($scopedUser ?? $this->auth->user())->latest()->limit($count)->get();
2022-06-10 10:47:46 +00:00
}
/** @return Collection|array<array-key, Song> */
public function getMostPlayed(int $count = 7, ?User $scopedUser = null): Collection
{
return Song::query()
->withMeta($scopedUser ?? $this->auth->user())
2022-06-10 10:47:46 +00:00
->where('interactions.play_count', '>', 0)
->orderByDesc('interactions.play_count')
->limit($count)
->get();
}
/** @return Collection|array<array-key, Song> */
public function getRecentlyPlayed(int $count = 7, ?User $scopedUser = null): Collection
{
return Song::query()
->withMeta($scopedUser ?? $this->auth->user())
->orderByDesc('interactions.last_played_at')
2022-06-10 10:47:46 +00:00
->limit($count)
->get();
}
public function getForListing(
string $sortColumn,
string $sortDirection,
?User $scopedUser = null,
int $perPage = 50
): Paginator {
return self::applySort(
Song::query()->withMeta($scopedUser ?? $this->auth->user()),
2022-06-10 10:47:46 +00:00
$sortColumn,
$sortDirection
)
->simplePaginate($perPage);
}
2022-10-21 20:06:43 +00:00
public function getByGenre(
string $genre,
string $sortColumn,
string $sortDirection,
?User $scopedUser = null,
int $perPage = 50
): Paginator {
return self::applySort(
Song::query()
->withMeta($scopedUser ?? $this->auth->user())
->where('genre', $genre),
$sortColumn,
$sortDirection
)
->simplePaginate($perPage);
}
2022-06-10 10:47:46 +00:00
/** @return Collection|array<array-key, Song> */
public function getForQueue(
string $sortColumn,
string $sortDirection,
2022-07-27 09:30:04 +00:00
int $limit = self::DEFAULT_QUEUE_LIMIT,
2022-06-10 10:47:46 +00:00
?User $scopedUser = null,
): Collection {
return self::applySort(
Song::query()->withMeta($scopedUser ?? $this->auth->user()),
2022-06-10 10:47:46 +00:00
$sortColumn,
$sortDirection
)
->limit($limit)
->get();
}
/** @return Collection|array<array-key, Song> */
public function getFavorites(?User $scopedUser = null): Collection
{
return Song::query()->withMeta($scopedUser ?? $this->auth->user())->where('interactions.liked', true)->get();
2022-06-10 10:47:46 +00:00
}
/** @return Collection|array<array-key, Song> */
public function getByAlbum(Album $album, ?User $scopedUser = null): Collection
{
return Song::query()
->withMeta($scopedUser ?? $this->auth->user())
2022-06-10 10:47:46 +00:00
->where('album_id', $album->id)
->orderBy('songs.disc')
->orderBy('songs.track')
2022-06-10 10:47:46 +00:00
->orderBy('songs.title')
->get();
}
/** @return Collection|array<array-key, Song> */
public function getByArtist(Artist $artist, ?User $scopedUser = null): Collection
{
return Song::query()
->withMeta($scopedUser ?? $this->auth->user())
2022-06-10 10:47:46 +00:00
->where('songs.artist_id', $artist->id)
->orWhere('albums.artist_id', $artist->id)
2022-06-10 10:47:46 +00:00
->orderBy('albums.name')
->orderBy('songs.disc')
->orderBy('songs.track')
2022-06-10 10:47:46 +00:00
->orderBy('songs.title')
->get();
}
/** @return Collection|array<array-key, Song> */
public function getByStandardPlaylist(Playlist $playlist, ?User $scopedUser = null): Collection
{
return Song::query()
->withMeta($scopedUser ?? $this->auth->user())
2022-06-10 10:47:46 +00:00
->leftJoin('playlist_song', 'songs.id', '=', 'playlist_song.song_id')
->leftJoin('playlists', 'playlists.id', '=', 'playlist_song.playlist_id')
->where('playlists.id', $playlist->id)
->orderBy('songs.title')
->get();
}
/** @return Collection|array<array-key, Song> */
public function getRandom(int $limit, ?User $scopedUser = null): Collection
{
return Song::query()->withMeta($scopedUser ?? $this->auth->user())->inRandomOrder()->limit($limit)->get();
2022-06-10 10:47:46 +00:00
}
/** @return Collection|array<array-key, Song> */
public function getByIds(array $ids, bool $inThatOrder = false, ?User $scopedUser = null): Collection
2022-06-10 10:47:46 +00:00
{
$songs = Song::query()
->withMeta($scopedUser ?? $this->auth->user())
->whereIn('songs.id', $ids)
->get();
return $inThatOrder ? $songs->orderByArray($ids) : $songs;
2022-06-10 10:47:46 +00:00
}
public function getOne(string $id, ?User $scopedUser = null): Song
2022-06-10 10:47:46 +00:00
{
return Song::query()->withMeta($scopedUser ?? $this->auth->user())->findOrFail($id);
2022-06-10 10:47:46 +00:00
}
public function findOne(string $id, ?User $scopedUser = null): ?Song
{
return Song::query()->withMeta($scopedUser ?? $this->auth->user())->find($id);
}
2022-06-10 10:47:46 +00:00
public function count(): int
{
return Song::query()->count();
2022-06-10 10:47:46 +00:00
}
public function getTotalLength(): float
{
return Song::query()->sum('length');
2022-06-10 10:47:46 +00:00
}
private static function normalizeSortColumn(string $column): string
{
return key_exists($column, self::SORT_COLUMNS_NORMALIZE_MAP)
? self::SORT_COLUMNS_NORMALIZE_MAP[$column]
: $column;
}
private static function applySort(Builder $query, string $column, string $direction): Builder
{
$column = self::normalizeSortColumn($column);
Assert::oneOf($column, self::VALID_SORT_COLUMNS);
Assert::oneOf(strtolower($direction), ['asc', 'desc']);
$query->orderBy($column, $direction);
if ($column === 'artists.name') {
$query->orderBy('albums.name')
->orderBy('songs.disc')
->orderBy('songs.track')
2022-06-10 10:47:46 +00:00
->orderBy('songs.title');
} elseif ($column === 'albums.name') {
$query->orderBy('artists.name')
->orderBy('songs.disc')
->orderBy('songs.track')
2022-06-10 10:47:46 +00:00
->orderBy('songs.title');
} elseif ($column === 'track') {
$query->orderBy('song.disc')
->orderBy('songs.track');
2022-06-10 10:47:46 +00:00
}
return $query;
}
2022-10-21 20:06:43 +00:00
/** @return Collection|array<array-key, Song> */
public function getRandomByGenre(string $genre, int $limit, ?User $scopedUser = null): Collection
{
return Song::query()
->withMeta($scopedUser ?? $this->auth->user())
->where('genre', $genre === Genre::NO_GENRE ? '' : $genre)
->limit($limit)
->inRandomOrder()
->get();
}
2018-08-29 06:15:11 +00:00
}