'integer']; /** @deprecated */ protected $appends = ['is_compilation']; /** * Get an album using some provided information. * If such is not found, a new album will be created using the information. */ public static function getOrCreate(Artist $artist, ?string $name = null): self { return static::firstOrCreate([ 'artist_id' => $artist->id, 'name' => trim($name) ?: self::UNKNOWN_NAME, ]); } public function artist(): BelongsTo { return $this->belongsTo(Artist::class); } public function songs(): HasMany { return $this->hasMany(Song::class); } protected function isUnknown(): Attribute { return Attribute::get(fn (): bool => $this->id === self::UNKNOWN_ID); } protected function cover(): Attribute { return Attribute::get(static fn (?string $value): ?string => album_cover_url($value)); } protected function hasCover(): Attribute { return Attribute::get(fn (): bool => $this->cover_path && file_exists($this->cover_path)); } protected function coverPath(): Attribute { return Attribute::get(function () { $cover = Arr::get($this->attributes, 'cover'); return $cover ? album_cover_path($cover) : null; }); } /** * Sometimes the tags extracted from getID3 are HTML entity encoded. * This makes sure they are always sane. */ protected function name(): Attribute { return Attribute::get(static fn (string $value) => html_entity_decode($value)); } protected function thumbnailName(): Attribute { return Attribute::get(function (): ?string { if (!$this->has_cover) { return null; } $parts = pathinfo($this->cover_path); return sprintf('%s_thumb.%s', $parts['filename'], $parts['extension']); }); } protected function thumbnailPath(): Attribute { return Attribute::get(fn () => $this->thumbnail_name ? album_cover_path($this->thumbnail_name) : null); } protected function thumbnail(): Attribute { return Attribute::get(fn () => $this->thumbnail_name ? album_cover_url($this->thumbnail_name) : null); } /** @deprecated Only here for backward compat with mobile apps */ protected function isCompilation(): Attribute { return Attribute::get(fn () => $this->artist_id === Artist::VARIOUS_ID); } public function scopeIsStandard(Builder $query): Builder { return $query->whereNot('albums.id', self::UNKNOWN_ID); } public static function withMeta(User $scopedUser): BuilderContract { return static::query() ->with('artist') ->leftJoin('songs', 'albums.id', '=', 'songs.album_id') ->leftJoin('interactions', static function (JoinClause $join) use ($scopedUser): void { $join->on('songs.id', '=', 'interactions.song_id') ->where('interactions.user_id', $scopedUser->id); }) ->groupBy('albums.id') ->select( 'albums.*', DB::raw('CAST(SUM(interactions.play_count) AS INTEGER) AS play_count') ) ->withCount('songs AS song_count') ->withSum('songs AS length', 'length'); } /** @return array */ public function toSearchableArray(): array { $array = [ 'id' => $this->id, 'name' => $this->name, ]; if (!$this->artist->is_unknown && !$this->artist->is_various) { $array['artist'] = $this->artist->name; } return $array; } }