*/ class SongRepository extends Repository { private const DEFAULT_QUEUE_LIMIT = 500; public function findOneByPath(string $path): ?Song { return Song::query()->where('path', $path)->first(); } /** @return Collection|array */ public function getAllStoredOnCloud(): Collection { return Song::query()->storedOnCloud()->get(); } /** @return Collection|array */ public function getRecentlyAdded(int $count = 10, ?User $scopedUser = null): Collection { return Song::query(type: PlayableType::SONG, user: $scopedUser ?? $this->auth->user()) ->accessible() ->withMeta() ->latest() ->limit($count) ->get(); } /** @return Collection|array */ public function getMostPlayed(int $count = 7, ?User $scopedUser = null): Collection { return Song::query(user: $scopedUser ?? $this->auth->user()) ->accessible() ->withMeta(requiresInteractions: true) ->where('interactions.play_count', '>', 0) ->orderByDesc('interactions.play_count') ->limit($count) ->get(); } /** @return Collection|array */ public function getRecentlyPlayed(int $count = 7, ?User $scopedUser = null): Collection { return Song::query(user: $scopedUser ?? $this->auth->user()) ->accessible() ->withMeta(requiresInteractions: true) ->addSelect('interactions.last_played_at') ->orderByDesc('interactions.last_played_at') ->limit($count) ->get(); } public function getForListing( array $sortColumns, string $sortDirection, bool $ownSongsOnly = false, ?User $scopedUser = null, int $perPage = 50 ): Paginator { $scopedUser ??= $this->auth->user(); return Song::query(type: PlayableType::SONG, user: $scopedUser) ->accessible() ->withMeta() ->when($ownSongsOnly, static fn (SongBuilder $query) => $query->where('songs.owner_id', $scopedUser->id)) ->sort($sortColumns, $sortDirection) ->simplePaginate($perPage); } public function getByGenre( string $genre, array $sortColumns, string $sortDirection, ?User $scopedUser = null, int $perPage = 50 ): Paginator { return Song::query(type: PlayableType::SONG, user: $scopedUser ?? $this->auth->user()) ->accessible() ->withMeta() ->where('genre', $genre) ->sort($sortColumns, $sortDirection) ->simplePaginate($perPage); } /** @return Collection|array */ public function getForQueue( array $sortColumns, string $sortDirection, int $limit = self::DEFAULT_QUEUE_LIMIT, ?User $scopedUser = null, ): Collection { return Song::query(type: PlayableType::SONG, user: $scopedUser ?? $this->auth->user()) ->accessible() ->withMeta() ->sort($sortColumns, $sortDirection) ->limit($limit) ->get(); } /** @return Collection|array */ public function getFavorites(?User $scopedUser = null): Collection { return Song::query(user: $scopedUser ?? $this->auth->user()) ->accessible() ->withMeta() ->where('interactions.liked', true) ->get(); } /** @return Collection|array */ public function getByAlbum(Album $album, ?User $scopedUser = null): Collection { return Song::query(user: $scopedUser ?? $this->auth->user()) ->accessible() ->withMeta() ->where('album_id', $album->id) ->orderBy('songs.disc') ->orderBy('songs.track') ->orderBy('songs.title') ->get(); } /** @return Collection|array */ public function getByArtist(Artist $artist, ?User $scopedUser = null): Collection { return Song::query(type: PlayableType::SONG, user: $scopedUser ?? $this->auth->user()) ->accessible() ->withMeta() ->where('songs.artist_id', $artist->id) ->orWhere('albums.artist_id', $artist->id) ->orderBy('albums.name') ->orderBy('songs.disc') ->orderBy('songs.track') ->orderBy('songs.title') ->get(); } /** @return Collection|array */ public function getByStandardPlaylist(Playlist $playlist, ?User $scopedUser = null): Collection { return Song::query(user: $scopedUser ?? $this->auth->user()) ->accessible() ->withMeta() ->leftJoin('playlist_song', 'songs.id', '=', 'playlist_song.song_id') ->leftJoin('playlists', 'playlists.id', '=', 'playlist_song.playlist_id') ->when(License::isPlus(), static function (SongBuilder $query): SongBuilder { return $query->join('users as collaborators', 'playlist_song.user_id', '=', 'collaborators.id') ->addSelect( 'collaborators.id as collaborator_id', 'collaborators.name as collaborator_name', 'collaborators.email as collaborator_email', 'collaborators.avatar as collaborator_avatar', 'playlist_song.created_at as added_at' ); }) ->where('playlists.id', $playlist->id) ->orderBy('playlist_song.position') ->get(); } /** @return Collection|array */ public function getRandom(int $limit, ?User $scopedUser = null): Collection { return Song::query(type: PlayableType::SONG, user: $scopedUser ?? $this->auth->user()) ->accessible() ->withMeta() ->inRandomOrder() ->limit($limit) ->get(); } /** @return Collection|array */ public function getMany(array $ids, bool $preserveOrder = false, ?User $scopedUser = null): Collection { $songs = Song::query(user: $scopedUser ?? $this->auth->user()) ->accessible() ->withMeta() ->whereIn('songs.id', $ids) ->get(); return $preserveOrder ? $songs->orderByArray($ids) : $songs; } /** * Gets several songs, but also includes collaborative information. * * @return Collection|array */ public function getManyInCollaborativeContext(array $ids, ?User $scopedUser = null): Collection { return Song::query(user: $scopedUser ?? $this->auth->user()) ->accessible() ->withMeta() ->when(License::isPlus(), static function (SongBuilder $query): SongBuilder { return $query->leftJoin('playlist_song', 'songs.id', '=', 'playlist_song.song_id') ->leftJoin('playlists', 'playlists.id', '=', 'playlist_song.playlist_id') ->join('users as collaborators', 'playlist_song.user_id', '=', 'collaborators.id') ->addSelect( 'collaborators.id as collaborator_id', 'collaborators.name as collaborator_name', 'collaborators.email as collaborator_email', 'playlist_song.created_at as added_at' ); }) ->whereIn('songs.id', $ids) ->get(); } /** @param string $id */ public function getOne($id, ?User $scopedUser = null): Song { return Song::query(user: $scopedUser ?? $this->auth->user()) ->accessible() ->withMeta() ->findOrFail($id); } /** @param string $id */ public function findOne($id, ?User $scopedUser = null): ?Song { return Song::query(user: $scopedUser ?? $this->auth->user()) ->accessible() ->withMeta() ->find($id); } public function countSongs(?User $scopedUser = null): int { return Song::query(type: PlayableType::SONG, user: $scopedUser ?? $this->auth->user()) ->accessible() ->count(); } public function getTotalSongLength(?User $scopedUser = null): float { return Song::query(type: PlayableType::SONG, user: $scopedUser ?? $this->auth->user()) ->accessible() ->sum('length'); } /** @return Collection|array */ public function getRandomByGenre(string $genre, int $limit, ?User $scopedUser = null): Collection { return Song::query(type: PlayableType::SONG, user: $scopedUser ?? $this->auth->user()) ->accessible() ->withMeta() ->where('genre', $genre === Genre::NO_GENRE ? '' : $genre) ->limit($limit) ->inRandomOrder() ->get(); } /** @return array */ public function getEpisodeGuidsByPodcast(Podcast $podcast): array { return $podcast->episodes()->pluck('episode_guid')->toArray(); } /** @return Collection */ public function getEpisodesByPodcast(Podcast $podcast): Collection { return $podcast->episodes; } }