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;
github-actions[bot] marked this conversation as resolved.
Show resolved Hide resolved
}

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;
github-actions[bot] marked this conversation as resolved.
Show resolved Hide resolved
}

if (instance.lastPlayerData && !compareQueues(current, instance.playlist)) {
return;
github-actions[bot] marked this conversation as resolved.
Show resolved Hide resolved
}

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);
github-actions[bot] marked this conversation as resolved.
Show resolved Hide resolved
}

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

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

if (append) {
ids.push(item.Id);
github-actions[bot] marked this conversation as resolved.
Show resolved Hide resolved
}

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