diff --git a/src/apps/stable/routes/legacyRoutes/user.ts b/src/apps/stable/routes/legacyRoutes/user.ts index 19b87c7cd85..95a3ee07b04 100644 --- a/src/apps/stable/routes/legacyRoutes/user.ts +++ b/src/apps/stable/routes/legacyRoutes/user.ts @@ -67,6 +67,12 @@ export const LEGACY_USER_ROUTES: LegacyRoute[] = [ controller: 'user/subtitles/index', view: 'user/subtitles/index.html' } + }, { + path: 'mypreferencesopensubtitles.html', + pageProps: { + controller: 'user/opensubtitles/index', + view: 'user/opensubtitles/index.html' + } }, { path: 'tv.html', pageProps: { diff --git a/src/components/opensubtitlesSettings/opensubtitlesSettings.html b/src/components/opensubtitlesSettings/opensubtitlesSettings.html new file mode 100644 index 00000000000..5fe91831f56 --- /dev/null +++ b/src/components/opensubtitlesSettings/opensubtitlesSettings.html @@ -0,0 +1,37 @@ +
+
+

+ ${Settings} +

+
+ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
\ No newline at end of file diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index c5f5182cc89..a2f33895d78 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -29,6 +29,7 @@ import { toApi } from 'utils/jellyfin-apiclient/compat'; import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind.js'; import browser from 'scripts/browser.js'; import { bindSkipSegment } from './skipsegment.ts'; +import OpenSubtitlesManager from '../../scripts/opensubtitles/opensubtitles'; const UNLIMITED_ITEMS = -1; @@ -1252,6 +1253,7 @@ export class PlaybackManager { mediaStreams.push(currentMediaSource.MediaStreams[i]); } } + OpenSubtitlesManager.appendSubtitleTracks( mediaStreams, currentMediaSource ); // No known streams, nothing to change if (!mediaStreams.length) { @@ -2591,7 +2593,7 @@ export class PlaybackManager { const getMediaStreams = isLiveTv ? Promise.resolve([]) : apiClient.getItem(apiClient.getCurrentUserId(), mediaSourceId) .then(fullItem => { - return fullItem.MediaStreams; + return OpenSubtitlesManager.appendSubtitleTracks( fullItem.MediaStreams, fullItem ); }); return Promise.all([promise, player.getDeviceProfile(item), apiClient.getCurrentUser(), getMediaStreams]).then(function (responses) { @@ -2643,8 +2645,16 @@ export class PlaybackManager { mediaSource.DefaultSecondarySubtitleStreamIndex = -1; } - const subtitleTrack1 = mediaSource.MediaStreams[mediaSource.DefaultSubtitleStreamIndex]; - const subtitleTrack2 = mediaSource.MediaStreams[mediaSource.DefaultSecondarySubtitleStreamIndex]; + // Append web subtitles + if ( mediaSource.DefaultSubtitleStreamIndex >= mediaSource.MediaStreams.length ) { + OpenSubtitlesManager.appendSubtitleTracks( mediaSource.MediaStreams, mediaSource ); + } + const subtitleTrack1 = mediaSource.MediaStreams.filter(function (t) { + return t.Index === mediaSource.DefaultSubtitleStreamIndex; + })[0]; + const subtitleTrack2 = mediaSource.MediaStreams.filter(function (t) { + return t.Index === mediaSource.DefaultSecondarySubtitleStreamIndex; + })[0]; if (!self.trackHasSecondarySubtitleSupport(subtitleTrack1, player) || !self.trackHasSecondarySubtitleSupport(subtitleTrack2, player)) { @@ -2874,6 +2884,7 @@ export class PlaybackManager { format: textStream.Codec }); } + OpenSubtitlesManager.appendSubtitleTracks( tracks, mediaSource ); return tracks; } @@ -3866,9 +3877,13 @@ export class PlaybackManager { return Promise.reject(); } - getSubtitleUrl(textStream, serverId) { + async getSubtitleUrl(textStream, serverId) { const apiClient = ServerConnections.getApiClient(serverId); - + if ( textStream?.OpenSubstitlesFileId ) { + // This is an opensubtitles item + await OpenSubtitlesManager.getDownloadLink( textStream.OpenSubstitlesFileId ); + return OpenSubtitlesManager.downloadData.link; + } return !textStream.IsExternalUrl ? apiClient.getUrl(textStream.DeliveryUrl) : textStream.DeliveryUrl; } @@ -3997,8 +4012,8 @@ export class PlaybackManager { } const mediaSource = this.currentMediaSource(player); - const mediaStreams = mediaSource?.MediaStreams || []; + OpenSubtitlesManager.appendSubtitleTracks( mediaStreams, mediaSource ); return mediaStreams.filter(function (s) { return s.Type === 'Subtitle'; }).sort(itemHelper.sortTracks); diff --git a/src/controllers/itemDetails/index.js b/src/controllers/itemDetails/index.js index bdb5a9fe08f..0f5000537df 100644 --- a/src/controllers/itemDetails/index.js +++ b/src/controllers/itemDetails/index.js @@ -33,6 +33,7 @@ import { getPortraitShape, getSquareShape } from 'utils/card'; import Dashboard from 'utils/dashboard'; import Events from 'utils/events'; import { getItemBackdropImageUrl } from 'utils/jellyfin-apiclient/backdropImage'; +import OpenSubtitlesManager from '../../scripts/opensubtitles/opensubtitles'; import 'elements/emby-itemscontainer/emby-itemscontainer'; import 'elements/emby-checkbox/emby-checkbox'; @@ -279,13 +280,15 @@ function renderAudioSelections(page, mediaSources) { } } -function renderSubtitleSelections(page, mediaSources) { +async function renderSubtitleSelections(page, mediaSources) { const mediaSource = getSelectedMediaSource(page, mediaSources); - + // Append web subtitles to the mediaSource + await OpenSubtitlesManager.appendSubtitleTracks(mediaSource.MediaStreams, mediaSource); const tracks = mediaSource.MediaStreams.filter(function (m) { return m.Type === 'Subtitle'; }); tracks.sort(itemHelper.sortTracks); + const select = page.querySelector('.selectSubtitles'); select.setLabel(globalize.translate('Subtitles')); const selectedId = mediaSource.DefaultSubtitleStreamIndex == null ? -1 : mediaSource.DefaultSubtitleStreamIndex; @@ -293,7 +296,12 @@ function renderSubtitleSelections(page, mediaSources) { let selected = selectedId === -1 ? ' selected' : ''; select.innerHTML = '' + tracks.map(function (v) { selected = v.Index === selectedId ? ' selected' : ''; - return ''; + let out = ''; + } else { + select.innerHTML = ''; + } + select.innerHTML += OpenSubtitlesManager.utils.Languages.map(function (v) { + const selected = (language === v.language_code) ? ' selected' : ''; + let out = '