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