<?php
namespace App\Values\Scanning;
use App\Models\Album;
use App\Models\Artist;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
class ScanInformation implements Arrayable
{
private function __construct(
public ?string $title,
public ?string $albumName,
public ?string $artistName,
public ?string $albumArtistName,
public ?int $track,
public ?int $disc,
public ?int $year,
public ?string $genre,
public ?string $lyrics,
public ?float $length,
public ?array $cover,
public ?string $path,
public ?string $hash,
public ?int $mTime,
public ?string $mimeType,
public ?int $fileSize,
) {
}
public static function fromGetId3Info(array $info, string $path): self
{
$tags = array_merge(
Arr::get($info, 'tags.id3v1', []),
Arr::get($info, 'tags.id3v2', []),
Arr::get($info, 'comments', []),
Arr::get($info, 'tags.vorbiscomment', []),
);
$comments = Arr::get($info, 'comments', []);
$albumArtistName = self::getTag($tags, ['albumartist', 'album_artist', 'band']);
if (!$albumArtistName && self::getTag($tags, 'part_of_a_compilation')) {
$albumArtistName = Artist::VARIOUS_NAME;
}
$cover = [self::getTag($comments, 'cover', null)];
if ($cover[0] === null) {
$cover = self::getTag($comments, 'picture', []);
}
$lyrics = html_entity_decode(self::getTag($tags, [
'unsynchronised_lyric',
'unsychronised_lyric',
'unsyncedlyrics',
'lyrics',
]));
return new self(
title: html_entity_decode(self::getTag($tags, 'title', pathinfo($path, PATHINFO_FILENAME))),
albumName: html_entity_decode(self::getTag($tags, 'album', Album::UNKNOWN_NAME)),
artistName: html_entity_decode(self::getTag($tags, 'artist', Artist::UNKNOWN_NAME)),
albumArtistName: html_entity_decode($albumArtistName),
track: (int) self::getTag($tags, ['track', 'tracknumber', 'track_number']),
disc: (int) self::getTag($tags, ['discnumber', 'part_of_a_set'], 1),
year: (int) self::getTag($tags, 'year') ?: null,
genre: self::getTag($tags, 'genre'),
lyrics: $lyrics,
length: (float) Arr::get($info, 'playtime_seconds'),
cover: $cover,
path: $path,
hash: File::hash($path),
mTime: get_mtime($path),
mimeType: Str::lower(Arr::get($info, 'mime_type')) ?: 'audio/mpeg',
fileSize: File::size($path),
);
}
public static function make(
?string $title = null,
?string $albumName = null,
?string $artistName = null,
?string $albumArtistName = null,
?int $track = null,
?int $disc = null,
?int $year = null,
?string $genre = null,
?string $lyrics = null,
?float $length = null,
?array $cover = null,
?string $path = null,
?string $hash = null,
?int $mTime = null,
?string $mimeType = null,
?int $fileSize = null,
): self {
return new self(
title: $title,
albumName: $albumName,
artistName: $artistName,
albumArtistName: $albumArtistName,
track: $track,
disc: $disc,
year: $year,
genre: $genre,
lyrics: $lyrics,
length: $length,
cover: $cover,
path: $path,
hash: $hash,
mTime: $mTime,
mimeType: $mimeType,
fileSize: $fileSize,
);
}
private static function getTag(array $arr, string|array $keys, $default = ''): mixed
{
foreach (Arr::wrap($keys) as $name) {
$value = Arr::get($arr, $name . '.0');
if ($value) {
break;
}
}
return $value ?? $default;
}
public function toArray(): array
{
return [
'title' => $this->title,
'album' => $this->albumName,
'artist' => $this->artistName,
'albumartist' => $this->albumArtistName,
'track' => $this->track,
'disc' => $this->disc,
'year' => $this->year,
'genre' => $this->genre,
'lyrics' => $this->lyrics,
'length' => $this->length,
'cover' => $this->cover,
'path' => $this->path,
'hash' => $this->hash,
'mtime' => $this->mTime,
'mime_type' => $this->mimeType,
'file_size' => $this->fileSize,
];
}
}