1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

Add subtitle setting for native vs custom element (#5737)

* Fixed subtitles styling in firefox.

* Fixed subtitles styling in firefox.

* Initial changes to support native or custom styling.

* Changes to support native or custom styling.

* linting changes.

* Changes to support native or custom styling.

* Changes to support native or custom styling.

* minor changes.

* indentation changes and simplification changes.

* minor changes.

---------

Co-authored-by: Bill Thornton <thornbill@users.noreply.github.com>
This commit is contained in:
venkata nadha reddy 2025-01-24 14:46:45 -06:00 committed by GitHub
parent 9d63a715eb
commit 2689c51b84
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 85 additions and 42 deletions

View file

@ -26,6 +26,7 @@ import template from './subtitlesettings.template.html';
function getSubtitleAppearanceObject(context) { function getSubtitleAppearanceObject(context) {
return { return {
subtitleStyling: context.querySelector('#selectSubtitleStyling').value,
textSize: context.querySelector('#selectTextSize').value, textSize: context.querySelector('#selectTextSize').value,
textWeight: context.querySelector('#selectTextWeight').value, textWeight: context.querySelector('#selectTextWeight').value,
dropShadow: context.querySelector('#selectDropShadow').value, dropShadow: context.querySelector('#selectDropShadow').value,
@ -51,6 +52,8 @@ function loadForm(context, user, userSettings, appearanceSettings, apiClient) {
context.querySelector('#selectSubtitlePlaybackMode').dispatchEvent(new CustomEvent('change', {})); context.querySelector('#selectSubtitlePlaybackMode').dispatchEvent(new CustomEvent('change', {}));
context.querySelector('#selectSubtitleStyling').value = appearanceSettings.subtitleStyling || 'Auto';
context.querySelector('#selectSubtitleStyling').dispatchEvent(new CustomEvent('change', {}));
context.querySelector('#selectTextSize').value = appearanceSettings.textSize || ''; context.querySelector('#selectTextSize').value = appearanceSettings.textSize || '';
context.querySelector('#selectTextWeight').value = appearanceSettings.textWeight || 'normal'; context.querySelector('#selectTextWeight').value = appearanceSettings.textWeight || 'normal';
context.querySelector('#selectDropShadow').value = appearanceSettings.dropShadow || ''; context.querySelector('#selectDropShadow').value = appearanceSettings.dropShadow || '';
@ -117,6 +120,16 @@ function onSubtitleModeChange(e) {
view.querySelector('.subtitles' + this.value + 'Help').classList.remove('hide'); view.querySelector('.subtitles' + this.value + 'Help').classList.remove('hide');
} }
function onSubtitleStyleChange(e) {
const view = dom.parentWithClass(e.target, 'subtitlesettings');
const subtitleStylingHelperElements = view.querySelectorAll('.subtitleStylingHelp');
subtitleStylingHelperElements.forEach((elem)=>{
elem.classList.add('hide');
});
view.querySelector(`.subtitleStyling${this.value}Help`).classList.remove('hide');
}
function onSubtitleBurnInChange(e) { function onSubtitleBurnInChange(e) {
const view = dom.parentWithClass(e.target, 'subtitlesettings'); const view = dom.parentWithClass(e.target, 'subtitlesettings');
const fieldRenderPgs = view.querySelector('.fldRenderPgs'); const fieldRenderPgs = view.querySelector('.fldRenderPgs');
@ -180,6 +193,7 @@ function embed(options, self) {
options.element.querySelector('form').addEventListener('submit', self.onSubmit.bind(self)); options.element.querySelector('form').addEventListener('submit', self.onSubmit.bind(self));
options.element.querySelector('#selectSubtitlePlaybackMode').addEventListener('change', onSubtitleModeChange); options.element.querySelector('#selectSubtitlePlaybackMode').addEventListener('change', onSubtitleModeChange);
options.element.querySelector('#selectSubtitleStyling').addEventListener('change', onSubtitleStyleChange);
options.element.querySelector('#selectSubtitleBurnIn').addEventListener('change', onSubtitleBurnInChange); options.element.querySelector('#selectSubtitleBurnIn').addEventListener('change', onSubtitleBurnInChange);
options.element.querySelector('#selectTextSize').addEventListener('change', onAppearanceFieldChange); options.element.querySelector('#selectTextSize').addEventListener('change', onAppearanceFieldChange);
options.element.querySelector('#selectTextWeight').addEventListener('change', onAppearanceFieldChange); options.element.querySelector('#selectTextWeight').addEventListener('change', onAppearanceFieldChange);

View file

@ -77,6 +77,17 @@
<div class="fieldDescription">${SubtitleAppearanceSettingsAlsoPassedToCastDevices}</div> <div class="fieldDescription">${SubtitleAppearanceSettingsAlsoPassedToCastDevices}</div>
</div> </div>
<div class="selectContainer">
<select is="emby-select" id="selectSubtitleStyling" label="${LabelSubtitleStyling}">
<option value="Auto">${Auto}</option>
<option value="Custom">${Custom}</option>
<option value="Native">${Native}</option>
</select>
<div class="fieldDescription subtitleStylingAutoHelp subtitleStylingHelp hide">${AutoSubtitleStylingHelp}</div>
<div class="fieldDescription subtitleStylingCustomHelp subtitleStylingHelp hide">${CustomSubtitleStylingHelp}</div>
<div class="fieldDescription subtitleStylingNativeHelp subtitleStylingHelp hide">${NativeSubtitleStylingHelp}</div>
</div>
<div class="selectContainer"> <div class="selectContainer">
<select is="emby-select" id="selectTextSize" label="${LabelTextSize}"> <select is="emby-select" id="selectTextSize" label="${LabelTextSize}">
<option value="smaller">${Smaller}</option> <option value="smaller">${Smaller}</option>

View file

@ -1349,31 +1349,44 @@ export class HtmlVideoPlayer {
/** /**
* @private * @private
*/ */
requiresCustomSubtitlesElement() { requiresCustomSubtitlesElement(userSettings) {
// after a system update, ps4 isn't showing anything when creating a track element dynamically const subtitleAppearance = userSettings.getSubtitleAppearanceSettings();
// going to have to do it ourselves switch (subtitleAppearance.subtitleStyling) {
if (browser.ps4) { case 'Native':
return true; return false;
} case 'Custom':
// Tizen 5 doesn't support displaying secondary subtitles
if (browser.tizenVersion >= 5 || browser.web0s) {
return true;
}
if (browser.edge) {
return true;
}
if (browser.iOS) {
const userAgent = navigator.userAgent.toLowerCase();
// works in the browser but not the native app
if ((userAgent.includes('os 9') || userAgent.includes('os 8')) && !userAgent.includes('safari')) {
return true; return true;
} default:
} // after a system update, ps4 isn't showing anything when creating a track element dynamically
// going to have to do it ourselves
if (browser.ps4) {
return true;
}
return false; // Tizen 5 doesn't support displaying secondary subtitles
if (browser.tizenVersion >= 5 || browser.web0s) {
return true;
}
if (browser.edge) {
return true;
}
// font-size styling does not seem to work natively in firefox. Switching to custom subtitles element for firefox.
if (browser.firefox) {
return true;
}
if (browser.iOS) {
const userAgent = navigator.userAgent.toLowerCase();
// works in the browser but not the native app
if ((userAgent.includes('os 9') || userAgent.includes('os 8')) && !userAgent.includes('safari')) {
return true;
}
}
return false;
}
} }
/** /**
@ -1458,7 +1471,9 @@ export class HtmlVideoPlayer {
/** /**
* @private * @private
*/ */
renderTracksEvents(videoElement, track, item, targetTextTrackIndex = PRIMARY_TEXT_TRACK_INDEX) { async renderTracksEvents(videoElement, track, item, targetTextTrackIndex = PRIMARY_TEXT_TRACK_INDEX) {
const { currentSettings: userSettings } = await import('../../scripts/settings/userSettings');
if (!itemHelper.isLocalItem(item) || track.IsExternal) { if (!itemHelper.isLocalItem(item) || track.IsExternal) {
const format = (track.Codec || '').toLowerCase(); const format = (track.Codec || '').toLowerCase();
if (format === 'ssa' || format === 'ass') { if (format === 'ssa' || format === 'ass') {
@ -1470,7 +1485,7 @@ export class HtmlVideoPlayer {
return; return;
} }
if (this.requiresCustomSubtitlesElement()) { if (this.requiresCustomSubtitlesElement(userSettings)) {
this.renderSubtitlesWithCustomElement(videoElement, track, item, targetTextTrackIndex); this.renderSubtitlesWithCustomElement(videoElement, track, item, targetTextTrackIndex);
return; return;
} }
@ -1500,28 +1515,25 @@ export class HtmlVideoPlayer {
// download the track json // download the track json
this.fetchSubtitles(track, item).then(function (data) { this.fetchSubtitles(track, item).then(function (data) {
import('../../scripts/settings/userSettings').then((userSettings) => { console.debug(`downloaded ${data.TrackEvents.length} track events`);
// show in ui
console.debug(`downloaded ${data.TrackEvents.length} track events`);
const subtitleAppearance = userSettings.getSubtitleAppearanceSettings(); const subtitleAppearance = userSettings.getSubtitleAppearanceSettings();
const cueLine = parseInt(subtitleAppearance.verticalPosition, 10); const cueLine = parseInt(subtitleAppearance.verticalPosition, 10);
// add some cues to show the text // add some cues to show the text
// in safari, the cues need to be added before setting the track mode to showing // in safari, the cues need to be added before setting the track mode to showing
for (const trackEvent of data.TrackEvents) { for (const trackEvent of data.TrackEvents) {
const TrackCue = window.VTTCue || window.TextTrackCue; const TrackCue = window.VTTCue || window.TextTrackCue;
const cue = new TrackCue(trackEvent.StartPositionTicks / 10000000, trackEvent.EndPositionTicks / 10000000, normalizeTrackEventText(trackEvent.Text, false)); const cue = new TrackCue(trackEvent.StartPositionTicks / 10000000, trackEvent.EndPositionTicks / 10000000, normalizeTrackEventText(trackEvent.Text, false));
if (cue.line === 'auto') { if (cue.line === 'auto') {
cue.line = cueLine; cue.line = cueLine;
}
trackElement.addCue(cue);
} }
trackElement.mode = 'showing'; trackElement.addCue(cue);
}); }
trackElement.mode = 'showing';
}); });
} }

View file

@ -72,6 +72,7 @@
"Authorize": "Authorize", "Authorize": "Authorize",
"AuthProviderHelp": "Select an authentication provider to be used to authenticate this user's password.", "AuthProviderHelp": "Select an authentication provider to be used to authenticate this user's password.",
"Auto": "Auto", "Auto": "Auto",
"AutoSubtitleStylingHelp": "This mode will automatically switch between the native and custom subtitle styling mechanisms based on your device type.",
"Backdrop": "Backdrop", "Backdrop": "Backdrop",
"Backdrops": "Backdrops", "Backdrops": "Backdrops",
"BackdropScreensaver": "Backdrop Screensaver", "BackdropScreensaver": "Backdrop Screensaver",
@ -191,6 +192,8 @@
"Creator": "Creator", "Creator": "Creator",
"CriticRating": "Critics rating", "CriticRating": "Critics rating",
"Cursive": "Cursive", "Cursive": "Cursive",
"Custom": "Custom",
"CustomSubtitleStylingHelp": "Subtitle styling will work on most devices, but comes with an additional performance overhead.",
"DailyAt": "Daily at {0}", "DailyAt": "Daily at {0}",
"Data": "Data", "Data": "Data",
"DateAdded": "Date added", "DateAdded": "Date added",
@ -907,6 +910,7 @@
"LabelStreamType": "Stream type", "LabelStreamType": "Stream type",
"LabelSubtitleDownloaders": "Subtitle downloaders", "LabelSubtitleDownloaders": "Subtitle downloaders",
"LabelSubtitlePlaybackMode": "Subtitle mode", "LabelSubtitlePlaybackMode": "Subtitle mode",
"LabelSubtitleStyling": "Subtitle styling",
"LabelSubtitleVerticalPosition": "Vertical position", "LabelSubtitleVerticalPosition": "Vertical position",
"LabelSyncPlayAccess": "SyncPlay access", "LabelSyncPlayAccess": "SyncPlay access",
"LabelSyncPlayAccessCreateAndJoinGroups": "Allow user to create and join groups", "LabelSyncPlayAccessCreateAndJoinGroups": "Allow user to create and join groups",
@ -1190,6 +1194,8 @@
"Mute": "Mute", "Mute": "Mute",
"MySubtitles": "My Subtitles", "MySubtitles": "My Subtitles",
"Name": "Name", "Name": "Name",
"Native": "Native",
"NativeSubtitleStylingHelp": "Subtitle styling will not work on some devices. However, it does not come with any performance overhead.",
"Never": "Never", "Never": "Never",
"New": "New", "New": "New",
"NewCollection": "New Collection", "NewCollection": "New Collection",