mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-03-11 21:27:05 +00:00
Merge branch 'development' into fix/copy-download-and-copy-streaming-urls
This commit is contained in:
commit
370443609b
19 changed files with 352 additions and 161 deletions
|
|
@ -17,9 +17,9 @@
|
|||
"@babel/runtime": "7.26.0",
|
||||
"@sentry/browser": "8.42.0",
|
||||
"@stremio/stremio-colors": "5.2.0",
|
||||
"@stremio/stremio-core-web": "0.51.1",
|
||||
"@stremio/stremio-core-web": "0.52.0",
|
||||
"@stremio/stremio-icons": "5.8.0",
|
||||
"@stremio/stremio-video": "0.0.64",
|
||||
"@stremio/stremio-video": "0.0.70",
|
||||
"a-color-picker": "1.2.1",
|
||||
"bowser": "2.11.0",
|
||||
"buffer": "6.0.3",
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
"react-i18next": "^15.1.3",
|
||||
"react-is": "18.3.1",
|
||||
"spatial-navigation-polyfill": "github:Stremio/spatial-navigation#64871b1422466f5f45d24ebc8bbd315b2ebab6a6",
|
||||
"stremio-translations": "github:Stremio/stremio-translations#0e7fbd8522148f5727ac6adee3b2eb96132c10ac",
|
||||
"stremio-translations": "github:Stremio/stremio-translations#7c0c337f32163aa13158bb90cd6133da43feafef",
|
||||
"url": "0.11.4",
|
||||
"use-long-press": "^3.2.0"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -18,14 +18,14 @@ importers:
|
|||
specifier: 5.2.0
|
||||
version: 5.2.0
|
||||
'@stremio/stremio-core-web':
|
||||
specifier: 0.51.1
|
||||
version: 0.51.1
|
||||
specifier: 0.52.0
|
||||
version: 0.52.0
|
||||
'@stremio/stremio-icons':
|
||||
specifier: 5.8.0
|
||||
version: 5.8.0
|
||||
'@stremio/stremio-video':
|
||||
specifier: 0.0.64
|
||||
version: 0.0.64
|
||||
specifier: 0.0.70
|
||||
version: 0.0.70
|
||||
a-color-picker:
|
||||
specifier: 1.2.1
|
||||
version: 1.2.1
|
||||
|
|
@ -90,8 +90,8 @@ importers:
|
|||
specifier: github:Stremio/spatial-navigation#64871b1422466f5f45d24ebc8bbd315b2ebab6a6
|
||||
version: https://codeload.github.com/Stremio/spatial-navigation/tar.gz/64871b1422466f5f45d24ebc8bbd315b2ebab6a6
|
||||
stremio-translations:
|
||||
specifier: github:Stremio/stremio-translations#0e7fbd8522148f5727ac6adee3b2eb96132c10ac
|
||||
version: https://codeload.github.com/Stremio/stremio-translations/tar.gz/0e7fbd8522148f5727ac6adee3b2eb96132c10ac
|
||||
specifier: github:Stremio/stremio-translations#7c0c337f32163aa13158bb90cd6133da43feafef
|
||||
version: https://codeload.github.com/Stremio/stremio-translations/tar.gz/7c0c337f32163aa13158bb90cd6133da43feafef
|
||||
url:
|
||||
specifier: 0.11.4
|
||||
version: 0.11.4
|
||||
|
|
@ -1120,14 +1120,14 @@ packages:
|
|||
'@stremio/stremio-colors@5.2.0':
|
||||
resolution: {integrity: sha512-dYlPgu9W/H7c9s1zmW5tiDnRenaUa4Hg1QCyOg1lhOcgSfM/bVTi5nnqX+IfvGTTUNA0zgzh8hI3o3miwnZxTg==}
|
||||
|
||||
'@stremio/stremio-core-web@0.51.1':
|
||||
resolution: {integrity: sha512-BD8i6zkDdMPeCyH50Bb7SB8r4nYx4eJwz4kLEJEl0PFjdr0gOmwHtEIgNa89ShJLNXUjPnpv4sVSNxFRG8fb5Q==}
|
||||
'@stremio/stremio-core-web@0.52.0':
|
||||
resolution: {integrity: sha512-zT0P8JspGZ1oI9/11f3RIt7XG9b/1fOZE+xSnP+oAyhRmzzkqrnPUJkHdJdgoVD9XELDFAS2awNfl5/eRdh5kA==}
|
||||
|
||||
'@stremio/stremio-icons@5.8.0':
|
||||
resolution: {integrity: sha512-IVUvQbIWfA4YEHCTed7v/sdQJCJ+OOCf84LTWpkE2W6GLQ+15WHcMEJrVkE1X3ekYJnGg3GjT0KLO6tKSU0P4w==}
|
||||
|
||||
'@stremio/stremio-video@0.0.64':
|
||||
resolution: {integrity: sha512-29w/lwU8BB6ai8LUyCnpRc2F9kPf7cpys40NCobt70MqBP/UqvYISsrnD/ijoBwvtpKdZ6ptv5h9BbDj6rrerw==}
|
||||
'@stremio/stremio-video@0.0.70':
|
||||
resolution: {integrity: sha512-a0flQYAUdrZNMm7mmts2vpZOqN1nus7Hs9Mjl4mrN5rtduD0ojUyhD5J4lPcCpZ7WB0YdEUOGLXR19qHpgoKmg==}
|
||||
|
||||
'@stylistic/eslint-plugin-jsx@4.4.1':
|
||||
resolution: {integrity: sha512-83SInq4u7z71vWwGG+6ViOtlOmZ6tSrDkMPhrvdBBTGMLA0gs22WSdhQ4vZP3oJ5Xg4ythvqeUiFSedvVxzhyA==}
|
||||
|
|
@ -3738,9 +3738,6 @@ packages:
|
|||
prr@1.0.1:
|
||||
resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==}
|
||||
|
||||
punycode@1.3.2:
|
||||
resolution: {integrity: sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==}
|
||||
|
||||
punycode@1.4.1:
|
||||
resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==}
|
||||
|
||||
|
|
@ -3759,11 +3756,6 @@ packages:
|
|||
resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==}
|
||||
engines: {node: '>=0.6'}
|
||||
|
||||
querystring@0.2.0:
|
||||
resolution: {integrity: sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==}
|
||||
engines: {node: '>=0.4.x'}
|
||||
deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.
|
||||
|
||||
queue-microtask@1.2.3:
|
||||
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
|
||||
|
||||
|
|
@ -4141,9 +4133,9 @@ packages:
|
|||
resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
stremio-translations@https://codeload.github.com/Stremio/stremio-translations/tar.gz/0e7fbd8522148f5727ac6adee3b2eb96132c10ac:
|
||||
resolution: {tarball: https://codeload.github.com/Stremio/stremio-translations/tar.gz/0e7fbd8522148f5727ac6adee3b2eb96132c10ac}
|
||||
version: 1.44.14
|
||||
stremio-translations@https://codeload.github.com/Stremio/stremio-translations/tar.gz/7c0c337f32163aa13158bb90cd6133da43feafef:
|
||||
resolution: {tarball: https://codeload.github.com/Stremio/stremio-translations/tar.gz/7c0c337f32163aa13158bb90cd6133da43feafef}
|
||||
version: 1.45.0
|
||||
|
||||
string-length@4.0.2:
|
||||
resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==}
|
||||
|
|
@ -4420,9 +4412,6 @@ packages:
|
|||
uri-js@4.4.1:
|
||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||
|
||||
url@0.11.0:
|
||||
resolution: {integrity: sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==}
|
||||
|
||||
url@0.11.4:
|
||||
resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
|
@ -5881,13 +5870,13 @@ snapshots:
|
|||
|
||||
'@stremio/stremio-colors@5.2.0': {}
|
||||
|
||||
'@stremio/stremio-core-web@0.51.1':
|
||||
'@stremio/stremio-core-web@0.52.0':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.24.1
|
||||
|
||||
'@stremio/stremio-icons@5.8.0': {}
|
||||
|
||||
'@stremio/stremio-video@0.0.64':
|
||||
'@stremio/stremio-video@0.0.70':
|
||||
dependencies:
|
||||
buffer: 6.0.3
|
||||
color: 4.2.3
|
||||
|
|
@ -5897,7 +5886,7 @@ snapshots:
|
|||
hls.js: https://github.com/Stremio/hls.js/releases/download/v1.5.4-patch2/hls.js-1.5.4-patch2.tgz
|
||||
lodash.clonedeep: 4.5.0
|
||||
magnet-uri: 6.2.0
|
||||
url: 0.11.0
|
||||
url: 0.11.4
|
||||
video-name-parser: 1.4.6
|
||||
vtt.js: https://codeload.github.com/jaruba/vtt.js/tar.gz/84d33d157848407d790d78423dacc41a096294f0
|
||||
|
||||
|
|
@ -8941,8 +8930,6 @@ snapshots:
|
|||
prr@1.0.1:
|
||||
optional: true
|
||||
|
||||
punycode@1.3.2: {}
|
||||
|
||||
punycode@1.4.1: {}
|
||||
|
||||
punycode@2.3.1: {}
|
||||
|
|
@ -8957,8 +8944,6 @@ snapshots:
|
|||
dependencies:
|
||||
side-channel: 1.1.0
|
||||
|
||||
querystring@0.2.0: {}
|
||||
|
||||
queue-microtask@1.2.3: {}
|
||||
|
||||
randombytes@2.1.0:
|
||||
|
|
@ -9393,7 +9378,7 @@ snapshots:
|
|||
es-errors: 1.3.0
|
||||
internal-slot: 1.1.0
|
||||
|
||||
stremio-translations@https://codeload.github.com/Stremio/stremio-translations/tar.gz/0e7fbd8522148f5727ac6adee3b2eb96132c10ac: {}
|
||||
stremio-translations@https://codeload.github.com/Stremio/stremio-translations/tar.gz/7c0c337f32163aa13158bb90cd6133da43feafef: {}
|
||||
|
||||
string-length@4.0.2:
|
||||
dependencies:
|
||||
|
|
@ -9688,11 +9673,6 @@ snapshots:
|
|||
dependencies:
|
||||
punycode: 2.3.1
|
||||
|
||||
url@0.11.0:
|
||||
dependencies:
|
||||
punycode: 1.3.2
|
||||
querystring: 0.2.0
|
||||
|
||||
url@0.11.4:
|
||||
dependencies:
|
||||
punycode: 1.4.1
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@
|
|||
"name": "العربية",
|
||||
"codes": ["ar-AR", "ara"]
|
||||
},
|
||||
{
|
||||
"name": "Беларуская",
|
||||
"codes": ["be-BY", "bel"]
|
||||
},
|
||||
{
|
||||
"name": "български език",
|
||||
"codes": ["bg-BG", "bul"]
|
||||
|
|
@ -13,7 +17,7 @@
|
|||
},
|
||||
{
|
||||
"name": "català",
|
||||
"codes": ["ca-CA", "cat"]
|
||||
"codes": ["ca-ES", "cat"]
|
||||
},
|
||||
{
|
||||
"name": "čeština",
|
||||
|
|
@ -43,6 +47,10 @@
|
|||
"name": "español",
|
||||
"codes": ["es-ES", "spa"]
|
||||
},
|
||||
{
|
||||
"name": "Eesti",
|
||||
"codes": ["et-EE", "est"]
|
||||
},
|
||||
{
|
||||
"name": "euskara",
|
||||
"codes": ["eu-ES", "eus"]
|
||||
|
|
@ -111,6 +119,10 @@
|
|||
"name": "Norsk nynorsk",
|
||||
"codes": ["nn-NO", "nno"]
|
||||
},
|
||||
{
|
||||
"name": "ਪੰਜਾਬੀ",
|
||||
"codes": ["pa-IN", "pan"]
|
||||
},
|
||||
{
|
||||
"name": "język polski",
|
||||
"codes": ["pl-PL", "pol"]
|
||||
|
|
@ -151,6 +163,10 @@
|
|||
"name": "తెలుగు",
|
||||
"codes": ["te-IN", "tel"]
|
||||
},
|
||||
{
|
||||
"name": "தமிழ்",
|
||||
"codes": ["tl-TM", "tam"]
|
||||
},
|
||||
{
|
||||
"name": "Türkçe",
|
||||
"codes": ["tr-TR", "tur"]
|
||||
|
|
@ -159,6 +175,10 @@
|
|||
"name": "українська мова",
|
||||
"codes": ["uk-UA", "ukr"]
|
||||
},
|
||||
{
|
||||
"name": "اُرْدُو",
|
||||
"codes": ["ur-PK", "urd"]
|
||||
},
|
||||
{
|
||||
"name": "Tiếng Việt",
|
||||
"codes": ["vi-VN", "vie"]
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
align-self: stretch;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 25rem;
|
||||
width: 16rem;
|
||||
|
||||
.header {
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ const styles = require('./styles');
|
|||
const Video = require('./Video');
|
||||
const { default: Indicator } = require('./Indicator/Indicator');
|
||||
|
||||
const findTrackByLang = (tracks, lang) => tracks.find((track) => track.lang === lang || langs.where('1', track.lang)?.[2] === lang);
|
||||
const findTrackById = (tracks, id) => tracks.find((track) => track.id === id);
|
||||
|
||||
const Player = ({ urlParams, queryParams }) => {
|
||||
const { t } = useTranslation();
|
||||
const services = useServices();
|
||||
|
|
@ -37,8 +40,8 @@ const Player = ({ urlParams, queryParams }) => {
|
|||
return queryParams.has('forceTranscoding');
|
||||
}, [queryParams]);
|
||||
const profile = useProfile();
|
||||
const [player, videoParamsChanged, timeChanged, seek, pausedChanged, ended, nextVideo] = usePlayer(urlParams);
|
||||
const [settings, updateSettings] = useSettings();
|
||||
const [player, videoParamsChanged, streamStateChanged, timeChanged, seek, pausedChanged, ended, nextVideo] = usePlayer(urlParams);
|
||||
const [settings] = useSettings();
|
||||
const streamingServer = useStreamingServer();
|
||||
const statistics = useStatistics(player, streamingServer);
|
||||
const video = useVideo();
|
||||
|
|
@ -93,17 +96,12 @@ const Player = ({ urlParams, queryParams }) => {
|
|||
const isNavigating = React.useRef(false);
|
||||
|
||||
const onImplementationChanged = React.useCallback(() => {
|
||||
video.setProp('subtitlesSize', settings.subtitlesSize);
|
||||
video.setProp('subtitlesOffset', settings.subtitlesOffset);
|
||||
video.setProp('subtitlesTextColor', settings.subtitlesTextColor);
|
||||
video.setProp('subtitlesBackgroundColor', settings.subtitlesBackgroundColor);
|
||||
video.setProp('subtitlesOutlineColor', settings.subtitlesOutlineColor);
|
||||
video.setProp('extraSubtitlesSize', settings.subtitlesSize);
|
||||
video.setProp('extraSubtitlesOffset', settings.subtitlesOffset);
|
||||
video.setProp('extraSubtitlesTextColor', settings.subtitlesTextColor);
|
||||
video.setProp('extraSubtitlesBackgroundColor', settings.subtitlesBackgroundColor);
|
||||
video.setProp('extraSubtitlesOutlineColor', settings.subtitlesOutlineColor);
|
||||
}, [settings.subtitlesSize, settings.subtitlesOffset, settings.subtitlesTextColor, settings.subtitlesBackgroundColor, settings.subtitlesOutlineColor]);
|
||||
video.setSubtitlesSize(settings.subtitlesSize);
|
||||
video.setSubtitlesOffset(settings.subtitlesOffset);
|
||||
video.setSubtitlesTextColor(settings.subtitlesTextColor);
|
||||
video.setSubtitlesBackgroundColor(settings.subtitlesBackgroundColor);
|
||||
video.setSubtitlesOutlineColor(settings.subtitlesOutlineColor);
|
||||
}, [settings]);
|
||||
|
||||
const handleNextVideoNavigation = React.useCallback((deepLinks, bingeWatching, ended) => {
|
||||
if (ended) {
|
||||
|
|
@ -190,53 +188,71 @@ const Player = ({ urlParams, queryParams }) => {
|
|||
}, []);
|
||||
|
||||
const onPlayRequested = React.useCallback(() => {
|
||||
video.setProp('paused', false);
|
||||
video.setPaused(false);
|
||||
setSeeking(false);
|
||||
}, []);
|
||||
|
||||
const onPlayRequestedDebounced = React.useCallback(debounce(onPlayRequested, 200), []);
|
||||
|
||||
const onPauseRequested = React.useCallback(() => {
|
||||
video.setProp('paused', true);
|
||||
video.setPaused(true);
|
||||
}, []);
|
||||
|
||||
const onPauseRequestedDebounced = React.useCallback(debounce(onPauseRequested, 200), []);
|
||||
const onMuteRequested = React.useCallback(() => {
|
||||
video.setProp('muted', true);
|
||||
video.setMuted(true);
|
||||
}, []);
|
||||
|
||||
const onUnmuteRequested = React.useCallback(() => {
|
||||
video.setProp('muted', false);
|
||||
video.setMuted(false);
|
||||
}, []);
|
||||
|
||||
const onVolumeChangeRequested = React.useCallback((volume) => {
|
||||
video.setProp('volume', volume);
|
||||
video.setVolume(volume);
|
||||
}, []);
|
||||
|
||||
const onSeekRequested = React.useCallback((time) => {
|
||||
video.setProp('time', time);
|
||||
video.setTime(time);
|
||||
seek(time, video.state.duration, video.state.manifest?.name);
|
||||
}, [video.state.duration, video.state.manifest]);
|
||||
|
||||
const onPlaybackSpeedChanged = React.useCallback((rate) => {
|
||||
video.setProp('playbackSpeed', rate);
|
||||
video.setPlaybackSpeed(rate);
|
||||
}, []);
|
||||
|
||||
const onSubtitlesTrackSelected = React.useCallback((id) => {
|
||||
video.setSubtitlesTrack(id);
|
||||
}, []);
|
||||
streamStateChanged({
|
||||
subtitleTrack: {
|
||||
id,
|
||||
embedded: true,
|
||||
},
|
||||
});
|
||||
}, [streamStateChanged]);
|
||||
|
||||
const onExtraSubtitlesTrackSelected = React.useCallback((id) => {
|
||||
video.setExtraSubtitlesTrack(id);
|
||||
}, []);
|
||||
streamStateChanged({
|
||||
subtitleTrack: {
|
||||
id,
|
||||
embedded: false,
|
||||
},
|
||||
});
|
||||
}, [streamStateChanged]);
|
||||
|
||||
const onAudioTrackSelected = React.useCallback((id) => {
|
||||
video.setProp('selectedAudioTrackId', id);
|
||||
}, []);
|
||||
video.setAudioTrack(id);
|
||||
streamStateChanged({
|
||||
audioTrack: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
}, [streamStateChanged]);
|
||||
|
||||
const onExtraSubtitlesDelayChanged = React.useCallback((delay) => {
|
||||
video.setProp('extraSubtitlesDelay', delay);
|
||||
}, []);
|
||||
video.setSubtitlesDelay(delay);
|
||||
streamStateChanged({ subtitleDelay: delay });
|
||||
}, [streamStateChanged]);
|
||||
|
||||
const onIncreaseSubtitlesDelay = React.useCallback(() => {
|
||||
const delay = video.state.extraSubtitlesDelay + 250;
|
||||
|
|
@ -249,8 +265,9 @@ const Player = ({ urlParams, queryParams }) => {
|
|||
}, [video.state.extraSubtitlesDelay, onExtraSubtitlesDelayChanged]);
|
||||
|
||||
const onSubtitlesSizeChanged = React.useCallback((size) => {
|
||||
updateSettings({ subtitlesSize: size });
|
||||
}, [updateSettings]);
|
||||
video.setSubtitlesSize(size);
|
||||
streamStateChanged({ subtitleSize: size });
|
||||
}, [streamStateChanged]);
|
||||
|
||||
const onUpdateSubtitlesSize = React.useCallback((delta) => {
|
||||
const sizeIndex = CONSTANTS.SUBTITLES_SIZES.indexOf(video.state.subtitlesSize);
|
||||
|
|
@ -259,8 +276,9 @@ const Player = ({ urlParams, queryParams }) => {
|
|||
}, [video.state.subtitlesSize, onSubtitlesSizeChanged]);
|
||||
|
||||
const onSubtitlesOffsetChanged = React.useCallback((offset) => {
|
||||
updateSettings({ subtitlesOffset: offset });
|
||||
}, [updateSettings]);
|
||||
video.setSubtitlesOffset(offset);
|
||||
streamStateChanged({ subtitleOffset: offset });
|
||||
}, [streamStateChanged]);
|
||||
|
||||
const onDismissNextVideoPopup = React.useCallback(() => {
|
||||
closeNextVideoPopup();
|
||||
|
|
@ -361,6 +379,7 @@ const Player = ({ urlParams, queryParams }) => {
|
|||
forceTranscoding: forceTranscoding || casting,
|
||||
maxAudioChannels: settings.surroundSound ? 32 : 2,
|
||||
hardwareDecoding: settings.hardwareDecoding,
|
||||
assSubtitlesStyling: settings.assSubtitlesStyling,
|
||||
videoMode: settings.videoMode,
|
||||
platform: platform.name,
|
||||
streamingServerURL: streamingServer.baseUrl ?
|
||||
|
|
@ -387,31 +406,6 @@ const Player = ({ urlParams, queryParams }) => {
|
|||
}
|
||||
}, [player.subtitles, video.state.stream]);
|
||||
|
||||
React.useEffect(() => {
|
||||
video.setProp('subtitlesSize', settings.subtitlesSize);
|
||||
video.setProp('extraSubtitlesSize', settings.subtitlesSize);
|
||||
}, [settings.subtitlesSize]);
|
||||
|
||||
React.useEffect(() => {
|
||||
video.setProp('subtitlesOffset', settings.subtitlesOffset);
|
||||
video.setProp('extraSubtitlesOffset', settings.subtitlesOffset);
|
||||
}, [settings.subtitlesOffset]);
|
||||
|
||||
React.useEffect(() => {
|
||||
video.setProp('subtitlesTextColor', settings.subtitlesTextColor);
|
||||
video.setProp('extraSubtitlesTextColor', settings.subtitlesTextColor);
|
||||
}, [settings.subtitlesTextColor]);
|
||||
|
||||
React.useEffect(() => {
|
||||
video.setProp('subtitlesBackgroundColor', settings.subtitlesBackgroundColor);
|
||||
video.setProp('extraSubtitlesBackgroundColor', settings.subtitlesBackgroundColor);
|
||||
}, [settings.subtitlesBackgroundColor]);
|
||||
|
||||
React.useEffect(() => {
|
||||
video.setProp('subtitlesOutlineColor', settings.subtitlesOutlineColor);
|
||||
video.setProp('extraSubtitlesOutlineColor', settings.subtitlesOutlineColor);
|
||||
}, [settings.subtitlesOutlineColor]);
|
||||
|
||||
React.useEffect(() => {
|
||||
!seeking && timeChanged(video.state.time, video.state.duration, video.state.manifest?.name);
|
||||
}, [video.state.time, video.state.duration, video.state.manifest, seeking]);
|
||||
|
|
@ -444,41 +438,69 @@ const Player = ({ urlParams, queryParams }) => {
|
|||
}
|
||||
}, [player.nextVideo, video.state.time, video.state.duration]);
|
||||
|
||||
// Auto subtitles track selection
|
||||
React.useEffect(() => {
|
||||
if (!defaultSubtitlesSelected.current) {
|
||||
const findTrackByLang = (tracks, lang) => tracks.find((track) => track.lang === lang || langs.where('1', track.lang)?.[2] === lang);
|
||||
|
||||
if (settings.subtitlesLanguage === null) {
|
||||
onSubtitlesTrackSelected(null);
|
||||
onExtraSubtitlesTrackSelected(null);
|
||||
video.setSubtitlesTrack(null);
|
||||
video.setExtraSubtitlesTrack(null);
|
||||
defaultSubtitlesSelected.current = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const subtitlesTrack = findTrackByLang(video.state.subtitlesTracks, settings.subtitlesLanguage);
|
||||
const extraSubtitlesTrack = findTrackByLang(video.state.extraSubtitlesTracks, settings.subtitlesLanguage);
|
||||
const savedTrackId = player.streamState?.subtitleTrack?.id;
|
||||
const subtitlesTrack = savedTrackId ?
|
||||
findTrackById(video.state.subtitlesTracks, savedTrackId) :
|
||||
findTrackByLang(video.state.subtitlesTracks, settings.subtitlesLanguage);
|
||||
|
||||
const extraSubtitlesTrack = savedTrackId ?
|
||||
findTrackById(video.state.extraSubtitlesTracks, savedTrackId) :
|
||||
findTrackByLang(video.state.extraSubtitlesTracks, settings.subtitlesLanguage);
|
||||
|
||||
if (subtitlesTrack && subtitlesTrack.id) {
|
||||
onSubtitlesTrackSelected(subtitlesTrack.id);
|
||||
video.setSubtitlesTrack(subtitlesTrack.id);
|
||||
defaultSubtitlesSelected.current = true;
|
||||
} else if (extraSubtitlesTrack && extraSubtitlesTrack.id) {
|
||||
onExtraSubtitlesTrackSelected(extraSubtitlesTrack.id);
|
||||
video.setExtraSubtitlesTrack(extraSubtitlesTrack.id);
|
||||
defaultSubtitlesSelected.current = true;
|
||||
}
|
||||
}
|
||||
}, [video.state.subtitlesTracks, video.state.extraSubtitlesTracks]);
|
||||
}, [video.state.subtitlesTracks, video.state.extraSubtitlesTracks, player.streamState]);
|
||||
|
||||
// Auto audio track selection
|
||||
React.useEffect(() => {
|
||||
if (!defaultAudioTrackSelected.current) {
|
||||
const findTrackByLang = (tracks, lang) => tracks.find((track) => track.lang === lang || langs.where('1', track.lang)?.[2] === lang);
|
||||
const audioTrack = findTrackByLang(video.state.audioTracks, settings.audioLanguage);
|
||||
const savedTrackId = player.streamState?.audioTrack?.id;
|
||||
const audioTrack = savedTrackId ?
|
||||
findTrackById(video.state.audioTracks, savedTrackId) :
|
||||
findTrackByLang(video.state.audioTracks, settings.audioLanguage);
|
||||
|
||||
if (audioTrack && audioTrack.id) {
|
||||
onAudioTrackSelected(audioTrack.id);
|
||||
video.setAudioTrack(audioTrack.id);
|
||||
defaultAudioTrackSelected.current = true;
|
||||
}
|
||||
}
|
||||
}, [video.state.audioTracks]);
|
||||
}, [video.state.audioTracks, player.streamState]);
|
||||
|
||||
// Saved subtitles settings
|
||||
React.useEffect(() => {
|
||||
if (video.state.stream !== null) {
|
||||
const delay = player.streamState?.subtitleDelay;
|
||||
if (typeof delay === 'number') {
|
||||
video.setSubtitlesDelay(delay);
|
||||
}
|
||||
|
||||
const size = player.streamState?.subtitleSize;
|
||||
if (typeof size === 'number') {
|
||||
video.setSubtitlesSize(size);
|
||||
}
|
||||
|
||||
const offset = player.streamState?.subtitleOffset;
|
||||
if (typeof offset === 'number') {
|
||||
video.setSubtitlesOffset(offset);
|
||||
}
|
||||
}
|
||||
}, [video.state.stream, player.streamState]);
|
||||
|
||||
React.useEffect(() => {
|
||||
defaultSubtitlesSelected.current = false;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useCallback, useEffect, useRef } from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import classNames from 'classnames';
|
||||
import Icon from '@stremio/stremio-icons/react';
|
||||
|
|
@ -37,6 +37,18 @@ const Stepper = ({ className, label, value, unit, step, min, max, disabled, onCh
|
|||
timeout.cancel();
|
||||
};
|
||||
|
||||
const decreaseDisabled = useMemo(() => {
|
||||
return disabled || typeof value !== 'number' || (typeof min === 'number' && value <= min);
|
||||
}, [disabled, min, value]);
|
||||
|
||||
const increaseDisabled = useMemo(() => {
|
||||
return disabled || typeof value !== 'number' || (typeof max === 'number' && value >= max);
|
||||
}, [disabled, max, value]);
|
||||
|
||||
const valueLabel = useMemo(() => {
|
||||
return (disabled || typeof value !== 'number') ? '--' : `${value}${unit}`;
|
||||
}, [disabled, value, unit]);
|
||||
|
||||
const updateValue = useCallback((delta: number) => {
|
||||
onChange(clamp(localValue.current + delta, min, max));
|
||||
}, [onChange]);
|
||||
|
|
@ -72,7 +84,7 @@ const Stepper = ({ className, label, value, unit, step, min, max, disabled, onCh
|
|||
</div>
|
||||
<div className={styles['content']}>
|
||||
<Button
|
||||
className={classNames(styles['button'], { 'disabled': disabled })}
|
||||
className={classNames(styles['button'], { 'disabled': decreaseDisabled })}
|
||||
onMouseDown={onDecrementMouseDown}
|
||||
onMouseUp={onDecrementMouseUp}
|
||||
onMouseLeave={cancel}
|
||||
|
|
@ -80,10 +92,10 @@ const Stepper = ({ className, label, value, unit, step, min, max, disabled, onCh
|
|||
<Icon className={styles['icon']} name={'remove'} />
|
||||
</Button>
|
||||
<div className={styles['value']}>
|
||||
{ disabled ? '--' : `${value}${unit}` }
|
||||
{ valueLabel }
|
||||
</div>
|
||||
<Button
|
||||
className={classNames(styles['button'], { 'disabled': disabled })}
|
||||
className={classNames(styles['button'], { 'disabled': increaseDisabled })}
|
||||
onMouseDown={onIncrementMouseDown}
|
||||
onMouseUp={onIncrementMouseUp}
|
||||
onMouseLeave={cancel}
|
||||
|
|
|
|||
|
|
@ -86,6 +86,9 @@ const usePlayer = (urlParams) => {
|
|||
};
|
||||
}
|
||||
}, [urlParams]);
|
||||
|
||||
const player = useModelState({ model: 'player', action, map });
|
||||
|
||||
const videoParamsChanged = React.useCallback((videoParams) => {
|
||||
core.transport.dispatch({
|
||||
action: 'Player',
|
||||
|
|
@ -153,8 +156,22 @@ const usePlayer = (urlParams) => {
|
|||
}, 'player');
|
||||
}, []);
|
||||
|
||||
const player = useModelState({ model: 'player', action, map });
|
||||
return [player, videoParamsChanged, timeChanged, seek, pausedChanged, ended, nextVideo];
|
||||
const streamStateChanged = React.useCallback((partialStreamState) => {
|
||||
return core.transport.dispatch({
|
||||
action: 'Player',
|
||||
args: {
|
||||
action: 'StreamStateChanged',
|
||||
args: {
|
||||
state: {
|
||||
...player.streamState,
|
||||
...partialStreamState,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, 'player');
|
||||
}, [player.streamState]);
|
||||
|
||||
return [player, videoParamsChanged, streamStateChanged, timeChanged, seek, pausedChanged, ended, nextVideo];
|
||||
};
|
||||
|
||||
module.exports = usePlayer;
|
||||
|
|
|
|||
|
|
@ -94,6 +94,30 @@ const useVideo = () => {
|
|||
dispatch({ type: 'setProp', propName: name, propValue: value });
|
||||
};
|
||||
|
||||
const setPaused = (state) => {
|
||||
setProp('paused', state);
|
||||
};
|
||||
|
||||
const setVolume = (volume) => {
|
||||
setProp('volume', volume);
|
||||
};
|
||||
|
||||
const setMuted = (state) => {
|
||||
setProp('muted', state);
|
||||
};
|
||||
|
||||
const setTime = (time) => {
|
||||
setProp('time', time);
|
||||
};
|
||||
|
||||
const setPlaybackSpeed = (rate) => {
|
||||
setProp('playbackSpeed', rate);
|
||||
};
|
||||
|
||||
const setAudioTrack = (id) => {
|
||||
setProp('selectedAudioTrackId', id);
|
||||
};
|
||||
|
||||
const setSubtitlesTrack = (id) => {
|
||||
setProp('selectedSubtitlesTrackId', id);
|
||||
setProp('selectedExtraSubtitlesTrackId', null);
|
||||
|
|
@ -104,6 +128,35 @@ const useVideo = () => {
|
|||
setProp('selectedExtraSubtitlesTrackId', id);
|
||||
};
|
||||
|
||||
const setSubtitlesDelay = (delay) => {
|
||||
setProp('extraSubtitlesDelay', delay);
|
||||
};
|
||||
|
||||
const setSubtitlesSize = (size) => {
|
||||
setProp('subtitlesSize', size);
|
||||
setProp('extraSubtitlesSize', size);
|
||||
};
|
||||
|
||||
const setSubtitlesOffset = (offset) => {
|
||||
setProp('subtitlesOffset', offset);
|
||||
setProp('extraSubtitlesOffset', offset);
|
||||
};
|
||||
|
||||
const setSubtitlesTextColor = (color) => {
|
||||
setProp('subtitlesTextColor', color);
|
||||
setProp('extraSubtitlesTextColor', color);
|
||||
};
|
||||
|
||||
const setSubtitlesBackgroundColor = (color) => {
|
||||
setProp('subtitlesBackgroundColor', color);
|
||||
setProp('extraSubtitlesBackgroundColor', color);
|
||||
};
|
||||
|
||||
const setSubtitlesOutlineColor = (color) => {
|
||||
setProp('subtitlesOutlineColor', color);
|
||||
setProp('extraSubtitlesOutlineColor', color);
|
||||
};
|
||||
|
||||
const onError = (error) => {
|
||||
events.emit('error', error);
|
||||
};
|
||||
|
|
@ -171,8 +224,19 @@ const useVideo = () => {
|
|||
unload,
|
||||
addExtraSubtitlesTracks,
|
||||
addLocalSubtitles,
|
||||
setProp,
|
||||
setPaused,
|
||||
setVolume,
|
||||
setMuted,
|
||||
setTime,
|
||||
setPlaybackSpeed,
|
||||
setAudioTrack,
|
||||
setSubtitlesTrack,
|
||||
setSubtitlesDelay,
|
||||
setSubtitlesSize,
|
||||
setSubtitlesOffset,
|
||||
setSubtitlesTextColor,
|
||||
setSubtitlesBackgroundColor,
|
||||
setSubtitlesOutlineColor,
|
||||
setExtraSubtitlesTrack,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
import React, { forwardRef, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, MultiselectMenu, Toggle } from 'stremio/components';
|
||||
import { Button } from 'stremio/components';
|
||||
import { useServices } from 'stremio/services';
|
||||
import { usePlatform, useToast } from 'stremio/common';
|
||||
import { Section, Option, Link } from '../components';
|
||||
import User from './User';
|
||||
import useDataExport from './useDataExport';
|
||||
import styles from './General.less';
|
||||
import useGeneralOptions from './useGeneralOptions';
|
||||
|
||||
type Props = {
|
||||
profile: Profile,
|
||||
|
|
@ -15,18 +14,11 @@ type Props = {
|
|||
|
||||
const General = forwardRef<HTMLDivElement, Props>(({ profile }: Props, ref) => {
|
||||
const { t } = useTranslation();
|
||||
const { core, shell } = useServices();
|
||||
const { core } = useServices();
|
||||
const platform = usePlatform();
|
||||
const toast = useToast();
|
||||
const [dataExport, loadDataExport] = useDataExport();
|
||||
|
||||
const {
|
||||
interfaceLanguageSelect,
|
||||
quitOnCloseToggle,
|
||||
escExitFullscreenToggle,
|
||||
hideSpoilersToggle,
|
||||
} = useGeneralOptions(profile);
|
||||
|
||||
const [traktAuthStarted, setTraktAuthStarted] = useState(false);
|
||||
|
||||
const isTraktAuthenticated = useMemo(() => {
|
||||
|
|
@ -143,39 +135,6 @@ const General = forwardRef<HTMLDivElement, Props>(({ profile }: Props, ref) => {
|
|||
</Button>
|
||||
</Option>
|
||||
</Section>
|
||||
|
||||
<Section>
|
||||
<Option label={'SETTINGS_UI_LANGUAGE'}>
|
||||
<MultiselectMenu
|
||||
className={'multiselect'}
|
||||
{...interfaceLanguageSelect}
|
||||
/>
|
||||
</Option>
|
||||
{
|
||||
shell.active &&
|
||||
<Option label={'SETTINGS_QUIT_ON_CLOSE'}>
|
||||
<Toggle
|
||||
tabIndex={-1}
|
||||
{...quitOnCloseToggle}
|
||||
/>
|
||||
</Option>
|
||||
}
|
||||
{
|
||||
shell.active &&
|
||||
<Option label={'SETTINGS_FULLSCREEN_EXIT'}>
|
||||
<Toggle
|
||||
tabIndex={-1}
|
||||
{...escExitFullscreenToggle}
|
||||
/>
|
||||
</Option>
|
||||
}
|
||||
<Option label={'SETTINGS_BLUR_UNWATCHED_IMAGE'}>
|
||||
<Toggle
|
||||
tabIndex={-1}
|
||||
{...hideSpoilersToggle}
|
||||
/>
|
||||
</Option>
|
||||
</Section>
|
||||
</>;
|
||||
});
|
||||
|
||||
|
|
|
|||
57
src/routes/Settings/Interface/Interface.tsx
Normal file
57
src/routes/Settings/Interface/Interface.tsx
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import React, { forwardRef } from 'react';
|
||||
import { useServices } from 'stremio/services';
|
||||
import { MultiselectMenu, Toggle } from 'stremio/components';
|
||||
import { Section, Option } from '../components';
|
||||
import useInterfaceOptions from './useInterfaceOptions';
|
||||
|
||||
type Props = {
|
||||
profile: Profile,
|
||||
};
|
||||
|
||||
const Interface = forwardRef<HTMLDivElement, Props>(({ profile }: Props, ref) => {
|
||||
const { shell } = useServices();
|
||||
|
||||
const {
|
||||
interfaceLanguageSelect,
|
||||
quitOnCloseToggle,
|
||||
escExitFullscreenToggle,
|
||||
hideSpoilersToggle,
|
||||
} = useInterfaceOptions(profile);
|
||||
|
||||
return (
|
||||
<Section ref={ref} label={'INTERFACE'}>
|
||||
<Option label={'SETTINGS_UI_LANGUAGE'}>
|
||||
<MultiselectMenu
|
||||
className={'multiselect'}
|
||||
{...interfaceLanguageSelect}
|
||||
/>
|
||||
</Option>
|
||||
{
|
||||
shell.active &&
|
||||
<Option label={'SETTINGS_QUIT_ON_CLOSE'}>
|
||||
<Toggle
|
||||
tabIndex={-1}
|
||||
{...quitOnCloseToggle}
|
||||
/>
|
||||
</Option>
|
||||
}
|
||||
{
|
||||
shell.active &&
|
||||
<Option label={'SETTINGS_FULLSCREEN_EXIT'}>
|
||||
<Toggle
|
||||
tabIndex={-1}
|
||||
{...escExitFullscreenToggle}
|
||||
/>
|
||||
</Option>
|
||||
}
|
||||
<Option label={'SETTINGS_BLUR_UNWATCHED_IMAGE'}>
|
||||
<Toggle
|
||||
tabIndex={-1}
|
||||
{...hideSpoilersToggle}
|
||||
/>
|
||||
</Option>
|
||||
</Section>
|
||||
);
|
||||
});
|
||||
|
||||
export default Interface;
|
||||
2
src/routes/Settings/Interface/index.ts
Normal file
2
src/routes/Settings/Interface/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
import Interface from './Interface';
|
||||
export default Interface;
|
||||
|
|
@ -2,7 +2,7 @@ import { useMemo } from 'react';
|
|||
import { interfaceLanguages, useLanguageSorting } from 'stremio/common';
|
||||
import { useServices } from 'stremio/services';
|
||||
|
||||
const useGeneralOptions = (profile: Profile) => {
|
||||
const useInterfaceOptions = (profile: Profile) => {
|
||||
const { core } = useServices();
|
||||
|
||||
const interfaceLanguageOptions = useMemo(() =>
|
||||
|
|
@ -89,4 +89,4 @@ const useGeneralOptions = (profile: Profile) => {
|
|||
};
|
||||
};
|
||||
|
||||
export default useGeneralOptions;
|
||||
export default useInterfaceOptions;
|
||||
|
|
@ -26,6 +26,9 @@ const Menu = ({ selected, streamingServer, onSelect }: Props) => {
|
|||
<Button className={classNames(styles['button'], { [styles['selected']]: selected === SECTIONS.GENERAL })} title={t('SETTINGS_NAV_GENERAL')} data-section={SECTIONS.GENERAL} onClick={onSelect}>
|
||||
{ t('SETTINGS_NAV_GENERAL') }
|
||||
</Button>
|
||||
<Button className={classNames(styles['button'], { [styles['selected']]: selected === SECTIONS.INTERFACE })} title={t('INTERFACE')} data-section={SECTIONS.INTERFACE} onClick={onSelect}>
|
||||
{ t('INTERFACE') }
|
||||
</Button>
|
||||
<Button className={classNames(styles['button'], { [styles['selected']]: selected === SECTIONS.PLAYER })} title={t('SETTINGS_NAV_PLAYER')} data-section={SECTIONS.PLAYER} onClick={onSelect}>
|
||||
{ t('SETTINGS_NAV_PLAYER') }
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ const Player = forwardRef<HTMLDivElement, Props>(({ profile }: Props, ref) => {
|
|||
subtitlesTextColorInput,
|
||||
subtitlesBackgroundColorInput,
|
||||
subtitlesOutlineColorInput,
|
||||
assSubtitlesStylingToggle,
|
||||
audioLanguageSelect,
|
||||
surroundSoundToggle,
|
||||
seekTimeDurationSelect,
|
||||
|
|
@ -149,6 +150,15 @@ const Player = forwardRef<HTMLDivElement, Props>(({ profile }: Props, ref) => {
|
|||
/>
|
||||
</Option>
|
||||
}
|
||||
{
|
||||
shell.active &&
|
||||
<Option label={'SETTINGS_ASS_SUBTITLES_STYLING'}>
|
||||
<Toggle
|
||||
tabIndex={-1}
|
||||
{...assSubtitlesStylingToggle}
|
||||
/>
|
||||
</Option>
|
||||
}
|
||||
</Category>
|
||||
</Section>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -92,6 +92,22 @@ const usePlayerOptions = (profile: Profile) => {
|
|||
}
|
||||
}), [profile.settings]);
|
||||
|
||||
const assSubtitlesStylingToggle = useMemo(() => ({
|
||||
checked: profile.settings.assSubtitlesStyling,
|
||||
onClick: () => {
|
||||
core.transport.dispatch({
|
||||
action: 'Ctx',
|
||||
args: {
|
||||
action: 'UpdateSettings',
|
||||
args: {
|
||||
...profile.settings,
|
||||
assSubtitlesStyling: !profile.settings.assSubtitlesStyling
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}), [profile.settings]);
|
||||
|
||||
const subtitlesOutlineColorInput = useMemo(() => ({
|
||||
value: profile.settings.subtitlesOutlineColor,
|
||||
onChange: (value: string) => {
|
||||
|
|
@ -341,6 +357,7 @@ const usePlayerOptions = (profile: Profile) => {
|
|||
subtitlesTextColorInput,
|
||||
subtitlesBackgroundColorInput,
|
||||
subtitlesOutlineColorInput,
|
||||
assSubtitlesStylingToggle,
|
||||
audioLanguageSelect,
|
||||
surroundSoundToggle,
|
||||
seekTimeDurationSelect,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { MainNavBars } from 'stremio/components';
|
|||
import { SECTIONS } from './constants';
|
||||
import Menu from './Menu';
|
||||
import General from './General';
|
||||
import Interface from './Interface';
|
||||
import Player from './Player';
|
||||
import Streaming from './Streaming';
|
||||
import Shortcuts from './Shortcuts';
|
||||
|
|
@ -23,12 +24,14 @@ const Settings = () => {
|
|||
|
||||
const sectionsContainerRef = useRef<HTMLDivElement>(null);
|
||||
const generalSectionRef = useRef<HTMLDivElement>(null);
|
||||
const interfaceSectionRef = useRef<HTMLDivElement>(null);
|
||||
const playerSectionRef = useRef<HTMLDivElement>(null);
|
||||
const streamingServerSectionRef = useRef<HTMLDivElement>(null);
|
||||
const shortcutsSectionRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const sections = useMemo(() => ([
|
||||
{ ref: generalSectionRef, id: SECTIONS.GENERAL },
|
||||
{ ref: interfaceSectionRef, id: SECTIONS.INTERFACE },
|
||||
{ ref: playerSectionRef, id: SECTIONS.PLAYER },
|
||||
{ ref: streamingServerSectionRef, id: SECTIONS.STREAMING },
|
||||
{ ref: shortcutsSectionRef, id: SECTIONS.SHORTCUTS },
|
||||
|
|
@ -82,6 +85,10 @@ const Settings = () => {
|
|||
ref={generalSectionRef}
|
||||
profile={profile}
|
||||
/>
|
||||
<Interface
|
||||
ref={interfaceSectionRef}
|
||||
profile={profile}
|
||||
/>
|
||||
<Player
|
||||
ref={playerSectionRef}
|
||||
profile={profile}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
const SECTIONS = {
|
||||
GENERAL: 'general',
|
||||
PLAYER: 'player',
|
||||
INTERFACE: 'interface',
|
||||
STREAMING: 'streaming',
|
||||
SHORTCUTS: 'shortcuts',
|
||||
};
|
||||
|
|
|
|||
1
src/types/models/Ctx.d.ts
vendored
1
src/types/models/Ctx.d.ts
vendored
|
|
@ -42,6 +42,7 @@ type Settings = {
|
|||
subtitlesOutlineColor: string,
|
||||
subtitlesSize: number,
|
||||
subtitlesTextColor: string,
|
||||
assSubtitlesStyling: boolean,
|
||||
surroundSound: boolean,
|
||||
pauseOnMinimize: boolean,
|
||||
};
|
||||
|
|
|
|||
18
src/types/models/Player.d.ts
vendored
18
src/types/models/Player.d.ts
vendored
|
|
@ -30,6 +30,23 @@ type SeriesInfo = {
|
|||
season: number,
|
||||
};
|
||||
|
||||
type SubtitlesTrackState = {
|
||||
id: string,
|
||||
embedded: boolean,
|
||||
};
|
||||
|
||||
type AudioTrackState = {
|
||||
id: string,
|
||||
};
|
||||
|
||||
type StreamState = {
|
||||
subtitleTrack?: SubtitlesTrackState,
|
||||
subtitleDelay?: number,
|
||||
subtitleSize?: number,
|
||||
subtitleOffset?: number,
|
||||
audioTrack?: AudioTrackState,
|
||||
};
|
||||
|
||||
type Player = {
|
||||
addon: Addon | null,
|
||||
libraryItem: LibraryItemPlayer | null,
|
||||
|
|
@ -42,6 +59,7 @@ type Player = {
|
|||
subtitlesPath: ResourceRequestPath,
|
||||
} | null,
|
||||
seriesInfo: SeriesInfo | null,
|
||||
streamState: StreamState | null,
|
||||
subtitles: Subtitle[],
|
||||
title: string | null,
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue