Merge branch 'br-img' of https://github.com/dav1312/stremio-web into pr/1231

This commit is contained in:
Timothy Z. 2026-04-28 11:40:36 +03:00
commit 4107366094
7 changed files with 64 additions and 18 deletions

View file

@ -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#c23317eec194b5a3318e98c2ea6acae5cfa32e2a",
"stremio-translations": "github:Stremio/stremio-translations#fcad3f8077db865bd08b0f93d785f4090f19db40",
"url": "0.11.4",
"use-long-press": "^3.2.0"
},

View file

@ -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#c23317eec194b5a3318e98c2ea6acae5cfa32e2a
version: https://codeload.github.com/Stremio/stremio-translations/tar.gz/c23317eec194b5a3318e98c2ea6acae5cfa32e2a
specifier: github:Stremio/stremio-translations#fcad3f8077db865bd08b0f93d785f4090f19db40
version: https://codeload.github.com/Stremio/stremio-translations/tar.gz/fcad3f8077db865bd08b0f93d785f4090f19db40
url:
specifier: 0.11.4
version: 0.11.4
@ -4133,8 +4133,8 @@ packages:
resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
engines: {node: '>= 0.4'}
stremio-translations@https://codeload.github.com/Stremio/stremio-translations/tar.gz/c23317eec194b5a3318e98c2ea6acae5cfa32e2a:
resolution: {tarball: https://codeload.github.com/Stremio/stremio-translations/tar.gz/c23317eec194b5a3318e98c2ea6acae5cfa32e2a}
stremio-translations@https://codeload.github.com/Stremio/stremio-translations/tar.gz/fcad3f8077db865bd08b0f93d785f4090f19db40:
resolution: {tarball: https://codeload.github.com/Stremio/stremio-translations/tar.gz/fcad3f8077db865bd08b0f93d785f4090f19db40}
version: 1.51.0
string-length@4.0.2:
@ -9378,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/c23317eec194b5a3318e98c2ea6acae5cfa32e2a: {}
stremio-translations@https://codeload.github.com/Stremio/stremio-translations/tar.gz/fcad3f8077db865bd08b0f93d785f4090f19db40: {}
string-length@4.0.2:
dependencies:

View file

@ -19,10 +19,20 @@ type Props = {
onShortcut: (name: ShortcutName) => void,
};
const REPEAT_THROTTLE_MS = 130;
const ShortcutsProvider = ({ children, onShortcut }: Props) => {
const listeners = useRef<Map<ShortcutName, Set<ShortcutListener>>>(new Map());
const lastRepeatTime = useRef<Map<string, number>>(new Map());
const onKeyDown = useCallback(({ ctrlKey, shiftKey, code, key, repeat }: KeyboardEvent) => {
if (repeat) {
const now = Date.now();
const last = lastRepeatTime.current.get(code) ?? 0;
if (now - last < REPEAT_THROTTLE_MS) return;
lastRepeatTime.current.set(code, now);
}
const onKeyDown = useCallback(({ ctrlKey, shiftKey, code, key }: KeyboardEvent) => {
SHORTCUTS.forEach(({ name, combos }) => combos.forEach((keys) => {
const modifers = (keys.includes('Ctrl') ? ctrlKey : true)
&& (keys.includes('Shift') ? shiftKey : true);

View file

@ -1,6 +1,7 @@
// Copyright (C) 2017-2025 Smart code 203358507
import React, { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import useRating from './useRating';
import { ActionsGroup } from 'stremio/components';
@ -11,17 +12,20 @@ type Props = {
};
const Ratings = ({ ratingInfo, className }: Props) => {
const { t } = useTranslation();
const { onLiked, onLoved, liked, loved } = useRating(ratingInfo);
const disabled = useMemo(() => ratingInfo?.type !== 'Ready', [ratingInfo]);
const items = useMemo(() => [
{
icon: liked ? 'thumbs-up' : 'thumbs-up-outline',
label: liked ? t('RATING_UNLIKE') : t('RATING_LIKE'),
disabled,
onClick: onLiked,
},
{
icon: loved ? 'heart' : 'heart-outline',
label: loved ? t('RATING_UNLOVE') : t('RATING_LOVE'),
disabled,
onClick: onLoved,
},

View file

@ -32,7 +32,7 @@
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
object-position: right;
opacity: 0.3;
}
}
@ -137,6 +137,12 @@
@media only screen and (max-width: @minimum) {
.metadetails-container {
.background-image-layer {
.background-image {
object-position: center;
}
}
.metadetails-content {
display: block;
overflow-y: auto;

View file

@ -91,7 +91,7 @@ const Player = ({ urlParams, queryParams }) => {
const nextVideoPopupDismissed = React.useRef(false);
const defaultSubtitlesSelected = React.useRef(false);
const subtitlesEnabled = React.useRef(true);
const lastSubtitleTrack = React.useRef(null);
const defaultAudioTrackSelected = React.useRef(false);
const playingOnExternalDevice = React.useRef(false);
const [error, setError] = React.useState(null);
@ -247,14 +247,22 @@ const Player = ({ urlParams, queryParams }) => {
}, [video.state.videoScale]);
const onSubtitlesTrackSelected = React.useCallback((track) => {
defaultSubtitlesSelected.current = true;
video.setSubtitlesTrack(track?.id ?? null);
if (track) {
lastSubtitleTrack.current = { id: track.id, embedded: true };
}
streamStateChanged({
subtitleTrack: track ? { id: track.id, embedded: true, lang: track.lang } : null,
});
}, [streamStateChanged]);
const onExtraSubtitlesTrackSelected = React.useCallback((track) => {
defaultSubtitlesSelected.current = true;
video.setExtraSubtitlesTrack(track?.id ?? null);
if (track) {
lastSubtitleTrack.current = { id: track.id, embedded: false };
}
streamStateChanged({
subtitleTrack: track ? { id: track.id, embedded: false, lang: track.lang } : null,
});
@ -538,6 +546,7 @@ const Player = ({ urlParams, queryParams }) => {
React.useEffect(() => {
defaultSubtitlesSelected.current = false;
defaultAudioTrackSelected.current = false;
lastSubtitleTrack.current = null;
nextVideoPopupDismissed.current = false;
playingOnExternalDevice.current = false;
// we need a timeout here to make sure that previous page unloads and the new one loads
@ -660,7 +669,7 @@ const Player = ({ urlParams, queryParams }) => {
onShortcut('volumeDown', () => {
if (video.state.volume !== null) {
onVolumeChangeRequested(Math.min(video.state.volume - 5, 200));
onVolumeChangeRequested(Math.max(video.state.volume - 5, 0));
}
}, [video.state.volume], !menusOpen);
@ -669,21 +678,27 @@ const Player = ({ urlParams, queryParams }) => {
}, [onIncreaseSubtitlesDelay, onDecreaseSubtitlesDelay], !menusOpen);
onShortcut('subtitlesSize', (combo) => {
combo === 1 ? onUpdateSubtitlesSize(-1) : onUpdateSubtitlesSize(1);
combo === 1 ? onUpdateSubtitlesSize(1) : onUpdateSubtitlesSize(-1);
}, [onUpdateSubtitlesSize, onUpdateSubtitlesSize], !menusOpen);
onShortcut('toggleSubtitles', () => {
const savedTrack = player.streamState?.subtitleTrack;
const isEnabled = video.state.selectedSubtitlesTrackId !== null || video.state.selectedExtraSubtitlesTrackId !== null;
if (subtitlesEnabled.current) {
if (isEnabled) {
if (video.state.selectedSubtitlesTrackId) {
lastSubtitleTrack.current = { id: video.state.selectedSubtitlesTrackId, embedded: true };
} else if (video.state.selectedExtraSubtitlesTrackId) {
lastSubtitleTrack.current = { id: video.state.selectedExtraSubtitlesTrackId, embedded: false };
}
video.setSubtitlesTrack(null);
video.setExtraSubtitlesTrack(null);
} else if (savedTrack?.id) {
savedTrack.embedded ? video.setSubtitlesTrack(savedTrack.id) : video.setExtraSubtitlesTrack(savedTrack.id);
} else {
const savedTrack = player.streamState?.subtitleTrack ?? lastSubtitleTrack.current;
if (savedTrack?.id) {
savedTrack.embedded ? video.setSubtitlesTrack(savedTrack.id) : video.setExtraSubtitlesTrack(savedTrack.id);
}
}
subtitlesEnabled.current = !subtitlesEnabled.current;
}, [player.streamState], !menusOpen);
}, [player.streamState, video.state.selectedSubtitlesTrackId, video.state.selectedExtraSubtitlesTrackId], !menusOpen);
onShortcut('subtitlesMenu', () => {
closeMenus();

View file

@ -24,6 +24,17 @@
transition: transform 0.3s ease-in-out;
z-index: 1;
// Safari has a compositing bug where transform animations on a parent with
// scrollable children causes the video player element to shift left during the animation.
// Disable the slide animation on Safari until WebKit resolves this.
@supports (hanging-punctuation: first) and (-webkit-appearance: none) {
&:global(.slide-left-enter),
&:global(.slide-left-active),
&:global(.slide-left-exit) {
transition: none;
}
}
.close-button {
display: none;
position: absolute;