Skip to content

Commit 6e80e97

Browse files
committed
Convert more functions to async/await
1 parent 8c0b9a8 commit 6e80e97

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
@@ -841,7 +841,6 @@ let audioElement = [],
841841
supportsFileSystemAPI, // browser supports File System API (may be disabled via config.yaml)
842842
useFileSystemAPI, // load music from local device when in web server mode
843843
userPresets,
844-
waitingMetadata = 0,
845844
wasMuted, // mute status before switching to microphone input
846845
webServer; // web server available? (boolean)
847846

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

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

1224-
return new Promise( resolve => {
1225-
if ( queueLength() >= MAX_QUEUED_SONGS ) {
1226-
resolve(0);
1227-
return;
1228-
}
1231+
if ( queueLength() >= MAX_QUEUED_SONGS ) {
1232+
return 0;
1233+
}
12291234

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

1235-
Object.assign( trackData, DATASET_TEMPLATE ); // initialize element's dataset attributes
1240+
Object.assign( trackData, DATASET_TEMPLATE ); // initialize element's dataset attributes
12361241

1237-
if ( ! content )
1238-
content = parseTrackName( baseName );
1242+
if ( ! content )
1243+
content = parseTrackName( baseName );
12391244

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

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

1252-
playlist.appendChild( newEl );
1257+
playlist.appendChild( newEl );
12531258

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

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

12701274
/**
@@ -2017,7 +2021,7 @@ function keyboardControls( event ) {
20172021
}
20182022

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

20612071
/**
@@ -3295,60 +3305,54 @@ async function retrieveBackgrounds() {
32953305
}
32963306

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

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

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

3313-
waitingMetadata++;
33143321
delete queueItem.dataset.retrieve;
33153322

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

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

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

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

33543358
/**

0 commit comments

Comments
 (0)