id; } public function getAlbum(): ?Album { return $this->album; } public function setAlbum(?Album $album): void { $this->album = $album; } public function getExternalTrackId(): ?string { return $this->externalTrackId; } public function setExternalTrackId(?string $externalTrackId): void { $this->externalTrackId = $externalTrackId; } public function getDiscNumber(): int { return $this->discNumber; } public function setDiscNumber(int $discNumber): void { $this->discNumber = max(1, $discNumber); } public function getTrackNumber(): int { return $this->trackNumber; } public function setTrackNumber(int $trackNumber): void { $this->trackNumber = max(1, $trackNumber); } public function getName(): string { return $this->name; } public function setName(string $name): void { $this->name = $name; } public function getDurationMs(): int { return $this->durationMs; } public function setDurationMs(int $durationMs): void { $this->durationMs = max(0, $durationMs); } public function getPreviewUrl(): ?string { return $this->previewUrl; } public function setPreviewUrl(?string $previewUrl): void { $this->previewUrl = $previewUrl; } /** * Normalizes the track for template rendering. * * @return array{disc:int,track:int,name:string,duration_label:string,duration_seconds:int,preview_url:?string} */ public function toTemplateArray(): array { $seconds = (int) floor($this->durationMs / 1000); $minutes = intdiv($seconds, 60); $remainingSeconds = $seconds % 60; return [ 'disc' => $this->discNumber, 'track' => $this->trackNumber, 'name' => $this->name, 'duration_label' => sprintf('%d:%02d', $minutes, $remainingSeconds), 'duration_seconds' => $seconds, 'preview_url' => $this->previewUrl, ]; } }