diff --git a/package.json b/package.json index 87886609b..1cd112fea 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "@stremio/stremio-colors": "5.2.0", "@stremio/stremio-core-web": "0.56.4", "@stremio/stremio-icons": "5.10.0", - "@stremio/stremio-video": "0.0.76", + "@stremio/stremio-video": "0.0.77", "a-color-picker": "1.2.1", "bowser": "2.11.0", "buffer": "6.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c55322654..4ff70efdc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,8 +24,8 @@ importers: specifier: 5.10.0 version: 5.10.0 '@stremio/stremio-video': - specifier: 0.0.76 - version: 0.0.76 + specifier: 0.0.77 + version: 0.0.77 a-color-picker: specifier: 1.2.1 version: 1.2.1 @@ -1126,8 +1126,8 @@ packages: '@stremio/stremio-icons@5.10.0': resolution: {integrity: sha512-Zw/vGC3D2yeQfk8xv/tfMJTDvbCPOI91tBg4XpR2+EgbZSX8Xvm7Vz457PIhFPhTAwdOPHp0VX0M3gzjbt0zOg==} - '@stremio/stremio-video@0.0.76': - resolution: {integrity: sha512-q/mCnp4mBReWbtreyeYAf0wD8z+jL4wA5GdkOLPY8o5OPZPUv9Qa9p3FNkK3CMVWf3TP1FzeNj3KYKqUVf5/2Q==} + '@stremio/stremio-video@0.0.77': + resolution: {integrity: sha512-bnKBS5a9R3+M0zx95YpDUiPs1gXcKCsybgdxfZmpWuQaN0RE9bTBAUlIfBSrcEjVhufMOvg+cfXScT+0fBzTTw==} '@stylistic/eslint-plugin-jsx@4.4.1': resolution: {integrity: sha512-83SInq4u7z71vWwGG+6ViOtlOmZ6tSrDkMPhrvdBBTGMLA0gs22WSdhQ4vZP3oJ5Xg4ythvqeUiFSedvVxzhyA==} @@ -5876,7 +5876,7 @@ snapshots: '@stremio/stremio-icons@5.10.0': {} - '@stremio/stremio-video@0.0.76': + '@stremio/stremio-video@0.0.77': dependencies: buffer: 6.0.3 color: 4.2.3 diff --git a/src/routes/Player/ControlBar/ControlBar.js b/src/routes/Player/ControlBar/ControlBar.js index e00f66d00..c9ba5cd7e 100644 --- a/src/routes/Player/ControlBar/ControlBar.js +++ b/src/routes/Player/ControlBar/ControlBar.js @@ -39,6 +39,9 @@ const ControlBar = React.forwardRef(({ onToggleSpeedMenu, onToggleSideDrawer, onToggleOptionsMenu, + videoScale, + videoScaleLabel, + onVideoScaleChanged, onToggleStatisticsMenu, onTouchEnd, ...props @@ -176,6 +179,9 @@ const ControlBar = React.forwardRef(({ : null } + @@ -194,6 +200,9 @@ ControlBar.propTypes = { volume: PropTypes.number, muted: PropTypes.bool, playbackSpeed: PropTypes.number, + videoScale: PropTypes.string, + videoScaleLabel: PropTypes.string, + onVideoScaleChanged: PropTypes.func, subtitlesTracks: PropTypes.array, audioTracks: PropTypes.array, metaItem: PropTypes.object, diff --git a/src/routes/Player/Indicator/Indicator.tsx b/src/routes/Player/Indicator/Indicator.tsx index 7525fe1cd..b9290ad64 100644 --- a/src/routes/Player/Indicator/Indicator.tsx +++ b/src/routes/Player/Indicator/Indicator.tsx @@ -7,7 +7,13 @@ import styles from './Indicator.less'; type Property = { label: string, - format: (value: number) => string, + format: (value: number | string) => string, +}; + +const VIDEO_SCALE_LABELS: Record = { + 'contain': 'Fit', + 'cover': 'Crop', + 'fill': 'Stretch', }; const PROPERTIES: Record = { @@ -15,9 +21,13 @@ const PROPERTIES: Record = { label: 'SUBTITLES_DELAY', format: (value) => `${(value / 1000).toFixed(2)}s`, }, + 'videoScale': { + label: 'VIDEO_SCALE', + format: (value) => VIDEO_SCALE_LABELS[String(value)] || String(value), + }, }; -type VideoState = Record; +type VideoState = Record; type Props = { className: string, diff --git a/src/routes/Player/Player.js b/src/routes/Player/Player.js index c31272398..2ef6db67a 100644 --- a/src/routes/Player/Player.js +++ b/src/routes/Player/Player.js @@ -98,6 +98,9 @@ const Player = ({ urlParams, queryParams }) => { const isNavigating = React.useRef(false); + const VIDEO_SCALES = ['contain', 'cover', 'fill']; + const VIDEO_SCALE_LABELS = { contain: 'Fit', cover: 'Crop', fill: 'Stretch' }; + const playbackSpeed = React.useRef(video.state.playbackSpeed || 1); const pressTimer = React.useRef(null); const longPress = React.useRef(false); @@ -236,6 +239,13 @@ const Player = ({ urlParams, queryParams }) => { }, []); + const onVideoScaleChanged = React.useCallback(() => { + const currentScale = video.state.videoScale || 'contain'; + const currentIndex = VIDEO_SCALES.indexOf(currentScale); + const nextScale = VIDEO_SCALES[(currentIndex + 1) % VIDEO_SCALES.length]; + video.setVideoScale(nextScale); + }, [video.state.videoScale]); + const onSubtitlesTrackSelected = React.useCallback((track) => { video.setSubtitlesTrack(track?.id ?? null); streamStateChanged({ @@ -956,6 +966,9 @@ const Player = ({ urlParams, queryParams }) => { onToggleSubtitlesMenu={toggleSubtitlesMenu} onToggleAudioMenu={toggleAudioMenu} onToggleSpeedMenu={toggleSpeedMenu} + videoScale={video.state.videoScale} + videoScaleLabel={VIDEO_SCALE_LABELS[video.state.videoScale || 'contain']} + onVideoScaleChanged={onVideoScaleChanged} onToggleStatisticsMenu={toggleStatisticsMenu} onToggleSideDrawer={toggleSideDrawer} onMouseMove={onBarMouseMove} diff --git a/src/routes/Player/useVideo.js b/src/routes/Player/useVideo.js index bfa8ddf94..241a5af00 100644 --- a/src/routes/Player/useVideo.js +++ b/src/routes/Player/useVideo.js @@ -143,6 +143,10 @@ const useVideo = () => { setProp('extraSubtitlesOffset', offset); }; + const setVideoScale = (scale) => { + setProp('videoScale', scale); + }; + const setSubtitlesTextColor = (color) => { setProp('subtitlesTextColor', color); setProp('extraSubtitlesTextColor', color); @@ -239,6 +243,7 @@ const useVideo = () => { setSubtitlesBackgroundColor, setSubtitlesOutlineColor, setExtraSubtitlesTrack, + setVideoScale, }; };