Skip to content

Commit

Permalink
feat: bidirectional looping when repeat all is enabled
Browse files Browse the repository at this point in the history
Resolves #32 by adding logic to loop to the last element when navigating backwards from the first
item in the playlist while Repeat All is enabled.
  • Loading branch information
jboix committed Oct 22, 2024
1 parent 9248026 commit 0674a4e
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 8 deletions.
3 changes: 1 addition & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,7 @@ and testing the element.
## Contributing

Contributions are welcome! If you'd like to contribute, please follow the project's code style and
linting rules. Here
are some commands to help you get started:
linting rules. Here are some commands to help you get started:

Check your JavaScript code:

Expand Down
21 changes: 15 additions & 6 deletions packages/pillarbox-playlist/src/pillarbox-playlist.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,6 @@ export class PillarboxPlaylist extends Plugin {
this.updateState_();
}


/**
* Get the currently playing index.
*
Expand Down Expand Up @@ -350,9 +349,9 @@ export class PillarboxPlaylist extends Plugin {
}

/**
* Advances to the next item in the playlist. If repeat mode is enabled, then
* once the last item of the playlist is reached this function will play
* the first one.
* Advances to the next item in the playlist. If {@link RepeatMode#REPEAT_ALL}
* mode is enabled, then once the last item of the playlist is reached this
* function will play the first one.
*/
next() {
if (this.hasNext()) {
Expand Down Expand Up @@ -382,6 +381,8 @@ export class PillarboxPlaylist extends Plugin {
* - If the media is live, navigates to the previous item regardless of the threshold.
* - If playback is beyond the threshold, restarts the current media.
* - If playback is within the threshold, navigates to the previous item.
* - If {@link RepeatMode#REPEAT_ALL} mode is enabled, then once the first
* item of the playlist is reached this function will play the last one.
*
* @see previousNavigationThreshold
*/
Expand All @@ -393,7 +394,15 @@ export class PillarboxPlaylist extends Plugin {
return;
}

this.select(this.currentIndex_ - 1);
if (this.hasPrevious()) {
this.select(this.currentIndex_ - 1);

return;
}

if (this.repeat === RepeatMode.REPEAT_ALL) {
this.select(this.items_.length - 1);
}
}

isLive() {
Expand Down Expand Up @@ -463,7 +472,7 @@ export class PillarboxPlaylist extends Plugin {
updateState_() {
this.setState({
// Converts the items array to a JSON string before setting it in the state.
// Otherwise the change is not detected.
// Otherwise, the change is not detected.
items: JSON.stringify(this.items_),
currentIndex: this.currentIndex_
});
Expand Down
68 changes: 68 additions & 0 deletions packages/pillarbox-playlist/test/pillarbox-playlist.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,29 @@ describe('PillarboxPlaylist', () => {
expect(srcSpy).toHaveBeenLastCalledWith(playlist[3].sources);
expect(posterSpy).toHaveBeenLastCalledWith(playlist[3].poster);
});

it('should play first element if the current index is the last of the playlist and repeat mode all is enabled', () => {
// Given
const srcSpy = vi.spyOn(player, 'src').mockImplementation(() => {
});
const posterSpy = vi.spyOn(player, 'poster').mockImplementation(() => {
});

// When
pillarboxPlaylist.toggleRepeat(RepeatMode.REPEAT_ALL);
pillarboxPlaylist.load(playlist);
pillarboxPlaylist.select(3);
pillarboxPlaylist.next();

// Then
expect(pillarboxPlaylist.hasPrevious()).toBeFalsy();
expect(pillarboxPlaylist.hasNext()).toBeTruthy();
expect(pillarboxPlaylist.items.length).toBe(4);
expect(pillarboxPlaylist.currentIndex).toBe(0);
expect(pillarboxPlaylist.currentItem).toBe(playlist[0]);
expect(srcSpy).toHaveBeenLastCalledWith(playlist[0].sources);
expect(posterSpy).toHaveBeenLastCalledWith(playlist[0].poster);
});
});

describe('previous', () => {
Expand Down Expand Up @@ -246,6 +269,51 @@ describe('PillarboxPlaylist', () => {
expect(pillarboxPlaylist.currentItem).toBe(playlist[2]);
expect(currentTime).toHaveBeenLastCalledWith(0);
});

it('should not play previous if the current index is the last of the playlist', () => {
// Given
const srcSpy = vi.spyOn(player, 'src').mockImplementation(() => {
});
const posterSpy = vi.spyOn(player, 'poster').mockImplementation(() => {
});

// When
pillarboxPlaylist.load(playlist);
pillarboxPlaylist.select(0);
pillarboxPlaylist.previous();

// Then
expect(pillarboxPlaylist.hasPrevious()).toBeFalsy();
expect(pillarboxPlaylist.hasNext()).toBeTruthy();
expect(pillarboxPlaylist.items.length).toBe(4);
expect(pillarboxPlaylist.currentIndex).toBe(0);
expect(pillarboxPlaylist.currentItem).toBe(playlist[0]);
expect(srcSpy).toHaveBeenLastCalledWith(playlist[0].sources);
expect(posterSpy).toHaveBeenLastCalledWith(playlist[0].poster);
});

it('should play last element if the current index is the first of the playlist and repeat mode all is enabled', () => {
// Given
const srcSpy = vi.spyOn(player, 'src').mockImplementation(() => {
});
const posterSpy = vi.spyOn(player, 'poster').mockImplementation(() => {
});

// When
pillarboxPlaylist.toggleRepeat(RepeatMode.REPEAT_ALL);
pillarboxPlaylist.load(playlist);
pillarboxPlaylist.select(0);
pillarboxPlaylist.previous();

// Then
expect(pillarboxPlaylist.hasPrevious()).toBeTruthy();
expect(pillarboxPlaylist.hasNext()).toBeFalsy();
expect(pillarboxPlaylist.items.length).toBe(4);
expect(pillarboxPlaylist.currentIndex).toBe(3);
expect(pillarboxPlaylist.currentItem).toBe(playlist[3]);
expect(srcSpy).toHaveBeenLastCalledWith(playlist[3].sources);
expect(posterSpy).toHaveBeenLastCalledWith(playlist[3].poster);
});
});

describe('autoadvance', () => {
Expand Down

0 comments on commit 0674a4e

Please sign in to comment.