import { Observable , of } from 'rxjs' ; import { catchError , flatMap , map , timeout } from 'rxjs/operators' ; import { ID3WriterService , IID3Writer } from 'src/ts/download/metadata/id3-writer-service' ; import { ITrackMetadata } from 'src/ts/download/metadata/track-metadata' ; import { ITrackDownloadInfo } from 'src/ts/download/track-download-info' ; import { logger } from 'src/ts/util/logger' ; import { XhrService } from 'src/ts/util/xhr-service' ; /**
 * Adds ID3 v2.4 tags and returns downloadInfo with url in downloadOptions set to the updated URL.
 * To add the tags, it must download the entire mp3 file as an array buffer in memory, hence the
 * generous timeout allotted for the operation.
 */ export const ID3MetadataService = { addID3V2Metadata$ ( metadata , downloadInfo ) { return XhrService . getArrayBuffer$ ( downloadInfo . downloadOptions . url ) . pipe ( timeout ( 1800000 ) , flatMap ( writeMetadata$ . bind ( null , metadata ) ) , map ( ID3WriterService . getURL ) , map ( ( url ) => ( { ... downloadInfo , downloadOptions : { ... downloadInfo . downloadOptions , url , } , } as any ) ) , catchError ( ( err ) => { logger . error ( `Unable to fetch metadata for track ${ downloadInfo . trackInfo . title }` , err ) ; return of ( downloadInfo ) ; } ) ) ; } , } ; function writeMetadata$ ( metadata , arrayBuffer ) { return of ( ID3WriterService . createWriter ( arrayBuffer ) ) . pipe ( map ( withTextualMetadata . bind ( null , metadata ) ) , flatMap ( withCoverArt$ . bind ( null , metadata ) ) , map ( ID3WriterService . addTag ) ) ; } function withTextualMetadata ( metadata , writer ) { ID3WriterService . setFrame ( writer , 'TIT2' , metadata . title ) ; ID3WriterService . setFrame ( writer , 'TPE1' , [ metadata . albumArtist ] ) ; ID3WriterService . setFrame ( writer , 'TPE2' , metadata . albumArtist ) ; ID3WriterService . setFrame ( writer , 'TCON' , metadata . genres ) ; ID3WriterService . setFrame ( writer , 'TLEN' , metadata . duration ) ; ID3WriterService . setFrame ( writer , 'TYER' , metadata . release_year ) ; ID3WriterService . setFrame ( writer , 'TBPM' , metadata . bpm ) ; ID3WriterService . setFrame ( writer , 'WOAR' , metadata . artist_url ) ; ID3WriterService . setFrame ( writer , 'WOAS' , metadata . audio_source_url ) ; ID3WriterService . setFrame ( writer , 'COMM' , { description : 'Soundcloud description' , text : metadata . description || '' , } ) ; return writer ; } function withCoverArt$ ( metadata , writer ) { const url = metadata . cover_url ; if ( ! url ) { return of ( writer ) ; } return XhrService . getArrayBuffer$ ( url ) . pipe ( timeout ( 60000 ) , map ( ( arrayBuffer ) => ID3WriterService . setFrame ( writer , 'APIC' , { data : arrayBuffer , description : `Soundcloud artwork. Source: ${ url }` , type : 3 , useUnicodeEncoding : false , } ) ) , catchError ( ( err ) => { logger . error ( `Unable to fetch cover art for track ${ metadata . title }` , err ) ; return of ( writer ) ; } ) ) ; }