Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix queue when playing on remote device (partial) #3381

Merged
merged 14 commits into from
Oct 17, 2024
4 changes: 4 additions & 0 deletions src/components/remotecontrol/remotecontrol.js
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,10 @@ export default function () {

function loadPlaylist(context, player) {
getPlaylistItems(player).then(function (items) {
if (items.length === 0) {
return;
}

let html = '';
let favoritesEnabled = true;
if (layoutManager.mobile) {
Expand Down
139 changes: 133 additions & 6 deletions src/plugins/sessionPlayer/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,58 @@ function unsubscribeFromPlayerUpdates(instance) {
}
}

async function updatePlaylist(instance, queue) {
const options = {
ids: queue.map(i => i.Id),
serverId: getCurrentApiClient(instance).serverId()
};

const result = await playbackManager.getItemsForPlayback(options.serverId, {
Ids: options.ids.join(',')
});

const items = await playbackManager.translateItemsForPlayback(result.Items, options);

for (let i = 0; i < items.length; i++) {
items[i].PlaylistItemId = queue[i].PlaylistItemId;
}

instance.playlist = items;
}

function compareQueues(q1, q2) {
if (q1.length !== q2.length) {
return true;
}

for (let i = 0; i < q1.length; i++) {
if (q1[i].Id !== q2[i].Id || q1[i].PlaylistItemId !== q2[i].PlaylistItemId) {
return true;
}
}
return false;
}

function updateCurrentQueue(instance, session) {
const current = session.NowPlayingQueue;
if (instance.isUpdatingPlaylist) {
return;
}

if (instance.lastPlayerData && !compareQueues(current, instance.playlist)) {
return;
}

instance.isUpdatingPlaylist = true;

const finish = () => {
instance.isUpdatingPlaylist = false;
instance.isPlaylistRendered = true;
};

updatePlaylist(instance, current).then(finish, finish);
}

function processUpdatedSessions(instance, sessions, apiClient) {
const serverId = apiClient.serverId();

Expand All @@ -103,11 +155,13 @@ function processUpdatedSessions(instance, sessions, apiClient) {
normalizeImages(session, apiClient);

const eventNames = getChangedEvents(instance.lastPlayerData);
updateCurrentQueue(instance, session);

instance.lastPlayerData = session;

for (let i = 0, length = eventNames.length; i < length; i++) {
Events.trigger(instance, eventNames[i], [session]);
}
eventNames.forEach(eventName => {
Events.trigger(instance, eventName, [session]);
});
} else {
instance.lastPlayerData = session;

Expand Down Expand Up @@ -178,6 +232,8 @@ function normalizeImages(state, apiClient) {
}

class SessionPlayer {
lastPlaylistItemId;

constructor() {
const self = this;

Expand All @@ -186,6 +242,10 @@ class SessionPlayer {
this.isLocalPlayer = false;
this.id = 'remoteplayer';

this.playlist = [];
this.isPlaylistRendered = true;
this.isUpdatingPlaylist = false;

Events.on(serverNotifications, 'Sessions', function (e, apiClient, data) {
processUpdatedSessions(self, data, apiClient);
});
Expand Down Expand Up @@ -484,16 +544,83 @@ class SessionPlayer {
return state.MediaType === 'Audio';
}

getTrackIndex(playlistItemId) {
for (let i = 0; i < this.playlist.length; i++) {
if (this.playlist[i].PlaylistItemId === playlistItemId) {
return i;
}
}
}

getPlaylist() {
let itemId;

if (this.lastPlayerData) {
itemId = this.lastPlayerData.PlaylistItemId;
}

if (this.playlist.length > 0 && (this.isPlaylistRendered || itemId !== this.lastPlaylistItemId)) {
this.isPlaylistRendered = false;
this.lastPlaylistItemId = itemId;
return Promise.resolve(this.playlist);
}
return Promise.resolve([]);
}

movePlaylistItem(playlistItemId, newIndex) {
const index = this.getTrackIndex(playlistItemId);
if (index === newIndex) return;

const current = this.getCurrentPlaylistItemId();
let currentIndex = 0;

if (current === playlistItemId) {
currentIndex = newIndex;
}

const append = (newIndex + 1 >= this.playlist.length);

if (newIndex > index) newIndex++;

const ids = [];
const item = this.playlist[index];

for (let i = 0; i < this.playlist.length; i++) {
if (i === index) continue;

if (i === newIndex) {
ids.push(item.Id);
}

if (this.playlist[i].PlaylistItemId === current) {
currentIndex = ids.length;
}

ids.push(this.playlist[i].Id);
}

if (append) {
ids.push(item.Id);
}

const options = {
ids,
startIndex: currentIndex
};

return sendPlayCommand(getCurrentApiClient(this), options, 'PlayNow');
}

getCurrentPlaylistItemId() {
// not supported?
return this.lastPlayerData.PlaylistItemId;
}

setCurrentPlaylistItem() {
return Promise.resolve();
setCurrentPlaylistItem(playlistItemId) {
const options = {
ids: this.playlist.map(i => i.Id),
startIndex: this.getTrackIndex(playlistItemId)
};
return sendPlayCommand(getCurrentApiClient(this), options, 'PlayNow');
}

removeFromPlaylist() {
Expand Down
Loading