mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-01-11 22:40:31 +00:00
Merge branch 'development' into feat/right-click-context-menu
This commit is contained in:
commit
ca582a9879
20 changed files with 232 additions and 36 deletions
67
.well-known/apple-app-site-association
Normal file
67
.well-known/apple-app-site-association
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
{
|
||||
"applinks": {
|
||||
"apps": [],
|
||||
"details": [
|
||||
{
|
||||
"appID": "9EWRZ4QP3J.com.stremio.one",
|
||||
"paths": [
|
||||
"/",
|
||||
"/#/player/*",
|
||||
"/#/discover/*",
|
||||
"/#/detail/*",
|
||||
"/#/library/*",
|
||||
"/#/addons/*",
|
||||
"/#/settings",
|
||||
"/#/search/*"
|
||||
],
|
||||
"components": [
|
||||
{
|
||||
"/": "/",
|
||||
"#": "/player/*",
|
||||
"comment": "Matches deep link for player"
|
||||
},
|
||||
{
|
||||
"/": "/",
|
||||
"#": "/discover/*",
|
||||
"comment": "Matches deep link for discover"
|
||||
},
|
||||
{
|
||||
"/": "/",
|
||||
"#": "/detail/*",
|
||||
"comment": "Matches deep link for detail"
|
||||
},
|
||||
{
|
||||
"/": "/",
|
||||
"#": "/library/*",
|
||||
"comment": "Matches deep link for library"
|
||||
},
|
||||
{
|
||||
"/": "/",
|
||||
"#": "/addons/*",
|
||||
"comment": "Matches deep link for addons"
|
||||
},
|
||||
{
|
||||
"/": "/",
|
||||
"#": "/settings",
|
||||
"comment": "Matches deep link for settings"
|
||||
},
|
||||
{
|
||||
"/": "/",
|
||||
"#": "/search/*",
|
||||
"comment": "Matches deep link for search"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"activitycontinuation": {
|
||||
"apps": [
|
||||
"9EWRZ4QP3J.com.stremio.one"
|
||||
]
|
||||
},
|
||||
"webcredentials": {
|
||||
"apps": [
|
||||
"9EWRZ4QP3J.com.stremio.one"
|
||||
]
|
||||
}
|
||||
}
|
||||
16
package-lock.json
generated
16
package-lock.json
generated
|
|
@ -12,7 +12,7 @@
|
|||
"@babel/runtime": "7.26.0",
|
||||
"@sentry/browser": "8.42.0",
|
||||
"@stremio/stremio-colors": "5.2.0",
|
||||
"@stremio/stremio-core-web": "0.49.0",
|
||||
"@stremio/stremio-core-web": "0.49.2",
|
||||
"@stremio/stremio-icons": "5.4.1",
|
||||
"@stremio/stremio-video": "0.0.53",
|
||||
"a-color-picker": "1.2.1",
|
||||
|
|
@ -36,7 +36,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#62bcc6e8f44258203c7375af59210771efb6f634",
|
||||
"stremio-translations": "github:Stremio/stremio-translations#4bb1b7e31df274f538b8588c2a2b360d6e14ab27",
|
||||
"url": "0.11.4",
|
||||
"use-long-press": "^3.2.0"
|
||||
},
|
||||
|
|
@ -3371,9 +3371,9 @@
|
|||
"integrity": "sha512-dYlPgu9W/H7c9s1zmW5tiDnRenaUa4Hg1QCyOg1lhOcgSfM/bVTi5nnqX+IfvGTTUNA0zgzh8hI3o3miwnZxTg=="
|
||||
},
|
||||
"node_modules/@stremio/stremio-core-web": {
|
||||
"version": "0.49.0",
|
||||
"resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.49.0.tgz",
|
||||
"integrity": "sha512-oxJRVAE6z6Eh1B0qomdz6L2CVaTkwt70kDNC1TmHyGNo+Hhp2RaMlygqBKvBLXyHUXi82R67Mc11gT/JqlmaMw==",
|
||||
"version": "0.49.2",
|
||||
"resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.49.2.tgz",
|
||||
"integrity": "sha512-IYU+pdHkq4iEfqZ9G+DFZheIE53nY8XyhI1OJLvZp68/4ntRwssXwfj9InHK2Wau20fH+oV2KD1ZWb0CsTLqPA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.24.1"
|
||||
|
|
@ -13372,9 +13372,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/stremio-translations": {
|
||||
"version": "1.44.9",
|
||||
"resolved": "git+ssh://git@github.com/Stremio/stremio-translations.git#62bcc6e8f44258203c7375af59210771efb6f634",
|
||||
"integrity": "sha512-8Sc5Qvd4IiObwGXkmj1XFXFavUc15My5po6G48HHDBbp42SVc5I/t7h+1yxW1A81byyBCXbL23a9iU9v49vpQA==",
|
||||
"version": "1.44.10",
|
||||
"resolved": "git+ssh://git@github.com/Stremio/stremio-translations.git#4bb1b7e31df274f538b8588c2a2b360d6e14ab27",
|
||||
"integrity": "sha512-+RLkoytMyqP90mn9Wkh1MhwB2fxVuvMxsxxceGnFgYlyyEL8fxuHTRnSaBjWBw+xFtsaeMLmDfA1n3l+UEzg4A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
"@babel/runtime": "7.26.0",
|
||||
"@sentry/browser": "8.42.0",
|
||||
"@stremio/stremio-colors": "5.2.0",
|
||||
"@stremio/stremio-core-web": "0.49.0",
|
||||
"@stremio/stremio-core-web": "0.49.2",
|
||||
"@stremio/stremio-icons": "5.4.1",
|
||||
"@stremio/stremio-video": "0.0.53",
|
||||
"a-color-picker": "1.2.1",
|
||||
|
|
@ -40,7 +40,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#62bcc6e8f44258203c7375af59210771efb6f634",
|
||||
"stremio-translations": "github:Stremio/stremio-translations#4bb1b7e31df274f538b8588c2a2b360d6e14ab27",
|
||||
"url": "0.11.4",
|
||||
"use-long-press": "^3.2.0"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -100,14 +100,29 @@ const App = () => {
|
|||
};
|
||||
}, []);
|
||||
|
||||
// Handle shell window visibility changed event
|
||||
// Handle shell events
|
||||
React.useEffect(() => {
|
||||
const onWindowVisibilityChanged = (state) => {
|
||||
setWindowHidden(state.visible === false && state.visibility === 0);
|
||||
};
|
||||
|
||||
const onOpenMedia = (data) => {
|
||||
if (data.startsWith('stremio:///')) return;
|
||||
if (data.startsWith('stremio://')) {
|
||||
const transportUrl = data.replace('stremio://', 'https://');
|
||||
if (URL.canParse(transportUrl)) {
|
||||
window.location.href = `#/addons?addon=${encodeURIComponent(transportUrl)}`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
shell.on('win-visibility-changed', onWindowVisibilityChanged);
|
||||
return () => shell.off('win-visibility-changed', onWindowVisibilityChanged);
|
||||
shell.on('open-media', onOpenMedia);
|
||||
|
||||
return () => {
|
||||
shell.off('win-visibility-changed', onWindowVisibilityChanged);
|
||||
shell.off('open-media', onOpenMedia);
|
||||
};
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
bottom: 0;
|
||||
left: var(--vertical-nav-bar-size);
|
||||
z-index: 0;
|
||||
overflow: scroll;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,14 +31,18 @@ const Slider = ({ className, value, buffered, minimumValue, maximumValue, disabl
|
|||
const retainThumb = React.useCallback(() => {
|
||||
window.addEventListener('blur', onBlur);
|
||||
window.addEventListener('mouseup', onMouseUp);
|
||||
window.addEventListener('touchend', onTouchEnd);
|
||||
window.addEventListener('mousemove', onMouseMove);
|
||||
window.addEventListener('touchmove', onTouchMove);
|
||||
document.documentElement.className = classnames(document.documentElement.className, styles['active-slider-within']);
|
||||
}, []);
|
||||
const releaseThumb = React.useCallback(() => {
|
||||
cancelThumbAnimation();
|
||||
window.removeEventListener('blur', onBlur);
|
||||
window.removeEventListener('mouseup', onMouseUp);
|
||||
window.removeEventListener('touchend', onTouchEnd);
|
||||
window.removeEventListener('mousemove', onMouseMove);
|
||||
window.removeEventListener('touchmove', onTouchMove);
|
||||
const classList = document.documentElement.className.split(' ');
|
||||
const classIndex = classList.indexOf(styles['active-slider-within']);
|
||||
if (classIndex !== -1) {
|
||||
|
|
@ -85,6 +89,36 @@ const Slider = ({ className, value, buffered, minimumValue, maximumValue, disabl
|
|||
|
||||
retainThumb();
|
||||
}, []);
|
||||
const onTouchStart = React.useCallback((event) => {
|
||||
const touch = event.touches[0];
|
||||
const value = calculateValueForMouseX(touch.clientX);
|
||||
if (typeof onSlideRef.current === 'function') {
|
||||
onSlideRef.current(value);
|
||||
}
|
||||
|
||||
retainThumb();
|
||||
event.preventDefault();
|
||||
}, []);
|
||||
const onTouchMove = React.useCallback((event) => {
|
||||
requestThumbAnimation(() => {
|
||||
const touch = event.touches[0];
|
||||
const value = calculateValueForMouseX(touch.clientX);
|
||||
if (typeof onSlideRef.current === 'function') {
|
||||
onSlideRef.current(value);
|
||||
}
|
||||
});
|
||||
|
||||
event.preventDefault();
|
||||
}, []);
|
||||
const onTouchEnd = React.useCallback((event) => {
|
||||
const touch = event.changedTouches[0];
|
||||
const value = calculateValueForMouseX(touch.clientX);
|
||||
if (typeof onCompleteRef.current === 'function') {
|
||||
onCompleteRef.current(value);
|
||||
}
|
||||
|
||||
releaseThumb();
|
||||
}, []);
|
||||
React.useLayoutEffect(() => {
|
||||
if (!routeFocused || disabled) {
|
||||
releaseThumb();
|
||||
|
|
@ -98,7 +132,7 @@ const Slider = ({ className, value, buffered, minimumValue, maximumValue, disabl
|
|||
const thumbPosition = Math.max(0, Math.min(1, (valueRef.current - minimumValueRef.current) / (maximumValueRef.current - minimumValueRef.current)));
|
||||
const bufferedPosition = Math.max(0, Math.min(1, (bufferedRef.current - minimumValueRef.current) / (maximumValueRef.current - minimumValueRef.current)));
|
||||
return (
|
||||
<div ref={sliderContainerRef} className={classnames(className, styles['slider-container'], { 'disabled': disabled })} onMouseDown={onMouseDown}>
|
||||
<div ref={sliderContainerRef} className={classnames(className, styles['slider-container'], { 'disabled': disabled })} onMouseDown={onMouseDown} onTouchStart={onTouchStart}>
|
||||
<div className={styles['layer']}>
|
||||
<div className={classnames(styles['track'], { [styles['audio-boost']]: audioBoost })} />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -46,7 +46,8 @@ html.active-slider-within {
|
|||
width: 100%;
|
||||
height: var(--track-size);
|
||||
border-radius: var(--track-size);
|
||||
background-color: var(--overlay-color);
|
||||
background-color: var(--primary-accent-color);
|
||||
opacity: 0.2;
|
||||
|
||||
&.audio-boost {
|
||||
opacity: 0.3;
|
||||
|
|
|
|||
|
|
@ -8,11 +8,13 @@ const { useRouteFocused } = require('stremio-router');
|
|||
const { default: Icon } = require('@stremio/stremio-icons/react');
|
||||
const { Button, Image, Popup } = require('stremio/components');
|
||||
const useBinaryState = require('stremio/common/useBinaryState');
|
||||
const useProfile = require('stremio/common/useProfile');
|
||||
const VideoPlaceholder = require('./VideoPlaceholder');
|
||||
const styles = require('./styles');
|
||||
|
||||
const Video = ({ className, id, title, thumbnail, season, episode, released, upcoming, watched, progress, scheduled, seasonWatched, deepLinks, onMarkVideoAsWatched, onMarkSeasonAsWatched, ...props }) => {
|
||||
const routeFocused = useRouteFocused();
|
||||
const profile = useProfile();
|
||||
const [menuOpen, , closeMenu, toggleMenu] = useBinaryState(false);
|
||||
const popupLabelOnMouseUp = React.useCallback((event) => {
|
||||
if (!event.nativeEvent.togglePopupPrevented) {
|
||||
|
|
@ -66,13 +68,14 @@ const Video = ({ className, id, title, thumbnail, season, episode, released, upc
|
|||
}
|
||||
}, [deepLinks]);
|
||||
const renderLabel = React.useMemo(() => function renderLabel({ className, id, title, thumbnail, episode, released, upcoming, watched, progress, scheduled, children, ...props }) {
|
||||
const blurThumbnail = profile.settings.hideSpoilers && season && episode && !watched;
|
||||
return (
|
||||
<Button {...props} className={classnames(className, styles['video-container'])} title={title}>
|
||||
{
|
||||
typeof thumbnail === 'string' && thumbnail.length > 0 ?
|
||||
<div className={styles['thumbnail-container']}>
|
||||
<Image
|
||||
className={styles['thumbnail']}
|
||||
className={classnames(styles['thumbnail'], { [styles['blurred']]: blurThumbnail })}
|
||||
src={thumbnail}
|
||||
alt={' '}
|
||||
renderFallback={() => (
|
||||
|
|
|
|||
|
|
@ -41,6 +41,11 @@
|
|||
object-position: center;
|
||||
opacity: 0.9;
|
||||
background-color: var(--overlay-color);
|
||||
|
||||
&.blurred {
|
||||
filter: blur(0.5rem);
|
||||
-webkit-filter: blur(0.5rem);
|
||||
}
|
||||
}
|
||||
|
||||
.placeholder-icon {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ const { useServices } = require('stremio/services');
|
|||
const SeekBar = require('./SeekBar');
|
||||
const VolumeSlider = require('./VolumeSlider');
|
||||
const styles = require('./styles');
|
||||
const { useBinaryState } = require('stremio/common');
|
||||
const { useBinaryState, usePlatform } = require('stremio/common');
|
||||
const { t } = require('i18next');
|
||||
|
||||
const ControlBar = ({
|
||||
|
|
@ -40,9 +40,11 @@ const ControlBar = ({
|
|||
onToggleSideDrawer,
|
||||
onToggleOptionsMenu,
|
||||
onToggleStatisticsMenu,
|
||||
onTouchEnd,
|
||||
...props
|
||||
}) => {
|
||||
const { chromecast } = useServices();
|
||||
const platform = usePlatform();
|
||||
const [chromecastServiceActive, setChromecastServiceActive] = React.useState(() => chromecast.active);
|
||||
const [buttonsMenuOpen, , , toggleButtonsMenu] = useBinaryState(false);
|
||||
const onSubtitlesButtonMouseDown = React.useCallback((event) => {
|
||||
|
|
@ -103,7 +105,7 @@ const ControlBar = ({
|
|||
};
|
||||
}, []);
|
||||
return (
|
||||
<div {...props} className={classnames(className, styles['control-bar-container'])}>
|
||||
<div {...props} onTouchStart={props.onMouseOver} onTouchMove={props.onMouseMove} onTouchEnd={onTouchEnd} className={classnames(className, styles['control-bar-container'])}>
|
||||
<SeekBar
|
||||
className={styles['seek-bar']}
|
||||
time={time}
|
||||
|
|
@ -129,18 +131,23 @@ const ControlBar = ({
|
|||
name={
|
||||
(typeof muted === 'boolean' && muted) ? 'volume-mute' :
|
||||
(volume === null || isNaN(volume)) ? 'volume-off' :
|
||||
volume < 30 ? 'volume-low' :
|
||||
volume < 70 ? 'volume-medium' :
|
||||
'volume-high'
|
||||
volume === 0 ? 'volume-mute' :
|
||||
volume < 30 ? 'volume-low' :
|
||||
volume < 70 ? 'volume-medium' :
|
||||
'volume-high'
|
||||
}
|
||||
/>
|
||||
</Button>
|
||||
<VolumeSlider
|
||||
className={styles['volume-slider']}
|
||||
volume={volume}
|
||||
muted={muted}
|
||||
onVolumeChangeRequested={onVolumeChangeRequested}
|
||||
/>
|
||||
{
|
||||
!platform.isMobile ?
|
||||
<VolumeSlider
|
||||
className={styles['volume-slider']}
|
||||
volume={volume}
|
||||
muted={muted}
|
||||
onVolumeChangeRequested={onVolumeChangeRequested}
|
||||
/>
|
||||
: null
|
||||
}
|
||||
<div className={styles['spacing']} />
|
||||
<Button className={styles['control-bar-buttons-menu-button']} onClick={toggleButtonsMenu}>
|
||||
<Icon className={styles['icon']} name={'more-vertical'} />
|
||||
|
|
@ -206,6 +213,9 @@ ControlBar.propTypes = {
|
|||
onToggleSideDrawer: PropTypes.func,
|
||||
onToggleOptionsMenu: PropTypes.func,
|
||||
onToggleStatisticsMenu: PropTypes.func,
|
||||
onMouseOver: PropTypes.func,
|
||||
onMouseMove: PropTypes.func,
|
||||
onTouchEnd: PropTypes.func,
|
||||
};
|
||||
|
||||
module.exports = ControlBar;
|
||||
|
|
|
|||
|
|
@ -4,11 +4,13 @@ const React = require('react');
|
|||
const PropTypes = require('prop-types');
|
||||
const classnames = require('classnames');
|
||||
const { default: Icon } = require('@stremio/stremio-icons/react');
|
||||
const { CONSTANTS } = require('stremio/common');
|
||||
const { CONSTANTS, useProfile } = require('stremio/common');
|
||||
const { Button, Image } = require('stremio/components');
|
||||
const styles = require('./styles');
|
||||
|
||||
const NextVideoPopup = ({ className, metaItem, nextVideo, onDismiss, onNextVideoRequested }) => {
|
||||
const profile = useProfile();
|
||||
const blurPosterImage = profile.settings.hideSpoilers && metaItem.type === 'series';
|
||||
const watchNowButtonRef = React.useRef(null);
|
||||
const [animationEnded, setAnimationEnded] = React.useState(false);
|
||||
const videoName = React.useMemo(() => {
|
||||
|
|
@ -51,7 +53,7 @@ const NextVideoPopup = ({ className, metaItem, nextVideo, onDismiss, onNextVideo
|
|||
<div className={classnames(className, styles['next-video-popup-container'])} onAnimationEnd={onAnimationEnd}>
|
||||
<div className={styles['poster-container']}>
|
||||
<Image
|
||||
className={styles['poster-image']}
|
||||
className={classnames(styles['poster-image'], { [styles['blurred']]: blurPosterImage })}
|
||||
src={nextVideo?.thumbnail}
|
||||
alt={' '}
|
||||
fallbackSrc={metaItem?.poster}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,11 @@
|
|||
height: 100%;
|
||||
object-position: center;
|
||||
object-fit: cover;
|
||||
|
||||
&.blurred {
|
||||
filter: blur(0.5rem);
|
||||
-webkit-filter: blur(0.5rem);
|
||||
}
|
||||
}
|
||||
|
||||
.placeholder-icon {
|
||||
|
|
|
|||
|
|
@ -733,6 +733,7 @@ const Player = ({ urlParams, queryParams }) => {
|
|||
onToggleSideDrawer={toggleSideDrawer}
|
||||
onMouseMove={onBarMouseMove}
|
||||
onMouseOver={onBarMouseMove}
|
||||
onTouchEnd={onContainerMouseLeave}
|
||||
/>
|
||||
{
|
||||
nextVideoPopupOpen ?
|
||||
|
|
|
|||
|
|
@ -14,11 +14,12 @@ const VolumeChangeIndicator = React.memo(({ muted, volume }) => {
|
|||
const prevVolume = React.useRef(volume);
|
||||
|
||||
const iconName = React.useMemo(() => {
|
||||
return typeof muted === 'boolean' && muted ? 'volume-mute' :
|
||||
return (typeof muted === 'boolean' && muted) ? 'volume-mute' :
|
||||
volume === null || isNaN(volume) ? 'volume-off' :
|
||||
volume < 30 ? 'volume-low' :
|
||||
volume < 70 ? 'volume-medium' :
|
||||
'volume-high';
|
||||
volume === 0 ? 'volume-mute' :
|
||||
volume < 30 ? 'volume-low' :
|
||||
volume < 70 ? 'volume-medium' :
|
||||
'volume-high';
|
||||
}, [muted, volume]);
|
||||
|
||||
React.useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ const Settings = () => {
|
|||
const toast = useToast();
|
||||
const {
|
||||
interfaceLanguageSelect,
|
||||
hideSpoilersToggle,
|
||||
subtitlesLanguageSelect,
|
||||
subtitlesSizeSelect,
|
||||
subtitlesTextColorInput,
|
||||
|
|
@ -181,7 +182,12 @@ const Settings = () => {
|
|||
{ t('SETTINGS_NAV_SHORTCUTS') }
|
||||
</Button>
|
||||
<div className={styles['spacing']} />
|
||||
<div className={styles['version-info-label']} title={process.env.VERSION}>App Version: {process.env.VERSION}</div>
|
||||
<div className={styles['version-info-label']} title={process.env.VERSION}>
|
||||
App Version: {process.env.VERSION}
|
||||
</div>
|
||||
<div className={styles['version-info-label']} title={process.env.COMMIT_HASH}>
|
||||
Build Version: {process.env.COMMIT_HASH}
|
||||
</div>
|
||||
{
|
||||
streamingServer.settings !== null && streamingServer.settings.type === 'Ready' ?
|
||||
<div className={styles['version-info-label']} title={streamingServer.settings.content.serverVersion}>Server Version: {streamingServer.settings.content.serverVersion}</div>
|
||||
|
|
@ -336,12 +342,22 @@ const Settings = () => {
|
|||
/>
|
||||
</div>
|
||||
}
|
||||
<div className={styles['option-container']}>
|
||||
<div className={styles['option-name-container']}>
|
||||
<div className={styles['label']}>{ t('SETTINGS_BLUR_UNWATCHED_IMAGE') }</div>
|
||||
</div>
|
||||
<Toggle
|
||||
className={classnames(styles['option-input-container'], styles['toggle-container'])}
|
||||
tabIndex={-1}
|
||||
{...hideSpoilersToggle}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div ref={playerSectionRef} className={styles['section-container']}>
|
||||
<div className={styles['section-title']}>{ t('SETTINGS_NAV_PLAYER') }</div>
|
||||
<div className={styles['section-category-container']}>
|
||||
<Icon className={styles['icon']} name={'subtitles'} />
|
||||
<div className={styles['label']}>{t('SETTINGS_CLOSE_WINDOW')}</div>
|
||||
<div className={styles['label']}>{t('SETTINGS_SECTION_SUBTITLES')}</div>
|
||||
</div>
|
||||
<div className={styles['option-container']}>
|
||||
<div className={styles['option-name-container']}>
|
||||
|
|
@ -722,6 +738,18 @@ const Settings = () => {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles['option-container']}>
|
||||
<div className={styles['option-name-container']}>
|
||||
<div className={styles['label']}>
|
||||
Build Version
|
||||
</div>
|
||||
</div>
|
||||
<div className={classnames(styles['option-input-container'], styles['info-container'])}>
|
||||
<div className={styles['label']}>
|
||||
{process.env.COMMIT_HASH}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
streamingServer.settings !== null && streamingServer.settings.type === 'Ready' ?
|
||||
<div className={styles['option-container']}>
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ const URLsManager = () => {
|
|||
}
|
||||
</div>
|
||||
<div className={styles['footer']}>
|
||||
<Button label={'Add URL'} className={styles['add-url']} onClick={onAdd}>
|
||||
<Button title={'Add URL'} className={styles['add-url']} onClick={onAdd}>
|
||||
<Icon name={'add'} className={styles['icon']} />
|
||||
{t('SETTINGS_SERVER_ADD_URL')}
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -64,8 +64,11 @@
|
|||
.version-info-label {
|
||||
flex: 0 1 auto;
|
||||
margin: 0.5rem 0;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
color: var(--primary-foreground-color);
|
||||
opacity: 0.3;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -242,6 +245,8 @@
|
|||
flex-shrink: 1;
|
||||
flex-basis: auto;
|
||||
line-height: 1.5rem;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
color: var(--primary-foreground-color);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,22 @@ const useProfileSettingsInputs = (profile) => {
|
|||
}
|
||||
}), [profile.settings]);
|
||||
|
||||
const hideSpoilersToggle = React.useMemo(() => ({
|
||||
checked: profile.settings.hideSpoilers,
|
||||
onClick: () => {
|
||||
core.transport.dispatch({
|
||||
action: 'Ctx',
|
||||
args: {
|
||||
action: 'UpdateSettings',
|
||||
args: {
|
||||
...profile.settings,
|
||||
hideSpoilers: !profile.settings.hideSpoilers
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}), [profile.settings]);
|
||||
|
||||
const quitOnCloseToggle = React.useMemo(() => ({
|
||||
checked: profile.settings.quitOnClose,
|
||||
onClick: () => {
|
||||
|
|
@ -325,6 +341,7 @@ const useProfileSettingsInputs = (profile) => {
|
|||
}), [profile.settings]);
|
||||
return {
|
||||
interfaceLanguageSelect,
|
||||
hideSpoilersToggle,
|
||||
subtitlesLanguageSelect,
|
||||
subtitlesSizeSelect,
|
||||
subtitlesTextColorInput,
|
||||
|
|
|
|||
1
src/types/models/Ctx.d.ts
vendored
1
src/types/models/Ctx.d.ts
vendored
|
|
@ -21,6 +21,7 @@ type Settings = {
|
|||
hardwareDecoding: boolean,
|
||||
escExitFullscreen: boolean,
|
||||
interfaceLanguage: string,
|
||||
hideSpoilers: boolean,
|
||||
nextVideoNotificationDuration: number,
|
||||
playInBackground: boolean,
|
||||
playerType: string | null,
|
||||
|
|
|
|||
|
|
@ -234,6 +234,7 @@ module.exports = (env, argv) => ({
|
|||
{ from: 'favicons', to: 'favicons' },
|
||||
{ from: 'images', to: 'images' },
|
||||
{ from: 'screenshots/*.webp', to: './' },
|
||||
{ from: '.well-known', to: '.well-known' },
|
||||
]
|
||||
}),
|
||||
new MiniCssExtractPlugin({
|
||||
|
|
|
|||
Loading…
Reference in a new issue