From 54db12359c34b20b305ad081bf188151c9a142cf Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Thu, 12 Nov 2020 20:03:38 +0800 Subject: [PATCH 01/34] add initial support for fMP4-HLS --- src/components/apphost.js | 1 - .../playbackSettings/playbackSettings.js | 6 +- .../playbackSettings.template.html | 18 ++ .../dashboard/encodingsettings.html | 9 + src/controllers/dashboard/encodingsettings.js | 2 + src/scripts/browserDeviceProfile.js | 217 ++++++++++++++---- src/scripts/settings/userSettings.js | 29 +++ src/strings/en-us.json | 9 +- src/strings/zh-cn.json | 9 +- 9 files changed, 255 insertions(+), 45 deletions(-) diff --git a/src/components/apphost.js b/src/components/apphost.js index df2f7c2d2c..1afe9f543f 100644 --- a/src/components/apphost.js +++ b/src/components/apphost.js @@ -33,7 +33,6 @@ function getDeviceProfile(item, options = {}) { profile = window.NativeShell.AppHost.getDeviceProfile(profileBuilder); } else { const builderOpts = getBaseProfileOptions(item); - builderOpts.enableSsaRender = (item && !options.isRetry && appSettings.get('subtitleburnin') !== 'allcomplexformats'); profile = profileBuilder(builderOpts); } diff --git a/src/components/playbackSettings/playbackSettings.js b/src/components/playbackSettings/playbackSettings.js index 782e3d38e1..44a9b607d6 100644 --- a/src/components/playbackSettings/playbackSettings.js +++ b/src/components/playbackSettings/playbackSettings.js @@ -145,6 +145,8 @@ import 'emby-checkbox'; showHideQualityFields(context, user, apiClient); + context.querySelector('#selectAllowedAudioChannels').value = userSettings.allowedAudioChannels(); + apiClient.getCultures().then(allCultures => { populateLanguages(context.querySelector('#selectAudioLanguage'), allCultures); @@ -187,6 +189,7 @@ import 'emby-checkbox'; } context.querySelector('.chkPlayDefaultAudioTrack').checked = user.Configuration.PlayDefaultAudioTrack || false; + context.querySelector('.chkPreferFmp4HlsContainer').checked = userSettings.preferFmp4HlsContainer(); context.querySelector('.chkEnableCinemaMode').checked = userSettings.enableCinemaMode(); context.querySelector('.chkEnableNextVideoOverlay').checked = userSettings.enableNextVideoInfoOverlay(); context.querySelector('.chkExternalVideoPlayer').checked = appSettings.enableSystemExternalPlayers(); @@ -222,10 +225,11 @@ import 'emby-checkbox'; setMaxBitrateFromField(context.querySelector('.selectVideoInternetQuality'), false, 'Video'); setMaxBitrateFromField(context.querySelector('.selectMusicInternetQuality'), false, 'Audio'); + userSettingsInstance.allowedAudioChannels(context.querySelector('#selectAllowedAudioChannels').value); user.Configuration.AudioLanguagePreference = context.querySelector('#selectAudioLanguage').value; user.Configuration.PlayDefaultAudioTrack = context.querySelector('.chkPlayDefaultAudioTrack').checked; user.Configuration.EnableNextEpisodeAutoPlay = context.querySelector('.chkEpisodeAutoPlay').checked; - + userSettingsInstance.preferFmp4HlsContainer(context.querySelector('.chkPreferFmp4HlsContainer').checked); userSettingsInstance.enableCinemaMode(context.querySelector('.chkEnableCinemaMode').checked); userSettingsInstance.enableNextVideoInfoOverlay(context.querySelector('.chkEnableNextVideoOverlay').checked); diff --git a/src/components/playbackSettings/playbackSettings.template.html b/src/components/playbackSettings/playbackSettings.template.html index d10b069bb2..ae6429ed95 100644 --- a/src/components/playbackSettings/playbackSettings.template.html +++ b/src/components/playbackSettings/playbackSettings.template.html @@ -4,6 +4,16 @@ ${HeaderAudioSettings} +
+ +
+
@@ -49,6 +59,14 @@ ${TabAdvanced} +
+ +
${PreferFmp4HlsContainerHelp}
+
+
+ +
+
+ +
+
diff --git a/src/controllers/dashboard/encodingsettings.js b/src/controllers/dashboard/encodingsettings.js index 6a54e8105d..48b31e4dc1 100644 --- a/src/controllers/dashboard/encodingsettings.js +++ b/src/controllers/dashboard/encodingsettings.js @@ -13,6 +13,7 @@ import libraryMenu from 'libraryMenu'; page.querySelector('#chkDecodingColorDepth10Hevc').checked = config.EnableDecodingColorDepth10Hevc; page.querySelector('#chkDecodingColorDepth10Vp9').checked = config.EnableDecodingColorDepth10Vp9; page.querySelector('#chkHardwareEncoding').checked = config.EnableHardwareEncoding; + page.querySelector('#chkAllowHevcEncoding').checked = config.AllowHevcEncoding; $('#selectVideoDecoder', page).val(config.HardwareAccelerationType); $('#selectThreadCount', page).val(config.EncodingThreadCount); $('#txtDownMixAudioBoost', page).val(config.DownMixAudioBoost); @@ -98,6 +99,7 @@ import libraryMenu from 'libraryMenu'; config.EnableDecodingColorDepth10Hevc = form.querySelector('#chkDecodingColorDepth10Hevc').checked; config.EnableDecodingColorDepth10Vp9 = form.querySelector('#chkDecodingColorDepth10Vp9').checked; config.EnableHardwareEncoding = form.querySelector('#chkHardwareEncoding').checked; + config.AllowHevcEncoding = form.querySelector('#chkAllowHevcEncoding').checked; ApiClient.updateNamedConfiguration('encoding', config).then(function () { updateEncoder(form); }, function () { diff --git a/src/scripts/browserDeviceProfile.js b/src/scripts/browserDeviceProfile.js index 3ce60cfe7a..5b3ee64ac4 100644 --- a/src/scripts/browserDeviceProfile.js +++ b/src/scripts/browserDeviceProfile.js @@ -1,4 +1,4 @@ -define(['browser'], function (browser) { +define(['browser', 'userSettings', 'appSettings'], function (browser, userSettings, appSettings) { 'use strict'; browser = browser.default || browser; @@ -7,7 +7,7 @@ define(['browser'], function (browser) { return !!(videoTestElement.canPlayType && videoTestElement.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/, '')); } - function canPlayH265(videoTestElement, options) { + function canPlayHevc(videoTestElement, options) { if (browser.tizen || browser.xboxOne || browser.web0s || options.supportsHevc) { return true; } @@ -16,6 +16,7 @@ define(['browser'], function (browser) { return false; } + // hevc main level 4.0 return !!videoTestElement.canPlayType && (videoTestElement.canPlayType('video/mp4; codecs="hvc1.1.L120"').replace(/no/, '') || videoTestElement.canPlayType('video/mp4; codecs="hev1.1.L120"').replace(/no/, '') || @@ -207,8 +208,7 @@ define(['browser'], function (browser) { // Explicitly add supported codecs to make other codecs be transcoded if (browser.tizenVersion >= 4) { videoCodecs.push('h264'); - if (canPlayH265(videoTestElement, options)) { - videoCodecs.push('h265'); + if (canPlayHevc(videoTestElement, options)) { videoCodecs.push('hevc'); } } @@ -248,8 +248,8 @@ define(['browser'], function (browser) { case 'ts': supported = testCanPlayTs(); videoCodecs.push('h264'); - if (canPlayH265(videoTestElement, options)) { - videoCodecs.push('h265'); + // safari doesn't support hevc in TS-HLS + if ((browser.tizen || browser.web0s) && canPlayHevc(videoTestElement, options)) { videoCodecs.push('hevc'); } if (supportsVc1(videoTestElement)) { @@ -297,7 +297,9 @@ define(['browser'], function (browser) { return function (options) { options = options || {}; - const physicalAudioChannels = options.audioChannels || (browser.tv || browser.ps4 || browser.xboxOne ? 6 : 2); + const isSurroundSoundSupportedBrowser = browser.safari || browser.chrome || browser.edgeChromium || browser.firefox; + const allowedAudioChannels = parseInt(userSettings.allowedAudioChannels() || '-1'); + const physicalAudioChannels = (allowedAudioChannels > 0 ? allowedAudioChannels : null) || options.audioChannels || (isSurroundSoundSupportedBrowser || browser.tv || browser.ps4 || browser.xboxOne ? 6 : 2); const bitrateSetting = getMaxBitrate(); @@ -313,12 +315,13 @@ define(['browser'], function (browser) { profile.MaxStreamingBitrate = bitrateSetting; profile.MaxStaticBitrate = 100000000; - profile.MusicStreamingTranscodingBitrate = Math.min(bitrateSetting, 192000); + profile.MusicStreamingTranscodingBitrate = Math.min(bitrateSetting, 384000); profile.DirectPlayProfiles = []; let videoAudioCodecs = []; - let hlsVideoAudioCodecs = []; + let hlsInTsVideoAudioCodecs = []; + let hlsInFmp4VideoAudioCodecs = []; const supportsMp3VideoAudio = videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"').replace(/no/, '') || videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.6B"').replace(/no/, '') @@ -353,16 +356,19 @@ define(['browser'], function (browser) { // Transcoding codec is the first in hlsVideoAudioCodecs // Put ac3/eac3 first only when the audio channels > 2 and need transcoding if (canPlayAc3VideoAudioInHls && physicalAudioChannels > 2) { - hlsVideoAudioCodecs.push('ac3'); + hlsInTsVideoAudioCodecs.push('ac3'); + hlsInFmp4VideoAudioCodecs.push('ac3'); if (canPlayEac3VideoAudio) { - hlsVideoAudioCodecs.push('eac3'); + hlsInTsVideoAudioCodecs.push('eac3'); + hlsInFmp4VideoAudioCodecs.push('eac3'); } } } if (canPlayAacVideoAudio) { videoAudioCodecs.push('aac'); - hlsVideoAudioCodecs.push('aac'); + hlsInTsVideoAudioCodecs.push('aac'); + hlsInFmp4VideoAudioCodecs.push('aac'); } if (supportsMp3VideoAudio) { @@ -370,16 +376,31 @@ define(['browser'], function (browser) { // PS4 fails to load HLS with mp3 audio if (!browser.ps4) { - hlsVideoAudioCodecs.push('mp3'); + hlsInTsVideoAudioCodecs.push('mp3'); } + + hlsInFmp4VideoAudioCodecs.push('mp3'); } // For ac3/eac3 directstream if (canPlayAc3VideoAudio) { - if (canPlayAc3VideoAudioInHls && hlsVideoAudioCodecs.indexOf('ac3') === -1) { - hlsVideoAudioCodecs.push('ac3'); - if (canPlayEac3VideoAudio && hlsVideoAudioCodecs.indexOf('eac3') === -1) { - hlsVideoAudioCodecs.push('eac3'); + if (canPlayAc3VideoAudioInHls) { + if (hlsInTsVideoAudioCodecs.indexOf('ac3') === -1) { + hlsInTsVideoAudioCodecs.push('ac3'); + } + + if (hlsInFmp4VideoAudioCodecs.indexOf('ac3') === -1) { + hlsInFmp4VideoAudioCodecs.push('ac3'); + } + + if (canPlayEac3VideoAudio) { + if (hlsInTsVideoAudioCodecs.indexOf('eac3') === -1) { + hlsInTsVideoAudioCodecs.push('eac3'); + } + + if (hlsInFmp4VideoAudioCodecs.indexOf('eac3') === -1) { + hlsInFmp4VideoAudioCodecs.push('eac3'); + } } } } @@ -415,38 +436,54 @@ define(['browser'], function (browser) { if (canPlayAudioFormat('opus')) { videoAudioCodecs.push('opus'); - hlsVideoAudioCodecs.push('opus'); + hlsInTsVideoAudioCodecs.push('opus'); webmAudioCodecs.push('opus'); } if (canPlayAudioFormat('flac')) { videoAudioCodecs.push('flac'); + hlsInFmp4VideoAudioCodecs.push('flac'); + } + + if (canPlayAudioFormat('alac')) { + videoAudioCodecs.push('alac'); + hlsInFmp4VideoAudioCodecs.push('alac'); } videoAudioCodecs = videoAudioCodecs.filter(function (c) { return (options.disableVideoAudioCodecs || []).indexOf(c) === -1; }); - hlsVideoAudioCodecs = hlsVideoAudioCodecs.filter(function (c) { + hlsInTsVideoAudioCodecs = hlsInTsVideoAudioCodecs.filter(function (c) { + return (options.disableHlsVideoAudioCodecs || []).indexOf(c) === -1; + }); + + hlsInFmp4VideoAudioCodecs = hlsInFmp4VideoAudioCodecs.filter(function (c) { return (options.disableHlsVideoAudioCodecs || []).indexOf(c) === -1; }); const mp4VideoCodecs = []; const webmVideoCodecs = []; - const hlsVideoCodecs = []; + const hlsInTsVideoCodecs = []; + const hlsInFmp4VideoCodecs = []; + + if (browser.safari || browser.tizen || browser.web0s && canPlayHevc(videoTestElement, options)) { + hlsInFmp4VideoCodecs.push('hevc'); + } if (canPlayH264(videoTestElement)) { mp4VideoCodecs.push('h264'); - hlsVideoCodecs.push('h264'); + hlsInTsVideoCodecs.push('h264'); + + if (browser.safari || browser.tizen || browser.web0s) { + hlsInFmp4VideoCodecs.push('h264'); + } } - if (canPlayH265(videoTestElement, options)) { - mp4VideoCodecs.push('h265'); - mp4VideoCodecs.push('hevc'); - - if (browser.tizen || browser.web0s) { - hlsVideoCodecs.push('h265'); - hlsVideoCodecs.push('hevc'); + if (canPlayHevc(videoTestElement, options)) { + // safari is lying on HDR and 60fps videos, use fMP4 instead + if (!browser.safari) { + mp4VideoCodecs.push('hevc'); } } @@ -606,18 +643,34 @@ define(['browser'], function (browser) { }); } - if (canPlayHls() && hlsVideoAudioCodecs.length && options.enableHls !== false) { - profile.TranscodingProfiles.push({ - Container: 'ts', - Type: 'Video', - AudioCodec: hlsVideoAudioCodecs.join(','), - VideoCodec: hlsVideoCodecs.join(','), - Context: 'Streaming', - Protocol: 'hls', - MaxAudioChannels: physicalAudioChannels.toString(), - MinSegments: browser.iOS || browser.osx ? '2' : '1', - BreakOnNonKeyFrames: hlsBreakOnNonKeyFrames - }); + if (canPlayHls() && options.enableHls !== false) { + if (hlsInFmp4VideoCodecs.length && hlsInFmp4VideoAudioCodecs.length && userSettings.preferFmp4HlsContainer() && (browser.safari || browser.tizen || browser.web0s)) { + profile.TranscodingProfiles.push({ + Container: 'mp4', + Type: 'Video', + AudioCodec: hlsInFmp4VideoAudioCodecs.join(','), + VideoCodec: hlsInFmp4VideoCodecs.join(','), + Context: 'Streaming', + Protocol: 'hls', + MaxAudioChannels: physicalAudioChannels.toString(), + MinSegments: browser.iOS || browser.osx ? '2' : '1', + BreakOnNonKeyFrames: hlsBreakOnNonKeyFrames + }); + } + + if (hlsInTsVideoCodecs.length && hlsInTsVideoAudioCodecs.length) { + profile.TranscodingProfiles.push({ + Container: 'ts', + Type: 'Video', + AudioCodec: hlsInTsVideoAudioCodecs.join(','), + VideoCodec: hlsInTsVideoCodecs.join(','), + Context: 'Streaming', + Protocol: 'hls', + MaxAudioChannels: physicalAudioChannels.toString(), + MinSegments: browser.iOS || browser.osx ? '2' : '1', + BreakOnNonKeyFrames: hlsBreakOnNonKeyFrames + }); + } } if (canPlayVp8) { @@ -713,6 +766,36 @@ define(['browser'], function (browser) { } } + let maxHevcLevel = 120; + let hevcProfiles = 'main'; + + // hevc main level 4.1 + if (videoTestElement.canPlayType('video/mp4; codecs="hvc1.1.4.L123"').replace(/no/, '') || + videoTestElement.canPlayType('video/mp4; codecs="hev1.1.4.L123"').replace(/no/, '')) { + maxHevcLevel = 123; + } + + // hevc main10 level 4.1 + if (videoTestElement.canPlayType('video/mp4; codecs="hvc1.2.4.L123"').replace(/no/, '') || + videoTestElement.canPlayType('video/mp4; codecs="hev1.2.4.L123"').replace(/no/, '')) { + maxHevcLevel = 123; + hevcProfiles = 'main|main 10'; + } + + // hevc main10 level 5.1 + if (videoTestElement.canPlayType('video/mp4; codecs="hvc1.2.4.L153"').replace(/no/, '') || + videoTestElement.canPlayType('video/mp4; codecs="hev1.2.4.L153"').replace(/no/, '')) { + maxHevcLevel = 153; + hevcProfiles = 'main|main 10'; + } + + // hevc main10 level 6.1 + if (videoTestElement.canPlayType('video/mp4; codecs="hvc1.2.4.L183"').replace(/no/, '') || + videoTestElement.canPlayType('video/mp4; codecs="hvc1.2.4.L183"').replace(/no/, '')) { + maxHevcLevel = 183; + hevcProfiles = 'main|main 10'; + } + const h264CodecProfileConditions = [ { Condition: 'NotEquals', @@ -734,6 +817,27 @@ define(['browser'], function (browser) { } ]; + const hevcCodecProfileConditions = [ + { + Condition: 'NotEquals', + Property: 'IsAnamorphic', + Value: 'true', + IsRequired: false + }, + { + Condition: 'EqualsAny', + Property: 'VideoProfile', + Value: hevcProfiles, + IsRequired: false + }, + { + Condition: 'LessThanEqual', + Property: 'VideoLevel', + Value: maxHevcLevel.toString(), + IsRequired: false + } + ]; + if (!browser.edgeUwp && !browser.tizen && !browser.web0s) { h264CodecProfileConditions.push({ Condition: 'NotEquals', @@ -741,6 +845,13 @@ define(['browser'], function (browser) { Value: 'true', IsRequired: false }); + + hevcCodecProfileConditions.push({ + Condition: 'NotEquals', + Property: 'IsInterlaced', + Value: 'true', + IsRequired: false + }); } if (maxVideoWidth) { @@ -750,12 +861,21 @@ define(['browser'], function (browser) { Value: maxVideoWidth.toString(), IsRequired: false }); + + hevcCodecProfileConditions.push({ + Condition: 'LessThanEqual', + Property: 'Width', + Value: maxVideoWidth.toString(), + IsRequired: false + }); } const globalMaxVideoBitrate = (getGlobalMaxVideoBitrate() || '').toString(); const h264MaxVideoBitrate = globalMaxVideoBitrate; + const hevcMaxVideoBitrate = globalMaxVideoBitrate; + if (h264MaxVideoBitrate) { h264CodecProfileConditions.push({ Condition: 'LessThanEqual', @@ -765,6 +885,15 @@ define(['browser'], function (browser) { }); } + if (hevcMaxVideoBitrate) { + hevcCodecProfileConditions.push({ + Condition: 'LessThanEqual', + Property: 'VideoBitrate', + Value: hevcMaxVideoBitrate, + IsRequired: true + }); + } + // On iOS 12.x, for TS container max h264 level is 4.2 if (browser.iOS && browser.iOSVersion < 13) { const codecProfile = { @@ -792,6 +921,12 @@ define(['browser'], function (browser) { Conditions: h264CodecProfileConditions }); + profile.CodecProfiles.push({ + Type: 'Video', + Codec: 'hevc', + Conditions: hevcCodecProfileConditions + }); + const globalVideoConditions = []; if (globalMaxVideoBitrate) { @@ -827,7 +962,7 @@ define(['browser'], function (browser) { Method: 'External' }); } - if (options.enableSsaRender) { + if (options.enableSsaRender !== false && (!options.isRetry && appSettings.get('subtitleburnin') !== 'allcomplexformats')) { profile.SubtitleProfiles.push({ Format: 'ass', Method: 'External' diff --git a/src/scripts/settings/userSettings.js b/src/scripts/settings/userSettings.js index 263d74ed37..4a27d7ad9a 100644 --- a/src/scripts/settings/userSettings.js +++ b/src/scripts/settings/userSettings.js @@ -114,6 +114,33 @@ export class UserSettings { }); } + /** + * Get or set 'Allowed Audio Channels'. + * @param {string|undefined} val - 'Allowed Audio Channels'. + * @return {string} 'Allowed Audio Channels'. + */ + allowedAudioChannels(val) { + if (val !== undefined) { + return this.set('allowedAudioChannels', val, false); + } + + return this.get('allowedAudioChannels', false) || '-1'; + } + + /** + * Get or set 'Perfer fMP4-HLS Container' state. + * @param {boolean|undefined} val - Flag to enable 'Perfer fMP4-HLS Container' or undefined. + * @return {boolean} 'Prefer fMP4-HLS Container' state. + */ + preferFmp4HlsContainer(val) { + if (val !== undefined) { + return this.set('preferFmp4HlsContainer', val.toString(), false); + } + + val = this.get('preferFmp4HlsContainer', false); + return val === 'true'; + } + /** * Get or set 'Cinema Mode' state. * @param {boolean|undefined} val - Flag to enable 'Cinema Mode' or undefined. @@ -457,6 +484,8 @@ export const importFrom = currentSettings.importFrom.bind(currentSettings); export const set = currentSettings.set.bind(currentSettings); export const get = currentSettings.get.bind(currentSettings); export const serverConfig = currentSettings.serverConfig.bind(currentSettings); +export const allowedAudioChannels = currentSettings.allowedAudioChannels.bind(currentSettings); +export const preferFmp4HlsContainer = currentSettings.preferFmp4HlsContainer.bind(currentSettings); export const enableCinemaMode = currentSettings.enableCinemaMode.bind(currentSettings); export const enableNextVideoInfoOverlay = currentSettings.enableNextVideoInfoOverlay.bind(currentSettings); export const enableThemeSongs = currentSettings.enableThemeSongs.bind(currentSettings); diff --git a/src/strings/en-us.json b/src/strings/en-us.json index c2ad064922..23cead75bd 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -1424,5 +1424,12 @@ "SubtitleVerticalPositionHelp": "Line number where text appears. Positive numbers indicate top down. Negative numbers indicate bottom up.", "Preview": "Preview", "LabelMaxMuxingQueueSize": "Max muxing queue size:", - "LabelMaxMuxingQueueSizeHelp": "Maximum number of packets that can be buffered while waiting for all streams to initialize. Try to increase it if you still encounter \"Too many packets buffered for output stream\" error in ffmpeg logs. The recommended value is 2048." + "LabelMaxMuxingQueueSizeHelp": "Maximum number of packets that can be buffered while waiting for all streams to initialize. Try to increase it if you still encounter \"Too many packets buffered for output stream\" error in ffmpeg logs. The recommended value is 2048.", + "PreferFmp4HlsContainer": "Prefer fMP4-HLS Media Container", + "PreferFmp4HlsContainerHelp": "Prefer to use fMP4 as the default container for HLS, making it possible to direct streaming HEVC content on supported devices.", + "AllowHevcEncoding": "Allow encoding in HEVC format", + "LabelAllowedAudioChannels": "Maximum Allowed Audio Channels", + "LabelSelectAudioChannels": "Channels", + "LabelSelectMono": "Mono", + "LabelSelectStereo": "Stereo" } diff --git a/src/strings/zh-cn.json b/src/strings/zh-cn.json index d6603c6eb9..af8d036da2 100644 --- a/src/strings/zh-cn.json +++ b/src/strings/zh-cn.json @@ -1425,5 +1425,12 @@ "OptionAllowContentDownload": "允许媒体下载", "HeaderDeleteDevices": "删除所有设备", "DeleteDevicesConfirmation": "您确定要删除所有设备吗?所有其他会话将被注销。用户下次登录时,设备会重新出现。", - "DeleteAll": "删除全部" + "DeleteAll": "删除全部", + "PreferFmp4HlsContainer": "优先使用 fMP4-HLS 媒体容器", + "PreferFmp4HlsContainerHelp": "优先使用 fMP4 作为 HLS 播放的默认容器,从而可以在支持的设备上直接串流 HEVC 格式的内容。", + "AllowHevcEncoding": "允许以 HEVC 格式编码", + "LabelAllowedAudioChannels": "允许的最大声道数量", + "LabelSelectAudioChannels": "声道", + "LabelSelectMono": "单声道", + "LabelSelectStereo": "立体声" } From aff83c93d28e8679af6beed83734408818e45d62 Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Thu, 12 Nov 2020 20:35:56 +0800 Subject: [PATCH 02/34] minor changes --- src/scripts/browserDeviceProfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/browserDeviceProfile.js b/src/scripts/browserDeviceProfile.js index 5b3ee64ac4..ea58e84aae 100644 --- a/src/scripts/browserDeviceProfile.js +++ b/src/scripts/browserDeviceProfile.js @@ -791,7 +791,7 @@ define(['browser', 'userSettings', 'appSettings'], function (browser, userSettin // hevc main10 level 6.1 if (videoTestElement.canPlayType('video/mp4; codecs="hvc1.2.4.L183"').replace(/no/, '') || - videoTestElement.canPlayType('video/mp4; codecs="hvc1.2.4.L183"').replace(/no/, '')) { + videoTestElement.canPlayType('video/mp4; codecs="hev1.2.4.L183"').replace(/no/, '')) { maxHevcLevel = 183; hevcProfiles = 'main|main 10'; } From 9e9ecbd6771f78063f52df7ff12c20273df178b2 Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Sat, 14 Nov 2020 03:32:25 +0800 Subject: [PATCH 03/34] expose h265 crf option --- .../dashboard/encodingsettings.html | 18 ++++++++++-------- src/controllers/dashboard/encodingsettings.js | 2 ++ src/strings/en-us.json | 5 +++-- src/strings/zh-cn.json | 5 +++-- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/controllers/dashboard/encodingsettings.html b/src/controllers/dashboard/encodingsettings.html index 4fdb1a0975..7be830780d 100644 --- a/src/controllers/dashboard/encodingsettings.html +++ b/src/controllers/dashboard/encodingsettings.html @@ -92,14 +92,14 @@
+ -
-
- -
+
+
+
@@ -211,11 +211,13 @@
${EncoderPresetHelp}
+
+ +
${H264CrfHelp}
-
-
+
@@ -46,8 +46,6 @@
- -
diff --git a/src/controllers/playback/video/index.js b/src/controllers/playback/video/index.js index 492f4aeee9..e6d3cca473 100644 --- a/src/controllers/playback/video/index.js +++ b/src/controllers/playback/video/index.js @@ -760,7 +760,7 @@ import 'css!assets/css/videoosd'; } if (runtimeTicks && positionTicks != null && currentRuntimeTicks && !enableProgressByTimeOfDay && currentItem.RunTimeTicks && currentItem.Type !== 'Recording') { - endsAtText.innerHTML = '  -  ' + mediaInfo.getEndsAtFromPosition(runtimeTicks, positionTicks, true); + endsAtText.innerHTML = '    ' + mediaInfo.getEndsAtFromPosition(runtimeTicks, positionTicks, true); } else { endsAtText.innerHTML = ''; } @@ -770,8 +770,20 @@ import 'css!assets/css/videoosd'; nowPlayingPositionSlider.setBufferedRanges(bufferedRanges, runtimeTicks, positionTicks); } - updateTimeText(nowPlayingPositionText, positionTicks); - updateTimeText(nowPlayingDurationText, runtimeTicks, true); + if (positionTicks >= 0) { + updateTimeText(nowPlayingPositionText, positionTicks); + nowPlayingPositionText.classList.remove('hide'); + } else { + nowPlayingPositionText.classList.add('hide'); + } + + const leftTicks = runtimeTicks - positionTicks; + if (leftTicks >= 0) { + updateTimeText(nowPlayingDurationText, leftTicks); + nowPlayingDurationText.classList.remove('hide'); + } else { + nowPlayingPositionText.classList.add('hide'); + } } } diff --git a/src/elements/emby-slider/emby-slider.css b/src/elements/emby-slider/emby-slider.css index 01221b6cae..f7503d4fd5 100644 --- a/src/elements/emby-slider/emby-slider.css +++ b/src/elements/emby-slider/emby-slider.css @@ -157,7 +157,7 @@ } .mdl-slider-background-flex { - background: #333; + background: rgba(255, 255, 255, 0.3); height: 0.2em; margin-top: -0.1em; width: 100%; diff --git a/src/elements/emby-slider/emby-slider.js b/src/elements/emby-slider/emby-slider.js index 555394af0d..ded72b338d 100644 --- a/src/elements/emby-slider/emby-slider.js +++ b/src/elements/emby-slider/emby-slider.js @@ -442,7 +442,9 @@ import 'emby-input'; position = (position / runtime) * 100; } - for (const range in ranges) { + for (let i = 0, length = ranges.length; i < length; i++) { + const range = ranges[i]; + if (position != null) { if (position >= range.end) { continue; From d3ee7b68fbb3170f047b86ed5669067cf6461fbd Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Tue, 17 Nov 2020 22:55:48 +0800 Subject: [PATCH 06/34] translation for video aspect ratio --- src/plugins/htmlVideoPlayer/plugin.js | 6 +++--- src/strings/en-us.json | 4 +++- src/strings/zh-cn.json | 4 +++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/plugins/htmlVideoPlayer/plugin.js b/src/plugins/htmlVideoPlayer/plugin.js index d2b395ffc6..f669cbaa68 100644 --- a/src/plugins/htmlVideoPlayer/plugin.js +++ b/src/plugins/htmlVideoPlayer/plugin.js @@ -1741,13 +1741,13 @@ function tryRemoveElement(elem) { getSupportedAspectRatios() { return [{ - name: 'Auto', + name: globalize.translate('Auto'), id: 'auto' }, { - name: 'Cover', + name: globalize.translate('AspectRatioCover'), id: 'cover' }, { - name: 'Fill', + name: globalize.translate('AspectRatioFill'), id: 'fill' }]; } diff --git a/src/strings/en-us.json b/src/strings/en-us.json index 4193b05ff5..274562f856 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -1428,5 +1428,7 @@ "SubtitleVerticalPositionHelp": "Line number where text appears. Positive numbers indicate top down. Negative numbers indicate bottom up.", "Preview": "Preview", "LabelMaxMuxingQueueSize": "Max muxing queue size:", - "LabelMaxMuxingQueueSizeHelp": "Maximum number of packets that can be buffered while waiting for all streams to initialize. Try to increase it if you still encounter \"Too many packets buffered for output stream\" error in ffmpeg logs. The recommended value is 2048." + "LabelMaxMuxingQueueSizeHelp": "Maximum number of packets that can be buffered while waiting for all streams to initialize. Try to increase it if you still encounter \"Too many packets buffered for output stream\" error in ffmpeg logs. The recommended value is 2048.", + "AspectRatioCover": "Cover", + "AspectRatioFill": "Fill" } diff --git a/src/strings/zh-cn.json b/src/strings/zh-cn.json index a59866de3b..80818c3602 100644 --- a/src/strings/zh-cn.json +++ b/src/strings/zh-cn.json @@ -1431,5 +1431,7 @@ "OptionAllowContentDownload": "允许媒体下载", "HeaderDeleteDevices": "删除所有设备", "DeleteDevicesConfirmation": "您确定要删除所有设备吗?所有其他会话将被注销。用户下次登录时,设备会重新出现。", - "DeleteAll": "删除全部" + "DeleteAll": "删除全部", + "AspectRatioCover": "覆盖", + "AspectRatioFill": "填充" } From 1cf3b0e75666247cb3cb315346f3f692caf5242b Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Tue, 17 Nov 2020 23:57:07 +0800 Subject: [PATCH 07/34] localize playback stats --- src/components/playerstats/playerstats.js | 14 +++++++------- src/controllers/dashboard/dashboard.js | 2 -- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/components/playerstats/playerstats.js b/src/components/playerstats/playerstats.js index 354002a267..593320047a 100644 --- a/src/components/playerstats/playerstats.js +++ b/src/components/playerstats/playerstats.js @@ -385,12 +385,12 @@ import 'css!./playerstats'; const baseCategory = { stats: [], - name: 'Playback Info' + name: globalize.translate('LabelPlaybackInfo') }; baseCategory.stats.unshift({ label: globalize.translate('LabelPlayMethod'), - value: displayPlayMethod + value: localizedDisplayMethod }); baseCategory.stats.unshift({ @@ -405,9 +405,9 @@ import 'css!./playerstats'; for (let i = 0, length = playerStats.length; i < length; i++) { const category = playerStats[i]; if (category.type === 'audio') { - category.name = 'Audio Info'; + category.name = globalize.translate('LabelAudioInfo'); } else if (category.type === 'video') { - category.name = 'Video Info'; + category.name = globalize.translate('LabelVideoInfo'); } categories.push(category); } @@ -422,20 +422,20 @@ import 'css!./playerstats'; if (session.TranscodingInfo) { categories.push({ stats: getTranscodingStats(session, player, displayPlayMethod), - name: displayPlayMethod === 'Transcode' ? 'Transcoding Info' : 'Direct Stream Info' + name: localizedTranscodingInfo }); } categories.push({ stats: getMediaSourceStats(session, player), - name: 'Original Media Info' + name: globalize.translate('LabelOriginalMediaInfo') }); const apiClient = window.connectionManager.getApiClient(playbackManager.currentItem(player).ServerId); if (syncPlayManager.isSyncPlayEnabled() && apiClient.isMinServerVersion('10.6.0')) { categories.push({ stats: getSyncPlayStats(), - name: 'SyncPlay Info' + name: globalize.translate('LabelSyncPlayInfo') }); } diff --git a/src/controllers/dashboard/dashboard.js b/src/controllers/dashboard/dashboard.js index d5dcf9ca49..9e5740bb8b 100644 --- a/src/controllers/dashboard/dashboard.js +++ b/src/controllers/dashboard/dashboard.js @@ -414,8 +414,6 @@ import 'emby-itemscontainer'; } showTranscodingInfo = true; - } else if (displayPlayMethod === 'DirectPlay') { - html += globalize.translate('DirectPlaying'); } if (showTranscodingInfo) { From c6862bfdfe321575433131ca165d280d229a88c6 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Tue, 17 Nov 2020 22:20:34 -0500 Subject: [PATCH 08/34] Add prepare script to allow CI to skip build --- .ci/azure-pipelines-build.yml | 6 +++--- .ci/azure-pipelines-lint.yml | 6 +++--- package.json | 2 +- scripts/prepare.sh | 5 +++++ 4 files changed, 12 insertions(+), 7 deletions(-) create mode 100755 scripts/prepare.sh diff --git a/.ci/azure-pipelines-build.yml b/.ci/azure-pipelines-build.yml index 128fe54605..05196d9d53 100644 --- a/.ci/azure-pipelines-build.yml +++ b/.ci/azure-pipelines-build.yml @@ -21,15 +21,15 @@ jobs: versionSpec: '12.x' - task: Cache@2 - displayName: 'Check Cache' + displayName: 'Cache node_modules' inputs: key: 'yarn | yarn.lock' path: 'node_modules' - cacheHitVar: CACHE_RESTORED - script: 'yarn install --frozen-lockfile' displayName: 'Install Dependencies' - condition: ne(variables.CACHE_RESTORED, 'true') + env: + SKIP_PREPARE: 'true' - script: 'yarn build:development' displayName: 'Build Development' diff --git a/.ci/azure-pipelines-lint.yml b/.ci/azure-pipelines-lint.yml index 1e4bddbd04..8d9efbd73a 100644 --- a/.ci/azure-pipelines-lint.yml +++ b/.ci/azure-pipelines-lint.yml @@ -12,15 +12,15 @@ jobs: versionSpec: '12.x' - task: Cache@2 - displayName: 'Check Cache' + displayName: 'Cache node_modules' inputs: key: 'yarn | yarn.lock' path: 'node_modules' - cacheHitVar: CACHE_RESTORED - script: 'yarn install --frozen-lockfile' displayName: 'Install Dependencies' - condition: ne(variables.CACHE_RESTORED, 'true') + env: + SKIP_PREPARE: 'true' - script: 'yarn run lint --quiet' displayName: 'Run ESLint' diff --git a/package.json b/package.json index 45d1a83fe7..8ec204d98c 100644 --- a/package.json +++ b/package.json @@ -394,7 +394,7 @@ "scripts": { "start": "yarn serve", "serve": "gulp serve --development", - "prepare": "gulp --production", + "prepare": "./scripts/prepare.sh", "build:development": "gulp --development", "build:production": "gulp --production", "build:standalone": "gulp standalone --development", diff --git a/scripts/prepare.sh b/scripts/prepare.sh new file mode 100755 index 0000000000..7626746365 --- /dev/null +++ b/scripts/prepare.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +if [ -z "${SKIP_PREPARE}" ]; then + npx gulp --production +fi From 87965aa7a46dd39f82fb71bf190ded4c99bc168a Mon Sep 17 00:00:00 2001 From: Nyanmisaka Date: Wed, 18 Nov 2020 05:39:17 +0000 Subject: [PATCH 09/34] Apply suggestions from code review Co-authored-by: dkanada --- src/strings/en-us.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strings/en-us.json b/src/strings/en-us.json index f4f111a096..87dea5f1d0 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -164,7 +164,7 @@ "DetectingDevices": "Detecting devices", "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.", "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is in an incompatible file container (mkv, avi, wmv, etc) and the video stream is compatible with the device, but has an incompatible audio format (DTS, TRUEHD, etc) or audio channels (5.1, 7.1, etc). The video stream will be re-packaged losslessly on the fly before being sent to the device. Only audio stream will be transcoded.", + "DirectStreamHelp1": "The media is in an incompatible file container (MKV, AVI, WMV, etc) and the video stream is compatible with the device, but has an incompatible audio format (DTS, TRUEHD, etc) or number of audio channels. The video stream will be repackaged losslessly on the fly before being sent to the device. Only the audio stream will be transcoded.", "DirectStreamHelp2": "Power consumed by direct streaming usually depends on the audio profile. Only the video stream is lossless.", "DirectStreaming": "Direct streaming", "Director": "Director", @@ -1432,7 +1432,7 @@ "LabelMaxMuxingQueueSize": "Max muxing queue size:", "LabelMaxMuxingQueueSizeHelp": "Maximum number of packets that can be buffered while waiting for all streams to initialize. Try to increase it if you still encounter \"Too many packets buffered for output stream\" error in ffmpeg logs. The recommended value is 2048.", "Remuxing": "Remuxing", - "RemuxHelp1": "The media is in an incompatible file container (mkv, avi, wmv, etc). But both video stream and audio stream are compatible with the device. The media will be re-packaged losslessly on the fly before being sent to the device.", + "RemuxHelp1": "The media is in an incompatible file container (MKV, AVI, WMV, etc) but both the video stream and audio stream are compatible with the device. The media will be repackaged losslessly on the fly before being sent to the device.", "RemuxHelp2": "Remux uses very little processing power with a completely lossless media quality.", "LabelPlaybackInfo": "Playback Info", "LabelAudioInfo": "Audio Info", From c636386bc07b35e5eb8904697df8d5f8964786f6 Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Wed, 18 Nov 2020 13:41:58 +0800 Subject: [PATCH 10/34] minor changes for Directstream --- src/strings/en-us.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strings/en-us.json b/src/strings/en-us.json index 87dea5f1d0..2297934f0d 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -164,7 +164,7 @@ "DetectingDevices": "Detecting devices", "DeviceAccessHelp": "This only applies to devices that can be uniquely identified and will not prevent browser access. Filtering user device access will prevent them from using new devices until they've been approved here.", "DirectPlaying": "Direct playing", - "DirectStreamHelp1": "The media is in an incompatible file container (MKV, AVI, WMV, etc) and the video stream is compatible with the device, but has an incompatible audio format (DTS, TRUEHD, etc) or number of audio channels. The video stream will be repackaged losslessly on the fly before being sent to the device. Only the audio stream will be transcoded.", + "DirectStreamHelp1": "The video stream is compatible with the device, but has an incompatible audio format (DTS, TRUEHD, etc) or number of audio channels. The video stream will be repackaged losslessly on the fly before being sent to the device. Only the audio stream will be transcoded.", "DirectStreamHelp2": "Power consumed by direct streaming usually depends on the audio profile. Only the video stream is lossless.", "DirectStreaming": "Direct streaming", "Director": "Director", From f3c9b9da15a0f8a0325b94c6a155fd7ad8f5ef5f Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Fri, 20 Nov 2020 12:21:55 +0800 Subject: [PATCH 11/34] use uppercase for codecs in dashboard --- src/controllers/dashboard/dashboard.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/controllers/dashboard/dashboard.js b/src/controllers/dashboard/dashboard.js index 57436f7537..2bfecee080 100644 --- a/src/controllers/dashboard/dashboard.js +++ b/src/controllers/dashboard/dashboard.js @@ -431,15 +431,15 @@ import confirm from '../../components/confirm/confirm'; } if (session.TranscodingInfo.Container) { - line.push(session.TranscodingInfo.Container); + line.push(session.TranscodingInfo.Container.toUpperCase()); } if (session.TranscodingInfo.VideoCodec) { - line.push(session.TranscodingInfo.VideoCodec); + line.push(session.TranscodingInfo.VideoCodec.toUpperCase()); } if (session.TranscodingInfo.AudioCodec && session.TranscodingInfo.AudioCodec != session.TranscodingInfo.Container) { - line.push(session.TranscodingInfo.AudioCodec); + line.push(session.TranscodingInfo.AudioCodec.toUpperCase()); } } From bb7313270ce54aa57b1d31766fcaf06d73add281 Mon Sep 17 00:00:00 2001 From: Nyanmisaka Date: Fri, 20 Nov 2020 06:45:52 +0000 Subject: [PATCH 12/34] Apply suggestions from code review Co-authored-by: Julien Machiels --- src/strings/en-us.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strings/en-us.json b/src/strings/en-us.json index 2bcf4bc831..b0bb085249 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -1431,7 +1431,7 @@ "LabelMaxMuxingQueueSize": "Max muxing queue size:", "LabelMaxMuxingQueueSizeHelp": "Maximum number of packets that can be buffered while waiting for all streams to initialize. Try to increase it if you still encounter \"Too many packets buffered for output stream\" error in ffmpeg logs. The recommended value is 2048.", "PreferFmp4HlsContainer": "Prefer fMP4-HLS Media Container", - "PreferFmp4HlsContainerHelp": "Prefer to use fMP4 as the default container for HLS, making it possible to direct streaming HEVC content on supported devices.", + "PreferFmp4HlsContainerHelp": "Prefer to use fMP4 as the default container for HLS, making it possible to direct stream HEVC content on supported devices.", "AllowHevcEncoding": "Allow encoding in HEVC format", "LabelAllowedAudioChannels": "Maximum Allowed Audio Channels", "LabelSelectAudioChannels": "Channels", From cd99b752c51f172835c028846ace388c76f792ab Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Fri, 20 Nov 2020 17:33:35 +0800 Subject: [PATCH 13/34] fix hevc check for fMP4 --- src/scripts/browserDeviceProfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/browserDeviceProfile.js b/src/scripts/browserDeviceProfile.js index 73ccff35bd..a6f26cd040 100644 --- a/src/scripts/browserDeviceProfile.js +++ b/src/scripts/browserDeviceProfile.js @@ -467,7 +467,7 @@ import browser from './browser'; const hlsInTsVideoCodecs = []; const hlsInFmp4VideoCodecs = []; - if (browser.safari || browser.tizen || browser.web0s && canPlayHevc(videoTestElement, options)) { + if ((browser.safari || browser.tizen || browser.web0s) && canPlayHevc(videoTestElement, options)) { hlsInFmp4VideoCodecs.push('hevc'); } From a9755fbb1fbf29f5c6c88de18e969b6cff5ab9e1 Mon Sep 17 00:00:00 2001 From: HavilandTuff Date: Fri, 20 Nov 2020 09:25:02 +0000 Subject: [PATCH 14/34] Translated using Weblate (Polish) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/pl/ --- src/strings/pl.json | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/strings/pl.json b/src/strings/pl.json index 1ca467c70c..1ee938b79e 100644 --- a/src/strings/pl.json +++ b/src/strings/pl.json @@ -416,7 +416,7 @@ "Items": "Pozycje", "Kids": "Dla dzieci", "Label3DFormat": "Format 3D:", - "LabelAbortedByServerShutdown": "(Przerwano w skuter wyłączenia serwera)", + "LabelAbortedByServerShutdown": "(Przerwano w skutek wyłączenia serwera)", "LabelAccessDay": "Dzień tygodnia:", "LabelAccessEnd": "Czas zakończenia:", "LabelAccessStart": "Czas startu:", @@ -1381,5 +1381,9 @@ "Authorize": "Autoryzuj", "HeaderDeleteDevices": "Usuń wszystkie urządzenia", "DeleteAll": "Usuń wszystkie", - "LabelKnownProxies": "Znane serwery proxy:" + "LabelKnownProxies": "Znane serwery proxy:", + "MediaInfoColorSpace": "Przestrzeń kolorów", + "LabelColorSpace": "Przestrzeń kolorów:", + "KnownProxiesHelp": "Podzielona przecinkami lista znanych serwerów proxy, używana do łączenia z twoją instancją Jellyfin. Wymagana do poprawnego użycia nagłówka X-Forwarded-For. Wymaga restartu po zapisaniu.", + "DeleteDevicesConfirmation": "Na pewno usunąć wszystkie urządzenia? Wszystkie pozostałe sesje zostaną wylogowane. Urządzenia pojawią się ponownie po następnym zalogowaniu użytkownika." } From 3bfb8f42f1d59bbba215f858b69d62c92ac8ff64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Struijk=20Holmen?= Date: Thu, 19 Nov 2020 22:12:05 +0100 Subject: [PATCH 15/34] Just return original server address in chromecastHelper --- .../chromecastPlayer/chromecastHelper.js | 225 +----------------- 1 file changed, 1 insertion(+), 224 deletions(-) diff --git a/src/plugins/chromecastPlayer/chromecastHelper.js b/src/plugins/chromecastPlayer/chromecastHelper.js index bdcbc7c963..80555a4fd9 100644 --- a/src/plugins/chromecastPlayer/chromecastHelper.js +++ b/src/plugins/chromecastPlayer/chromecastHelper.js @@ -1,230 +1,7 @@ -import { Events } from 'jellyfin-apiclient'; -import ServerConnections from '../../components/ServerConnections'; - -// LinkParser -// -// https://github.com/ravisorg/LinkParser -// -// Locate and extract almost any URL within a string. Handles protocol-less domains, IPv4 and -// IPv6, unrecognised TLDs, and more. -// -// This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License. -// http://creativecommons.org/licenses/by-sa/4.0/ -(function () { - // Original URL regex from the Android android.text.util.Linkify function, found here: - // http://stackoverflow.com/a/19696443 - // - // However there were problems with it, most probably related to the fact it was - // written in 2007, and it's been highly modified. - // - // 1) I didn't like the fact that it was tied to specific TLDs, since new ones - // are being added all the time it wouldn't be reasonable to expect developer to - // be continually updating their regular expressions. - // - // 2) It didn't allow unicode characters in the domains which are now allowed in - // many languages, (including some IDN TLDs). Again these are constantly being - // added to and it doesn't seem reasonable to hard-code them. Note this ended up - // not being possible in standard JS due to the way it handles multibyte strings. - // It is possible using XRegExp, however a big performance hit results. Disabled - // for now. - // - // 3) It didn't allow for IPv6 hostnames - // IPv6 regex from http://stackoverflow.com/a/17871737 - // - // 4) It was very poorly commented - // - // 5) It wasn't as smart as it could have been about what should be part of a - // URL and what should be part of human language. - - const protocols = '(?:(?:http|https|rtsp|ftp):\\/\\/)'; - const credentials = "(?:(?:[a-z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-f0-9]{2})){1,64}" // username (1-64 normal or url escaped characters) - + "(?:\\:(?:[a-z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-f0-9]{2})){1,25})?" // followed by optional password (: + 1-25 normal or url escaped characters) - + '\\@)'; - - // IPv6 Regex http://forums.intermapper.com/viewtopic.php?t=452 - // by Dartware, LLC is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License - // http://intermapper.com/ - const ipv6 = '(' - + '(([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))' - + '|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))' - + '|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))' - + '|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))' - + '|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))' - + '|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))' - + '|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))' - + '|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))' - + ')(%.+)?'; - - const ipv4 = '(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.' - + '(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.' - + '(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.' - + '(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])'; - - // This would have been a lot cleaner if JS RegExp supported conditionals... - const linkRegExpString = - - // begin match for protocol / username / password / host - '(?:' - - // ============================ - // If we have a recognized protocol at the beginning of the URL, we're - // more relaxed about what we accept, because we assume the user wants - // this to be a URL, and we're not accidentally matching human language - + protocols + '?' - - // optional username:password@ - + credentials + '?' - - // IP address (both v4 and v6) - + '(?:' - - // IPv6 - + ipv6 - - // IPv4 - + '|' + ipv4 - - + ')' - - // end match for protocol / username / password / host - + ')' - - // optional port number - + '(?:\\:\\d{1,5})?' - - // plus optional path and query params (no unicode allowed here?) - + '(?:' - + '\\/(?:' - // some characters we'll accept because it's unlikely human language - // would use them after a URL unless they were part of the url - + '(?:[a-z0-9\\/\\@\\&\\#\\~\\*\\_\\-\\+])' - + '|(?:\\%[a-f0-9]{2})' - // some characters are much more likely to be used AFTER a url and - // were not intended to be included in the url itself. Mostly end - // of sentence type things. It's also likely that the URL would - // still work if any of these characters were missing from the end - // because we parsed it incorrectly. For these characters to be accepted - // they must be followed by another character that we're reasonably - // sure is part of the url - + "|(?:[\\;\\?\\:\\.\\!\\'\\(\\)\\,\\=]+(?=(?:[a-z0-9\\/\\@\\&\\#\\~\\*\\_\\-\\+])|(?:\\%[a-f0-9]{2})))" - + ')*' - + '|\\b|\$' - + ')'; - - // regex = XRegExp(regex,'gi'); - const linkRegExp = RegExp(linkRegExpString, 'gi'); - - const protocolRegExp = RegExp('^' + protocols, 'i'); - - // if url doesn't begin with a known protocol, add http by default - function ensureProtocol(url) { - if (!url.match(protocolRegExp)) { - url = 'http://' + url; - } - return url; - } - - // look for links in the text - const LinkParser = { - parse: function (text) { - const links = []; - let match; - - // eslint-disable-next-line no-cond-assign - while (match = linkRegExp.exec(text)) { - console.debug(match); - const txt = match[0]; - const pos = match.index; - const len = txt.length; - const url = ensureProtocol(text); - links.push({ 'pos': pos, 'text': txt, 'len': len, 'url': url }); - } - - return links; - } - - }; - - window.LinkParser = LinkParser; -})(); - -let cache = {}; - -// TODO: Replace with isIP (https://www.npmjs.com/package/is-ip) -function isValidIpAddress(address) { - const links = LinkParser.parse(address); - - return links.length == 1; -} - -// TODO: Add IPv6 support. Potentially replace with isLocalhost (https://www.npmjs.com/package/is-localhost-ip) -function isLocalIpAddress(address) { - address = address.toLowerCase(); - - if (address.includes('127.0.0.1')) { - return true; - } - if (address.includes('localhost')) { - return true; - } - - return false; -} - export function getServerAddress(apiClient) { - const serverAddress = apiClient.serverAddress(); - - if (isValidIpAddress(serverAddress) && !isLocalIpAddress(serverAddress)) { - return Promise.resolve(serverAddress); - } - - const cachedValue = getCachedValue(serverAddress); - if (cachedValue) { - return Promise.resolve(cachedValue); - } - - return apiClient.getEndpointInfo().then(function (endpoint) { - if (endpoint.IsInNetwork) { - return apiClient.getPublicSystemInfo().then(function (info) { - let localAddress = info.LocalAddress; - if (!localAddress) { - console.debug('No valid local address returned, defaulting to external one'); - localAddress = serverAddress; - } - addToCache(serverAddress, localAddress); - return localAddress; - }); - } else { - addToCache(serverAddress, serverAddress); - return serverAddress; - } - }); + return Promise.resolve(apiClient.serverAddress()); } -function clearCache() { - cache = {}; -} - -function addToCache(key, value) { - cache[key] = { - value: value, - time: new Date().getTime() - }; -} - -function getCachedValue(key) { - const obj = cache[key]; - - if (obj && (new Date().getTime() - obj.time) < 180000) { - return obj.value; - } - - return null; -} - -Events.on(ServerConnections, 'localusersignedin', clearCache); -Events.on(ServerConnections, 'localusersignedout', clearCache); - export default { getServerAddress: getServerAddress }; From d4dce77bb6e9a4a2590a992e2855d033b420795b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Struijk=20Holmen?= Date: Fri, 20 Nov 2020 08:43:45 +0100 Subject: [PATCH 16/34] remove chromecastHelper entirely --- src/plugins/chromecastPlayer/chromecastHelper.js | 7 ------- src/plugins/chromecastPlayer/plugin.js | 9 +-------- 2 files changed, 1 insertion(+), 15 deletions(-) delete mode 100644 src/plugins/chromecastPlayer/chromecastHelper.js diff --git a/src/plugins/chromecastPlayer/chromecastHelper.js b/src/plugins/chromecastPlayer/chromecastHelper.js deleted file mode 100644 index 80555a4fd9..0000000000 --- a/src/plugins/chromecastPlayer/chromecastHelper.js +++ /dev/null @@ -1,7 +0,0 @@ -export function getServerAddress(apiClient) { - return Promise.resolve(apiClient.serverAddress()); -} - -export default { - getServerAddress: getServerAddress -}; diff --git a/src/plugins/chromecastPlayer/plugin.js b/src/plugins/chromecastPlayer/plugin.js index 81bbb7e3dc..41341066b3 100644 --- a/src/plugins/chromecastPlayer/plugin.js +++ b/src/plugins/chromecastPlayer/plugin.js @@ -353,14 +353,7 @@ class CastPlayer { message.subtitleBurnIn = appSettings.get('subtitleburnin') || ''; } - return new Promise(function (resolve, reject) { - import('./chromecastHelper').then(({ default: chromecastHelper }) => { - chromecastHelper.getServerAddress(apiClient).then(function (serverAddress) { - message.serverAddress = serverAddress; - player.sendMessageInternal(message).then(resolve, reject); - }, reject); - }); - }); + return player.sendMessageInternal(message); } sendMessageInternal(message) { From 2a02e7f23fdc59518c2415a3256ed494b293013e Mon Sep 17 00:00:00 2001 From: Decoy7 Date: Fri, 20 Nov 2020 12:47:03 +0000 Subject: [PATCH 17/34] Translated using Weblate (Greek) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/el/ --- src/strings/el.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/strings/el.json b/src/strings/el.json index 0140b0646b..142405fe31 100644 --- a/src/strings/el.json +++ b/src/strings/el.json @@ -162,8 +162,8 @@ "EnableHardwareEncoding": "Ενεργοποίηση αποκωδικοποίησης υλικού", "EnableNextVideoInfoOverlay": "Εμφάνιση πληροφοριών επόμενου βίντεο κατά την αναπαραγωγή", "EnableNextVideoInfoOverlayHelp": "Στο τέλος ενός βίντεο, εμφανίστε πληροφορίες σχετικά με το επόμενο βίντεο που εμφανίζεται στην τρέχουσα λίστα αναπαραγωγής.", - "EnableThemeSongsHelp": "Αν είναι ενεργοποιημένη, τα τραγούδια θεμάτων θα αναπαραχθούν στο παρασκήνιο κατά την περιήγηση στη βιβλιοθήκη.", - "EnableThemeVideosHelp": "Αν είναι ενεργοποιημένη, τα βίντεο θεμάτων θα αναπαραχθούν στο παρασκήνιο κατά την περιήγηση στη βιβλιοθήκη.", + "EnableThemeSongsHelp": "Αν είναι ενεργοποιημένη, τα τραγούδια θεμάτων θα αναπαράγονται στο παρασκήνιο κατά την περιήγηση στη βιβλιοθήκη.", + "EnableThemeVideosHelp": "Αν είναι ενεργοποιημένη, τα βίντεο θεμάτων θα αναπαράγονται στο παρασκήνιο κατά την περιήγηση στη βιβλιοθήκη.", "Ended": "Τέλος", "EndsAtValue": "Τελειώνει σε {0}", "Episodes": "Επεισόδια", @@ -1056,5 +1056,7 @@ "EnableDecodingColorDepth10Vp9": "Ενεργοποίηση αποκωδικοποίησης υλικού 10-bit για το VP9", "EnableDecodingColorDepth10Hevc": "Ενεργοποίηση αποκωδικοποίησης υλικού 10-bit για HEVC", "EnableAutoCast": "Ορίσετε ως προεπιλογή", - "ButtonUseQuickConnect": "Χρήση γρήγορης σύνδεσης" + "ButtonUseQuickConnect": "Χρήση γρήγορης σύνδεσης", + "EnableDetailsBanner": "Πανό Λεπτομερειών", + "DeleteAll": "Διαγραφή Ολων" } From ea8a2d55496dd0f48c5c07eb82eaf147586245f4 Mon Sep 17 00:00:00 2001 From: Nyanmisaka Date: Fri, 20 Nov 2020 23:43:55 +0000 Subject: [PATCH 18/34] Apply suggestions from code review Co-authored-by: Dmitry Lyzo <56478732+dmitrylyzo@users.noreply.github.com> --- src/elements/emby-slider/emby-slider.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/elements/emby-slider/emby-slider.js b/src/elements/emby-slider/emby-slider.js index ded72b338d..671f730cc1 100644 --- a/src/elements/emby-slider/emby-slider.js +++ b/src/elements/emby-slider/emby-slider.js @@ -442,9 +442,7 @@ import 'emby-input'; position = (position / runtime) * 100; } - for (let i = 0, length = ranges.length; i < length; i++) { - const range = ranges[i]; - + for (const range of ranges) { if (position != null) { if (position >= range.end) { continue; From 109d5bf32c3f512de5da7d2978b246af8e49d3be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Struijk=20Holmen?= Date: Sat, 21 Nov 2020 04:07:37 +0100 Subject: [PATCH 19/34] restore Assets --- webpack.common.js | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/webpack.common.js b/webpack.common.js index f6b23c197b..c9be6c7b98 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -5,6 +5,24 @@ const packageConfig = require('./package.json'); const WorkboxPlugin = require('workbox-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); +const Assets = [ + 'alameda/alameda.js', + 'native-promise-only/npo.js', + 'libarchive.js/dist/worker-bundle.js', + 'libass-wasm/dist/js/subtitles-octopus-worker.js', + 'libass-wasm/dist/js/subtitles-octopus-worker.data', + 'libass-wasm/dist/js/subtitles-octopus-worker.wasm', + 'libass-wasm/dist/js/subtitles-octopus-worker-legacy.js', + 'libass-wasm/dist/js/subtitles-octopus-worker-legacy.data', + 'libass-wasm/dist/js/subtitles-octopus-worker-legacy.js.mem', + 'pdfjs-dist/build/pdf.worker.js' +]; + +const LibarchiveWasm = [ + 'libarchive.js/dist/wasm-gen/libarchive.js', + 'libarchive.js/dist/wasm-gen/libarchive.wasm' +]; + module.exports = { context: path.resolve(__dirname, 'src'), target: 'web', @@ -39,6 +57,22 @@ module.exports = { } ] }), + new CopyPlugin({ + patterns: Assets.map(asset => { + return { + from: path.resolve(__dirname, `./node_modules/${asset}`), + to: path.resolve(__dirname, './dist/libraries') + }; + }) + }), + new CopyPlugin({ + patterns: LibarchiveWasm.map(asset => { + return { + from: path.resolve(__dirname, `./node_modules/${asset}`), + to: path.resolve(__dirname, './dist/libraries/wasm-gen') + }; + }) + }), new WorkboxPlugin.InjectManifest({ swSrc: path.resolve(__dirname, 'src/serviceworker.js'), swDest: 'serviceworker.js' From b9b3ed00eaad51dfe0a29a4aa344ff57aa6bd72d Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Fri, 20 Nov 2020 23:28:21 -0500 Subject: [PATCH 20/34] Fix pdfjs import --- src/plugins/pdfPlayer/plugin.js | 35 ++++++++++++++++----------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/plugins/pdfPlayer/plugin.js b/src/plugins/pdfPlayer/plugin.js index a90e2b26ef..5bface5911 100644 --- a/src/plugins/pdfPlayer/plugin.js +++ b/src/plugins/pdfPlayer/plugin.js @@ -7,6 +7,7 @@ import { appRouter } from '../../components/appRouter'; import './style.css'; import '../../elements/emby-button/paper-icon-button-light'; import { Events } from 'jellyfin-apiclient'; +import { GlobalWorkerOptions, getDocument } from 'pdfjs-dist'; export class PdfPlayer { constructor() { @@ -189,28 +190,26 @@ export class PdfPlayer { const apiClient = ServerConnections.getApiClient(serverId); return new Promise((resolve, reject) => { - import('pdfjs-dist').then(({default: pdfjs}) => { - const downloadHref = apiClient.getItemDownloadUrl(item.Id); + const downloadHref = apiClient.getItemDownloadUrl(item.Id); - this.bindEvents(); - pdfjs.GlobalWorkerOptions.workerSrc = appRouter.baseUrl() + '/libraries/pdf.worker.js'; + this.bindEvents(); + GlobalWorkerOptions.workerSrc = appRouter.baseUrl() + '/libraries/pdf.worker.js'; - const downloadTask = pdfjs.getDocument(downloadHref); - downloadTask.promise.then(book => { - if (this.cancellationToken) return; - this.book = book; - this.loaded = true; + const downloadTask = getDocument(downloadHref); + downloadTask.promise.then(book => { + if (this.cancellationToken) return; + this.book = book; + this.loaded = true; - const percentageTicks = options.startPositionTicks / 10000; - if (percentageTicks !== 0) { - this.loadPage(percentageTicks); - this.progress = percentageTicks; - } else { - this.loadPage(1); - } + const percentageTicks = options.startPositionTicks / 10000; + if (percentageTicks !== 0) { + this.loadPage(percentageTicks); + this.progress = percentageTicks; + } else { + this.loadPage(1); + } - return resolve(); - }); + return resolve(); }); }); } From fd3c6ad55313bc4640d7adcbc6470cf5685a201f Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Sat, 21 Nov 2020 12:47:43 +0800 Subject: [PATCH 21/34] resolve confict --- src/strings/zh-cn.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strings/zh-cn.json b/src/strings/zh-cn.json index d9f79bb091..ff10f7c3af 100644 --- a/src/strings/zh-cn.json +++ b/src/strings/zh-cn.json @@ -1443,7 +1443,7 @@ "LabelDirectStreamingInfo": "直接串流信息", "LabelRemuxingInfo": "转封装信息", "LabelOriginalMediaInfo": "媒体源信息", - "LabelSyncPlayInfo": "同步播放信息" + "LabelSyncPlayInfo": "同步播放信息", "PreferFmp4HlsContainer": "优先使用 fMP4-HLS 媒体容器", "PreferFmp4HlsContainerHelp": "优先使用 fMP4 作为 HLS 播放的默认容器,从而可以在支持的设备上直接串流 HEVC 格式的内容。", "AllowHevcEncoding": "允许以 HEVC 格式编码", From 34df6baf227084dc9b78af9be10275e8f14c5d25 Mon Sep 17 00:00:00 2001 From: nyanmisaka Date: Sat, 21 Nov 2020 13:20:44 +0800 Subject: [PATCH 22/34] fix airplay in safari --- src/plugins/htmlVideoPlayer/plugin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/htmlVideoPlayer/plugin.js b/src/plugins/htmlVideoPlayer/plugin.js index c5b614bcc7..0ee3b5e147 100644 --- a/src/plugins/htmlVideoPlayer/plugin.js +++ b/src/plugins/htmlVideoPlayer/plugin.js @@ -1539,7 +1539,7 @@ function tryRemoveElement(elem) { return false; } - static isAirPlayEnabled() { + isAirPlayEnabled() { if (document.AirPlayEnabled) { return !!document.AirplayElement; } From fc3ba04d95a4601b3edad5a9e1e530dcc17c686b Mon Sep 17 00:00:00 2001 From: lelamamalgache Date: Sat, 21 Nov 2020 08:36:52 +0000 Subject: [PATCH 23/34] Translated using Weblate (French) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/fr/ --- src/strings/fr.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strings/fr.json b/src/strings/fr.json index 41b5b680b2..a2e96fbbbf 100644 --- a/src/strings/fr.json +++ b/src/strings/fr.json @@ -211,7 +211,7 @@ "GroupVersions": "Grouper les versions", "GuideProviderLogin": "Connexion", "GuideProviderSelectListings": "Sélectionner les listings", - "H264CrfHelp": "Le facteur de débit constant (CRF) est le paramètre de qualité par défaut pour l'encodeur x264. Vous pouvez régler les valeurs entre 0 et 51, où des valeurs plus faibles se traduiraient par une meilleure qualité (en augmentant le taille des fichiers). De bonne valeurs se situent entre 18 et 28. La valeur par défaut pour le x264 est 23, vous pouvez l'utiliser comme point de départ.", + "H264CrfHelp": "Le facteur de débit constant (CRF) est le paramètre de qualité par défaut pour les encodeurs x264 et x265. Vous pouvez définir les valeurs entre 0 et 51, où des valeurs inférieures entraîneraient une meilleure qualité (au détriment de tailles de fichier plus élevées). Les valeurs saines sont comprises entre 18 et 28. La valeur par défaut pour x264 est 23 et pour x265 est 28, vous pouvez donc l'utiliser comme point de départ.", "EncoderPresetHelp": "Choisissez une valeur plus rapide pour améliorer la performance, ou plus lente pour améliorer la qualité.", "HDPrograms": "Programmes HD", "HardwareAccelerationWarning": "L'activation de l'accélération matérielle peut provoquer une instabilité dans certains environnements. Assurez-vous que votre système d'exploitation et vos pilotes vidéo sont complètement à jour. Si vous avez des difficultés pour lire des vidéos après l'activation, vous devrez remettre ce paramètre sur Aucun.", From b2a30accd060065fa37643c7783351f5ccd8c54f Mon Sep 17 00:00:00 2001 From: Thomas Schwery Date: Sat, 21 Nov 2020 11:22:18 +0000 Subject: [PATCH 24/34] Translated using Weblate (French) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/fr/ --- src/strings/fr.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/strings/fr.json b/src/strings/fr.json index a2e96fbbbf..9f22d52e14 100644 --- a/src/strings/fr.json +++ b/src/strings/fr.json @@ -516,7 +516,7 @@ "LabelGroupMoviesIntoCollections": "Grouper les films en collections", "LabelGroupMoviesIntoCollectionsHelp": "Dans l'affichage des listes de films, les films d'une collection seront affichés comme un élément groupé.", "LabelH264Crf": "CRF d'encodage H264 :", - "LabelEncoderPreset": "Profil d'encodage H264 :", + "LabelEncoderPreset": "Profil d'encodage :", "LabelHardwareAccelerationType": "Accélération matérielle :", "LabelHardwareAccelerationTypeHelp": "L'accélération matérielle nécessite une configuration supplémentaire.", "LabelHomeNetworkQuality": "Qualité du réseau local :", @@ -1431,5 +1431,6 @@ "LabelFallbackFontPathHelp": "Spécifiez un chemin contenant les polices de remplacement pour le rendu des sous-titres ASS / SSA. La taille de police totale maximale autorisée est de 20 Mo. Les formats de police légers et conviviaux pour le Web tels que woff2 sont recommandés.", "LabelFallbackFontPath": "Chemin du dossier des polices de secours :", "HeaderSelectFallbackFontPathHelp": "Parcourez ou entrez le chemin du dossier de polices de secours à utiliser pour le rendu des sous-titres ASS/SSA.", - "HeaderSelectFallbackFontPath": "Sélectionnez le dossier des polices de secours" + "HeaderSelectFallbackFontPath": "Sélectionnez le dossier des polices de secours", + "LabelH265Crf": "CRF d'encodage H265 :" } From 362e75d167989e644453a8da2686fb9f8448b7ec Mon Sep 17 00:00:00 2001 From: dkanada Date: Sat, 21 Nov 2020 22:11:27 +0900 Subject: [PATCH 25/34] use webpack inside prepare script --- scripts/prepare.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/prepare.sh b/scripts/prepare.sh index 7626746365..bde12b36a5 100755 --- a/scripts/prepare.sh +++ b/scripts/prepare.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash if [ -z "${SKIP_PREPARE}" ]; then - npx gulp --production + webpack --config webpack.prod.js fi From 1bc033f081a15a0361bd28241e153cd6c8fed246 Mon Sep 17 00:00:00 2001 From: hoanghuy309 Date: Sat, 21 Nov 2020 15:29:38 +0000 Subject: [PATCH 26/34] Translated using Weblate (Vietnamese) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/vi/ --- src/strings/vi.json | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/strings/vi.json b/src/strings/vi.json index 216203ae61..34c7ad3ef1 100644 --- a/src/strings/vi.json +++ b/src/strings/vi.json @@ -294,7 +294,7 @@ "HeaderAccessSchedule": "Thời Gian Truy Cập", "HDPrograms": "Chương trình chất lượng cao (HD)", "EncoderPresetHelp": "Chọn một giá trị nhanh hơn để cải thiện hiệu suất máy chủ, hoặc một giá trị chậm hơn để tăng chất lượng video.", - "H264CrfHelp": "Hệ Số Tỉ Lệ Cố Định (Constant Rate Factor (CRF)) là thiết lập chất lượng mặc định dành cho bộ mã hoá x264. Bạn có thể điều chỉnh giá trị trong khoảng 0 đến 51, trong đó giá trị càng nhỏ thì chất lượng càng tốt (đồng nghĩa với việc dung lượng tập tin lớn hơn). Giá trị vừa phải nằm trong khoảng từ 18 đến 28. Giá trị mặc định dành cho x264 là 23, vì thế bạn có thể sử dụng nó để bắt đầu điều chỉnh cho phù hợp.", + "H264CrfHelp": "Hệ Số Tỉ Lệ Cố Định (CRF) là cài đặt chất lượng mặc định cho mã hóa x264 và x265. Bạn có thể chỉnh giá trị từ 0 đến 51, giá trị càng nhỏ thì chất lượng càng tốt (dung lượng tệp sẽ lớn hơn). Giá trị vừa phải từ 18 đến 28. Giá trị mặc định cho x264 là 23 và x265 là 28, vì vậy bạn có thể bắt đầu với những giá trị tham khảo này.", "GuideProviderSelectListings": "Chọn Danh Sách", "GuideProviderLogin": "Đăng nhập", "Guide": "Lịch phát sóng", @@ -641,7 +641,7 @@ "LabelHomeNetworkQuality": "Chất lượng mạng nhà:", "LabelHardwareAccelerationTypeHelp": "Hỗ trợ phần cần những thiết lập bổ sung.", "LabelHardwareAccelerationType": "Tăng tốc phần cứng:", - "LabelEncoderPreset": "Thiết lập cài sẵn của mã H264 và H265:", + "LabelEncoderPreset": "Mẫu cài đặt sẵn H264 và H265:", "LabelH264Crf": "CRF của mã H264:", "LabelGroupMoviesIntoCollectionsHelp": "Khi hiển thị danh sách phim, các bộ phim trong một bộ sưu tập sẽ hiển thị như một mục được nhóm lại.", "LabelGroupMoviesIntoCollections": "Gom nhóm các phim vào bộ sưu tập", @@ -1431,5 +1431,13 @@ "LabelFallbackFontPathHelp": "Chỉ định đường dẫn chứa phông chữ dự phòng để hiển thị phụ đề ASS / SSA. Tổng kích thước phông chữ tối đa được phép là 20 MB. Các định dạng phông chữ nhẹ và thân thiện với web như woff2 được khuyến khích.", "LabelFallbackFontPath": "Đường dẫn thư mục phông chữ dự phòng:", "HeaderSelectFallbackFontPathHelp": "Duyệt qua hoặc nhập đường dẫn của thư mục phông chữ dự phòng để sử dụng cho việc hiển thị phụ đề ASS / SSA.", - "HeaderSelectFallbackFontPath": "Chọn Đường dẫn Thư mục Phông chữ Dự phòng" + "HeaderSelectFallbackFontPath": "Chọn Đường dẫn Thư mục Phông chữ Dự phòng", + "LabelSelectStereo": "Âm Thanh Nổi", + "LabelSelectMono": "", + "LabelSelectAudioChannels": "Kênh", + "LabelAllowedAudioChannels": "Kênh Âm Thanh Cho Phép Tối Đa", + "AllowHevcEncoding": "Cho phép mã hóa ở định dạng HEVC", + "PreferFmp4HlsContainerHelp": "Thích sử dụng fMP4 làm vùng chứa mặc định cho HLS, giúp bạn có thể truyền trực tiếp nội dung HEVC trên các thiết bị được hỗ trợ.", + "PreferFmp4HlsContainer": "Thích vùng chứa phương tiện fMP4-HLS", + "LabelH265Crf": "CRF mã hóa H265:" } From cad0653d21652f39e0b25e7ef8f6ea6b8b053df0 Mon Sep 17 00:00:00 2001 From: Sojo Date: Sat, 21 Nov 2020 16:29:36 +0000 Subject: [PATCH 27/34] Translated using Weblate (Spanish) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/es/ --- src/strings/es.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/strings/es.json b/src/strings/es.json index 6518eafab9..054682d1ef 100644 --- a/src/strings/es.json +++ b/src/strings/es.json @@ -1431,5 +1431,12 @@ "LabelFallbackFontPathHelp": "Especifica el camino conteniendo las fuentes alternativas para el renderizado de subtítulos ASS/SSA. El tamaño total máximo de la fuente es de 20 MB. Formatos de fuente ligeras y compatibles web como woff2 son recomendadas.", "LabelFallbackFontPath": "Dirección de la carpeta alternativa de fuentes:", "HeaderSelectFallbackFontPathHelp": "Busca o escribe la dirección de la carpeta alternativa de fuentes usada para la renderización de los subtitulos ASS/SSA.", - "HeaderSelectFallbackFontPath": "Seleccionar carpeta de fuentes alternativa" + "HeaderSelectFallbackFontPath": "Seleccionar carpeta de fuentes alternativa", + "LabelSelectMono": "Mono", + "LabelSelectAudioChannels": "Canales", + "LabelAllowedAudioChannels": "Canales de audio máximos permitidos", + "AllowHevcEncoding": "Permitir la codificación en formato HEVC", + "PreferFmp4HlsContainerHelp": "Preferir usar fMP4 como contenedor predeterminado para HLS, haciendo posible transmitir contenido HEVC directo en dispositivos compatibles.", + "PreferFmp4HlsContainer": "Preferir contenedor de medios fMP4-HLS", + "LabelH265Crf": "CRF de codificación H265:" } From 2f1b6ef9c44ca2962d3edf44ae4279d0f57b0865 Mon Sep 17 00:00:00 2001 From: hoanghuy309 Date: Sat, 21 Nov 2020 15:41:40 +0000 Subject: [PATCH 28/34] Translated using Weblate (Vietnamese) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/vi/ --- src/strings/vi.json | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/strings/vi.json b/src/strings/vi.json index 34c7ad3ef1..cac7a2ea63 100644 --- a/src/strings/vi.json +++ b/src/strings/vi.json @@ -341,7 +341,7 @@ "EnablePhotosHelp": "Hình ảnh sẽ được nhận diện và hiển thị bên cạnh những nội dung media.", "EnablePhotos": "Hiển thị hình ảnh", "EnableNextVideoInfoOverlayHelp": "Lúc cuối video, hiển thị thông tin video sắp phát tiếp theo trong danh sách phát hiện tại.", - "EnableNextVideoInfoOverlay": "Hiển thị thông tin video tiếp theo ở phần cuối video", + "EnableNextVideoInfoOverlay": "Hiển thị thông tin video kế tiếp ở phần cuối video", "EnableHardwareEncoding": "Sử dụng phần cứng để hỗ trợ chuyển mã", "EnableExternalVideoPlayersHelp": "Phần mềm phát video từ thiết bị sẽ được hiển thị khi bắt đầu phát video.", "EnableExternalVideoPlayers": "Sử dụng phần mềm phát video từ thiết bị", @@ -480,17 +480,17 @@ "LabelBlockContentWithTags": "Chặn những mục có nhãn:", "LabelBlastMessageIntervalHelp": "Xác định thời gian tồn tại giữa các tin nhắn (tính bằng giây).", "LabelBlastMessageInterval": "Khoảng thời gian gửi tin nhắn tồn tại (giây)", - "LabelBitrate": "Bitrate:", + "LabelBitrate": "Tốc độ bit:", "LabelBirthYear": "Năm sinh:", "LabelBirthDate": "Ngày sinh:", "LabelBindToLocalNetworkAddressHelp": "Ghi đè địa chỉ IP cục bộ cho máy chủ HTTP. Nếu bỏ trống, máy chủ sẽ kết hợp tất cả địa chỉ có sẵn. Thay đổi giá trị này buộc phải khởi động lại.", "LabelBindToLocalNetworkAddress": "Liên kết với địa chỉ mạng cục bộ:", "LabelAutomaticallyRefreshInternetMetadataEvery": "Tự động cập nhật dữ liệu mô tả từ Internet:", "LabelAuthProvider": "Cách Xác Thực:", - "LabelAudioSampleRate": "Sample rate âm thanh:", + "LabelAudioSampleRate": "Tỉ lệ mẫu âm thanh:", "LabelAudioCodec": "Bộ giải mã âm thanh:", "LabelAudioChannels": "Các kênh âm thanh:", - "LabelAudioBitrate": "Bitrate của âm thanh:", + "LabelAudioBitrate": "Tốc độ bit âm thanh:", "LabelAudioBitDepth": "Chiều sâu của âm thanh:", "LabelArtistsHelp": "Tách nhiều nghệ sĩ bằng dấu chấm phẩy \";\".", "LabelArtists": "Nghệ sĩ:", @@ -655,7 +655,7 @@ "LabelFailed": "Thất bại", "LabelMaxResumePercentage": "Phần trăm tối đa có thể phát tiếp tục:", "LabelMaxParentalRating": "Xếp hạng tối đa cho phép của phụ huynh:", - "LabelMaxChromecastBitrate": "Chất lượng truyền tải Chromecast:", + "LabelMaxChromecastBitrate": "Chất lượng luồng phát Chromecast:", "LabelMaxBackdropsPerItem": "Số lượng phông nền tối đa mỗi mục:", "LabelMatchType": "Loại phù hợp:", "LabelManufacturerUrl": "URL của nhà sản xuất", @@ -691,8 +691,8 @@ "LabelMetadata": "Dữ Liệu Mô Tả:", "LabelMessageTitle": "Tiêu đề tin nhắn:", "LabelMessageText": "Nội dung tin nhắn:", - "LabelMaxStreamingBitrateHelp": "Thiết lập bitrate tối đa khi truyền tải.", - "LabelMaxStreamingBitrate": "Chất lượng phát tối đa:", + "LabelMaxStreamingBitrateHelp": "Thiết lập tốc độ bit tối đa khi phát.", + "LabelMaxStreamingBitrate": "Chất lượng luồng phát tối đa:", "LabelMaxScreenshotsPerItem": "Số lượng ảnh chụp tối đa mỗi mục:", "LabelMaxResumePercentageHelp": "Nội dung sẽ được cho là đã kết thúc nếu ngừng phát sau thời gian này.", "ButtonSyncPlay": "Đồng Bộ Phát", @@ -817,8 +817,8 @@ "LabelRuntimeMinutes": "Thời lượng:", "LabelRequireHttpsHelp": "Nếu được chọn, máy chủ sẽ tự động chuyển hướng tất cả các yêu cầu qua HTTP sang HTTPS. Điều này không ảnh hưởng nếu máy chủ không nghe trên HTTPS.", "LabelRequireHttps": "Yêu cầu HTTPS", - "LabelRemoteClientBitrateLimitHelp": "Giới hạn tốc độ bit trên mỗi luồng cho tất cả các thiết bị ngoài mạng. Nó hữu ích để ngăn các thiết bị yêu cầu tốc độ bit cao hơn mức kết nối internet của bạn có thể xử lý. Điều này có thể dẫn đến việc tăng tải CPU trên máy chủ của bạn để chuyển mã video nhanh chóng xuống tốc độ bit thấp hơn.", - "LabelRemoteClientBitrateLimit": "Giới hạn tốc độ bit phát trực tuyến Internet (Mbps):", + "LabelRemoteClientBitrateLimitHelp": "Giới hạn tốc độ bit trên mỗi luồng cho tất cả các thiết bị ngoài mạng. Nó hữu ích để ngăn các thiết bị yêu cầu tốc độ bit cao hơn mức kết nối internet của bạn. Điều này có thể dẫn đến tăng tải CPU trên máy chủ của bạn để chuyển mã video nhanh chóng xuống tốc độ bit thấp hơn.", + "LabelRemoteClientBitrateLimit": "Giới hạn tốc độ bit luồng phát qua Internet (Mbps):", "LabelReleaseDate": "Ngày phát hành:", "LabelRefreshMode": "Chế độ làm mới :", "LabelRecordingPathHelp": "Chỉ định vị trí mặc định để lưu bản ghi. Nếu để trống, thư mục dữ liệu chương trình của máy chủ sẽ được sử dụng.", @@ -869,7 +869,7 @@ "LabelNewName": "Tên mới:", "LabelUnstable": "Không ổn định", "LabelChromecastVersion": "Phiên bản Chromecast", - "LabelMusicStreamingTranscodingBitrateHelp": "Chỉ định tốc độ bit tối đa khi phát nhạc trực tuyến.", + "LabelMusicStreamingTranscodingBitrateHelp": "Chỉ định tốc độ bit tối đa khi phát nhạc.", "LabelMusicStreamingTranscodingBitrate": "Tốc độ bit chuyển mã âm nhạc:", "LabelMovieRecordingPath": "Đường dẫn quay phim:", "LabelCurrentStatus": "Tình trạng hiện tại:", @@ -1433,7 +1433,7 @@ "HeaderSelectFallbackFontPathHelp": "Duyệt qua hoặc nhập đường dẫn của thư mục phông chữ dự phòng để sử dụng cho việc hiển thị phụ đề ASS / SSA.", "HeaderSelectFallbackFontPath": "Chọn Đường dẫn Thư mục Phông chữ Dự phòng", "LabelSelectStereo": "Âm Thanh Nổi", - "LabelSelectMono": "", + "LabelSelectMono": "Âm Thanh Đơn Kênh", "LabelSelectAudioChannels": "Kênh", "LabelAllowedAudioChannels": "Kênh Âm Thanh Cho Phép Tối Đa", "AllowHevcEncoding": "Cho phép mã hóa ở định dạng HEVC", From 5fd1673c4a2a84959b1c739ca0dd5cc3a5407e11 Mon Sep 17 00:00:00 2001 From: Oatavandi Date: Sat, 21 Nov 2020 16:15:12 +0000 Subject: [PATCH 29/34] Translated using Weblate (Tamil) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/ta/ --- src/strings/ta.json | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/strings/ta.json b/src/strings/ta.json index e1e90f7446..ead20b63d3 100644 --- a/src/strings/ta.json +++ b/src/strings/ta.json @@ -276,7 +276,7 @@ "HardwareAccelerationWarning": "வன்பொருள் முடுக்கம் இயக்குவது சில சூழல்களில் உறுதியற்ற தன்மையை ஏற்படுத்தக்கூடும். உங்கள் இயக்க முறைமை மற்றும் வீடியோ இயக்கிகள் முழுமையாக புதுப்பித்த நிலையில் இருப்பதை உறுதிசெய்க. இதை இயக்கிய பின் வீடியோவை இயக்குவதில் சிக்கல் இருந்தால், நீங்கள் அமைப்பை எதுவும் இல்லை என மாற்ற வேண்டும்.", "HDPrograms": "HD நிரல்கள்", "EncoderPresetHelp": "செயல்திறனை மேம்படுத்த வேகமான மதிப்பை அல்லது தரத்தை மேம்படுத்த மெதுவான மதிப்பைத் தேர்வுசெய்க.", - "H264CrfHelp": "நிலையான விகித காரணி (CRF) என்பது x264 குறியாக்கிக்கான இயல்புநிலை தர அமைப்பாகும். நீங்கள் 0 மற்றும் 51 க்கு இடையில் மதிப்புகளை அமைக்கலாம், அங்கு குறைந்த மதிப்புகள் சிறந்த தரத்தை ஏற்படுத்தும் (அதிக கோப்பு அளவுகளின் இழப்பில்). சேன் மதிப்புகள் 18 முதல் 28 வரை உள்ளன. X264 இன் இயல்புநிலை 23 ஆகும், எனவே இதை நீங்கள் ஒரு தொடக்க புள்ளியாக பயன்படுத்தலாம்.", + "H264CrfHelp": "நிலையான விகித காரணி (CRF) என்பது x264 மற்றும் x265 குறியாக்கிக்கான இயல்புநிலை தர அமைப்பாகும். நீங்கள் 0 மற்றும் 51 க்கு இடையில் மதிப்புகளை அமைக்கலாம், அங்கு குறைந்த மதிப்புகள் சிறந்த தரத்தை ஏற்படுத்தும் (அதிக கோப்பு அளவுகளின் இழப்பில்). சேன் மதிப்புகள் 18 முதல் 28 வரை உள்ளன. X264 இன் இயல்புநிலை 23, மற்றும் x265 க்கு 28 ஆகும், எனவே இதை நீங்கள் ஒரு தொடக்க புள்ளியாக பயன்படுத்தலாம்.", "GuideProviderSelectListings": "பட்டியல்களைத் தேர்ந்தெடுக்கவும்", "GuideProviderLogin": "உள்நுழைய", "Guide": "வழிகாட்டி", @@ -668,7 +668,7 @@ "LabelHomeNetworkQuality": "முகப்பு நெட்வொர்க் தரம்:", "LabelHardwareAccelerationTypeHelp": "வன்பொருள் முடுக்கம் கூடுதல் உள்ளமைவு தேவை.", "LabelHardwareAccelerationType": "வன்பொருள் முடுக்கம்:", - "LabelEncoderPreset": "H264 மற்றும் H265 குறியாக்க முன்னமைவு:", + "LabelEncoderPreset": "குறியீட்டு முன்னமைவு:", "LabelH264Crf": "H264 குறியாக்கம் CRF:", "LabelGroupMoviesIntoCollectionsHelp": "மூவி பட்டியல்களைக் காண்பிக்கும் போது, ஒரு தொகுப்பில் உள்ள திரைப்படங்கள் ஒரு குழுவாகக் காட்டப்படும்.", "LabelGroupMoviesIntoCollections": "திரைப்படங்களை தொகுப்பாக குழு செய்யவும்", @@ -1446,5 +1446,13 @@ "LabelFallbackFontPathHelp": "ASS / SSA வசன வரிகளை வழங்குவதற்கான குறைவடையும் எழுத்துருக்களைக் கொண்ட பாதையைக் குறிப்பிடவும். அனுமதிக்கப்பட்ட அதிகபட்ச எழுத்துரு அளவு 20 எம்பி. Woff2 போன்ற இலகுரக மற்றும் வலை நட்பு எழுத்துரு வடிவங்கள் பரிந்துரைக்கப்படுகின்றன.", "LabelFallbackFontPath": "குறைவடையும் எழுத்துரு கோப்புறை பாதை:", "HeaderSelectFallbackFontPathHelp": "ASS / SSA வசன வரிகளை வழங்குவதற்கு குறைவடையும் எழுத்துரு கோப்புறையின் பாதையை உலாவவும் அல்லது உள்ளிடவும்.", - "HeaderSelectFallbackFontPath": "குறைவடையும் எழுத்துரு கோப்புறை பாதையைத் தேர்ந்தெடுக்கவும்" + "HeaderSelectFallbackFontPath": "குறைவடையும் எழுத்துரு கோப்புறை பாதையைத் தேர்ந்தெடுக்கவும்", + "LabelSelectStereo": "ஸ்டீரியோ", + "LabelSelectMono": "மோனோ", + "LabelSelectAudioChannels": "சேனல்கள்", + "LabelAllowedAudioChannels": "அதிகபட்ச அனுமதிக்கப்பட்ட ஆடியோ சேனல்கள்", + "AllowHevcEncoding": "HEVC வடிவத்தில் குறியாக்கத்தை அனுமதிக்கவும்", + "PreferFmp4HlsContainerHelp": "HEVC இயல்புநிலை கொள்கலனாக fMP4ஐப் பயன்படுத்த விரும்பினால், ஆதரிக்கப்படும் சாதனங்களில் ஸ்ட்ரீம் ஹெச்.வி.சி உள்ளடக்கத்தை நேரடியாக இயக்க முடியும்.", + "PreferFmp4HlsContainer": "FMP4-HLS மீடியா கொள்கலனை விரும்புங்கள்", + "LabelH265Crf": "H265 குறியாக்கம் CRF:" } From 48b0172cd8a6843b27595887b0cf19b12eb1ce31 Mon Sep 17 00:00:00 2001 From: Sojo Date: Sat, 21 Nov 2020 16:33:45 +0000 Subject: [PATCH 30/34] Translated using Weblate (Spanish) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/es/ --- src/strings/es.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/strings/es.json b/src/strings/es.json index 054682d1ef..7035c9fba4 100644 --- a/src/strings/es.json +++ b/src/strings/es.json @@ -1438,5 +1438,6 @@ "AllowHevcEncoding": "Permitir la codificación en formato HEVC", "PreferFmp4HlsContainerHelp": "Preferir usar fMP4 como contenedor predeterminado para HLS, haciendo posible transmitir contenido HEVC directo en dispositivos compatibles.", "PreferFmp4HlsContainer": "Preferir contenedor de medios fMP4-HLS", - "LabelH265Crf": "CRF de codificación H265:" + "LabelH265Crf": "CRF de codificación H265:", + "LabelSelectStereo": "Estéreo" } From fcb6ac4a96efe659b4792de6460b783c2b8121eb Mon Sep 17 00:00:00 2001 From: Sojo Date: Sat, 21 Nov 2020 16:38:11 +0000 Subject: [PATCH 31/34] Translated using Weblate (Spanish) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/es/ --- src/strings/es.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strings/es.json b/src/strings/es.json index 7035c9fba4..0e2bb083c9 100644 --- a/src/strings/es.json +++ b/src/strings/es.json @@ -171,7 +171,7 @@ "GuestStar": "Estrella invitada", "Guide": "Guía", "GuideProviderSelectListings": "Seleccionar listados", - "H264CrfHelp": "El factor de velocidad constante (CRF) es el ajuste de calidad predeterminado para el codificador x264. Puede establecer los valores entre 0 y 51, donde valores más bajos resultarían en una mejor calidad (a expensas de tamaños de archivo más altos). Los valores sanos están entre 18 y 28. El valor predeterminado para x264 es 23, por lo que puede utilizar esto como punto de partida.", + "H264CrfHelp": "El factor de velocidad constante (CRF) es el ajuste de calidad predeterminado para los codificadores x264 y x265. Puede establecer los valores entre 0 y 51, donde valores más bajos resultarían en una mejor calidad (a expensas de tamaños de archivo más altos). Los valores sanos están entre 18 y 28. El valor predeterminado para x264 es 23, y para x265 es 28, por lo que puede utilizar esto como punto de partida.", "EncoderPresetHelp": "Elija un valor más rápido para mejorar el rendimiento o un valor más lento para mejorar la calidad.", "HDPrograms": "Programas en HD", "HardwareAccelerationWarning": "Activar la aceleración por hardware puede producir inestabilidades en algunos entornos. Asegúrate de que tu sistema operativo y tus controladores de vídeo están actualizados. Si tienes dificultades para reproducir los vídeos después de activar esto, tendrás que volver a poner este ajuste en None.", @@ -461,7 +461,7 @@ "LabelGroupMoviesIntoCollections": "Agrupar películas en colecciones", "LabelGroupMoviesIntoCollectionsHelp": "Al mostrar las listas de películas, las películas pertenecientes a una colección se mostrarán como un elemento agrupado.", "LabelH264Crf": "H264 que codifica CRF:", - "LabelEncoderPreset": "Configuración de codificación H264:", + "LabelEncoderPreset": "Preajuste de codificación:", "LabelHardwareAccelerationType": "Aceleración por hardware:", "LabelHardwareAccelerationTypeHelp": "La aceleración por hardware requiere configuración adicional.", "LabelHomeScreenSectionValue": "Sección de la pantalla de inicio {0}:", From cae6ce5986f6a614d6f6b4a660921885665113b5 Mon Sep 17 00:00:00 2001 From: Sojo Date: Sat, 21 Nov 2020 17:05:24 +0000 Subject: [PATCH 32/34] Translated using Weblate (Spanish) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/es/ --- src/strings/es.json | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/strings/es.json b/src/strings/es.json index 0e2bb083c9..d809c6208a 100644 --- a/src/strings/es.json +++ b/src/strings/es.json @@ -1072,8 +1072,8 @@ "DateAdded": "Añadido el", "DatePlayed": "Reproducido el", "Descending": "Descendiente", - "DirectStreamHelp1": "El tipo de archivo (H.264, AC3, etc.) y la resolución son compatibles con el dispositivo, pero no el contenedor (mkv, avi, wmv, etc.). El vídeo será re-empaquetado al vuelo antes de transmitirlo al dispositivo.", - "DirectStreamHelp2": "La transmisión directa del archivo usa muy poco procesamiento sin mínima pérdida de calidad en el vídeo.", + "DirectStreamHelp1": "La transmisión de video es compatible con el dispositivo, pero tiene un formato de audio incompatible (DTS, TRUEHD, etc.) o un número de canales de audio. La transmisión de video se volverá a empaquetar sin pérdidas sobre la marcha antes de enviarse al dispositivo. Solo se transcodificará la transmisión de audio.", + "DirectStreamHelp2": "La energía consumida por la transmisión directa generalmente depende del perfil de audio. Solo la transmisión de video no tiene pérdidas.", "Director": "Director", "Directors": "Directores", "Display": "Visualización", @@ -1439,5 +1439,16 @@ "PreferFmp4HlsContainerHelp": "Preferir usar fMP4 como contenedor predeterminado para HLS, haciendo posible transmitir contenido HEVC directo en dispositivos compatibles.", "PreferFmp4HlsContainer": "Preferir contenedor de medios fMP4-HLS", "LabelH265Crf": "CRF de codificación H265:", - "LabelSelectStereo": "Estéreo" + "LabelSelectStereo": "Estéreo", + "LabelSyncPlayInfo": "Información de SyncPlay", + "LabelOriginalMediaInfo": "Información de medios originales", + "LabelRemuxingInfo": "Información de remuxing", + "LabelDirectStreamingInfo": "Información de transmisión directa", + "LabelTranscodingInfo": "Información de transcodificación", + "LabelVideoInfo": "Información de video", + "LabelAudioInfo": "Información de audio", + "LabelPlaybackInfo": "Información de reproducción", + "RemuxHelp2": "Remux utiliza muy poca potencia de procesamiento con una calidad multimedia sin pérdidas.", + "RemuxHelp1": "Los medios están en un contenedor de archivos incompatible (MKV, AVI, WMV, etc.) pero tanto la transmisión de video como la transmisión de audio son compatibles con el dispositivo. Los medios se volverán a empaquetar sin pérdidas sobre la marcha antes de enviarse al dispositivo.", + "Remuxing": "Remuxing" } From c7b898d4c32eef9e36e7b4047cba6ac6f99eb011 Mon Sep 17 00:00:00 2001 From: hoanghuy309 Date: Sat, 21 Nov 2020 17:58:54 +0000 Subject: [PATCH 33/34] Translated using Weblate (Vietnamese) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/vi/ --- src/strings/vi.json | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/strings/vi.json b/src/strings/vi.json index cac7a2ea63..f3735ac370 100644 --- a/src/strings/vi.json +++ b/src/strings/vi.json @@ -222,8 +222,8 @@ "Directors": "Đạo Diễn", "Director": "Đạo Diễn", "DirectStreaming": "Phát trực tuyến", - "DirectStreamHelp2": "Phát trực tiếp sử dụng ít sức mạnh xử lý với chất lượng video bị giảm thiểu chút ít.", - "DirectStreamHelp1": "Nội dung này tương thích với thiết bị về độ phân giải và loại mã hoá (H.264, AC3, v.v.), nhưng lại không tương thích định dạng (mkv, avi, wmv, v.v.). Video sẽ được đóng gói nhanh chóng trước khi được gửi đến phát trên thiết bị.", + "DirectStreamHelp2": "Mức độ tổn hao khi phát trực tiếp thường phụ thuộc vào cấu hình âm thanh. Chỉ có luồng video là không mất dữ liệu.", + "DirectStreamHelp1": "Luồng video tương thích với thiết bị, nhưng có định dạng âm thanh (DTS, TRUEHD, v.v.) hoặc số kênh âm thanh không tương thích. Luồng video sẽ được đóng gói lại không mất mát dữ liệu trước khi gửi đến thiết bị. Chỉ luồng âm thanh được chuyển mã.", "DirectPlaying": "Phát trực tiếp", "DeviceAccessHelp": "Thiết lập này chỉ áp dụng cho những thiết bị có thể định danh và sẽ không chặn được truy cập từ trình duyệt. Chọn lọc thiết bị người dùng sẽ chặn người dùng này truy cập từ những thiết bị mới cho đến khi được duyệt.", "DetectingDevices": "Đang tìm kiếm thiết bị", @@ -1439,5 +1439,16 @@ "AllowHevcEncoding": "Cho phép mã hóa ở định dạng HEVC", "PreferFmp4HlsContainerHelp": "Thích sử dụng fMP4 làm vùng chứa mặc định cho HLS, giúp bạn có thể truyền trực tiếp nội dung HEVC trên các thiết bị được hỗ trợ.", "PreferFmp4HlsContainer": "Thích vùng chứa phương tiện fMP4-HLS", - "LabelH265Crf": "CRF mã hóa H265:" + "LabelH265Crf": "CRF mã hóa H265:", + "LabelSyncPlayInfo": "Thông Tin Phát Đồng Bộ", + "LabelOriginalMediaInfo": "Thông Tin Phương Tiện Gốc", + "LabelRemuxingInfo": "Thông Tin Pha Trộn", + "LabelDirectStreamingInfo": "Thông Tin Phát Trực Tiếp", + "LabelTranscodingInfo": "Thông Tin Chuyển Mã", + "LabelVideoInfo": "Thông Tin Video", + "LabelAudioInfo": "Thông Tin Âm Thanh", + "LabelPlaybackInfo": "Thông Tin Phát Lại", + "RemuxHelp2": "Pha trộn sử dụng rất ít sức mạnh xử lý với chất lượng phương tiện hoàn toàn không mất dữ liệu.", + "RemuxHelp1": "Phương tiện nằm trong vùng chứa tệp không tương thích (MKV, AVI, WMV, v.v.) nhưng cả luồng video và luồng âm thanh đều tương thích với thiết bị. Phương tiện sẽ được đóng gói lại giữ chất lượng tốt trước khi được gửi đến thiết bị.", + "Remuxing": "Pha Trộn" } From 96d50e8d811d2d1858b68d5cd41b319bd24df4d3 Mon Sep 17 00:00:00 2001 From: hoanghuy309 Date: Sat, 21 Nov 2020 19:14:40 +0000 Subject: [PATCH 34/34] Translated using Weblate (Vietnamese) Translation: Jellyfin/Jellyfin Web Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/vi/ --- src/strings/vi.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/strings/vi.json b/src/strings/vi.json index f3735ac370..529daf4578 100644 --- a/src/strings/vi.json +++ b/src/strings/vi.json @@ -1450,5 +1450,7 @@ "LabelPlaybackInfo": "Thông Tin Phát Lại", "RemuxHelp2": "Pha trộn sử dụng rất ít sức mạnh xử lý với chất lượng phương tiện hoàn toàn không mất dữ liệu.", "RemuxHelp1": "Phương tiện nằm trong vùng chứa tệp không tương thích (MKV, AVI, WMV, v.v.) nhưng cả luồng video và luồng âm thanh đều tương thích với thiết bị. Phương tiện sẽ được đóng gói lại giữ chất lượng tốt trước khi được gửi đến thiết bị.", - "Remuxing": "Pha Trộn" + "Remuxing": "Pha Trộn", + "AspectRatioFill": "Lấp Đầy", + "AspectRatioCover": "Bao Phủ" }