'integer']; /** * 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 () => $this->id === self::UNKNOWN_ID); } protected function cover(): Attribute { return Attribute::get(static fn (?string $value) => $value ? album_cover_url($value) : ''); } protected function hasCover(): Attribute { return Attribute::get(function () { $cover = array_get($this->attributes, 'cover'); return $cover && file_exists(album_cover_path($cover)); }); } protected function coverPath(): Attribute { return Attribute::get(function () { $cover = array_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); } 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; } }