mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge pull request #5398 from ConnorS1110/fix-broken-next-episode-setting
Fix playing next episode when autoplay is disabled
This commit is contained in:
commit
573e9aba71
1 changed files with 162 additions and 122 deletions
|
@ -18,6 +18,7 @@ import { PluginType } from '../../types/plugin.ts';
|
||||||
import { includesAny } from '../../utils/container.ts';
|
import { includesAny } from '../../utils/container.ts';
|
||||||
import { getItems } from '../../utils/jellyfin-apiclient/getItems.ts';
|
import { getItems } from '../../utils/jellyfin-apiclient/getItems.ts';
|
||||||
import { getItemBackdropImageUrl } from '../../utils/jellyfin-apiclient/backdropImage';
|
import { getItemBackdropImageUrl } from '../../utils/jellyfin-apiclient/backdropImage';
|
||||||
|
import { MediaType } from '@jellyfin/sdk/lib/generated-client/models/media-type';
|
||||||
|
|
||||||
import { MediaError } from 'types/mediaError';
|
import { MediaError } from 'types/mediaError';
|
||||||
import { getMediaError } from 'utils/mediaError';
|
import { getMediaError } from 'utils/mediaError';
|
||||||
|
@ -1789,42 +1790,85 @@ class PlaybackManager {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function translateItemsForPlayback(items, options) {
|
async function translateItemsForPlayback(items, options) {
|
||||||
if (!items.length) return Promise.resolve([]);
|
if (!items.length) return [];
|
||||||
|
|
||||||
if (items.length > 1 && options && options.ids) {
|
sortItemsIfNeeded(items, options);
|
||||||
|
|
||||||
|
const firstItem = items[0];
|
||||||
|
const serverId = firstItem.ServerId;
|
||||||
|
const queryOptions = options.queryOptions || {};
|
||||||
|
|
||||||
|
const promise = getPlaybackPromise(firstItem, serverId, options, queryOptions, items);
|
||||||
|
|
||||||
|
if (promise) {
|
||||||
|
const result = await promise;
|
||||||
|
return result ? result.Items : items;
|
||||||
|
} else {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortItemsIfNeeded(items, options) {
|
||||||
|
if (items.length > 1 && options?.ids) {
|
||||||
// Use the original request id array for sorting the result in the proper order
|
// Use the original request id array for sorting the result in the proper order
|
||||||
items.sort(function (a, b) {
|
items.sort(function (a, b) {
|
||||||
return options.ids.indexOf(a.Id) - options.ids.indexOf(b.Id);
|
return options.ids.indexOf(a.Id) - options.ids.indexOf(b.Id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const firstItem = items[0];
|
function getPlaybackPromise(firstItem, serverId, options, queryOptions, items) {
|
||||||
let promise;
|
switch (firstItem.Type) {
|
||||||
|
case 'Program':
|
||||||
|
return getItemsForPlayback(serverId, {
|
||||||
|
Ids: firstItem.ChannelId
|
||||||
|
});
|
||||||
|
case 'Playlist':
|
||||||
|
return getItemsForPlayback(serverId, {
|
||||||
|
ParentId: firstItem.Id,
|
||||||
|
SortBy: options.shuffle ? 'Random' : null
|
||||||
|
});
|
||||||
|
case 'MusicArtist':
|
||||||
|
return getItemsForPlayback(serverId, mergePlaybackQueries({
|
||||||
|
ArtistIds: firstItem.Id,
|
||||||
|
Filters: 'IsNotFolder',
|
||||||
|
Recursive: true,
|
||||||
|
SortBy: options.shuffle ? 'Random' : 'SortName',
|
||||||
|
MediaTypes: 'Audio'
|
||||||
|
}, queryOptions));
|
||||||
|
case 'PhotoAlbum':
|
||||||
|
return getItemsForPlayback(serverId, mergePlaybackQueries({
|
||||||
|
ParentId: firstItem.Id,
|
||||||
|
Filters: 'IsNotFolder',
|
||||||
|
// Setting this to true may cause some incorrect sorting
|
||||||
|
Recursive: false,
|
||||||
|
SortBy: options.shuffle ? 'Random' : 'SortName',
|
||||||
|
// Only include Photos because we do not handle mixed queues currently
|
||||||
|
MediaTypes: 'Photo',
|
||||||
|
Limit: UNLIMITED_ITEMS
|
||||||
|
}, queryOptions));
|
||||||
|
case 'MusicGenre':
|
||||||
|
return getItemsForPlayback(serverId, mergePlaybackQueries({
|
||||||
|
GenreIds: firstItem.Id,
|
||||||
|
Filters: 'IsNotFolder',
|
||||||
|
Recursive: true,
|
||||||
|
SortBy: options.shuffle ? 'Random' : 'SortName',
|
||||||
|
MediaTypes: 'Audio'
|
||||||
|
}, queryOptions));
|
||||||
|
case 'Series':
|
||||||
|
case 'Season':
|
||||||
|
return getSeriesOrSeasonPlaybackPromise(firstItem, options);
|
||||||
|
case 'Episode':
|
||||||
|
return getEpisodePlaybackPromise(firstItem, options, items);
|
||||||
|
}
|
||||||
|
|
||||||
const serverId = firstItem.ServerId;
|
return getNonItemTypePromise(firstItem, serverId, options, queryOptions);
|
||||||
|
}
|
||||||
|
|
||||||
const queryOptions = options.queryOptions || {};
|
function getNonItemTypePromise(firstItem, serverId, options, queryOptions) {
|
||||||
|
if (firstItem.MediaType === 'Photo') {
|
||||||
if (firstItem.Type === 'Program') {
|
return getItemsForPlayback(serverId, mergePlaybackQueries({
|
||||||
promise = getItemsForPlayback(serverId, {
|
|
||||||
Ids: firstItem.ChannelId
|
|
||||||
});
|
|
||||||
} else if (firstItem.Type === 'Playlist') {
|
|
||||||
promise = getItemsForPlayback(serverId, {
|
|
||||||
ParentId: firstItem.Id,
|
|
||||||
SortBy: options.shuffle ? 'Random' : null
|
|
||||||
});
|
|
||||||
} else if (firstItem.Type === 'MusicArtist') {
|
|
||||||
promise = getItemsForPlayback(serverId, mergePlaybackQueries({
|
|
||||||
ArtistIds: firstItem.Id,
|
|
||||||
Filters: 'IsNotFolder',
|
|
||||||
Recursive: true,
|
|
||||||
SortBy: options.shuffle ? 'Random' : 'SortName',
|
|
||||||
MediaTypes: 'Audio'
|
|
||||||
}, queryOptions));
|
|
||||||
} else if (firstItem.MediaType === 'Photo') {
|
|
||||||
promise = getItemsForPlayback(serverId, mergePlaybackQueries({
|
|
||||||
ParentId: firstItem.ParentId,
|
ParentId: firstItem.ParentId,
|
||||||
Filters: 'IsNotFolder',
|
Filters: 'IsNotFolder',
|
||||||
// Setting this to true may cause some incorrect sorting
|
// Setting this to true may cause some incorrect sorting
|
||||||
|
@ -1847,66 +1891,8 @@ class PlaybackManager {
|
||||||
|
|
||||||
return Promise.resolve(result);
|
return Promise.resolve(result);
|
||||||
});
|
});
|
||||||
} else if (firstItem.Type === 'PhotoAlbum') {
|
|
||||||
promise = getItemsForPlayback(serverId, mergePlaybackQueries({
|
|
||||||
ParentId: firstItem.Id,
|
|
||||||
Filters: 'IsNotFolder',
|
|
||||||
// Setting this to true may cause some incorrect sorting
|
|
||||||
Recursive: false,
|
|
||||||
SortBy: options.shuffle ? 'Random' : 'SortName',
|
|
||||||
// Only include Photos because we do not handle mixed queues currently
|
|
||||||
MediaTypes: 'Photo',
|
|
||||||
Limit: UNLIMITED_ITEMS
|
|
||||||
}, queryOptions));
|
|
||||||
} else if (firstItem.Type === 'MusicGenre') {
|
|
||||||
promise = getItemsForPlayback(serverId, mergePlaybackQueries({
|
|
||||||
GenreIds: firstItem.Id,
|
|
||||||
Filters: 'IsNotFolder',
|
|
||||||
Recursive: true,
|
|
||||||
SortBy: options.shuffle ? 'Random' : 'SortName',
|
|
||||||
MediaTypes: 'Audio'
|
|
||||||
}, queryOptions));
|
|
||||||
} else if (firstItem.Type === 'Series' || firstItem.Type === 'Season') {
|
|
||||||
const apiClient = ServerConnections.getApiClient(firstItem.ServerId);
|
|
||||||
const isSeason = firstItem.Type === 'Season';
|
|
||||||
|
|
||||||
promise = apiClient.getEpisodes(firstItem.SeriesId || firstItem.Id, {
|
|
||||||
IsVirtualUnaired: false,
|
|
||||||
IsMissing: false,
|
|
||||||
SeasonId: isSeason ? firstItem.Id : undefined,
|
|
||||||
SortBy: options.shuffle ? 'Random' : undefined,
|
|
||||||
UserId: apiClient.getCurrentUserId(),
|
|
||||||
Fields: ['Chapters', 'Trickplay']
|
|
||||||
}).then(function (episodesResult) {
|
|
||||||
const originalResults = episodesResult.Items;
|
|
||||||
|
|
||||||
let foundItem = false;
|
|
||||||
|
|
||||||
if (!options.shuffle) {
|
|
||||||
episodesResult.Items = episodesResult.Items.filter(function (e) {
|
|
||||||
if (foundItem) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!e.UserData.Played) {
|
|
||||||
foundItem = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (episodesResult.Items.length === 0) {
|
|
||||||
episodesResult.Items = originalResults;
|
|
||||||
}
|
|
||||||
|
|
||||||
episodesResult.TotalRecordCount = episodesResult.Items.length;
|
|
||||||
|
|
||||||
return episodesResult;
|
|
||||||
});
|
|
||||||
} else if (firstItem.IsFolder && firstItem.CollectionType === 'homevideos') {
|
} else if (firstItem.IsFolder && firstItem.CollectionType === 'homevideos') {
|
||||||
promise = getItemsForPlayback(serverId, mergePlaybackQueries({
|
return getItemsForPlayback(serverId, mergePlaybackQueries({
|
||||||
ParentId: firstItem.Id,
|
ParentId: firstItem.Id,
|
||||||
Filters: 'IsNotFolder',
|
Filters: 'IsNotFolder',
|
||||||
Recursive: true,
|
Recursive: true,
|
||||||
|
@ -1922,7 +1908,8 @@ class PlaybackManager {
|
||||||
} else if (firstItem.Type !== 'BoxSet') {
|
} else if (firstItem.Type !== 'BoxSet') {
|
||||||
sortBy = 'SortName';
|
sortBy = 'SortName';
|
||||||
}
|
}
|
||||||
promise = getItemsForPlayback(serverId, mergePlaybackQueries({
|
|
||||||
|
return getItemsForPlayback(serverId, mergePlaybackQueries({
|
||||||
ParentId: firstItem.Id,
|
ParentId: firstItem.Id,
|
||||||
Filters: 'IsNotFolder',
|
Filters: 'IsNotFolder',
|
||||||
Recursive: true,
|
Recursive: true,
|
||||||
|
@ -1930,50 +1917,97 @@ class PlaybackManager {
|
||||||
SortBy: sortBy,
|
SortBy: sortBy,
|
||||||
MediaTypes: 'Audio,Video'
|
MediaTypes: 'Audio,Video'
|
||||||
}, queryOptions));
|
}, queryOptions));
|
||||||
} else if (firstItem.Type === 'Episode' && items.length === 1 && getPlayer(firstItem, options).supportsProgress !== false) {
|
}
|
||||||
promise = new Promise(function (resolve, reject) {
|
|
||||||
const apiClient = ServerConnections.getApiClient(firstItem.ServerId);
|
|
||||||
|
|
||||||
apiClient.getCurrentUser().then(function (user) {
|
return null;
|
||||||
if (!user.Configuration.EnableNextEpisodeAutoPlay || !firstItem.SeriesId) {
|
}
|
||||||
resolve(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
apiClient.getEpisodes(firstItem.SeriesId, {
|
async function getSeriesOrSeasonPlaybackPromise(firstItem, options) {
|
||||||
IsVirtualUnaired: false,
|
const apiClient = ServerConnections.getApiClient(firstItem.ServerId);
|
||||||
IsMissing: false,
|
const isSeason = firstItem.Type === 'Season';
|
||||||
UserId: apiClient.getCurrentUserId(),
|
|
||||||
Fields: ['Chapters', 'Trickplay']
|
|
||||||
}).then(function (episodesResult) {
|
|
||||||
let foundItem = false;
|
|
||||||
episodesResult.Items = episodesResult.Items.filter(function (e) {
|
|
||||||
if (foundItem) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (e.Id === firstItem.Id) {
|
|
||||||
foundItem = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
const episodesResult = await apiClient.getEpisodes(firstItem.SeriesId || firstItem.Id, {
|
||||||
});
|
IsVirtualUnaired: false,
|
||||||
episodesResult.TotalRecordCount = episodesResult.Items.length;
|
IsMissing: false,
|
||||||
resolve(episodesResult);
|
SeasonId: isSeason ? firstItem.Id : undefined,
|
||||||
}, reject);
|
SortBy: options.shuffle ? 'Random' : undefined,
|
||||||
});
|
UserId: apiClient.getCurrentUserId(),
|
||||||
|
Fields: ['Chapters', 'Trickplay']
|
||||||
|
});
|
||||||
|
|
||||||
|
const originalResults = episodesResult.Items;
|
||||||
|
|
||||||
|
let foundItem = false;
|
||||||
|
|
||||||
|
if (!options.shuffle) {
|
||||||
|
episodesResult.Items = episodesResult.Items.filter(function (e) {
|
||||||
|
if (foundItem) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!e.UserData.Played) {
|
||||||
|
foundItem = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (promise) {
|
if (episodesResult.Items.length === 0) {
|
||||||
return promise.then(function (result) {
|
episodesResult.Items = originalResults;
|
||||||
return result ? result.Items : items;
|
}
|
||||||
});
|
|
||||||
|
episodesResult.TotalRecordCount = episodesResult.Items.length;
|
||||||
|
|
||||||
|
return episodesResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getEpisodePlaybackPromise(firstItem, options, items) {
|
||||||
|
if (items.length === 1 && getPlayer(firstItem, options).supportsProgress !== false) {
|
||||||
|
return getEpisodes(firstItem);
|
||||||
} else {
|
} else {
|
||||||
return Promise.resolve(items);
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getEpisodes(firstItem) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
const apiClient = ServerConnections.getApiClient(firstItem.ServerId);
|
||||||
|
|
||||||
|
if (!firstItem.SeriesId) {
|
||||||
|
resolve(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
apiClient.getEpisodes(firstItem.SeriesId, {
|
||||||
|
IsVirtualUnaired: false,
|
||||||
|
IsMissing: false,
|
||||||
|
UserId: apiClient.getCurrentUserId(),
|
||||||
|
Fields: ['Chapters', 'Trickplay']
|
||||||
|
}).then(function (episodesResult) {
|
||||||
|
resolve(filterEpisodes(episodesResult, firstItem));
|
||||||
|
}, reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterEpisodes(episodesResult, firstItem) {
|
||||||
|
let foundItem = false;
|
||||||
|
episodesResult.Items = episodesResult.Items.filter(function (e) {
|
||||||
|
if (foundItem) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (e.Id === firstItem.Id) {
|
||||||
|
foundItem = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
episodesResult.TotalRecordCount = episodesResult.Items.length;
|
||||||
|
return episodesResult;
|
||||||
|
}
|
||||||
|
|
||||||
self.translateItemsForPlayback = translateItemsForPlayback;
|
self.translateItemsForPlayback = translateItemsForPlayback;
|
||||||
self.getItemsForPlayback = getItemsForPlayback;
|
self.getItemsForPlayback = getItemsForPlayback;
|
||||||
|
|
||||||
|
@ -3313,7 +3347,13 @@ class PlaybackManager {
|
||||||
if (errorOccurred) {
|
if (errorOccurred) {
|
||||||
showPlaybackInfoErrorMessage(self, 'PlaybackError' + displayErrorCode);
|
showPlaybackInfoErrorMessage(self, 'PlaybackError' + displayErrorCode);
|
||||||
} else if (nextItem) {
|
} else if (nextItem) {
|
||||||
self.nextTrack();
|
const apiClient = ServerConnections.getApiClient(nextItem.item.ServerId);
|
||||||
|
|
||||||
|
apiClient.getCurrentUser().then(function (user) {
|
||||||
|
if (user.Configuration.EnableNextEpisodeAutoPlay || nextMediaType !== MediaType.Video) {
|
||||||
|
self.nextTrack();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue