@@ -36,6 +36,7 @@ import {parseBlob, parseWebStream} from 'music-metadata';
3636import './scrollIntoViewIfNeeded-polyfill.js' ;
3737import { get , set , del } from 'idb-keyval' ;
3838import * as yaml from 'js-yaml' ;
39+ import pLimit from 'p-limit' ;
3940
4041import Sortable , { MultiDrag } from 'sortablejs' ;
4142Sortable . mount ( new MultiDrag ( ) ) ;
@@ -958,6 +959,9 @@ const getCurrentSettings = _ => ({
958959 weighting : getControlValue ( elWeighting )
959960} ) ;
960961
962+ // Limit the number of parallel metadata requests
963+ const metadataRequestLimit = pLimit ( MAX_METADATA_REQUESTS ) ;
964+
961965// get the array index for a preset key, or validate a given index; if invalid or not found returns -1
962966const getPresetIndex = key => {
963967 const index = ( + key == key ) ? key : presets . findIndex ( item => item . key == key ) ;
@@ -1251,7 +1255,7 @@ async function addSongToPlayQueue( fileObject, content ) {
12511255 if ( FILE_EXT_AUDIO . includes ( extension ) || ! extension ) {
12521256 // disable retrieving metadata of video files for now - https://github.com/Borewit/music-metadata-browser/issues/950
12531257 trackData . retrieve = 1 ; // flag this item as needing metadata
1254- await retrieveMetadata ( ) ;
1258+ retrieveMetadata ( ) ; // ToDo improve handling promise
12551259 }
12561260
12571261 if ( queueLength ( ) === 1 && ! isPlaying ( ) )
@@ -1266,22 +1270,18 @@ async function addSongToPlayQueue( fileObject, content ) {
12661270/**
12671271 * Add a song or playlist to the play queue
12681272 */
1269- function addToPlayQueue ( fileObject , autoplay = false ) {
1270-
1271- let ret ;
1273+ async function addToPlayQueue ( fileObject , autoplay = false ) {
12721274
1275+ let n ;
12731276 if ( FILE_EXT_PLIST . includes ( parsePath ( fileObject . file ) . extension ) )
1274- ret = loadPlaylist ( fileObject ) ;
1277+ n = await loadPlaylist ( fileObject ) ;
12751278 else
1276- ret = addSongToPlayQueue ( fileObject ) ;
1279+ n = await addSongToPlayQueue ( fileObject ) ;
12771280
12781281 // when promise resolved, if autoplay requested start playing the first added song
1279- ret . then ( n => {
1280- if ( autoplay && ! isPlaying ( ) && n > 0 )
1281- playSong ( queueLength ( ) - n ) ;
1282- } ) ;
12831282
1284- return ret ;
1283+ if ( autoplay && ! isPlaying ( ) && n > 0 )
1284+ playSong ( queueLength ( ) - n ) ;
12851285}
12861286
12871287/**
@@ -1290,7 +1290,7 @@ function addToPlayQueue( fileObject, autoplay = false ) {
12901290function changeFsHeight ( incr ) {
12911291 const val = + elFsHeight . value ;
12921292
1293- if ( incr == 1 && val < + elFsHeight . max || incr == - 1 && val > + elFsHeight . min ) {
1293+ if ( incr === 1 && val < + elFsHeight . max || incr = == - 1 && val > + elFsHeight . min ) {
12941294 elFsHeight . value = val + elFsHeight . step * incr ;
12951295 setProperty ( elFsHeight ) ;
12961296 }
@@ -3274,81 +3274,98 @@ async function retrieveBackgrounds() {
32743274 catch ( e ) { } // needs permission to access local device
32753275 }
32763276
3277- if ( bgLocation != BGFOLDER_NONE ) {
3277+ if ( bgLocation !== BGFOLDER_NONE ) {
32783278 const imageCount = bgImages . length ,
32793279 videoCount = bgVideos . length ;
32803280
3281- consoleLog ( 'Found ' + ( imageCount + videoCount == 0 ? 'no media' : imageCount + ' image files and ' + videoCount + ' video' ) + ' files in the backgrounds folder' ) ;
3281+ consoleLog ( 'Found ' + ( imageCount + videoCount === 0 ? 'no media' : imageCount + ' image files and ' + videoCount + ' video' ) + ' files in the backgrounds folder' ) ;
32823282 }
32833283
32843284 populateBackgrounds ( ) ;
32853285}
32863286
32873287/**
3288- * Retrieve metadata for the first MAX_METADATA_REQUESTS files in the play queue,
3288+ * Retrieve metadata for queueItem
32893289 * which have no metadata assigned yet
32903290 */
3291- async function retrieveMetadata ( ) {
3291+ async function retrieveMetadataForQueueItem ( queueItem ) {
32923292
3293- // Process in sequential order
3294- for ( const queueItem of playlist . children ) {
3295-
3296- if ( ! queueItem . dataset . retrieve ) continue ;
3297- delete queueItem . dataset . retrieve ;
3298-
3299- let metadata ;
3300- let file ;
3293+ let metadata ;
3294+ let file ;
33013295
3302- try {
3303- if ( queueItem . handle ) {
3296+ try {
3297+ if ( queueItem . handle ) {
33043298
3305- // Fetch metadata from File object
3306- if ( await queueItem . handle . requestPermission ( ) !== 'granted' )
3307- return ;
3299+ // Fetch metadata from File object
3300+ if ( await queueItem . handle . requestPermission ( ) !== 'granted' )
3301+ return ;
33083302
3309- file = await queueItem . handle . getFile ( ) ;
3310- metadata = await parseBlob ( file ) ;
3311- }
3312- else
3313- {
3314- // Fetch metadata from URI
3315- const response = await fetch ( queueItem . dataset . file ) ;
3316- if ( response . ok ) {
3317- if ( response . body ?. getReader ) {
3318- const contentType = response . headers . get ( "Content-Type" ) ;
3319- const contentSize = response . headers . get ( "Content-Length" ) ;
3320- try {
3321- metadata = await parseWebStream ( response . body , {
3322- mimeType : contentType ,
3323- size : contentSize ? Number . parseInt ( contentSize , 10 ) : undefined
3324- } , { skipPostHeaders : true } ) ;
3325- } finally {
3326- await response . body . cancel ( ) ;
3327- }
3328- } else {
3329- // Fallback to Blob, in case the HTTP Result cannot be streamed
3330- metadata = await parseBlob ( await response . blob ( ) ) ;
3303+ file = await queueItem . handle . getFile ( ) ;
3304+ metadata = await parseBlob ( file ) ;
3305+ }
3306+ else
3307+ {
3308+ // Fetch metadata from URI
3309+ const response = await fetch ( queueItem . dataset . file ) ;
3310+ if ( response . ok ) {
3311+ if ( response . body ?. getReader ) {
3312+ const contentType = response . headers . get ( "Content-Type" ) ;
3313+ const contentSize = response . headers . get ( "Content-Length" ) ;
3314+ try {
3315+ metadata = await parseWebStream ( response . body , {
3316+ mimeType : contentType ,
3317+ size : contentSize ? Number . parseInt ( contentSize , 10 ) : undefined
3318+ } , { skipPostHeaders : true } ) ;
3319+ } finally {
3320+ await response . body . cancel ( ) ;
33313321 }
33323322 } else {
3333- consoleLog ( `Failed to fetch metadata http-response=${ response . status } for url=${ queueItem . dataset . file } ` , true ) ;
3323+ // Fallback to Blob, in case the HTTP Result cannot be streamed
3324+ metadata = await parseBlob ( await response . blob ( ) ) ;
33343325 }
3326+ } else {
3327+ consoleLog ( `Failed to fetch metadata http-response=${ response . status } for url=${ queueItem . dataset . file } ` , true ) ;
33353328 }
33363329 }
3337- catch ( e ) {
3338- consoleLog ( `Error converting queued file="${ queueItem . dataset . file ?? '?' } " to URI` , e ) ;
3339- return ;
3340- }
3330+ }
3331+ catch ( e ) {
3332+ consoleLog ( `Error converting queued file="${ queueItem . dataset . file ?? '?' } " to URI` , e ) ;
3333+ return ;
3334+ }
33413335
3342- console . log ( `Fetched metadata successful for url=${ queueItem . dataset . file } ` ) ;
3343- addMetadata ( metadata , queueItem ) ; // add metadata to play queue item
3336+ addMetadata ( metadata , queueItem ) ; // add metadata to play queue item
33443337
3345- // If no embedded picture, try folder cover
3346- if ( ! ( metadata . common . picture && metadata . common . picture . length > 0 ) ) {
3347- queueItem . dataset . cover = await getFolderCover ( queueItem ) ;
3348- }
3338+ // If no embedded picture, try folder cover
3339+ if ( ! ( metadata . common . picture && metadata . common . picture . length > 0 ) ) {
3340+ queueItem . dataset . cover = await getFolderCover ( queueItem ) ;
3341+ }
33493342
3350- syncMetadataToAudioElements ( queueItem ) ;
3343+ syncMetadataToAudioElements ( queueItem ) ;
3344+
3345+ }
3346+
3347+ /**
3348+ * Retrieve metadata for each entry of the queue which has not metadata assigned yet
3349+ * which have no metadata assigned yet
3350+ */
3351+ async function retrieveMetadata ( ) {
3352+
3353+
3354+ const promises = [ ] ;
3355+
3356+ // Process in sequential order
3357+ for ( const queueItem of playlist . children ) {
3358+
3359+ // Only process items with metadata
3360+ if ( queueItem . dataset . retrieve ) {
3361+ // Clear metadata retrieval flag
3362+ delete queueItem . dataset . retrieve ;
3363+ // Sets a global limit, as the function is call for each entry added
3364+ promises . push ( metadataRequestLimit ( ( ) => retrieveMetadataForQueueItem ( queueItem ) ) ) ;
3365+ }
33513366 }
3367+
3368+ return Promise . all ( promises ) ;
33523369}
33533370
33543371/**
0 commit comments