Album::getYearRange()   A
last analyzed

Complexity

Conditions 4
Paths 6

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 4
eloc 7
c 2
b 0
f 0
nc 6
nop 0
dl 0
loc 9
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'),
0 ignored issues
show
Deprecated Code introduced by
The function OCP\AppFramework\Db\Entity::slugify() has been deprecated: 24.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

216
			'slug'          => /** @scrutinizer ignore-deprecated */ $this->slugify('name'),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
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