import { Injectable } from '@angular/core' ; import { LoadingController , IonicSafeString } from '@ionic/angular' ; import { from , Observable } from 'rxjs' ; import { delay , retryWhen , timeout , map } from 'rxjs/operators' ; @ Injectable ( { providedIn : 'root' , } ) export class MusickitService { private musicKitInstance = ( window as any ) . MusicKit . getInstance ( ) ; constructor ( private loadingCtrl ) { } fetchAlbum ( id ) { return from ( this . musicKitInstance . api . music ( `v1/catalog/${ this . musicKitInstance . storefrontId }/albums/${ id }` , { } ) ) . pipe ( map ( ( res ) => res . data . data [ 0 ] ) ) ; } fetchPlaylist ( id ) { return from ( this . musicKitInstance . api . music ( `v1/catalog/${ this . musicKitInstance . storefrontId }/playlists/${ id }` ) ) . pipe ( map ( ( res ) => res . data . data [ 0 ] ) ) ; } fetchAlbumOrPlaylist ( type , id ) { if ( type === 'playlist' ) { return this . fetchPlaylist ( id ) ; } else { return this . fetchAlbum ( id ) ; } } fetchArtist ( id ) { return from ( this . musicKitInstance . api . artist ( id , { include : 'playlists,albums' , offset : '26' , } ) ) ; } search ( query ) { const searchTypes = [ 'songs' , 'albums' , 'playlists' ] ; return from ( this . musicKitInstance . api . music ( `v1/catalog/${ this . musicKitInstance . storefrontId }/search` , { term : query , types : searchTypes , limit : 25 , } ) ) . pipe ( map ( ( { data } ) => ( { albums : data . results . albums ?. data ?? null , songs : data . results . songs ?. data ?? null , playlists : data . results . playlists ?. data ?? null , } ) ) , retryWhen ( ( error ) => error . pipe ( delay ( 500 ) ) ) , timeout ( 5000 ) ) ; } fetchRecentPlayed ( ) { return from ( this . musicKitInstance . api . recentPlayed ( ) ) ; } fetchHeavyRotation ( ) { return from ( this . musicKitInstance . api . historyHeavyRotation ( ) ) ; } fetchChart ( ) { const searchTypes = [ 'songs' , 'albums' , 'playlists' ] ; return from ( this . musicKitInstance . api . music ( `v1/catalog/${ this . musicKitInstance . storefrontId }/charts` , { types : searchTypes , limit : 32 , } ) ) . pipe ( map ( ( { data } ) => ( { topAlbums : data . results . albums [ 0 ] . data , topPlaylists : data . results . playlists [ 0 ] . data , topSongs : data . results . songs [ 0 ] . data , } ) ) , retryWhen ( ( error ) => error . pipe ( delay ( 500 ) ) ) , timeout ( 5000 ) ) ; } fetchPlaylists ( offset ) { return from ( this . musicKitInstance . api . library . playlists ( null , { limit : 100 , offset , } ) ) . pipe ( retryWhen ( ( error ) => error . pipe ( delay ( 500 ) ) ) , timeout ( 5000 ) ) ; } fetchLibrarySongs ( offset = 0 ) { const url = 'v1/me/library/songs' ; return this . fetchLibPage ( url , offset ) ; } fetchLibPage ( url , offset ) { return from ( this . musicKitInstance . api . music ( url , { offset , limit : 100 } ) ) . pipe ( map ( ( res ) => res . data ) ) ; } parseNext ( next , fallback = 0 ) { return next ? parseInt ( next . match ( /\d*$/ ) [ 0 ] , 10 ) : fallback ; } fetchLibraryAlbums ( offset = 0 ) { return from ( this . musicKitInstance . api . music ( 'v1/me/library/albums' , { offset } ) ) . pipe ( map ( ( res ) => res . data ) ) ; } fetchLibraryAlbum ( id ) { return from ( this . musicKitInstance . api . music ( `v1/me/library/albums/${ id }` , { extend : [ 'editorialVideo' ] , } ) ) . pipe ( map ( ( res ) => res . data . data [ 0 ] ) ) ; } fetchLibraryArtists ( offset ) { return from ( this . musicKitInstance . api . library . artists ( null , { limit : 100 , offset , } ) ) ; } fetchLibraryArtist ( id ) { return from ( this . musicKitInstance . api . library . artist ( id , { include : 'albums' , } ) ) ; } searchLibrary ( query ) { const searchTypes = [ 'library-songs' , 'library-albums' , 'library-artists' , 'library-playlists' , ] ; return from ( this . musicKitInstance . api . library . search ( query , { types : searchTypes , limit : 20 , } ) ) . pipe ( map ( ( results ) => ( { songResults : results . songs . data , albumResults : results . albums . data , artistResults : results . artists . data , playlistResults : results . playlists . data , } ) ) ) ; } fetchLibraryPlaylist ( id ) { return from ( this . musicKitInstance . api . library . playlist ( id ) ) ; } async addToLibrary ( id , type ) { const message = new IonicSafeString ( `
      <div>
        <svg class="checkmark" xmlns="http://www.w3.org/2000/svg"  viewBox="0 0 52 52">
          <path class="checkmark__check" fill="none" stroke="grey" d="M14.1 27.2l7.1 7.2 16.7-16.8" />
        </svg>
        <h1>Added to Library</h1>
      <div>
    ` ) ; const loader = await this . loadingCtrl . create ( { cssClass : 'loader-add-to-library' , message , spinner : null , duration : 2000 , } ) ; await this . musicKitInstance . addToLibrary ( id , type ) ; await loader . present ( ) ; } }