Passed
Push — master ( ffd534...2be3f6 )
by Pauli
03:35
created

Album::uriToShivaApi()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 2
rs 10
1
<?php declare(strict_types=1);
2
3
/**
4
 * ownCloud - Music app
5
 *
6
 * This file is licensed under the Affero General Public License version 3 or
7
 * later. See the COPYING file.
8
 *
9
 * @author Morris Jobke <[email protected]>
10
 * @author Pauli Järvinen <[email protected]>
11
 * @copyright Morris Jobke 2013, 2014
12
 * @copyright Pauli Järvinen 2017 - 2025
13
 */
14
15
namespace OCA\Music\Db;
16
17
use OCA\Music\Utility\StringUtil;
18
use OCP\IL10N;
19
use OCP\IURLGenerator;
20
21
/**
22
 * @method ?string getName()
23
 * @method void setName(?string $name)
24
 * @method ?string getMbid()
25
 * @method void setMbid(?string $mbid)
26
 * @method ?string getMbidGroup()
27
 * @method void setMbidGroup(?string $mbidGroup)
28
 * @method ?int getCoverFileId()
29
 * @method void setCoverFileId(?int $coverFileId)
30
 * @method int getAlbumArtistId()
31
 * @method void setAlbumArtistId(int $albumArtistId)
32
 * @method string getHash()
33
 * @method void setHash(string $hash)
34
 * @method ?string getStarred()
35
 * @method void setStarred(?string $timestamp)
36
 * @method int getRating()
37
 * @method void setRating(int $rating)
38
 * @method ?string getAlbumArtistName()
39
 */
40
class Album extends Entity {
41
	public ?string $name = null;
42
	public ?string $mbid = null;
43
	public ?string $mbidGroup = null;
44
	public ?int $coverFileId = null;
45
	public ?int $albumArtistId = null;
46
	public string $hash = '';
47
	public ?string $starred = null;
48
	public int $rating = 0;
49
	public ?string $albumArtistName = null; // not from music_albums table but still part of the standard content
50
	public ?int $disk = 0; // deprecated
51
52
	// extra fields injected separately by AlbumBusinessLayer
53
	/** @var ?int[] $years */
54
	private ?array $years = null;
55
	/** @var ?Genre[] $genres - AlbumBusinessLayer injects *partial* Genre objects, not all properties are set */
56
	private ?array $genres = null;
57
	/** @var ?Artist[] $artists */
58
	private ?array $artists = null;
59
	private ?int $numberOfDisks = null;
60
61
	// injected separately when needed
62
	/** @var ?Track[] $tracks */
63
	private ?array $tracks = null;
64
65
	public function __construct() {
66
		$this->addType('disk', 'int');
67
		$this->addType('coverFileId', 'int');
68
		$this->addType('albumArtistId', 'int');
69
		$this->addType('rating', 'int');
70
	}
71
72
	/**
73
	 * @return ?int[]
74
	 */
75
	public function getYears() : ?array {
76
		return $this->years;
77
	}
78
79
	/**
80
	 * @param ?int[] $years
81
	 */
82
	public function setYears(?array $years) : void {
83
		$this->years = $years;
84
	}
85
86
	/**
87
	 * @return ?Genre[]
88
	 */
89
	public function getGenres() : ?array {
90
		return $this->genres;
91
	}
92
93
	/**
94
	 * @param ?Genre[] $genres
95
	 */
96
	public function setGenres(?array $genres) : void {
97
		$this->genres = $genres;
98
	}
99
100
	/**
101
	 * @return ?Artist[]
102
	 */
103
	public function getArtists() : ?array {
104
		return $this->artists;
105
	}
106
107
	/**
108
	 * @param ?Artist[] $artists
109
	 */
110
	public function setArtists(?array $artists) : void {
111
		$this->artists = $artists;
112
	}
113
114
	public function getNumberOfDisks() : ?int {
115
		return $this->numberOfDisks;
116
	}
117
118
	public function setNumberOfDisks(?int $count) : void {
119
		$this->numberOfDisks = $count;
120
	}
121
122
	/**
123
	 * @return ?Track[]
124
	 */
125
	public function getTracks() : ?array {
126
		return $this->tracks;
127
	}
128
129
	/**
130
	 * @param Track[] $tracks
131
	 */
132
	public function setTracks(array $tracks) : void {
133
		$this->tracks = $tracks;
134
	}
135
136
	/**
137
	 * Returns the years(s) of the album.
138
	 * The album may have zero, one, or multiple years as people may tag tracks of
139
	 * collection albums with their original release dates. The respective formatted
140
	 * year ranges could be e.g. null, '2016', and '1995 - 2000'.
141
	 * @return string|null
142
	 */
143
	public function getYearRange() : ?string {
144
		$count = empty($this->years) ? 0 : \count($this->years);
145
146
		if ($count == 0) {
147
			return null;
148
		} elseif ($count == 1) {
149
			return (string)$this->years[0];
150
		} else {
151
			return \min($this->years) . ' - ' . \max($this->years);
152
		}
153
	}
154
155
	/**
156
	 * The Shiva and Ampache API definitions require the year to be a single numeric value.
157
	 * In case the album has multiple years, output the largest of these in the API.
158
	 * @return int|null
159
	 */
160
	public function yearToAPI() : ?int {
161
		return empty($this->years) ? null : (int)\max($this->years);
162
	}
163
164
	/**
165
	 * Returns the name of the album - if empty it returns the translated
166
	 * version of "Unknown album"
167
	 * @param IL10N $l10n
168
	 * @return string
169
	 */
170
	public function getNameString(IL10N $l10n) : string {
171
		return $this->getName() ?: self::unknownNameString($l10n);
172
	}
173
174
	/**
175
	 * Returns the name of the album artist - if empty it returns the translated
176
	 * version of "Unknown artist"
177
	 * @param IL10N $l10n
178
	 * @return string
179
	 */
180
	public function getAlbumArtistNameString(IL10N $l10n) : string {
181
		return $this->getAlbumArtistName() ?: Artist::unknownNameString($l10n);
182
	}
183
184
	/**
185
	 * Creates object used for collection API (array with name, year, cover URL and ID)
186
	 * @param  IURLGenerator $urlGenerator URL Generator
187
	 * @param  IL10N $l10n Localization handler
188
	 * @param  string|null $cachedCoverHash Cached cover image hash if available
189
	 * @param  Track[] $tracks Tracks of the album in the "toCollection" format
190
	 * @return array collection API object
191
	 */
192
	public function toCollection(IURLGenerator $urlGenerator, IL10N $l10n, ?string $cachedCoverHash, array $tracks) : array {
193
		return [
194
			'name'      => $this->getNameString($l10n),
195
			'year'      => $this->getYearRange(),
196
			'cover'     => $this->coverToCollection($urlGenerator, $cachedCoverHash),
197
			'id'        => $this->getId(),
198
			'diskCount' => $this->getNumberOfDisks(),
199
			'tracks'    => $tracks
200
		];
201
	}
202
203
	/**
204
	 * Creates object used by the Shiva API (array with name, year, cover URL, ID, slug, URI and artists Array)
205
	 * @param  IURLGenerator $urlGenerator URL Generator
206
	 * @param  IL10N $l10n Localization handler
207
	 * @return array shiva API object
208
	 */
209
	public function toShivaApi(IURLGenerator $urlGenerator, IL10N $l10n) : array {
210
		return [
211
			'name'          => $this->getNameString($l10n),
212
			'year'          => $this->yearToAPI(),
213
			'cover'         => $this->coverToApi($urlGenerator),
214
			'id'            => $this->getId(),
215
			'uri'           => $this->uriToShivaApi($urlGenerator),
216
			'slug'          => $this->slugify('name'),
217
			'albumArtistId' => $this->getAlbumArtistId(),
218
			'artists'       => $this->artistsToShivaApi($urlGenerator)
219
		];
220
	}
221
222
	public static function compareYearAndName(Album $a, Album $b) : int {
223
		$yearResult = \strcmp($a->getYearRange() ?? '', $b->getYearRange() ?? '');
224
225
		return $yearResult ?: StringUtil::caselessCompare($a->getName(), $b->getName());
226
	}
227
228
	public static function unknownNameString(IL10N $l10n) : string {
229
		return (string) $l10n->t('Unknown album');
230
	}
231
232
	/**
233
	 * Return the cover URL to be used in the Shiva API
234
	 * @param IURLGenerator $urlGenerator
235
	 * @return string|null
236
	 */
237
	private function coverToApi(IURLGenerator $urlGenerator) : ?string {
238
		return ($this->getCoverFileId() > 0)
239
				? $urlGenerator->linkToRoute('music.coverApi.albumCover', ['albumId' => $this->getId()])
240
				: null;
241
	}
242
243
	/**
244
	 * If the cover image is already cached, the cover is presented with a link containing the image hash.
245
	 * Otherwise, the collection contains an URL which triggers the caching and then redirects to the
246
	 * URL with image hash.
247
	 * @param  IURLGenerator $urlGenerator URL Generator
248
	 * @param  string|null $cachedCoverHash Cached cover image hash if available
249
	 * @return string|null
250
	 */
251
	private function coverToCollection(IURLGenerator $urlGenerator, ?string $cachedCoverHash) : ?string {
252
		if (!empty($cachedCoverHash)) {
253
			return $urlGenerator->linkToRoute('music.coverApi.cachedCover', ['hash' => $cachedCoverHash]);
254
		} elseif ($this->getCoverFileId() > 0) {
255
			return $this->coverToApi($urlGenerator);
256
		} else {
257
			return null;
258
		}
259
	}
260
261
	/**
262
	 * Generates URL to album
263
	 * @param \OCP\IURLGenerator $urlGenerator
264
	 * @return string the url
265
	 */
266
	private function uriToShivaApi(IURLGenerator $urlGenerator) : string {
267
		return $urlGenerator->linkToRoute('music.shivaApi.album', ['id' => $this->id]);
268
	}
269
270
	/**
271
	 * Returns an array of all artists - each with ID and URL for that artist
272
	 * @param \OCP\IURLGenerator $urlGenerator URLGenerator
273
	 * @return array
274
	 */
275
	private function artistsToShivaApi(IURLGenerator $urlGenerator) : array {
276
		return \array_map(fn($artist) => [
277
			'id' => $artist->getId(),
278
			'uri' => $urlGenerator->linkToRoute('music.shivaApi.artist', ['id' => $artist->getId()])
279
		], $this->getArtists() ?? []);
280
	}
281
}
282