/**
* EasyStream Playlist Enhancements
* Adds shuffle, loop, and autoplay features to playlists
*/
class PlaylistEnhancer {
constructor(playlistId, options = {}) {
this.playlistId = playlistId;
this.currentIndex = 0;
this.items = [];
this.options = {
shuffle: options.shuffle || false,
loop: options.loop || false,
autoplay: options.autoplay !== false,
...options
};
this.originalOrder = [];
this.init();
}
async init() {
await this.loadPlaylistItems();
this.setupControls();
this.setupEventListeners();
}
async loadPlaylistItems() {
try {
const response = await fetch(`/api/playlists/${this.playlistId}/items`);
const data = await response.json();
this.items = data.items || [];
this.originalOrder = [...this.items];
} catch (error) {
console.error('Error loading playlist:', error);
}
}
setupControls() {
const controls = document.createElement('div');
controls.className = 'playlist-controls';
controls.innerHTML = `
`;
const playlistContainer = document.querySelector('.playlist-container');
if (playlistContainer) {
playlistContainer.insertBefore(controls, playlistContainer.firstChild);
}
}
setupEventListeners() {
document.getElementById('playlistShuffle')?.addEventListener('click', () => this.toggleShuffle());
document.getElementById('playlistLoop')?.addEventListener('click', () => this.toggleLoop());
document.getElementById('playlistAutoplay')?.addEventListener('click', () => this.toggleAutoplay());
// Listen for video end event
const video = document.querySelector('video');
if (video) {
video.addEventListener('ended', () => this.onVideoEnded());
}
}
toggleShuffle() {
this.options.shuffle = !this.options.shuffle;
document.getElementById('playlistShuffle').classList.toggle('active');
if (this.options.shuffle) {
this.shufflePlaylist();
} else {
this.items = [...this.originalOrder];
}
this.savePreferences();
}
toggleLoop() {
this.options.loop = !this.options.loop;
document.getElementById('playlistLoop').classList.toggle('active');
this.savePreferences();
}
toggleAutoplay() {
this.options.autoplay = !this.options.autoplay;
document.getElementById('playlistAutoplay').classList.toggle('active');
this.savePreferences();
}
shufflePlaylist() {
const currentItem = this.items[this.currentIndex];
// Fisher-Yates shuffle
for (let i = this.items.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[this.items[i], this.items[j]] = [this.items[j], this.items[i]];
}
// Keep current item at current position
if (currentItem) {
const newIndex = this.items.indexOf(currentItem);
[this.items[this.currentIndex], this.items[newIndex]] = [this.items[newIndex], this.items[this.currentIndex]];
}
this.updatePlaylistUI();
}
playNext() {
if (this.currentIndex < this.items.length - 1) {
this.currentIndex++;
} else if (this.options.loop) {
this.currentIndex = 0;
} else {
return; // End of playlist
}
this.playItem(this.currentIndex);
}
playPrevious() {
if (this.currentIndex > 0) {
this.currentIndex--;
} else if (this.options.loop) {
this.currentIndex = this.items.length - 1;
} else {
return; // Start of playlist
}
this.playItem(this.currentIndex);
}
playItem(index) {
if (index < 0 || index >= this.items.length) return;
this.currentIndex = index;
const item = this.items[index];
// Navigate to video
window.location.href = `/watch?v=${item.file_key}&list=${this.playlistId}`;
}
onVideoEnded() {
if (this.options.autoplay) {
setTimeout(() => this.playNext(), 1000); // 1 second delay
}
}
updatePlaylistUI() {
const playlistItems = document.querySelectorAll('.playlist-item');
playlistItems.forEach((item, index) => {
item.dataset.index = index;
item.classList.toggle('active', index === this.currentIndex);
});
}
savePreferences() {
localStorage.setItem('playlistPreferences', JSON.stringify({
shuffle: this.options.shuffle,
loop: this.options.loop,
autoplay: this.options.autoplay
}));
}
loadPreferences() {
const prefs = localStorage.getItem('playlistPreferences');
if (prefs) {
const parsed = JSON.parse(prefs);
this.options = { ...this.options, ...parsed };
}
}
}
// Export for global use
window.PlaylistEnhancer = PlaylistEnhancer;