import PouchDB from 'pouchdb' ; import * as PQueue from 'p-queue' ; const debounce = require ( 'debounce' ) ; import Session from 'app/session' ; const BLANK_IMAGE = 'data:image/png;base64,R0lGODlhFAAUAIAAAP///wAAACH5BAEAAAAALAAAAAAUABQAAAIRhI+py+0Po5y02ouz3rz7rxUAOw==' ; export default class Artwork { private queue : PQueue ; private blobCache : { [ id ] : [ number , Promise < string > ] ; } = { } ; private artworks : PouchDB . Database < { } > ; private static sInstance : Artwork ; private PouchDB : PouchDB . Static ; private constructor ( pouch = PouchDB ) { this . PouchDB = pouch ; this . artworks = new pouch ( 'artworks' ) ; this . queue = new PQueue ( { concurrency : 2 , } ) ; } loadLargeCover ( id , size = 64 , target ) { return this . load ( id , 'large' , target ) ; } loadSmallCover ( id , size = 32 , target ) { return this . load ( id , 'small' , target ) ; } attach ( blob , target ) { return new Promise ( ( resolve ) => { if ( ! window . document . contains ( target ) ) { return resolve ( blob ) ; } target . src = URL . createObjectURL ( blob ) ; target . addEventListener ( 'load' , function onload ( ) { resolve ( blob ) ; } , { once : true } as any ) ; } ) ; } shouldAttach ( docId , target ) { if ( ! document . contains ( target ) ) { return false ; } const attr = target . getAttribute ( 'data-doc-id' ) ; if ( attr && attr !== docId ) { return false ; } return true ; } param docId param size load ( docId , size , target , watch = true ) { if ( ! docId . startsWith ( 'artworks/' ) ) { docId = 'artworks/' + docId ; } target . src = BLANK_IMAGE ; return this . queue . add ( ( ) => { if ( ! this . shouldAttach ( docId , target ) ) { return Promise . resolve ( new Blob ( ) ) ; } if ( watch ) { const changes = this . artworks . changes ( { doc_ids : [ docId ] , live : true , since : 'now' } ) . on ( 'change' , debounce ( ( info ) => { if ( ! this . shouldAttach ( docId , target ) ) { return changes . cancel ( ) ; } this . load ( docId , size , target , false ) ; } , 500 , false ) ) ; } return this . artworks . getAttachment ( docId , size ) . catch ( ( err ) => { if ( size === 'hq' ) { return this . load ( docId , 'large' , target , false ) ; } console . log ( 'No attachment for: ' + docId ) ; return fetch ( '/api/assets/no-album.jpg' , { method : 'GET' , headers : Session . headers ( ) } ) . then ( ( res ) => { return res . blob ( ) ; } ) ; } ) . then ( ( res ) => { if ( ! this . shouldAttach ( docId , target ) ) { return Promise . resolve ( new Blob ( ) ) ; } return this . attach ( res , target ) ; } ) ; } ) ; } public static getInstance ( pouch = PouchDB ) { if ( ! Artwork . sInstance ) { if ( ! pouch ) { throw new Error ( "Missing pouch parameter for initialization" ) ; } Artwork . sInstance = new Artwork ( pouch ) ; } return Artwork . sInstance ; } public static createInstance ( pouch ? ) { Artwork . sInstance = new Artwork ( pouch ) ; } }