Skip to content

Commit f4fc3dc

Browse files
committed
Convert more functions to async/await
1 parent a6b6e3e commit f4fc3dc

File tree

1 file changed

+99
-95
lines changed

1 file changed

+99
-95
lines changed

src/index.js

Lines changed: 99 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -840,7 +840,6 @@ let audioElement = [],
840840
supportsFileSystemAPI, // browser supports File System API (may be disabled via config.json)
841841
useFileSystemAPI, // load music from local device when in web server mode
842842
userPresets,
843-
waitingMetadata = 0,
844843
wasMuted, // mute status before switching to microphone input
845844
webServer; // web server available? (boolean)
846845

@@ -1139,14 +1138,22 @@ const toggleDisplay = ( el, status ) => {
11391138
el.style.display = status ? '' : 'none';
11401139
}
11411140

1142-
// promise-compatible `onloadeddata` event handler for media elements
1143-
const waitForLoadedData = async audioEl => new Promise( ( resolve, reject ) => {
1141+
/**
1142+
* Wait for a media element to load data
1143+
* @param {HTMLMediaElement} audioEl
1144+
* @returns {Promise<void>}
1145+
*/
1146+
const waitForLoadedData = audioEl => new Promise((resolve, reject) => {
1147+
const cleanup = () => {
1148+
audioEl.onloadeddata = null;
1149+
audioEl.onerror = null;
1150+
};
11441151
audioEl.onerror = () => {
1145-
audioEl.onerror = audioEl.onloadeddata = null;
1146-
reject();
1147-
}
1152+
cleanup();
1153+
reject(new Error("Failed to load media element"));
1154+
};
11481155
audioEl.onloadeddata = () => {
1149-
audioEl.onerror = audioEl.onloadeddata = null;
1156+
cleanup();
11501157
debugLog( 'onLoadedData', { mediaEl: audioEl.id.slice(-1) } );
11511158
resolve();
11521159
};
@@ -1218,52 +1225,49 @@ function addMetadata( metadata, target ) {
12181225
* @param {object} { album, artist, codec, duration, title }
12191226
* @returns {Promise} resolves to 1 when song added, or 0 if queue is full
12201227
*/
1221-
function addSongToPlayQueue( fileObject, content ) {
1228+
async function addSongToPlayQueue( fileObject, content ) {
12221229

1223-
return new Promise( resolve => {
1224-
if ( queueLength() >= MAX_QUEUED_SONGS ) {
1225-
resolve(0);
1226-
return;
1227-
}
1230+
if ( queueLength() >= MAX_QUEUED_SONGS ) {
1231+
return 0;
1232+
}
12281233

1229-
const { fileName, baseName, extension } = parsePath( fileExplorer.decodeChars( fileObject.file ) ),
1230-
uri = normalizeSlashes( fileObject.file ),
1231-
newEl = document.createElement('li'), // create new list element
1232-
trackData = newEl.dataset;
1234+
const { fileName, baseName, extension } = parsePath( fileExplorer.decodeChars( fileObject.file ) ),
1235+
uri = normalizeSlashes( fileObject.file ),
1236+
newEl = document.createElement('li'), // create new list element
1237+
trackData = newEl.dataset;
12331238

1234-
Object.assign( trackData, DATASET_TEMPLATE ); // initialize element's dataset attributes
1239+
Object.assign( trackData, DATASET_TEMPLATE ); // initialize element's dataset attributes
12351240

1236-
if ( ! content )
1237-
content = parseTrackName( baseName );
1241+
if ( ! content )
1242+
content = parseTrackName( baseName );
12381243

1239-
trackData.album = content.album || '';
1240-
trackData.artist = content.artist || '';
1241-
trackData.title = content.title || fileName || uri.slice( uri.lastIndexOf('//') + 2 );
1242-
trackData.duration = content.duration || '';
1243-
trackData.codec = content.codec || extension.toUpperCase();
1244+
trackData.album = content.album || '';
1245+
trackData.artist = content.artist || '';
1246+
trackData.title = content.title || fileName || uri.slice( uri.lastIndexOf('//') + 2 );
1247+
trackData.duration = content.duration || '';
1248+
trackData.codec = content.codec || extension.toUpperCase();
12441249
// trackData.subs = + !! fileObject.subs; // show 'subs' badge in the playqueue (TO-DO: resolve CSS conflict)
12451250

1246-
trackData.file = uri; // for web server access
1247-
newEl.handle = fileObject.handle; // for File System API access
1248-
newEl.dirHandle = fileObject.dirHandle;
1249-
newEl.subs = fileObject.subs; // only defined when coming from the file explorer (not playlists)
1251+
trackData.file = uri; // for web server access
1252+
newEl.handle = fileObject.handle; // for File System API access
1253+
newEl.dirHandle = fileObject.dirHandle;
1254+
newEl.subs = fileObject.subs; // only defined when coming from the file explorer (not playlists)
12501255

1251-
playlist.appendChild( newEl );
1256+
playlist.appendChild( newEl );
12521257

1253-
if ( FILE_EXT_AUDIO.includes( extension ) || ! extension ) {
1254-
// disable retrieving metadata of video files for now - https://github.com/Borewit/music-metadata-browser/issues/950
1255-
trackData.retrieve = 1; // flag this item as needing metadata
1256-
retrieveMetadata();
1257-
}
1258+
if ( FILE_EXT_AUDIO.includes( extension ) || ! extension ) {
1259+
// disable retrieving metadata of video files for now - https://github.com/Borewit/music-metadata-browser/issues/950
1260+
trackData.retrieve = 1; // flag this item as needing metadata
1261+
await retrieveMetadata();
1262+
}
12581263

1259-
if ( queueLength() == 1 && ! isPlaying() )
1260-
loadSong(0).then( () => resolve(1) );
1261-
else {
1262-
if ( playlistPos > queueLength() - 3 )
1263-
loadSong( NEXT_TRACK );
1264-
resolve(1);
1265-
}
1266-
});
1264+
if ( queueLength() === 1 && ! isPlaying() ) {
1265+
await loadSong( 0 );
1266+
} else {
1267+
if ( playlistPos > queueLength() - 3 )
1268+
await loadSong( NEXT_TRACK );
1269+
}
1270+
return 1;
12671271
}
12681272

12691273
/**
@@ -2016,7 +2020,7 @@ function keyboardControls( event ) {
20162020
}
20172021

20182022
/**
2019-
* Sets (or removes) the `src` attribute of a audio element and
2023+
* Sets (or removes) the `src` attribute of an audio element and
20202024
* releases any data blob (File System API) previously in use by it
20212025
*
20222026
* @param {object} audio element
@@ -2039,22 +2043,28 @@ function loadAudioSource( audioEl, newSource ) {
20392043
/**
20402044
* Load a file blob into an audio element
20412045
*
2042-
* @param {object} audio element
2043-
* @param {object} file blob
2044-
* @param {boolean} `true` to start playing
2045-
* @returns {Promise} resolves to a string containing the URL created for the blob
2046+
* @param {Blob} fileBlob The audio file blob
2047+
* @param {HTMLAudioElement} audioEl The audio element
2048+
* @param {boolean} playIt When `true` will start playing
2049+
* @returns {Promise<string>} Resolves to blob URL
20462050
*/
2047-
async function loadFileBlob( fileBlob, audioEl, playIt ) {
2048-
const url = URL.createObjectURL( fileBlob );
2049-
loadAudioSource( audioEl, url );
2051+
async function loadFileBlob(fileBlob, audioEl, playIt) {
2052+
const url = URL.createObjectURL(fileBlob);
2053+
loadAudioSource(audioEl, url);
2054+
20502055
try {
2051-
await waitForLoadedData( audioEl );
2052-
if ( playIt )
2053-
audioEl.play();
2056+
await waitForLoadedData(audioEl);
2057+
if (playIt) {
2058+
try {
2059+
await audioEl.play();
2060+
} catch (err) {
2061+
consoleLog("Playback failed:", err);
2062+
}
2063+
}
2064+
return url;
2065+
} catch (err) {
2066+
throw new Error("Failed to load audio from Blob");
20542067
}
2055-
catch ( e ) {}
2056-
2057-
return url;
20582068
}
20592069

20602070
/**
@@ -3294,60 +3304,54 @@ async function retrieveBackgrounds() {
32943304
}
32953305

32963306
/**
3297-
* Retrieve metadata for files in the play queue
3307+
* Retrieve metadata for the first MAX_METADATA_REQUESTS files in the play queue,
3308+
* which have no metadata assigned yet
32983309
*/
32993310
async function retrieveMetadata() {
3300-
// leave when we already have enough concurrent requests pending
3301-
if ( waitingMetadata >= MAX_METADATA_REQUESTS )
3302-
return;
3303-
3304-
// find the first play queue item for which we haven't retrieved the metadata yet
3305-
const queueItem = Array.from( playlist.children ).find( el => el.dataset.retrieve );
33063311

3307-
if ( queueItem ) {
3312+
// find the first MAX_METADATA_REQUESTS items for which we haven't retrieved the metadata yet
3313+
const retrievalQueue = Array.from(playlist.children).filter(el => el.dataset.retrieve).slice(0, MAX_METADATA_REQUESTS);
33083314

3315+
// Execute in parallel
3316+
return Promise.all(retrievalQueue.map(async queueItem => {
33093317
let uri = queueItem.dataset.file,
33103318
revoke = false;
33113319

3312-
waitingMetadata++;
33133320
delete queueItem.dataset.retrieve;
33143321

3315-
queryMetadata: {
3316-
if ( queueItem.handle ) {
3317-
try {
3318-
if ( await queueItem.handle.requestPermission() != 'granted' )
3319-
break queryMetadata;
33203322

3321-
uri = URL.createObjectURL( await queueItem.handle.getFile() );
3322-
revoke = true;
3323-
}
3324-
catch( e ) {
3325-
break queryMetadata;
3326-
}
3323+
if ( queueItem.handle ) {
3324+
try {
3325+
if ( await queueItem.handle.requestPermission() !== 'granted' )
3326+
return;
3327+
3328+
uri = URL.createObjectURL( await queueItem.handle.getFile() );
3329+
revoke = true;
3330+
}
3331+
catch( e ) {
3332+
consoleLog(`Error converting queued file="${queueItem.handle.file}" to URI`, e);
3333+
return;
33273334
}
3335+
}
33283336

3329-
try {
3330-
const metadata = await mm.fetchFromUrl( uri, { skipPostHeaders: true } );
3331-
if ( metadata ) {
3332-
addMetadata( metadata, queueItem ); // add metadata to play queue item
3337+
try {
3338+
const metadata = await mm.fetchFromUrl( uri, { skipPostHeaders: true } );
3339+
addMetadata( metadata, queueItem ); // add metadata to play queue item
3340+
syncMetadataToAudioElements( queueItem );
3341+
if ( ! ( metadata.common.picture && metadata.common.picture.length ) ) {
3342+
getFolderCover( queueItem ).then( cover => {
3343+
queueItem.dataset.cover = cover;
33333344
syncMetadataToAudioElements( queueItem );
3334-
if ( ! ( metadata.common.picture && metadata.common.picture.length ) ) {
3335-
getFolderCover( queueItem ).then( cover => {
3336-
queueItem.dataset.cover = cover;
3337-
syncMetadataToAudioElements( queueItem );
3338-
});
3339-
}
3340-
}
3345+
});
33413346
}
3342-
catch( e ) {}
3343-
3344-
if ( revoke )
3345-
URL.revokeObjectURL( uri );
3347+
}
3348+
catch( e ) {
3349+
consoleLog(`Failed to fetch or add metadata for queued file="${queueItem.handle.file}"`, e);
33463350
}
33473351

3348-
waitingMetadata--;
3349-
retrieveMetadata(); // call again to continue processing the queue
3350-
}
3352+
if ( revoke )
3353+
URL.revokeObjectURL( uri );
3354+
}));
33513355
}
33523356

33533357
/**

0 commit comments

Comments
 (0)