44namespace Scottboms \MusicKit ;
55
66use Scottboms \MusicKit \Auth ;
7+ use Scottboms \MusicKit \Utils ;
78use Kirby \Http \Response ;
89use Kirby \Http \Remote ;
910
@@ -203,7 +204,7 @@ public static function songDetails(string $songId, string $language = 'en-US'):
203204 }
204205
205206 $ duration = isset ($ a ['durationInMillis ' ])
206- ? self :: ms_to_mmss ((int )$ a ['durationInMillis ' ])
207+ ? Utils:: format_mmss ((int )$ a ['durationInMillis ' ])
207208 : null ;
208209
209210 // releaseYear from releaseDate
@@ -230,7 +231,7 @@ public static function songDetails(string $songId, string $language = 'en-US'):
230231 'artistName ' => $ a ['artistName ' ] ?? '' ,
231232 'albumName ' => $ a ['albumName ' ] ?? '' ,
232233 'composerName ' => $ a ['composerName ' ] ?? '' ,
233- 'genreNames ' => $ a ['genreNames ' ] ?? [] ,
234+ 'genreName ' => Utils:: firstGenre ( $ a ['genreNames ' ] ?? null ) ,
234235 'releaseDate ' => $ releaseDate ,
235236 'releaseYear ' => $ releaseYear ,
236237 'url ' => $ url ,
@@ -241,22 +242,6 @@ public static function songDetails(string $songId, string $language = 'en-US'):
241242 ], 200 );
242243 }
243244
244- // helper: milliseconds to mm:ss
245- public static function ms_to_mmss (?int $ ms , bool $ forceHours = false ): ?string
246- {
247- if ($ ms === null ) return null ;
248- $ total = (int ) round ($ ms / 1000 );
249- $ h = intdiv ($ total , 3600 );
250- $ rem = $ total % 3600 ;
251- $ m = intdiv ($ total , 60 );
252- $ s = $ total % 60 ;
253-
254- if ($ forceHours || $ h > 0 ) {
255- return sprintf ('%d:%02d:%02d ' , $ h , $ m , $ s ); // H:MM:SS
256- }
257- return sprintf ('%d:%02d ' , $ m , $ s );
258- }
259-
260245 // get individual album details
261246 public static function albumDetails (string $ albumId , string $ language = 'en-US ' ): Response
262247 {
@@ -333,6 +318,18 @@ public static function albumDetails(string $albumId, string $language = 'en-US')
333318
334319 // albums tracks data
335320 $ tracksRaw = $ body ['data ' ][0 ]['relationships ' ]['tracks ' ]['data ' ] ?? [];
321+
322+ // compute album-level "isDigitalMaster" based on any track
323+ $ albumIsDigitalMaster = false ;
324+ foreach ($ tracksRaw as $ t ) {
325+ $ ta = $ t ['attributes ' ] ?? [];
326+ if (!empty ($ ta ['isAppleDigitalMaster ' ])) {
327+ $ albumIsDigitalMaster = true ;
328+ break ;
329+ }
330+ }
331+
332+ // build normalized tracks list
336333 $ tracks = array_map (function ($ t ) {
337334 $ a = $ t ['attributes ' ] ?? [];
338335 $ ms = $ a ['durationInMillis ' ] ?? null ;
@@ -341,32 +338,33 @@ public static function albumDetails(string $albumId, string $language = 'en-US')
341338 'number ' => $ a ['trackNumber ' ] ?? null ,
342339 'name ' => $ a ['name ' ] ?? '' ,
343340 'durationMs ' => $ ms ,
344- 'duration ' => self :: ms_to_mmss ($ ms ),
341+ 'duration ' => Utils:: format_mmss ($ ms ),
345342 ];
346343 }, $ tracksRaw );
347344
348345 // total duration
349346 $ totalDurationMs = array_sum (array_map (fn ($ t ) => $ t ['durationMs ' ] ?? 0 , $ tracks ));
350- $ totalDuration = self :: ms_to_mmss ($ totalDurationMs );
347+ $ totalDuration = Utils:: format_human ($ totalDurationMs );
351348
352349 return Response::json ([
353- 'id ' => $ id ,
354- 'name ' => $ a ['name ' ] ?? '' ,
355- 'artistName ' => $ a ['artistName ' ] ?? '' ,
356- 'genreNames ' => $ a ['genreNames ' ] ?? [],
357- 'isDigitalMaster ' => (bool )($ a ['isDigitalMaster ' ] ?? true ),
358- 'isMasteredForItunes ' => (bool )($ a ['isMasteredForItunes ' ] ?? false ),
359- 'contentRating ' => $ a ['contentRating ' ] ?? '' ,
360- 'releaseDate ' => $ releaseDate ,
361- 'releaseYear ' => $ releaseYear ,
362- 'url ' => $ url ,
363- 'image ' => $ img ,
364- 'recordLabel ' => $ a ['recordLabel ' ],
365- 'copyright ' => $ a ['copyright ' ],
366- 'trackCount ' => $ a ['trackCount ' ],
367- 'totalDuration ' => $ totalDuration ,
368- 'tracks ' => $ tracks ,
369- //'raw' => $body, // optional: full response payload
350+ 'id ' => $ id ,
351+ 'name ' => $ a ['name ' ] ?? '' ,
352+ 'artistName ' => $ a ['artistName ' ] ?? '' ,
353+ 'genreName ' => Utils::firstGenre ($ a ['genreNames ' ] ?? null ),
354+ 'isMasteredForItunes ' => (bool )($ a ['isMasteredForItunes ' ] ?? false ),
355+ 'isAppleDigitalMaster ' => $ albumIsDigitalMaster ,
356+ 'contentRating ' => $ a ['contentRating ' ] ?? '' ,
357+ 'releaseDate ' => $ releaseDate ,
358+ 'releaseDateFormatted ' => Utils::humanDate ($ releaseDate ),
359+ 'releaseYear ' => $ releaseYear ,
360+ 'url ' => $ url ,
361+ 'image ' => $ img ,
362+ 'recordLabel ' => $ a ['recordLabel ' ],
363+ 'copyright ' => $ a ['copyright ' ],
364+ 'trackCount ' => $ a ['trackCount ' ],
365+ 'totalDuration ' => $ totalDuration ,
366+ 'tracks ' => $ tracks ,
367+ 'raw ' => $ body , // optional: full response payload
370368 ], 200 );
371369 }
372370
@@ -375,7 +373,7 @@ public static function albumDetails(string $albumId, string $language = 'en-US')
375373 * fetches recently played for the shared token, cache it,
376374 * and normalize to a render-friendly array
377375 *
378- * @return array {items: list<array{id?:string,name:string,artist:string,url:string|null,image:string|null}>, error:?string}
376+ * @return Array {items: list<array{id?:string,name:string,artist:string,url:string|null,image:string|null}>, error:?string}
379377 */
380378 public static function recentForFrontend (int $ limit = 12 , string $ language = 'en-US ' , int $ cacheTtl = 120 ): array
381379 {
0 commit comments