Skip to content

Commit ec6146b

Browse files
committed
fix: skip to next track on file error; ensure queue pointer keeps in sync
1 parent f78726a commit ec6146b

File tree

2 files changed

+39
-39
lines changed

2 files changed

+39
-39
lines changed

src/index.js

Lines changed: 38 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,10 +1262,13 @@ function addSongToPlayQueue( fileObject, content ) {
12621262
retrieveMetadata();
12631263
}
12641264

1265-
if ( queueLength() == 1 && ! isPlaying() )
1265+
if ( queueLength() == 1 && ! isPlaying() ) {
1266+
// if the added song is the only one in the queue and no audio is currently playing, load it into the primary media element
12661267
loadSong(0).then( () => resolve(1) );
1268+
}
12671269
else {
1268-
if ( queueIndex > queueLength() - 3 )
1270+
// if the queue pointer was at the last song, load the newly added song into the secondary media element
1271+
if ( queueIndex == queueLength() - 2 )
12691272
loadSong( NEXT_TRACK );
12701273
resolve(1);
12711274
}
@@ -1349,14 +1352,13 @@ function clearPlayQueue() {
13491352
revokeBlobURL( elPlayqueue.removeChild( elPlayqueue.firstChild ) );
13501353

13511354
if ( ! isPlaying() ) {
1352-
queueIndex = 0;
1355+
setQueueIndex(0);
13531356
clearAudioElement( currAudio );
13541357
}
13551358
else
1356-
queueIndex = -1;
1359+
setQueueIndex(-1);
13571360

13581361
clearAudioElement( nextAudio );
1359-
updatePlaylistUI();
13601362
}
13611363

13621364
/**
@@ -1900,11 +1902,11 @@ function keyboardControls( event ) {
19001902
});
19011903
const current = getIndex( elPlayqueue.querySelector('.current') );
19021904
if ( current !== undefined )
1903-
queueIndex = current; // update queueIndex if current song hasn't been deleted
1905+
setQueueIndex( current ); // keep the pointer at the current track, if it hasn't been deleted
19041906
else if ( queueIndex > queueLength() - 1 )
1905-
queueIndex = queueLength() - 1;
1907+
setQueueIndex( queueLength() - 1 );
19061908
else
1907-
queueIndex--;
1909+
setQueueIndex( queueIndex - 1 );
19081910
if ( queueLength() )
19091911
loadSong( NEXT_TRACK );
19101912
else {
@@ -2572,20 +2574,20 @@ async function loadSavedPlaylists( keyName ) {
25722574
}
25732575

25742576
/**
2575-
* Load a song from the queue into the currently active audio element
2577+
* Load a song from the queue into one of the media elements
25762578
*
2577-
* @param {number} index to the desired play queue element
2579+
* @param {number} index to the desired queue element to load; -1 to load the track after the current queueIndex
25782580
* @param {boolean} `true` to start playing
2579-
* @returns {Promise} resolves to a boolean indicating success or failure (invalid queue index)
2581+
* @returns {Promise} resolves to a boolean indicating success or failure
25802582
*/
25812583
async function loadSong( n, playIt ) {
2582-
const isCurrent = n !== NEXT_TRACK,
2583-
index = isCurrent ? n : ( ( queueIndex < queueLength() - 1 ) ? queueIndex + 1 : 0 ),
2584-
mediaEl = isCurrent ? currAudio : nextAudio,
2584+
const isCurrent = n !== NEXT_TRACK || playIt, // if requested to play, always use the primary media element
2585+
index = n !== NEXT_TRACK ? n : ( ( queueIndex < queueLength() - 1 ) ? queueIndex + 1 : 0 ),
2586+
mediaEl = isCurrent ? currAudio : nextAudio, // next track is (usually) loaded in the secondary element
25852587
audioEl = audioElement[ mediaEl ],
25862588
song = elPlayqueue.children[ index ];
25872589

2588-
debugLog( 'loadSong start', { mediaEl, n, index } );
2590+
debugLog( 'loadSong start', { n, index, mediaEl } );
25892591

25902592
if ( ! isCurrent )
25912593
setSubtitlesDisplay(); // avoid stuck subtitles on track change
@@ -2594,7 +2596,7 @@ async function loadSong( n, playIt ) {
25942596

25952597
if ( song ) {
25962598
if ( isCurrent )
2597-
queueIndex = index;
2599+
setQueueIndex( index );
25982600

25992601
addMetadata( song, audioEl );
26002602
loadSubs( audioEl, song );
@@ -2617,29 +2619,27 @@ async function loadSong( n, playIt ) {
26172619
loadAudioSource( audioEl, song.dataset.file );
26182620
try {
26192621
await waitForLoadedData( audioEl );
2620-
if ( isCurrent && playIt )
2622+
if ( playIt )
26212623
audioEl.play();
26222624
success = true;
26232625
}
26242626
catch( e ) {} // error will be handled (logged) by `audioOnError()`
26252627
}
26262628

2627-
if ( success ) {
2628-
if ( isCurrent ) {
2629-
updatePlaylistUI();
2630-
loadSong( NEXT_TRACK );
2631-
}
2632-
else
2633-
audioEl.load();
2634-
}
2629+
if ( ! success && playIt ) // in case of error and play was requested, try the next track
2630+
loadSong( NEXT_TRACK, playIt );
2631+
else if ( isCurrent ) // load the next track in the secondary element
2632+
loadSong( NEXT_TRACK );
2633+
// else
2634+
// audioEl.load(); // intended to improve gapless playback, but its effectiveness was inconclusive (generates additional abort/emptied events)
26352635

26362636
song.classList.toggle( 'error', ! success );
26372637
}
26382638

26392639
if ( ! isCurrent )
26402640
skipping = false; // finished skipping track
26412641

2642-
debugLog( 'loadSong end', { mediaEl, success } );
2642+
debugLog( 'loadSong end', { n, index, mediaEl, success } );
26432643

26442644
return success;
26452645
}
@@ -2747,7 +2747,7 @@ function openGradientEditorNew( makeCopy ) {
27472747
}
27482748

27492749
/**
2750-
* Play next song on queue
2750+
* Plays the track loaded into the secondary media element (and make it the current one)
27512751
*/
27522752
function playNextSong( play ) {
27532753
debugLog( 'playNextSong', { play, queueIndex, skipping } );
@@ -2758,9 +2758,9 @@ function playNextSong( play ) {
27582758
skipping = true;
27592759

27602760
if ( queueIndex < queueLength() - 1 )
2761-
queueIndex++;
2761+
setQueueIndex( queueIndex + 1 );
27622762
else if ( isSwitchOn( elRepeat ) )
2763-
queueIndex = 0;
2763+
setQueueIndex(0);
27642764
else {
27652765
skipping = false;
27662766
return false;
@@ -2772,23 +2772,21 @@ function playNextSong( play ) {
27722772
setOverlay();
27732773
setCurrentCover();
27742774

2775-
if ( play && audioElement[ currAudio ].src ) { // note: play() on empty element never resolves!
2776-
audioElement[ currAudio ].play()
2775+
const audioEl = audioElement[ currAudio ];
2776+
if ( play && audioEl.src ) { // note: play() on empty element never resolves!
2777+
audioEl.play()
27772778
.then( () => loadSong( NEXT_TRACK ) )
27782779
.catch( err => {
2779-
debugLog( { err } );
27802780
// ignore AbortError when play promise is interrupted by a new load request or call to pause()
27812781
if ( err.code != ERR_ABORT ) {
27822782
consoleLog( err, true );
2783-
loadSong( NEXT_TRACK );
2784-
playNextSong( true );
2783+
loadSong( NEXT_TRACK, play );
27852784
}
27862785
});
27872786
}
27882787
else
27892788
loadSong( NEXT_TRACK );
27902789

2791-
updatePlaylistUI();
27922790
return true;
27932791
}
27942792

@@ -4818,9 +4816,10 @@ function toggleMultiChannel() {
48184816
}
48194817

48204818
/**
4821-
* Update the play queue
4819+
* Set the `queueIndex` global and update the play queue display
48224820
*/
4823-
function updatePlaylistUI() {
4821+
function setQueueIndex( newValue ) {
4822+
queueIndex = newValue;
48244823

48254824
const current = elPlayqueue.querySelector('.current'),
48264825
newCurr = elPlayqueue.children[ queueIndex ];
@@ -5247,7 +5246,7 @@ function updateRangeValue( el ) {
52475246
e.target.classList.remove( 'selected', 'sortable-chosen' );
52485247
}
52495248
});
5250-
queueIndex = 0;
5249+
setQueueIndex(0);
52515250

52525251
// Add drag-n-drop functionality to the play queue
52535252
Sortable.create( elPlayqueue, {
@@ -5261,7 +5260,7 @@ function updateRangeValue( el ) {
52615260
multiDragKey: 'ctrl',
52625261
selectedClass: 'selected',
52635262
onEnd: evt => {
5264-
queueIndex = getIndex( elPlayqueue.querySelector('.current') );
5263+
setQueueIndex( getIndex( elPlayqueue.querySelector('.current') ) );
52655264
if ( evt.newIndex == 0 && ! isPlaying() )
52665265
loadSong(0);
52675266
else

src/styles.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,6 +1261,7 @@ kbd.wide {
12611261
#console-content div {
12621262
margin-left: 8.75em;
12631263
text-indent: -9em;
1264+
word-break: break-all;
12641265
}
12651266

12661267
.credits {

0 commit comments

Comments
 (0)