Skip to content

Commit

Permalink
feat(playlist-plugin): add reverse and sort functionality
Browse files Browse the repository at this point in the history
Resolves #18 by adding `reverse` and `sort` methods to the playlist plugin.

- The `reverse` method reverses the order of the playlist items and updates the current index
  accordingly.
- The `sort` method sorts the playlist items based on a provided comparison function and updates the
  current index accordingly.
  • Loading branch information
jboix committed Jun 6, 2024
1 parent 9526479 commit a1a37b8
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 5 deletions.
6 changes: 4 additions & 2 deletions packages/pillarbox-playlist/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,14 @@ The following table outlines the key methods available in the this plugin:
| `push(...items)` | Adds new items to the end of the current playlist. |
| `splice(start, deleteCount, ...items)` | Modifies the playlist by adding, removing, or replacing items. Adjusts the current index if necessary. |
| `clear()` | Clears the internal playlist. Does not stop or unload the currently playing media. |
| `reverse()` | Reverses the order of the items in the playlist. Adjusts the current index if necessary. |
| `sort(compareFn?)` | Sorts the items in the playlist using the provided compare function. Adjusts the current index if necessary. |
| `next()` | Advances to the next item in the playlist, with support for repeat mode. |
| `previous()` | Moves to the previous item in the playlist. |
| `shuffle()` | Randomizes the order of the playlist items using the Fisher-Yates shuffle algorithm. |
| `select(index)` | Selects and plays the item at the specified index in the playlist. |
| `toggleRepeat(force)` | Toggles the repeat mode of the player to the opposite of its current state, or sets it to the specified boolean value if provided. |
| `toggleAutoadvance(force)` | Toggles the auto-advance mode of the player to the opposite of its current state, or sets it to the specified boolean value if provided. |
| `toggleRepeat(force?)` | Toggles the repeat mode of the player to the opposite of its current state, or sets it to the specified boolean value if provided. |
| `toggleAutoadvance(force?)` | Toggles the auto-advance mode of the player to the opposite of its current state, or sets it to the specified boolean value if provided. |

#### Options

Expand Down
45 changes: 44 additions & 1 deletion packages/pillarbox-playlist/src/pillarbox-playlist.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ class PillarboxPlaylist extends Plugin {
* running.
*
* @param {...PlaylistItem} items the items to add to the playlist.
*
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push
*/
push(...items) {
this.items_.push(...items);
Expand All @@ -136,14 +138,16 @@ class PillarboxPlaylist extends Plugin {
* @param {...PlaylistItem} items The items to add to the playlist.
*
* @return {PlaylistItem[]} An array containing the deleted elements.
*
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
*/
splice(start, deleteCount, ...items) {
const itemsAddedCount = items.length;
const deletedElements = this.items_.splice(start, deleteCount, ...items);
const deletedElementsCount = deletedElements.length;

if (this.currentIndex_ >= start &&
this.currentIndex_ < start + deletedElementsCount) {
this.currentIndex_ < start + deletedElementsCount) {
// Current item was removed, set currentIndex to -1
this.currentIndex_ = -1;
} else if (this.currentIndex_ >= start) {
Expand All @@ -169,6 +173,45 @@ class PillarboxPlaylist extends Plugin {
this.updateState_();
}

/**
* Reverses the order of the items in the playlist and updates the current index to reflect
* the new position of the previously current item after reversal.
*
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse
*/
reverse() {
if (!this.items_.length) return;

this.items_.reverse();
this.currentIndex_ = this.items_.length - 1 - this.currentIndex_;
this.updateState_();
}

/**
* Sorts the items in the playlist using the provided compare function and updates the current
* index to reflect the new position of the previously current item after sorting.
*
* @method sort
* @param {Function} compareFn - A function that defines the sort order.
* The return value should be a number whose sign indicates the relative order
* of the two elements: negative if a is less than b, positive if a is
* greater than b, and zero if they are equal. NaN is treated as 0. If omitted,
* the array elements are converted to strings, then sorted according to each
* character's Unicode code point value.
*
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
*/
sort(compareFn) {
if (!this.items_.length) return;

const currentItem = this.currentItem;

this.items_.sort(compareFn);
this.currentIndex_ = this.items_.indexOf(currentItem);
this.updateState_();
}


/**
* Get the currently playing index.
*
Expand Down
101 changes: 99 additions & 2 deletions packages/pillarbox-playlist/test/pillarbox-playlist.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const playlist = [
{
sources: [{ src: 'first-source', type: 'test' }],
poster: 'first-poster',
data: { title: 'first-source', duration: 120 }
data: { title: 'first-source', duration: 180 }
},
{
sources: [{ src: 'second-source', type: 'test' }],
Expand All @@ -17,7 +17,7 @@ const playlist = [
{
sources: [{ src: 'third-source', type: 'test' }],
poster: 'third-poster',
data: { title: 'third-source', duration: 180 }
data: { title: 'third-source', duration: 120 }
},
{
sources: [{ src: 'fourth-source', type: 'test' }],
Expand Down Expand Up @@ -389,6 +389,103 @@ describe('PillarboxPlaylist', () => {
});
});

describe('reverse', () => {
it('should reverse the order of items and update currentIndex correctly', () => {
// Given
pillarboxPlaylist.load(playlist);
pillarboxPlaylist.select(1);

// When
pillarboxPlaylist.reverse();

// Then
expect(pillarboxPlaylist.currentIndex).toBe(2);
expect(pillarboxPlaylist.currentItem).toBe(playlist[1]);
});

it('should reverse an empty playlist without errors', () => {
// Given
pillarboxPlaylist.load([]);

// When
pillarboxPlaylist.reverse();

// Then
expect(pillarboxPlaylist.items_.length).toBe(0);
expect(pillarboxPlaylist.currentIndex).toBe(-1);
expect(pillarboxPlaylist.currentItem).toBeUndefined();
});

it('should reverse a single-item playlist without changing the index', () => {
// Given
const items = [{
sources: [{ src: 'first-source', type: 'test' }],
poster: 'first-poster',
data: { title: 'first-source', duration: 120 }
}];

pillarboxPlaylist.load(items);

// When
pillarboxPlaylist.reverse();

// Then
expect(pillarboxPlaylist.currentIndex).toBe(0);
expect(pillarboxPlaylist.currentItem).toBe(items[0]);
});
});


describe('sort', () => {
it('should sort items by duration and update currentIndex correctly', () => {
// Given
pillarboxPlaylist.load(playlist);
pillarboxPlaylist.select(2);

// When
pillarboxPlaylist.sort((a, b) => a.data.duration - b.data.duration);

// Then
const durations = pillarboxPlaylist.items_.map(item => item.data.duration);

for (let i = 0; i < durations.length - 1; i++) {
expect(durations[i]).toBeLessThanOrEqual(durations[i + 1]);
}
expect(pillarboxPlaylist.currentIndex).toBe(0);
expect(pillarboxPlaylist.currentItem).toBe(playlist[2]);
});

it('should handle sorting an empty playlist without errors', () => {
// Given
pillarboxPlaylist.load([]);

// When
pillarboxPlaylist.sort((a, b) => a.data.duration - b.data.duration);

// Then
expect(pillarboxPlaylist.items_.length).toBe(0);
expect(pillarboxPlaylist.currentIndex).toBe(-1);
});

it('should sort a single-item playlist without changing the index', () => {
// Given
const items = [{
sources: [{ src: 'first-source', type: 'test' }],
poster: 'first-poster',
data: { title: 'first-source', duration: 120 }
}];

pillarboxPlaylist.load(items);

// When
pillarboxPlaylist.sort((a, b) => a.data.duration - b.data.duration);

// Then
expect(pillarboxPlaylist.currentIndex).toBe(0);
expect(pillarboxPlaylist.currentItem).toBe(items[0]);
});
});

describe('clear', () => {
it('should clear all the items of the playlist', () => {
// Given
Expand Down

0 comments on commit a1a37b8

Please sign in to comment.