mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Fix+enhance playback sequence of episodes in a series/season
- Adds an option to a season's menu to `Play All From Here` (default behavior is to play only the specific season) - Playback will start on the first unplayed episode, or at the beginning of the season - After starting playback, navigation to prior episodes is immediately possible using the previous episode navigation button - Fix previous button not navigating to previous episode when starting on a non-first episode (ex. episode 1 when starting playback on episode 2)
This commit is contained in:
parent
b12d92dffd
commit
46c749c547
2 changed files with 35 additions and 35 deletions
|
@ -1858,7 +1858,7 @@ class PlaybackManager {
|
||||||
}, queryOptions));
|
}, queryOptions));
|
||||||
case 'Series':
|
case 'Series':
|
||||||
case 'Season':
|
case 'Season':
|
||||||
return getSeriesOrSeasonPlaybackPromise(firstItem, options);
|
return getSeriesOrSeasonPlaybackPromise(firstItem, options, items);
|
||||||
case 'Episode':
|
case 'Episode':
|
||||||
return getEpisodePlaybackPromise(firstItem, options, items);
|
return getEpisodePlaybackPromise(firstItem, options, items);
|
||||||
}
|
}
|
||||||
|
@ -1922,41 +1922,44 @@ class PlaybackManager {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getSeriesOrSeasonPlaybackPromise(firstItem, options) {
|
async function getSeriesOrSeasonPlaybackPromise(firstItem, options, items) {
|
||||||
const apiClient = ServerConnections.getApiClient(firstItem.ServerId);
|
const apiClient = ServerConnections.getApiClient(firstItem.ServerId);
|
||||||
const isSeason = firstItem.Type === 'Season';
|
const startSeasonId = firstItem.Type === 'Season' ? items[options.startIndex || 0].Id : undefined;
|
||||||
|
|
||||||
const episodesResult = await apiClient.getEpisodes(firstItem.SeriesId || firstItem.Id, {
|
const episodesResult = await apiClient.getEpisodes(firstItem.SeriesId || firstItem.Id, {
|
||||||
IsVirtualUnaired: false,
|
IsVirtualUnaired: false,
|
||||||
IsMissing: false,
|
IsMissing: false,
|
||||||
SeasonId: isSeason ? firstItem.Id : undefined,
|
SeasonId: (startSeasonId && items.length === 1) ? startSeasonId : undefined,
|
||||||
SortBy: options.shuffle ? 'Random' : undefined,
|
SortBy: options.shuffle ? 'Random' : undefined,
|
||||||
UserId: apiClient.getCurrentUserId(),
|
UserId: apiClient.getCurrentUserId(),
|
||||||
Fields: ['Chapters', 'Trickplay']
|
Fields: ['Chapters', 'Trickplay']
|
||||||
});
|
});
|
||||||
|
|
||||||
const originalResults = episodesResult.Items;
|
if (options.shuffle) {
|
||||||
|
episodesResult.StartIndex = 0;
|
||||||
let foundItem = false;
|
} else {
|
||||||
|
episodesResult.StartIndex = undefined;
|
||||||
if (!options.shuffle) {
|
let seasonStartIndex;
|
||||||
episodesResult.Items = episodesResult.Items.filter(function (e) {
|
for (const [index, e] of episodesResult.Items.entries()) {
|
||||||
if (foundItem) {
|
if (startSeasonId) {
|
||||||
return true;
|
if (e.SeasonId == startSeasonId) {
|
||||||
|
if (seasonStartIndex === undefined) {
|
||||||
|
seasonStartIndex = index;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!e.UserData.Played) {
|
if (!e.UserData.Played) {
|
||||||
foundItem = true;
|
episodesResult.StartIndex = index;
|
||||||
return true;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
episodesResult.StartIndex = episodesResult.StartIndex || seasonStartIndex || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
// TODO: fix calling code to read episodesResult.StartIndex instead when set.
|
||||||
});
|
options.startIndex = episodesResult.StartIndex;
|
||||||
}
|
|
||||||
|
|
||||||
if (episodesResult.Items.length === 0) {
|
|
||||||
episodesResult.Items = originalResults;
|
|
||||||
}
|
|
||||||
|
|
||||||
episodesResult.TotalRecordCount = episodesResult.Items.length;
|
episodesResult.TotalRecordCount = episodesResult.Items.length;
|
||||||
|
|
||||||
|
@ -1965,13 +1968,13 @@ class PlaybackManager {
|
||||||
|
|
||||||
function getEpisodePlaybackPromise(firstItem, options, items) {
|
function getEpisodePlaybackPromise(firstItem, options, items) {
|
||||||
if (items.length === 1 && getPlayer(firstItem, options).supportsProgress !== false) {
|
if (items.length === 1 && getPlayer(firstItem, options).supportsProgress !== false) {
|
||||||
return getEpisodes(firstItem);
|
return getEpisodes(firstItem, options);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getEpisodes(firstItem) {
|
function getEpisodes(firstItem, options) {
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
const apiClient = ServerConnections.getApiClient(firstItem.ServerId);
|
const apiClient = ServerConnections.getApiClient(firstItem.ServerId);
|
||||||
|
|
||||||
|
@ -1986,24 +1989,21 @@ class PlaybackManager {
|
||||||
UserId: apiClient.getCurrentUserId(),
|
UserId: apiClient.getCurrentUserId(),
|
||||||
Fields: ['Chapters', 'Trickplay']
|
Fields: ['Chapters', 'Trickplay']
|
||||||
}).then(function (episodesResult) {
|
}).then(function (episodesResult) {
|
||||||
resolve(filterEpisodes(episodesResult, firstItem));
|
resolve(filterEpisodes(episodesResult, firstItem, options));
|
||||||
}, reject);
|
}, reject);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterEpisodes(episodesResult, firstItem) {
|
function filterEpisodes(episodesResult, firstItem, options) {
|
||||||
let foundItem = false;
|
for (const [index, e] of episodesResult.Items.entries()) {
|
||||||
episodesResult.Items = episodesResult.Items.filter(function (e) {
|
|
||||||
if (foundItem) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (e.Id === firstItem.Id) {
|
if (e.Id === firstItem.Id) {
|
||||||
foundItem = true;
|
episodesResult.StartIndex = index;
|
||||||
return true;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
// TODO: fix calling code to read episodesResult.StartIndex instead when set.
|
||||||
});
|
options.startIndex = episodesResult.StartIndex;
|
||||||
episodesResult.TotalRecordCount = episodesResult.Items.length;
|
episodesResult.TotalRecordCount = episodesResult.Items.length;
|
||||||
return episodesResult;
|
return episodesResult;
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,7 +116,7 @@ function showContextMenu(card, options) {
|
||||||
item: item,
|
item: item,
|
||||||
play: true,
|
play: true,
|
||||||
queue: true,
|
queue: true,
|
||||||
playAllFromHere: !item.IsFolder,
|
playAllFromHere: item.Type === 'Season' || !item.IsFolder,
|
||||||
queueAllFromHere: !item.IsFolder,
|
queueAllFromHere: !item.IsFolder,
|
||||||
playlistId: playlistId,
|
playlistId: playlistId,
|
||||||
collectionId: collectionId,
|
collectionId: collectionId,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue