From 3df8eb65d020940623b00cbfa94134dd9adb21e3 Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 8 Jan 2025 20:41:55 +0100 Subject: [PATCH 01/99] feat: allow to drop local subtitles --- src/common/CONSTANTS.js | 6 ++++ src/common/index.js | 2 ++ src/common/onFileDrop.ts | 31 +++++++++++++++++++ src/routes/Player/Player.js | 12 +++++-- .../Player/SubtitlesMenu/SubtitlesMenu.js | 12 +++++-- src/routes/Player/useVideo.js | 12 +++++++ src/services/DragAndDrop/DragAndDrop.js | 4 +++ 7 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 src/common/onFileDrop.ts diff --git a/src/common/CONSTANTS.js b/src/common/CONSTANTS.js index 727c152fa..ea88b0114 100644 --- a/src/common/CONSTANTS.js +++ b/src/common/CONSTANTS.js @@ -41,6 +41,11 @@ const ICON_FOR_TYPE = new Map([ ['other', 'movies'], ]); +const SUPPORTED_LOCAL_SUBTITLES = [ + 'application/x-subrip', + 'text/vtt', +]; + const EXTERNAL_PLAYERS = [ { label: 'EXTERNAL_PLAYER_DISABLED', @@ -113,6 +118,7 @@ module.exports = { WRITERS_LINK_CATEGORY, TYPE_PRIORITIES, ICON_FOR_TYPE, + SUPPORTED_LOCAL_SUBTITLES, EXTERNAL_PLAYERS, WHITELISTED_HOSTS, }; diff --git a/src/common/index.js b/src/common/index.js index 4c514dfbe..2dba2ad54 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -13,6 +13,7 @@ const languages = require('./languages'); const routesRegexp = require('./routesRegexp'); const useAnimationFrame = require('./useAnimationFrame'); const useBinaryState = require('./useBinaryState'); +const { default: onFileDrop } = require('./onFileDrop'); const useFullscreen = require('./useFullscreen'); const useLiveRef = require('./useLiveRef'); const useModelState = require('./useModelState'); @@ -41,6 +42,7 @@ module.exports = { routesRegexp, useAnimationFrame, useBinaryState, + onFileDrop, useFullscreen, useLiveRef, useModelState, diff --git a/src/common/onFileDrop.ts b/src/common/onFileDrop.ts new file mode 100644 index 000000000..0060a975a --- /dev/null +++ b/src/common/onFileDrop.ts @@ -0,0 +1,31 @@ +import { useEffect } from 'react'; + +const onFileDrop = (types: string[], callback: (file: File) => void) => { + const onDragOver = (event: DragEvent) => { + event.preventDefault(); + }; + + const onDrop = (event: DragEvent) => { + event.preventDefault(); + + if (event.dataTransfer && event.dataTransfer.files.length > 0) { + const file = event.dataTransfer.files[0]; + + if (types.includes(file.type)) { + callback(file); + } + } + }; + + useEffect(() => { + window.addEventListener('dragover', onDragOver); + window.addEventListener('drop', onDrop); + + return () => { + window.removeEventListener('dragover', onDragOver); + window.removeEventListener('drop', onDrop); + }; + }, []); +}; + +export default onFileDrop; diff --git a/src/routes/Player/Player.js b/src/routes/Player/Player.js index c76a8dcae..86867d3c0 100644 --- a/src/routes/Player/Player.js +++ b/src/routes/Player/Player.js @@ -8,7 +8,7 @@ const langs = require('langs'); const { useTranslation } = require('react-i18next'); const { useRouteFocused } = require('stremio-router'); const { useServices } = require('stremio/services'); -const { useFullscreen, useBinaryState, useToast, useStreamingServer, withCoreSuspender } = require('stremio/common'); +const { onFileDrop, useFullscreen, useBinaryState, useToast, useStreamingServer, withCoreSuspender, CONSTANTS } = require('stremio/common'); const { HorizontalNavBar, Transition } = require('stremio/components'); const BufferingLoader = require('./BufferingLoader'); const VolumeChangeIndicator = require('./VolumeChangeIndicator'); @@ -133,7 +133,10 @@ const Player = ({ urlParams, queryParams }) => { toast.show({ type: 'success', title: t('PLAYER_SUBTITLES_LOADED'), - message: track.exclusive ? t('PLAYER_SUBTITLES_LOADED_EXCLUSIVE') : t('PLAYER_SUBTITLES_LOADED_ORIGIN', { origin: track.origin }), + message: + track.exclusive ? t('PLAYER_SUBTITLES_LOADED_EXCLUSIVE') : + track.local ? t('PLAYER_SUBTITLES_LOADED_LOCAL') : + t('PLAYER_SUBTITLES_LOADED_ORIGIN', { origin: track.origin }), timeout: 3000 }); }, []); @@ -270,6 +273,11 @@ const Player = ({ urlParams, queryParams }) => { event.nativeEvent.immersePrevented = true; }, []); + onFileDrop(CONSTANTS.SUPPORTED_LOCAL_SUBTITLES, async (file) => { + const buffer = await file.arrayBuffer(); + video.addLocalSubtitles(file.name, buffer); + }); + React.useEffect(() => { setError(null); video.unload(); diff --git a/src/routes/Player/SubtitlesMenu/SubtitlesMenu.js b/src/routes/Player/SubtitlesMenu/SubtitlesMenu.js index 44cd20864..72de44e0b 100644 --- a/src/routes/Player/SubtitlesMenu/SubtitlesMenu.js +++ b/src/routes/Player/SubtitlesMenu/SubtitlesMenu.js @@ -10,11 +10,13 @@ const styles = require('./styles'); const { t } = require('i18next'); const ORIGIN_PRIORITIES = { + 'LOCAL': 3, 'EMBEDDED': 2, - 'EXCLUSIVE': 1 + 'EXCLUSIVE': 1, }; const LANGUAGE_PRIORITIES = { - 'eng': 1 + 'local': 2, + 'eng': 1, }; const SubtitlesMenu = React.memo((props) => { @@ -161,7 +163,11 @@ const SubtitlesMenu = React.memo((props) => { {subtitlesLanguages.map((lang, index) => ( + ); - }, [watched, toggleWatchedOnClick]); + }, [watched, seasonWatched, toggleWatchedOnClick]); React.useEffect(() => { if (!routeFocused) { closeMenu(); @@ -182,17 +191,20 @@ Video.propTypes = { id: PropTypes.string, title: PropTypes.string, thumbnail: PropTypes.string, + season: PropTypes.number, episode: PropTypes.number, released: PropTypes.instanceOf(Date), upcoming: PropTypes.bool, watched: PropTypes.bool, progress: PropTypes.number, scheduled: PropTypes.bool, + seasonWatched: PropTypes.bool, deepLinks: PropTypes.shape({ metaDetailsStreams: PropTypes.string, player: PropTypes.string }), onMarkVideoAsWatched: PropTypes.func, + onMarkSeasonAsWatched: PropTypes.func, }; module.exports = Video; diff --git a/src/routes/MetaDetails/VideosList/VideosList.js b/src/routes/MetaDetails/VideosList/VideosList.js index 999a1a1ae..557b3df1f 100644 --- a/src/routes/MetaDetails/VideosList/VideosList.js +++ b/src/routes/MetaDetails/VideosList/VideosList.js @@ -56,6 +56,11 @@ const VideosList = ({ className, metaItem, libraryItem, season, seasonOnSelect, return a.episode - b.episode; }); }, [videos, selectedSeason]); + + const seasonWatched = React.useMemo(() => { + return videosForSeason.every((video) => video.watched); + }, [videosForSeason]); + const [search, setSearch] = React.useState(''); const searchInputOnChange = React.useCallback((event) => { setSearch(event.currentTarget.value); @@ -71,6 +76,16 @@ const VideosList = ({ className, metaItem, libraryItem, season, seasonOnSelect, }); }; + const onMarkSeasonAsWatched = (season, watched) => { + core.transport.dispatch({ + action: 'MetaDetails', + args: { + action: 'MarkSeasonAsWatched', + args: [season, !watched] + } + }); + }; + return (
{ @@ -135,6 +150,7 @@ const VideosList = ({ className, metaItem, libraryItem, season, seasonOnSelect, id={video.id} title={video.title} thumbnail={video.thumbnail} + season={video.season} episode={video.episode} released={video.released} upcoming={video.upcoming} @@ -142,7 +158,9 @@ const VideosList = ({ className, metaItem, libraryItem, season, seasonOnSelect, progress={video.progress} deepLinks={video.deepLinks} scheduled={video.scheduled} + seasonWatched={seasonWatched} onMarkVideoAsWatched={onMarkVideoAsWatched} + onMarkSeasonAsWatched={onMarkSeasonAsWatched} /> )) } diff --git a/src/routes/Player/SideDrawer/SideDrawer.tsx b/src/routes/Player/SideDrawer/SideDrawer.tsx index 9ed713879..332ead719 100644 --- a/src/routes/Player/SideDrawer/SideDrawer.tsx +++ b/src/routes/Player/SideDrawer/SideDrawer.tsx @@ -47,6 +47,10 @@ const SideDrawer = memo(forwardRef(({ seriesInfo, classNa setSeason(parseInt(event.value)); }, []); + const seasonWatched = React.useMemo(() => { + return videos.every((video) => video.watched); + }, [videos]); + const onMarkVideoAsWatched = useCallback((video: Video, watched: boolean) => { core.transport.dispatch({ action: 'Player', @@ -57,6 +61,16 @@ const SideDrawer = memo(forwardRef(({ seriesInfo, classNa }); }, []); + const onMarkSeasonAsWatched = (season: number, watched: boolean) => { + core.transport.dispatch({ + action: 'MetaDetails', + args: { + action: 'MarkSeasonAsWatched', + args: [season, !watched] + } + }); + }; + const onMouseDown = (event: React.MouseEvent) => { event.stopPropagation(); }; @@ -95,14 +109,17 @@ const SideDrawer = memo(forwardRef(({ seriesInfo, classNa id={video.id} title={video.title} thumbnail={video.thumbnail} + season={video.season} episode={video.episode} released={video.released} upcoming={video.upcoming} watched={video.watched} + seasonWatched={seasonWatched} progress={video.progress} deepLinks={video.deepLinks} scheduled={video.scheduled} onMarkVideoAsWatched={onMarkVideoAsWatched} + onMarkSeasonAsWatched={onMarkSeasonAsWatched} /> ))}
From 0a1278b494863d2d82fa35a3deae4280656fa958 Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 29 Jan 2025 19:04:33 +0100 Subject: [PATCH 09/99] build: remove commit hash from images path --- webpack.config.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/webpack.config.js b/webpack.config.js index 878d52f97..751c5cbb6 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -163,7 +163,7 @@ module.exports = (env, argv) => ({ exclude: /node_modules/, type: 'asset/resource', generator: { - filename: `${COMMIT_HASH}/images/[name][ext][query]` + filename: 'images/[name][ext][query]' } }, { @@ -231,9 +231,9 @@ module.exports = (env, argv) => ({ }), new CopyWebpackPlugin({ patterns: [ - { from: 'favicons', to: `${COMMIT_HASH}/favicons` }, - { from: 'images', to: `${COMMIT_HASH}/images` }, - { from: 'screenshots/*.webp', to: `${COMMIT_HASH}` }, + { from: 'favicons', to: 'favicons' }, + { from: 'images', to: 'images' }, + { from: 'screenshots/*.webp', to: './' }, ] }), new MiniCssExtractPlugin({ @@ -243,8 +243,8 @@ module.exports = (env, argv) => ({ template: './src/index.html', inject: false, scriptLoading: 'blocking', - faviconsPath: `${COMMIT_HASH}/favicons`, - imagesPath: `${COMMIT_HASH}/images`, + faviconsPath: 'favicons', + imagesPath: '$images', }), new WebpackPwaManifest({ name: 'Stremio Web', @@ -261,33 +261,33 @@ module.exports = (env, argv) => ({ icons: [ { src: 'images/icon.png', - destination: `${COMMIT_HASH}/icons`, + destination: 'icons', sizes: [196, 512], purpose: 'any' }, { src: 'images/maskable_icon.png', - destination: `${COMMIT_HASH}/maskable_icons`, + destination: 'maskable_icons', sizes: [196, 512], purpose: 'maskable', ios: true }, { src: 'favicons/favicon.ico', - destination: `${COMMIT_HASH}/favicons`, + destination: 'favicons', sizes: [256], } ], screenshots : [ { - src: `${COMMIT_HASH}/screenshots/board_wide.webp`, + src: 'screenshots/board_wide.webp', sizes: '1440x900', type: 'image/webp', form_factor: 'wide', label: 'Homescreen of Stremio' }, { - src: `${COMMIT_HASH}/screenshots/board_narrow.webp`, + src: 'screenshots/board_narrow.webp', sizes: '414x896', type: 'image/webp', form_factor: 'narrow', From 7b8078421856cd5fe021469ec4831cd651b86206 Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 29 Jan 2025 23:56:48 +0100 Subject: [PATCH 10/99] feat: implement shell updater banner --- src/App/App.js | 2 + src/App/UpdaterBanner/UpdaterBanner.less | 39 +++++++++++++++++++ src/App/UpdaterBanner/UpdaterBanner.tsx | 49 ++++++++++++++++++++++++ src/App/UpdaterBanner/index.ts | 2 + src/App/styles.less | 8 ++++ src/common/animations.less | 13 +++++++ 6 files changed, 113 insertions(+) create mode 100644 src/App/UpdaterBanner/UpdaterBanner.less create mode 100644 src/App/UpdaterBanner/UpdaterBanner.tsx create mode 100644 src/App/UpdaterBanner/index.ts diff --git a/src/App/App.js b/src/App/App.js index 730e75f28..999da04a7 100644 --- a/src/App/App.js +++ b/src/App/App.js @@ -10,6 +10,7 @@ const { PlatformProvider, ToastProvider, TooltipProvider, CONSTANTS, withCoreSus const ServicesToaster = require('./ServicesToaster'); const DeepLinkHandler = require('./DeepLinkHandler'); const SearchParamsHandler = require('./SearchParamsHandler'); +const { default: UpdaterBanner } = require('./UpdaterBanner'); const ErrorDialog = require('./ErrorDialog'); const withProtectedRoutes = require('./withProtectedRoutes'); const routerViewsConfig = require('./routerViewsConfig'); @@ -168,6 +169,7 @@ const App = () => { + { + const { shell } = useServices(); + const [visible, show, hide] = useBinaryState(false); + + const onInstallClick = () => { + shell.transport && shell.transport.send('autoupdater-notif-clicked'); + }; + + useEffect(() => { + shell.on('autoupdater-show-notif', show); + + return () => { + shell.off('autoupdater-show-notif', show); + }; + }); + + return ( +
+ +
+
+ A new version of Stremio is available +
+
+ + +
+
+
+
+ ); +}; + +export default UpdaterBanner; diff --git a/src/App/UpdaterBanner/index.ts b/src/App/UpdaterBanner/index.ts new file mode 100644 index 000000000..e4306ecb2 --- /dev/null +++ b/src/App/UpdaterBanner/index.ts @@ -0,0 +1,2 @@ +import UpdaterBanner from './UpdaterBanner'; +export default UpdaterBanner; diff --git a/src/App/styles.less b/src/App/styles.less index a413ed163..e2eed685a 100644 --- a/src/App/styles.less +++ b/src/App/styles.less @@ -208,6 +208,14 @@ html { } } + .updater-banner-container { + z-index: 1; + position: absolute; + left: 0; + right: 0; + bottom: 0; + } + .router { width: 100%; height: 100%; diff --git a/src/common/animations.less b/src/common/animations.less index c7a30d2fb..91dbe386d 100644 --- a/src/common/animations.less +++ b/src/common/animations.less @@ -69,6 +69,19 @@ transform: translateX(100%); } +.slide-up-enter { + transform: translateY(100%); +} + +.slide-up-active { + transform: translateY(0%); + transition: transform 0.3s cubic-bezier(0.32, 0, 0.67, 0); +} + +.slide-up-exit { + transform: translateY(100%); +} + @keyframes fade-in-no-motion { 0% { opacity: 0; From e5882ea143359d53f5af44c07b98070eb4d23c88 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 30 Jan 2025 11:10:45 +0100 Subject: [PATCH 11/99] refactor(App): update updater banner style --- src/App/UpdaterBanner/UpdaterBanner.less | 49 ++++++++++++++---------- src/App/UpdaterBanner/UpdaterBanner.tsx | 16 ++++---- 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/src/App/UpdaterBanner/UpdaterBanner.less b/src/App/UpdaterBanner/UpdaterBanner.less index 83956ef50..9928fb493 100644 --- a/src/App/UpdaterBanner/UpdaterBanner.less +++ b/src/App/UpdaterBanner/UpdaterBanner.less @@ -2,38 +2,45 @@ height: 4rem; display: flex; align-items: center; - justify-content: space-between; + justify-content: center; + gap: 1rem; padding: 0 1rem; font-size: 1rem; font-weight: bold; color: var(--primary-foreground-color); background-color: var(--primary-accent-color); - .buttons { + .button { display: flex; flex-direction: row; - gap: 0.75rem; + align-items: center; + justify-content: center; + height: 2.5rem; + padding: 0 1rem; + border-radius: var(--border-radius); + color: var(--primary-background-color); + background-color: var(--primary-foreground-color); + transition: all 0.1s ease-out; - .button { - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - height: 2.75rem; - padding: 0 1rem; - border-radius: var(--border-radius); - transition: all 0.1s ease-out; + &:hover { + color: var(--primary-foreground-color); + background-color: transparent; + box-shadow: inset 0 0 0 0.15rem var(--primary-foreground-color); + } + } - &.suggested { - color: var(--primary-background-color); - background-color: var(--primary-foreground-color); - } + .close { + position: absolute; + right: 0; + height: 4rem; + width: 4rem; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; - &:hover { - color: var(--primary-foreground-color); - background-color: transparent; - box-shadow: inset 0 0 0 0.15rem var(--primary-foreground-color); - } + .icon { + height: 2rem; } } } \ No newline at end of file diff --git a/src/App/UpdaterBanner/UpdaterBanner.tsx b/src/App/UpdaterBanner/UpdaterBanner.tsx index bf18077a8..a6b48066d 100644 --- a/src/App/UpdaterBanner/UpdaterBanner.tsx +++ b/src/App/UpdaterBanner/UpdaterBanner.tsx @@ -1,9 +1,9 @@ import React, { useEffect } from 'react'; +import Icon from '@stremio/stremio-icons/react'; import { useServices } from 'stremio/services'; import { useBinaryState } from 'stremio/common'; import { Button, Transition } from 'stremio/components'; import styles from './UpdaterBanner.less'; -import classNames from 'classnames'; type Props = { className: string, @@ -32,14 +32,12 @@ const UpdaterBanner = ({ className }: Props) => {
A new version of Stremio is available
-
- - -
+ + From 77e283d9344b5242b54d58fec2a70df50d918ec2 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 30 Jan 2025 14:57:37 +0100 Subject: [PATCH 12/99] refactor: use useShell hook for UpdaterBanner --- src/App/UpdaterBanner/UpdaterBanner.tsx | 9 +++++---- src/common/Platform/Platform.tsx | 2 +- src/common/index.js | 2 ++ src/common/{Platform => }/useShell.ts | 0 4 files changed, 8 insertions(+), 5 deletions(-) rename src/common/{Platform => }/useShell.ts (100%) diff --git a/src/App/UpdaterBanner/UpdaterBanner.tsx b/src/App/UpdaterBanner/UpdaterBanner.tsx index a6b48066d..cf80c198a 100644 --- a/src/App/UpdaterBanner/UpdaterBanner.tsx +++ b/src/App/UpdaterBanner/UpdaterBanner.tsx @@ -1,7 +1,7 @@ import React, { useEffect } from 'react'; import Icon from '@stremio/stremio-icons/react'; import { useServices } from 'stremio/services'; -import { useBinaryState } from 'stremio/common'; +import { useBinaryState, useShell } from 'stremio/common'; import { Button, Transition } from 'stremio/components'; import styles from './UpdaterBanner.less'; @@ -11,17 +11,18 @@ type Props = { const UpdaterBanner = ({ className }: Props) => { const { shell } = useServices(); + const shellTransport = useShell(); const [visible, show, hide] = useBinaryState(false); const onInstallClick = () => { - shell.transport && shell.transport.send('autoupdater-notif-clicked'); + shellTransport.send('autoupdater-notif-clicked'); }; useEffect(() => { - shell.on('autoupdater-show-notif', show); + shell.transport && shell.transport.on('autoupdater-show-notif', show); return () => { - shell.off('autoupdater-show-notif', show); + shell.transport && shell.transport.off('autoupdater-show-notif', show); }; }); diff --git a/src/common/Platform/Platform.tsx b/src/common/Platform/Platform.tsx index 41e74b24f..375fe5e18 100644 --- a/src/common/Platform/Platform.tsx +++ b/src/common/Platform/Platform.tsx @@ -1,6 +1,6 @@ import React, { createContext, useContext } from 'react'; import { WHITELISTED_HOSTS } from 'stremio/common/CONSTANTS'; -import useShell from './useShell'; +import { useShell } from 'stremio/common'; import { name, isMobile } from './device'; interface PlatformContext { diff --git a/src/common/index.js b/src/common/index.js index 4c514dfbe..61d2a3933 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -19,6 +19,7 @@ const useModelState = require('./useModelState'); const useNotifications = require('./useNotifications'); const useOnScrollToBottom = require('./useOnScrollToBottom'); const useProfile = require('./useProfile'); +const { default: useShell } = require('./useShell'); const useStreamingServer = require('./useStreamingServer'); const useTorrent = require('./useTorrent'); const useTranslate = require('./useTranslate'); @@ -47,6 +48,7 @@ module.exports = { useNotifications, useOnScrollToBottom, useProfile, + useShell, useStreamingServer, useTorrent, useTranslate, diff --git a/src/common/Platform/useShell.ts b/src/common/useShell.ts similarity index 100% rename from src/common/Platform/useShell.ts rename to src/common/useShell.ts From e2b9114ecef90c5ae561f2163272c4b94fdcec71 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 30 Jan 2025 17:01:28 +0100 Subject: [PATCH 13/99] fix(Platform): import issue --- src/common/Platform/Platform.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/Platform/Platform.tsx b/src/common/Platform/Platform.tsx index 375fe5e18..2212303e4 100644 --- a/src/common/Platform/Platform.tsx +++ b/src/common/Platform/Platform.tsx @@ -1,6 +1,6 @@ import React, { createContext, useContext } from 'react'; import { WHITELISTED_HOSTS } from 'stremio/common/CONSTANTS'; -import { useShell } from 'stremio/common'; +import useShell from 'stremio/common/useShell'; import { name, isMobile } from './device'; interface PlatformContext { From a95f07f19d3652ce18eea8ffaa1c98bed53cc1f7 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 30 Jan 2025 17:02:24 +0100 Subject: [PATCH 14/99] fix(UpdateBanner): missing useEffect deps array --- src/App/UpdaterBanner/UpdaterBanner.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App/UpdaterBanner/UpdaterBanner.tsx b/src/App/UpdaterBanner/UpdaterBanner.tsx index cf80c198a..b3135a6c3 100644 --- a/src/App/UpdaterBanner/UpdaterBanner.tsx +++ b/src/App/UpdaterBanner/UpdaterBanner.tsx @@ -24,7 +24,7 @@ const UpdaterBanner = ({ className }: Props) => { return () => { shell.transport && shell.transport.off('autoupdater-show-notif', show); }; - }); + }, []); return (
From 74682ddb6f279e599ac82a9f79a0011d694b3a7d Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 31 Jan 2025 10:02:06 +0100 Subject: [PATCH 15/99] build: typo in HtmlWebPackPlugin imagesPath --- webpack.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webpack.config.js b/webpack.config.js index 751c5cbb6..36f6b6e50 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -244,7 +244,7 @@ module.exports = (env, argv) => ({ inject: false, scriptLoading: 'blocking', faviconsPath: 'favicons', - imagesPath: '$images', + imagesPath: 'images', }), new WebpackPwaManifest({ name: 'Stremio Web', From e13ec37227f1f0f167dc0127cf2ca261f9c1f579 Mon Sep 17 00:00:00 2001 From: Ivelin Megdanov Date: Mon, 3 Feb 2025 12:17:45 +0200 Subject: [PATCH 16/99] Added new maximum audio value for boosted audio --- src/routes/Player/ControlBar/VolumeSlider/VolumeSlider.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Player/ControlBar/VolumeSlider/VolumeSlider.js b/src/routes/Player/ControlBar/VolumeSlider/VolumeSlider.js index 420f4ba41..205b6f3af 100644 --- a/src/routes/Player/ControlBar/VolumeSlider/VolumeSlider.js +++ b/src/routes/Player/ControlBar/VolumeSlider/VolumeSlider.js @@ -50,7 +50,7 @@ const VolumeSlider = ({ className, volume, onVolumeChangeRequested }) => { 100 } minimumValue={0} - maximumValue={100} + maximumValue={200} disabled={disabled} onSlide={onSlide} onComplete={onComplete} From ad107ff98b43d5981fa7106f37cf068615d15e0a Mon Sep 17 00:00:00 2001 From: Ivelin Megdanov Date: Mon, 3 Feb 2025 12:19:40 +0200 Subject: [PATCH 17/99] Ensure Arrow Up-Down, and onWheel adjust volume correctly --- src/routes/Player/Player.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/routes/Player/Player.js b/src/routes/Player/Player.js index c76a8dcae..49e7ae4a2 100644 --- a/src/routes/Player/Player.js +++ b/src/routes/Player/Player.js @@ -494,14 +494,14 @@ const Player = ({ urlParams, queryParams }) => { } case 'ArrowUp': { if (!menusOpen && !nextVideoPopupOpen && video.state.volume !== null) { - onVolumeChangeRequested(video.state.volume + 5); + onVolumeChangeRequested(Math.min(video.state.volume + 5, 200)); } break; } case 'ArrowDown': { if (!menusOpen && !nextVideoPopupOpen && video.state.volume !== null) { - onVolumeChangeRequested(video.state.volume - 5); + onVolumeChangeRequested(Math.max(video.state.volume - 5, 0)); } break; @@ -559,13 +559,13 @@ const Player = ({ urlParams, queryParams }) => { } }; const onWheel = ({ deltaY }) => { + if (menusOpen || video.state.volume === null) return; + if (deltaY > 0) { - if (!menusOpen && video.state.volume !== null) { - onVolumeChangeRequested(video.state.volume - 5); - } + onVolumeChangeRequested(Math.max(video.state.volume - 5, 0)); } else { - if (!menusOpen && video.state.volume !== null) { - onVolumeChangeRequested(video.state.volume + 5); + if (video.state.volume < 100) { + onVolumeChangeRequested(Math.min(video.state.volume + 5, 100)); } } }; From 2f010168a3bb5df7b44c3ff91c31b4424261eb70 Mon Sep 17 00:00:00 2001 From: Ivelin Megdanov Date: Mon, 3 Feb 2025 12:22:03 +0200 Subject: [PATCH 18/99] Enhance volume slider with warning & danger gradient for boosting --- src/App/styles.less | 2 ++ src/components/Slider/Slider.js | 16 +++++++--- src/components/Slider/styles.less | 31 +++++++++++++++++++ .../ControlBar/VolumeSlider/VolumeSlider.js | 1 + 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/App/styles.less b/src/App/styles.less index a413ed163..7e44a9643 100644 --- a/src/App/styles.less +++ b/src/App/styles.less @@ -63,6 +63,8 @@ --overlay-color: rgba(255, 255, 255, 0.05); --modal-background-color: rgba(15, 13, 32, 1); --outer-glow: 0px 0px 15px rgba(123, 91, 245, 0.37); + --warning-accent-color: rgba(255, 165, 0, 1); + --danger-accent-color: rgba(220, 38, 38, 1); --border-radius: 0.75rem; --top-overlay-size: @top-overlay-size; --bottom-overlay-size: @bottom-overlay-size; diff --git a/src/components/Slider/Slider.js b/src/components/Slider/Slider.js index 238b6ed86..66fab7006 100644 --- a/src/components/Slider/Slider.js +++ b/src/components/Slider/Slider.js @@ -8,7 +8,7 @@ const useAnimationFrame = require('stremio/common/useAnimationFrame'); const useLiveRef = require('stremio/common/useLiveRef'); const styles = require('./styles'); -const Slider = ({ className, value, buffered, minimumValue, maximumValue, disabled, onSlide, onComplete }) => { +const Slider = ({ className, value, buffered, minimumValue, maximumValue, disabled, onSlide, onComplete, isVolumeSlider }) => { const minimumValueRef = useLiveRef(minimumValue !== null && !isNaN(minimumValue) ? minimumValue : 0); const maximumValueRef = useLiveRef(maximumValue !== null && !isNaN(maximumValue) ? maximumValue : 100); const valueRef = useLiveRef(value !== null && !isNaN(value) ? Math.min(maximumValueRef.current, Math.max(minimumValueRef.current, value)) : 0); @@ -99,14 +99,19 @@ const Slider = ({ className, value, buffered, minimumValue, maximumValue, disabl const bufferedPosition = Math.max(0, Math.min(1, (bufferedRef.current - minimumValueRef.current) / (maximumValueRef.current - minimumValueRef.current))); return (
-
-
+
+
-
+
@@ -123,7 +128,8 @@ Slider.propTypes = { maximumValue: PropTypes.number, disabled: PropTypes.bool, onSlide: PropTypes.func, - onComplete: PropTypes.func + onComplete: PropTypes.func, + isVolumeSlider: PropTypes.bool }; module.exports = Slider; diff --git a/src/components/Slider/styles.less b/src/components/Slider/styles.less index 66ad267c7..be85b671f 100644 --- a/src/components/Slider/styles.less +++ b/src/components/Slider/styles.less @@ -58,6 +58,37 @@ html.active-slider-within { background-color: var(--primary-foreground-color); } + .volume-track { + background: linear-gradient(to right, + var(--primary-foreground-color) 0%, + var(--primary-foreground-color) 50%, + var(--warning-accent-color) 75%, + var(--danger-accent-color) 100%) !important; + opacity: 0.3; + filter: brightness(1.2); + } + + .volume-track-after { + background: linear-gradient(to right, + var(--primary-foreground-color) 0%, + var(--primary-foreground-color) 50%, + var(--warning-accent-color) 75%, + var(--danger-accent-color) 100%) !important; + + width: 100%; + mask-image: linear-gradient(to right, + black 0%, + black calc(var(--progress-width) - 2px), + transparent var(--progress-width) + ); + + -webkit-mask-image: linear-gradient(to right, + black 0%, + black calc(var(--progress-width) - 2px), + transparent var(--progress-width) + ); + } + .thumb { z-index: 3; flex: none; diff --git a/src/routes/Player/ControlBar/VolumeSlider/VolumeSlider.js b/src/routes/Player/ControlBar/VolumeSlider/VolumeSlider.js index 205b6f3af..47b6b829b 100644 --- a/src/routes/Player/ControlBar/VolumeSlider/VolumeSlider.js +++ b/src/routes/Player/ControlBar/VolumeSlider/VolumeSlider.js @@ -54,6 +54,7 @@ const VolumeSlider = ({ className, volume, onVolumeChangeRequested }) => { disabled={disabled} onSlide={onSlide} onComplete={onComplete} + isVolumeSlider /> ); }; From 3375415bdcb7ddd82cd5577ee1c8914f0418fe60 Mon Sep 17 00:00:00 2001 From: Ivelin Megdanov Date: Mon, 3 Feb 2025 13:12:56 +0200 Subject: [PATCH 19/99] Restrict new volume boost logic only when shell is active --- src/routes/Player/ControlBar/VolumeSlider/VolumeSlider.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/routes/Player/ControlBar/VolumeSlider/VolumeSlider.js b/src/routes/Player/ControlBar/VolumeSlider/VolumeSlider.js index 47b6b829b..5510ed247 100644 --- a/src/routes/Player/ControlBar/VolumeSlider/VolumeSlider.js +++ b/src/routes/Player/ControlBar/VolumeSlider/VolumeSlider.js @@ -5,13 +5,16 @@ const PropTypes = require('prop-types'); const classnames = require('classnames'); const debounce = require('lodash.debounce'); const { useRouteFocused } = require('stremio-router'); +const { useServices } = require('stremio/services'); const { Slider } = require('stremio/components'); const styles = require('./styles'); const VolumeSlider = ({ className, volume, onVolumeChangeRequested }) => { + const { shell } = useServices(); const disabled = volume === null || isNaN(volume); const routeFocused = useRouteFocused(); const [slidingVolume, setSlidingVolume] = React.useState(null); + const maxVolume = shell.active ? 200: 100; const resetVolumeDebounced = React.useCallback(debounce(() => { setSlidingVolume(null); }, 100), []); @@ -50,11 +53,11 @@ const VolumeSlider = ({ className, volume, onVolumeChangeRequested }) => { 100 } minimumValue={0} - maximumValue={200} + maximumValue={maxVolume} disabled={disabled} onSlide={onSlide} onComplete={onComplete} - isVolumeSlider + isVolumeSlider={!!shell.active} /> ); }; From f865bca9ea6f9e6f4ff359f1aa0357e097257894 Mon Sep 17 00:00:00 2001 From: Ivelin Megdanov Date: Mon, 3 Feb 2025 14:54:19 +0200 Subject: [PATCH 20/99] Fixed code format --- src/components/Slider/Slider.js | 6 +++--- src/routes/Player/Player.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/Slider/Slider.js b/src/components/Slider/Slider.js index 66fab7006..c14f87dac 100644 --- a/src/components/Slider/Slider.js +++ b/src/components/Slider/Slider.js @@ -99,15 +99,15 @@ const Slider = ({ className, value, buffered, minimumValue, maximumValue, disabl const bufferedPosition = Math.max(0, Math.min(1, (bufferedRef.current - minimumValueRef.current) / (maximumValueRef.current - minimumValueRef.current))); return (
-
+
-
{ onVolumeChangeRequested(Math.max(video.state.volume - 5, 0)); } else { if (video.state.volume < 100) { - onVolumeChangeRequested(Math.min(video.state.volume + 5, 100)); + onVolumeChangeRequested(Math.min(video.state.volume + 5, 100)); } } }; From 05486a35bf41b74318344cf791ded0264dd6a1db Mon Sep 17 00:00:00 2001 From: Ivelin Megdanov Date: Tue, 4 Feb 2025 16:05:12 +0200 Subject: [PATCH 21/99] Add preview for truncated stream names --- .../MetaDetails/StreamsList/Stream/Stream.js | 5 +++++ .../StreamsList/Stream/styles.less | 22 +++++++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/routes/MetaDetails/StreamsList/Stream/Stream.js b/src/routes/MetaDetails/StreamsList/Stream/Stream.js index 768b8d40a..41f81b386 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/Stream.js +++ b/src/routes/MetaDetails/StreamsList/Stream/Stream.js @@ -181,12 +181,17 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio const renderMenu = React.useMemo(() => function renderMenu() { return (
+
+ {description} +
{ streamLink && } diff --git a/src/routes/MetaDetails/StreamsList/Stream/styles.less b/src/routes/MetaDetails/StreamsList/Stream/styles.less index 0461c77ee..06720a879 100644 --- a/src/routes/MetaDetails/StreamsList/Stream/styles.less +++ b/src/routes/MetaDetails/StreamsList/Stream/styles.less @@ -111,12 +111,29 @@ background-color: var(--secondary-accent-color); } + .menu-icon { + flex: none; + width: 1.7rem; + height: 1.7rem; + margin-right: 1rem; + color: var(--color-placeholder); + } + .context-menu-container { max-width: calc(90% - 1.5rem); z-index: 2; .context-menu-content { --spatial-navigation-contain: contain; + + .context-menu-title { + font-size: 0.9rem; + padding: 1rem 1.5rem; + font-weight: 100; + border-bottom: 1px solid var(--color-placeholder); + color: var(--primary-foreground-color); + white-space: break-spaces; + } .context-menu-option-container { display: flex; @@ -131,8 +148,9 @@ .context-menu-option-label { font-size: 1rem; - font-weight: 500; - color:var(--primary-foreground-color); + font-weight: 300; + color: var(--primary-foreground-color); + text-transform: capitalize; } } } From d9da7d5ab788e06bf6e2db79f16f0c88ab477e6c Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 5 Feb 2025 15:00:06 +0100 Subject: [PATCH 22/99] feat: support hardware decoding --- src/routes/Player/Player.js | 3 ++- src/routes/Settings/Settings.js | 24 +++++++++++++----------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/routes/Player/Player.js b/src/routes/Player/Player.js index c76a8dcae..d727d6811 100644 --- a/src/routes/Player/Player.js +++ b/src/routes/Player/Player.js @@ -296,6 +296,7 @@ const Player = ({ urlParams, queryParams }) => { 0, forceTranscoding: forceTranscoding || casting, maxAudioChannels: settings.surroundSound ? 32 : 2, + hardwareDecoding: settings.hardwareDecoding, streamingServerURL: streamingServer.baseUrl ? casting ? streamingServer.baseUrl @@ -303,7 +304,7 @@ const Player = ({ urlParams, queryParams }) => { streamingServer.selected.transportUrl : null, - seriesInfo: player.seriesInfo + seriesInfo: player.seriesInfo, }, { chromecastTransport: chromecast.active ? chromecast.transport : null, shellTransport: shell.active ? shell.transport : null, diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index 24eaaaf5d..6ad15163a 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -488,17 +488,19 @@ const Settings = () => { {...playInExternalPlayerSelect} />
-
-
-
{ t('SETTINGS_HWDEC') }
-
- -
+ { + shell.active && +
+
+
{ t('SETTINGS_HWDEC') }
+
+ +
+ }
{ t('SETTINGS_NAV_STREAMING') }
From a68f7ddd53dfe1777575c21ab2acea643813a8f6 Mon Sep 17 00:00:00 2001 From: Alexandru Branza Date: Wed, 5 Feb 2025 16:49:31 +0200 Subject: [PATCH 23/99] Bump stremio-video --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4477c0b4f..d0c7ad763 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@stremio/stremio-colors": "5.2.0", "@stremio/stremio-core-web": "0.48.5", "@stremio/stremio-icons": "5.4.1", - "@stremio/stremio-video": "0.0.48", + "@stremio/stremio-video": "0.0.52", "a-color-picker": "1.2.1", "bowser": "2.11.0", "buffer": "6.0.3", @@ -3409,9 +3409,9 @@ ] }, "node_modules/@stremio/stremio-video": { - "version": "0.0.48", - "resolved": "https://registry.npmjs.org/@stremio/stremio-video/-/stremio-video-0.0.48.tgz", - "integrity": "sha512-6ALGXCZC4NPsfhPcrwFWQzvH6UMMRsgSkHetnOhv9WmZ5ubiyUdbBzj9atGiGuuQz8pRcze66ztrub+dsaQbpw==", + "version": "0.0.52", + "resolved": "https://registry.npmjs.org/@stremio/stremio-video/-/stremio-video-0.0.52.tgz", + "integrity": "sha512-OlHC8FIvYEyGXcNAM4W044Dqx6CmGb5BV3fDU361SyUjO9gKXXUWdL7LwmwHeWFeuy2sK1MEg4AT2JPptvJ0rg==", "license": "MIT", "dependencies": { "buffer": "6.0.3", diff --git a/package.json b/package.json index 9587f9530..e80305bc9 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "@stremio/stremio-colors": "5.2.0", "@stremio/stremio-core-web": "0.48.5", "@stremio/stremio-icons": "5.4.1", - "@stremio/stremio-video": "0.0.48", + "@stremio/stremio-video": "0.0.52", "a-color-picker": "1.2.1", "bowser": "2.11.0", "buffer": "6.0.3", From 4081396ae086036457a84dcb55d3132554cf9626 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Thu, 6 Feb 2025 12:16:29 +0200 Subject: [PATCH 24/99] feat: Player - Volume slider - on muted show 0 volume Signed-off-by: Lachezar Lechev --- src/routes/Player/ControlBar/ControlBar.js | 1 + .../Player/ControlBar/VolumeSlider/VolumeSlider.js | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/routes/Player/ControlBar/ControlBar.js b/src/routes/Player/ControlBar/ControlBar.js index 0fa6de1a4..745e2bd49 100644 --- a/src/routes/Player/ControlBar/ControlBar.js +++ b/src/routes/Player/ControlBar/ControlBar.js @@ -138,6 +138,7 @@ const ControlBar = ({
diff --git a/src/routes/Player/ControlBar/VolumeSlider/VolumeSlider.js b/src/routes/Player/ControlBar/VolumeSlider/VolumeSlider.js index 420f4ba41..a65ebfe9c 100644 --- a/src/routes/Player/ControlBar/VolumeSlider/VolumeSlider.js +++ b/src/routes/Player/ControlBar/VolumeSlider/VolumeSlider.js @@ -8,7 +8,7 @@ const { useRouteFocused } = require('stremio-router'); const { Slider } = require('stremio/components'); const styles = require('./styles'); -const VolumeSlider = ({ className, volume, onVolumeChangeRequested }) => { +const VolumeSlider = ({ className, volume, onVolumeChangeRequested, muted }) => { const disabled = volume === null || isNaN(volume); const routeFocused = useRouteFocused(); const [slidingVolume, setSlidingVolume] = React.useState(null); @@ -45,7 +45,9 @@ const VolumeSlider = ({ className, volume, onVolumeChangeRequested }) => { className={classnames(className, styles['volume-slider'], { 'active': slidingVolume !== null })} value={ !disabled ? - slidingVolume !== null ? slidingVolume : volume + !muted ? + slidingVolume !== null ? slidingVolume : volume + : 0 : 100 } @@ -61,7 +63,8 @@ const VolumeSlider = ({ className, volume, onVolumeChangeRequested }) => { VolumeSlider.propTypes = { className: PropTypes.string, volume: PropTypes.number, - onVolumeChangeRequested: PropTypes.func + onVolumeChangeRequested: PropTypes.func, + muted: PropTypes.bool, }; module.exports = VolumeSlider; From 9d18a1bb61d969b05f4034565f7b64cdb747e847 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 6 Feb 2025 18:10:34 +0100 Subject: [PATCH 25/99] fix: drop srt file with shell --- src/common/CONSTANTS.js | 6 ++++++ src/common/FileDrop/FileDrop.tsx | 16 ++++++++++------ src/common/FileDrop/utils.ts | 19 +++++++++++++++++++ src/routes/Player/Player.js | 5 ++--- src/services/DragAndDrop/DragAndDrop.js | 2 ++ 5 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 src/common/FileDrop/utils.ts diff --git a/src/common/CONSTANTS.js b/src/common/CONSTANTS.js index ea88b0114..8e4e3efdc 100644 --- a/src/common/CONSTANTS.js +++ b/src/common/CONSTANTS.js @@ -41,6 +41,11 @@ const ICON_FOR_TYPE = new Map([ ['other', 'movies'], ]); +const MIME_SIGNATURES = { + 'application/x-subrip': ['310D0A', '310A'], + 'text/vtt': ['574542565454'], +}; + const SUPPORTED_LOCAL_SUBTITLES = [ 'application/x-subrip', 'text/vtt', @@ -118,6 +123,7 @@ module.exports = { WRITERS_LINK_CATEGORY, TYPE_PRIORITIES, ICON_FOR_TYPE, + MIME_SIGNATURES, SUPPORTED_LOCAL_SUBTITLES, EXTERNAL_PLAYERS, WHITELISTED_HOSTS, diff --git a/src/common/FileDrop/FileDrop.tsx b/src/common/FileDrop/FileDrop.tsx index 9117a4c7a..aae4e146b 100644 --- a/src/common/FileDrop/FileDrop.tsx +++ b/src/common/FileDrop/FileDrop.tsx @@ -1,8 +1,9 @@ import React, { createContext, useCallback, useContext, useEffect, useState } from 'react'; import classNames from 'classnames'; +import { isFileType } from './utils'; export type FileType = string; -export type FileDropListener = (file: File) => void; +export type FileDropListener = (filename: string, buffer: ArrayBuffer) => void; type FileDropContext = { on: (type: FileType, listener: FileDropListener) => void, @@ -31,15 +32,18 @@ const FileDropProvider = ({ className, children }: Props) => { const onDrop = useCallback((event: DragEvent) => { event.preventDefault(); - const { dataTransfer } = event; - if (dataTransfer && dataTransfer.files.length > 0) { + if (dataTransfer && dataTransfer?.files.length > 0) { const file = dataTransfer.files[0]; - listeners - .filter(([type]) => type === file.type) - .forEach(([, listerner]) => listerner(file)); + file + .arrayBuffer() + .then((buffer) => { + listeners + .filter(([type]) => file.type ? type === file.type : isFileType(buffer, type)) + .forEach(([, listerner]) => listerner(file.name, buffer)); + }); } setActive(false); diff --git a/src/common/FileDrop/utils.ts b/src/common/FileDrop/utils.ts new file mode 100644 index 000000000..b5427ecfb --- /dev/null +++ b/src/common/FileDrop/utils.ts @@ -0,0 +1,19 @@ +import { MIME_SIGNATURES } from 'stremio/common/CONSTANTS'; + +const SIGNATURES = MIME_SIGNATURES as Record; + +const isFileType = (buffer: ArrayBuffer, type: string) => { + const signatures = SIGNATURES[type]; + + return signatures.some((signature) => { + const array = new Uint8Array(buffer); + const signatureBuffer = Buffer.from(signature, 'hex'); + const bufferToCompare = array.subarray(0, signatureBuffer.length); + + return Buffer.compare(signatureBuffer, bufferToCompare) === 0; + }); +}; + +export { + isFileType, +}; \ No newline at end of file diff --git a/src/routes/Player/Player.js b/src/routes/Player/Player.js index 5ea8975f0..4dbc12295 100644 --- a/src/routes/Player/Player.js +++ b/src/routes/Player/Player.js @@ -277,9 +277,8 @@ const Player = ({ urlParams, queryParams }) => { event.nativeEvent.immersePrevented = true; }, []); - onFileDrop(CONSTANTS.SUPPORTED_LOCAL_SUBTITLES, async (file) => { - const buffer = await file.arrayBuffer(); - video.addLocalSubtitles(file.name, buffer); + onFileDrop(CONSTANTS.SUPPORTED_LOCAL_SUBTITLES, async (filename, buffer) => { + video.addLocalSubtitles(filename, buffer); }); React.useEffect(() => { diff --git a/src/services/DragAndDrop/DragAndDrop.js b/src/services/DragAndDrop/DragAndDrop.js index 6e20a840e..1538c328e 100644 --- a/src/services/DragAndDrop/DragAndDrop.js +++ b/src/services/DragAndDrop/DragAndDrop.js @@ -40,6 +40,8 @@ function DragAndDrop({ core }) { break; case 'text/vtt': break; + case '': + break; default: { events.emit('error', { message: 'Unsupported file', From 330fac3f3987d484a04d1eab5e63844fc7ff4d63 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 6 Feb 2025 18:29:15 +0100 Subject: [PATCH 26/99] style: lint --- src/common/FileDrop/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/FileDrop/utils.ts b/src/common/FileDrop/utils.ts index b5427ecfb..f9996aed3 100644 --- a/src/common/FileDrop/utils.ts +++ b/src/common/FileDrop/utils.ts @@ -16,4 +16,4 @@ const isFileType = (buffer: ArrayBuffer, type: string) => { export { isFileType, -}; \ No newline at end of file +}; From 617b0e3125f7cf199d5ab96d8466cc1e84cdd896 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 7 Feb 2025 11:28:51 +0100 Subject: [PATCH 27/99] chore: update stremio-video and stremio-translations --- package-lock.json | 14 +++++++------- package.json | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index be53e9ec7..994e15d3c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@stremio/stremio-colors": "5.2.0", "@stremio/stremio-core-web": "0.48.4", "@stremio/stremio-icons": "5.4.1", - "@stremio/stremio-video": "0.0.48", + "@stremio/stremio-video": "github:Stremio/stremio-video#436fe5a988ab0953a61aa043666cae1dd9522882", "a-color-picker": "1.2.1", "bowser": "2.11.0", "buffer": "6.0.3", @@ -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#a0f50634202f748a57907b645d2cd92fbaa479dd", + "stremio-translations": "github:Stremio/stremio-translations#f7d327d822f1061947568042bfb3dffde5525a30", "url": "0.11.4", "use-long-press": "^3.2.0" }, @@ -3409,9 +3409,9 @@ ] }, "node_modules/@stremio/stremio-video": { - "version": "0.0.48", - "resolved": "https://registry.npmjs.org/@stremio/stremio-video/-/stremio-video-0.0.48.tgz", - "integrity": "sha512-6ALGXCZC4NPsfhPcrwFWQzvH6UMMRsgSkHetnOhv9WmZ5ubiyUdbBzj9atGiGuuQz8pRcze66ztrub+dsaQbpw==", + "version": "0.0.50", + "resolved": "git+ssh://git@github.com/Stremio/stremio-video.git#436fe5a988ab0953a61aa043666cae1dd9522882", + "integrity": "sha512-yKVKGl+qHTki2wAhJEauql2nKFDuX8bZXX5SrWLyNTI9cw/86UbQd7TEqvS2d9cBTMj9UrxQxMAG6zrKaSmwxg==", "license": "MIT", "dependencies": { "buffer": "6.0.3", @@ -13374,8 +13374,8 @@ }, "node_modules/stremio-translations": { "version": "1.44.9", - "resolved": "git+ssh://git@github.com/Stremio/stremio-translations.git#a0f50634202f748a57907b645d2cd92fbaa479dd", - "integrity": "sha512-JJpd1JJet3T6/VTNdZ2NZ7uvHJ4zkuyqo5BnTcDGqLVNO/OpicGqKhZjE4WGSgmuhsfPBU8T0ICCfzKu2xpvKg==", + "resolved": "git+ssh://git@github.com/Stremio/stremio-translations.git#f7d327d822f1061947568042bfb3dffde5525a30", + "integrity": "sha512-kqOI4fjs0yaG/LuEgR7IobDfi5GFZkjaYzEvHS+Cb822sE/BECHIRFVNWy05j4TNtwK60kSQX0KPrILRwKXD/Q==", "license": "MIT" }, "node_modules/string_decoder": { diff --git a/package.json b/package.json index 79593f9d5..1c061061b 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "@stremio/stremio-colors": "5.2.0", "@stremio/stremio-core-web": "0.48.4", "@stremio/stremio-icons": "5.4.1", - "@stremio/stremio-video": "0.0.48", + "@stremio/stremio-video": "github:Stremio/stremio-video#436fe5a988ab0953a61aa043666cae1dd9522882", "a-color-picker": "1.2.1", "bowser": "2.11.0", "buffer": "6.0.3", @@ -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#a0f50634202f748a57907b645d2cd92fbaa479dd", + "stremio-translations": "github:Stremio/stremio-translations#f7d327d822f1061947568042bfb3dffde5525a30", "url": "0.11.4", "use-long-press": "^3.2.0" }, From e2b2286c98739fde26d5b17ce8b811d4783cb311 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 7 Feb 2025 11:32:31 +0100 Subject: [PATCH 28/99] chore: update stremio-video --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4477c0b4f..14e5f5e38 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@stremio/stremio-colors": "5.2.0", "@stremio/stremio-core-web": "0.48.5", "@stremio/stremio-icons": "5.4.1", - "@stremio/stremio-video": "0.0.48", + "@stremio/stremio-video": "github:Stremio/stremio-video#b5e6eb7c3aa85703c3468c53e489d7ec47daccae", "a-color-picker": "1.2.1", "bowser": "2.11.0", "buffer": "6.0.3", @@ -3409,9 +3409,9 @@ ] }, "node_modules/@stremio/stremio-video": { - "version": "0.0.48", - "resolved": "https://registry.npmjs.org/@stremio/stremio-video/-/stremio-video-0.0.48.tgz", - "integrity": "sha512-6ALGXCZC4NPsfhPcrwFWQzvH6UMMRsgSkHetnOhv9WmZ5ubiyUdbBzj9atGiGuuQz8pRcze66ztrub+dsaQbpw==", + "version": "0.0.52", + "resolved": "git+ssh://git@github.com/Stremio/stremio-video.git#b5e6eb7c3aa85703c3468c53e489d7ec47daccae", + "integrity": "sha512-ywXVR/blyHdP/8q458+sL7cfvPj5RyE6esuxZBU6qejKxX+U62x6qcky1dNL5ZWub5YYucbqfjftaVuuNz+dug==", "license": "MIT", "dependencies": { "buffer": "6.0.3", diff --git a/package.json b/package.json index 9587f9530..c6eda5722 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "@stremio/stremio-colors": "5.2.0", "@stremio/stremio-core-web": "0.48.5", "@stremio/stremio-icons": "5.4.1", - "@stremio/stremio-video": "0.0.48", + "@stremio/stremio-video": "github:Stremio/stremio-video#b5e6eb7c3aa85703c3468c53e489d7ec47daccae", "a-color-picker": "1.2.1", "bowser": "2.11.0", "buffer": "6.0.3", From 6605eafd7896307d38cce74a5383a10d69470874 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 7 Feb 2025 12:04:40 +0100 Subject: [PATCH 29/99] chore: update stremio-translations --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4477c0b4f..7317cea49 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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#a0f50634202f748a57907b645d2cd92fbaa479dd", + "stremio-translations": "github:Stremio/stremio-translations#afda3a5a52e3b91b39ed6e61a2849d8e6887641f", "url": "0.11.4", "use-long-press": "^3.2.0" }, @@ -13374,8 +13374,8 @@ }, "node_modules/stremio-translations": { "version": "1.44.9", - "resolved": "git+ssh://git@github.com/Stremio/stremio-translations.git#a0f50634202f748a57907b645d2cd92fbaa479dd", - "integrity": "sha512-JJpd1JJet3T6/VTNdZ2NZ7uvHJ4zkuyqo5BnTcDGqLVNO/OpicGqKhZjE4WGSgmuhsfPBU8T0ICCfzKu2xpvKg==", + "resolved": "git+ssh://git@github.com/Stremio/stremio-translations.git#afda3a5a52e3b91b39ed6e61a2849d8e6887641f", + "integrity": "sha512-uAWlQsiObblYeLUf/cATCecqNS3Md34pGgeCcH2HBjZI6drSD6DEVYHd4Sxjmv+vmjnngQyHWr6ThHP27mWc4Q==", "license": "MIT" }, "node_modules/string_decoder": { diff --git a/package.json b/package.json index 9587f9530..001eec76c 100644 --- a/package.json +++ b/package.json @@ -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#a0f50634202f748a57907b645d2cd92fbaa479dd", + "stremio-translations": "github:Stremio/stremio-translations#afda3a5a52e3b91b39ed6e61a2849d8e6887641f", "url": "0.11.4", "use-long-press": "^3.2.0" }, From 6ba966d306e3d9c1471ca12ed7bb5a181af9758b Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 7 Feb 2025 12:05:31 +0100 Subject: [PATCH 30/99] refactor(UpdaterBanner): add translation strings --- src/App/UpdaterBanner/UpdaterBanner.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/App/UpdaterBanner/UpdaterBanner.tsx b/src/App/UpdaterBanner/UpdaterBanner.tsx index cf80c198a..3c1a16ab9 100644 --- a/src/App/UpdaterBanner/UpdaterBanner.tsx +++ b/src/App/UpdaterBanner/UpdaterBanner.tsx @@ -1,5 +1,6 @@ import React, { useEffect } from 'react'; import Icon from '@stremio/stremio-icons/react'; +import { useTranslation } from 'react-i18next'; import { useServices } from 'stremio/services'; import { useBinaryState, useShell } from 'stremio/common'; import { Button, Transition } from 'stremio/components'; @@ -10,6 +11,7 @@ type Props = { }; const UpdaterBanner = ({ className }: Props) => { + const { t } = useTranslation(); const { shell } = useServices(); const shellTransport = useShell(); const [visible, show, hide] = useBinaryState(false); @@ -31,10 +33,10 @@ const UpdaterBanner = ({ className }: Props) => {
- A new version of Stremio is available + { t('UPDATER_TITLE') }
+ : null + } +
+ +
+ ); +}); + +export default Checkbox; diff --git a/src/components/Checkbox/index.ts b/src/components/Checkbox/index.ts new file mode 100644 index 000000000..fa5739580 --- /dev/null +++ b/src/components/Checkbox/index.ts @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2025 Smart code 203358507 + +import Checkbox from './Checkbox'; + +export default Checkbox; diff --git a/src/components/index.ts b/src/components/index.ts index f65d66f81..7ef75f888 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,6 +1,7 @@ import AddonDetailsModal from './AddonDetailsModal'; import BottomSheet from './BottomSheet'; import Button from './Button'; +import Checkbox from './Checkbox'; import Chips from './Chips'; import ColorInput from './ColorInput'; import ContinueWatchingItem from './ContinueWatchingItem'; @@ -31,6 +32,7 @@ export { AddonDetailsModal, BottomSheet, Button, + Checkbox, Chips, ColorInput, ContinueWatchingItem, From e3fda56a11f3a7081d44d6c2a5f5d7e826fc954e Mon Sep 17 00:00:00 2001 From: Botzy Date: Thu, 13 Feb 2025 13:06:05 +0200 Subject: [PATCH 47/99] refactor(Intro): reuse Checkbox component for consent items --- src/routes/Intro/Intro.js | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/routes/Intro/Intro.js b/src/routes/Intro/Intro.js index fc98fe5cf..989e6febd 100644 --- a/src/routes/Intro/Intro.js +++ b/src/routes/Intro/Intro.js @@ -8,9 +8,8 @@ const { default: Icon } = require('@stremio/stremio-icons/react'); const { Modal, useRouteFocused } = require('stremio-router'); const { useServices } = require('stremio/services'); const { useBinaryState } = require('stremio/common'); -const { Button, Image } = require('stremio/components'); +const { Button, Image, Checkbox } = require('stremio/components'); const CredentialsTextInput = require('./CredentialsTextInput'); -const ConsentToggle = require('./ConsentToggle'); const PasswordResetModal = require('./PasswordResetModal'); const useFacebookLogin = require('./useFacebookLogin'); const styles = require('./styles'); @@ -308,30 +307,27 @@ const Intro = ({ queryParams }) => { onChange={confirmPasswordOnChange} onSubmit={confirmPasswordOnSubmit} /> - - - : From c08bed630d0a87cbf02f8e07a1b8c98474c01c9c Mon Sep 17 00:00:00 2001 From: Tim Date: Sat, 15 Feb 2025 07:27:24 +0100 Subject: [PATCH 48/99] fix(Player): use Player action for MarkSeasonAsWatched Co-authored-by: Timothy Z. --- src/routes/Player/SideDrawer/SideDrawer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Player/SideDrawer/SideDrawer.tsx b/src/routes/Player/SideDrawer/SideDrawer.tsx index 332ead719..cb94e24e5 100644 --- a/src/routes/Player/SideDrawer/SideDrawer.tsx +++ b/src/routes/Player/SideDrawer/SideDrawer.tsx @@ -63,7 +63,7 @@ const SideDrawer = memo(forwardRef(({ seriesInfo, classNa const onMarkSeasonAsWatched = (season: number, watched: boolean) => { core.transport.dispatch({ - action: 'MetaDetails', + action: 'Player', args: { action: 'MarkSeasonAsWatched', args: [season, !watched] From 71bd470d31d2645ffb5a5d6dbcb3273846b503c9 Mon Sep 17 00:00:00 2001 From: Botzy Date: Mon, 17 Feb 2025 14:02:15 +0200 Subject: [PATCH 49/99] fix(Checkbox): use checkmark icon instead of styles and make bg color the primary accent one --- src/components/Checkbox/Checkbox.less | 35 +++++---------------------- src/components/Checkbox/Checkbox.tsx | 7 +++++- 2 files changed, 12 insertions(+), 30 deletions(-) diff --git a/src/components/Checkbox/Checkbox.less b/src/components/Checkbox/Checkbox.less index 7d43947ed..5890ce52e 100644 --- a/src/components/Checkbox/Checkbox.less +++ b/src/components/Checkbox/Checkbox.less @@ -30,9 +30,10 @@ position: relative; width: 1.75rem; height: 1.75rem; - border: 0.2rem solid var(--color-placeholder); + border: 0.2rem solid var(--primary-accent-color); border-radius: 0.5rem; background-color: transparent; + padding: 0.1rem; display: flex; flex: none; margin-right: 1rem; @@ -51,29 +52,9 @@ cursor: pointer; } - .checkmark { - position: absolute; - top: 0; - left: 0; - width: 1.5rem; - height: 1.5rem; - transition: opacity 0.2s ease-in-out; - background-color: transparent; - opacity: 0; - - &:after { - content: ""; - position: absolute; - left: 0.45rem; - top: 0.2rem; - width: 0.2rem; - height: 0.5rem; - border: solid var(--primary-foreground-color); - border-width: 0 0.2rem 0.2rem 0; - -webkit-transform: rotate(45deg); - -ms-transform: rotate(45deg); - transform: rotate(45deg); - } + .checkbox-icon { + width: 100%; + height: 100%; } &.disabled { @@ -85,11 +66,7 @@ } &.checked { - border: 3px solid var(--secondary-accent-color); - background-color: var(--secondary-accent-color); - .checkmark { - opacity: 1; - } + background-color: var(--primary-accent-color); } } } diff --git a/src/components/Checkbox/Checkbox.tsx b/src/components/Checkbox/Checkbox.tsx index b5c0b0e7c..8180ddd84 100644 --- a/src/components/Checkbox/Checkbox.tsx +++ b/src/components/Checkbox/Checkbox.tsx @@ -4,6 +4,7 @@ import React, { useCallback, ChangeEvent, KeyboardEvent, RefCallback } from 'rea import classNames from 'classnames'; import styles from './Checkbox.less'; import Button from '../Button'; +import Icon from '@stremio/stremio-icons/react'; type Props = { ref?: RefCallback; @@ -66,7 +67,11 @@ const Checkbox = React.forwardRef(({ name, disabled, cl onChange={handleSelect} className={styles['input']} /> - + { + checked ? + + : null + }
{label} From 6e806d5c8483b6d2f10a70c8ac5a2ea880fe4c87 Mon Sep 17 00:00:00 2001 From: Ivelin Megdanov Date: Mon, 17 Feb 2025 14:11:28 +0200 Subject: [PATCH 50/99] Revert previous changes and added margin/padding block --- src/routes/Calendar/List/Item/Item.less | 25 +++++++++---------------- src/routes/Calendar/List/List.less | 6 ++++++ 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/routes/Calendar/List/Item/Item.less b/src/routes/Calendar/List/Item/Item.less index 051e092df..e850d3e49 100644 --- a/src/routes/Calendar/List/Item/Item.less +++ b/src/routes/Calendar/List/Item/Item.less @@ -7,6 +7,8 @@ flex-direction: column; background-color: var(--overlay-color); border-radius: var(--border-radius); + border: 0.15rem solid transparent; + transition: border-color 0.1s ease-out; .heading { flex: none; @@ -80,19 +82,6 @@ } } - &::before { - border: 0.15rem solid transparent; - border-radius: var(--border-radius); - box-sizing: border-box; - content: ""; - width: 100%; - height: 100%; - position: absolute; - pointer-events: none; - z-index: 1; - transition: border-color 0.1s ease-out; - } - &.today { .heading { background-color: var(--primary-accent-color); @@ -100,12 +89,16 @@ } &.active { - &::before { - border-color: var(--primary-foreground-color); - } + border-color: var(--primary-foreground-color); } &:not(.active):hover { border-color: var(--overlay-color); } } + +@supports (scroll-margin-block-start: 2px) { + .item { + scroll-margin-block-start: 2px; + } +} \ No newline at end of file diff --git a/src/routes/Calendar/List/List.less b/src/routes/Calendar/List/List.less index f63078680..9a1904a70 100644 --- a/src/routes/Calendar/List/List.less +++ b/src/routes/Calendar/List/List.less @@ -35,3 +35,9 @@ display: none; } } + +@supports (scroll-padding-block-start: 2px) { + .list { + scroll-padding-block-start: 2px; + } +} \ No newline at end of file From b800e78c8b8205394b201e23dd7a1a1c4f59d7d7 Mon Sep 17 00:00:00 2001 From: Ivelin Megdanov Date: Mon, 17 Feb 2025 15:08:03 +0200 Subject: [PATCH 51/99] Added seek bar contrast --- src/components/Slider/styles.less | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Slider/styles.less b/src/components/Slider/styles.less index 66ad267c7..421826ea6 100644 --- a/src/components/Slider/styles.less +++ b/src/components/Slider/styles.less @@ -39,7 +39,8 @@ html.active-slider-within { flex: 1; height: var(--track-size); border-radius: var(--track-size); - background-color: var(--overlay-color); + background-color: var(--primary-accent-color); + opacity: 0.2; } .track-before { From 91ed45625bae6ada202c131148df845498512546 Mon Sep 17 00:00:00 2001 From: Ivelin Megdanov Date: Mon, 17 Feb 2025 15:21:06 +0200 Subject: [PATCH 52/99] Moved scroll padding/margin inside the classes --- src/routes/Calendar/List/Item/Item.less | 7 +------ src/routes/Calendar/List/List.less | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/routes/Calendar/List/Item/Item.less b/src/routes/Calendar/List/Item/Item.less index e850d3e49..90cc07f27 100644 --- a/src/routes/Calendar/List/Item/Item.less +++ b/src/routes/Calendar/List/Item/Item.less @@ -9,6 +9,7 @@ border-radius: var(--border-radius); border: 0.15rem solid transparent; transition: border-color 0.1s ease-out; + scroll-margin-block-start: 2px; .heading { flex: none; @@ -95,10 +96,4 @@ &:not(.active):hover { border-color: var(--overlay-color); } -} - -@supports (scroll-margin-block-start: 2px) { - .item { - scroll-margin-block-start: 2px; - } } \ No newline at end of file diff --git a/src/routes/Calendar/List/List.less b/src/routes/Calendar/List/List.less index 9a1904a70..21c5dc588 100644 --- a/src/routes/Calendar/List/List.less +++ b/src/routes/Calendar/List/List.less @@ -10,6 +10,7 @@ width: 20rem; padding: 0 1rem; overflow-y: auto; + scroll-padding-block-start: 2px; } @media only screen and (max-width: @small) and (orientation: portrait) { @@ -34,10 +35,4 @@ .list { display: none; } -} - -@supports (scroll-padding-block-start: 2px) { - .list { - scroll-padding-block-start: 2px; - } } \ No newline at end of file From 5c316f4a332036bc32a748f68a7e6e22a81f5904 Mon Sep 17 00:00:00 2001 From: Ivelin Megdanov Date: Mon, 17 Feb 2025 15:27:19 +0200 Subject: [PATCH 53/99] Added supports check --- src/routes/Calendar/List/Item/Item.less | 5 ++++- src/routes/Calendar/List/List.less | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/routes/Calendar/List/Item/Item.less b/src/routes/Calendar/List/Item/Item.less index 90cc07f27..742cc1e5b 100644 --- a/src/routes/Calendar/List/Item/Item.less +++ b/src/routes/Calendar/List/Item/Item.less @@ -9,7 +9,10 @@ border-radius: var(--border-radius); border: 0.15rem solid transparent; transition: border-color 0.1s ease-out; - scroll-margin-block-start: 2px; + + @supports (scroll-margin-block-start: 2px) { + scroll-margin-block-start: 2px; + } .heading { flex: none; diff --git a/src/routes/Calendar/List/List.less b/src/routes/Calendar/List/List.less index 21c5dc588..768ac8c24 100644 --- a/src/routes/Calendar/List/List.less +++ b/src/routes/Calendar/List/List.less @@ -10,7 +10,10 @@ width: 20rem; padding: 0 1rem; overflow-y: auto; - scroll-padding-block-start: 2px; + + @supports (scroll-padding-block-start: 2px) { + scroll-padding-block-start: 2px; + } } @media only screen and (max-width: @small) and (orientation: portrait) { From 72e7b7051ef55d8567482a063d5b7a75231ff0db Mon Sep 17 00:00:00 2001 From: Botzy Date: Mon, 17 Feb 2025 17:46:13 +0200 Subject: [PATCH 54/99] fix(Button): add missing target prop to type --- src/components/Button/Button.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/Button/Button.tsx b/src/components/Button/Button.tsx index f4b059bd3..f97e1ba82 100644 --- a/src/components/Button/Button.tsx +++ b/src/components/Button/Button.tsx @@ -8,6 +8,7 @@ import styles from './Button.less'; type Props = { className?: string, href?: string, + target?: string title?: string, disabled?: boolean, tabIndex?: number, From f5ef7d653d50003e24b98ea8f08ee1edf029f9e1 Mon Sep 17 00:00:00 2001 From: Botzy Date: Mon, 17 Feb 2025 18:09:17 +0200 Subject: [PATCH 55/99] fix(Checkbox): improve typings and styles to follow mockups --- src/components/Checkbox/Checkbox.less | 24 +++++++++++++++++------- src/components/Checkbox/Checkbox.tsx | 13 +++++++++---- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/components/Checkbox/Checkbox.less b/src/components/Checkbox/Checkbox.less index 5890ce52e..742506cc0 100644 --- a/src/components/Checkbox/Checkbox.less +++ b/src/components/Checkbox/Checkbox.less @@ -1,5 +1,7 @@ // Copyright (C) 2017-2025 Smart code 203358507 +@import (reference) '~@stremio/stremio-colors/less/stremio-colors.less'; + .checkbox { display: flex; align-items: center; @@ -10,6 +12,7 @@ flex-direction: row; align-items: center; padding: 0.5rem 0; + cursor: pointer; span { font-size: 0.9rem; @@ -28,21 +31,23 @@ .checkbox-container { position: relative; - width: 1.75rem; - height: 1.75rem; - border: 0.2rem solid var(--primary-accent-color); - border-radius: 0.5rem; - background-color: transparent; + width: 1.5rem; + height: 1.5rem; + border-radius: 0.3rem; + background-color: var(--overlay-color); padding: 0.1rem; display: flex; flex: none; - margin-right: 1rem; + margin: 0 1rem 0 0.3rem; align-items: center; justify-content: center; transition: all 0.2s ease-in-out; cursor: pointer; outline: none; user-select: none; + outline-width: var(--focus-outline-size); + outline-color: @color-surface-light5; + outline-offset: 2px; input[type='checkbox'] { opacity: 0; @@ -54,7 +59,8 @@ .checkbox-icon { width: 100%; - height: 100%; + height: 100%; + color: var(--primary-foreground-color); } &.disabled { @@ -68,5 +74,9 @@ &.checked { background-color: var(--primary-accent-color); } + + &:hover, &:focus { + outline-style: solid; + } } } diff --git a/src/components/Checkbox/Checkbox.tsx b/src/components/Checkbox/Checkbox.tsx index 8180ddd84..da4ae33eb 100644 --- a/src/components/Checkbox/Checkbox.tsx +++ b/src/components/Checkbox/Checkbox.tsx @@ -15,7 +15,12 @@ type Props = { label?: string; link?: string; href?: string; - onChange?: (props: any) => void; + onChange?: (props: { + type: string; + checked: boolean; + reactEvent: KeyboardEvent | ChangeEvent; + nativeEvent: Event; + }) => void; error?: string; }; @@ -32,12 +37,12 @@ const Checkbox = React.forwardRef(({ name, disabled, cl } }, [disabled, onChange]); - const onKeyDown = useCallback((event: KeyboardEvent) => { + const onKeyDown = useCallback((event: KeyboardEvent) => { if ((event.key === 'Enter' || event.key === ' ') && !disabled) { onChange && onChange({ type: 'select', - checked: event.target.checked, - reactEvent: event, + checked: !checked, + reactEvent: event as KeyboardEvent, nativeEvent: event.nativeEvent, }); } From e60cf6501e977259da4cdbef2fc6a362e8a2d19f Mon Sep 17 00:00:00 2001 From: Botsy Date: Mon, 17 Feb 2025 18:10:48 +0200 Subject: [PATCH 56/99] Update src/components/Checkbox/Checkbox.less Co-authored-by: Timothy Z. --- src/components/Checkbox/Checkbox.less | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/Checkbox/Checkbox.less b/src/components/Checkbox/Checkbox.less index 742506cc0..718a7b129 100644 --- a/src/components/Checkbox/Checkbox.less +++ b/src/components/Checkbox/Checkbox.less @@ -19,6 +19,7 @@ color: var(--primary-foreground-color); opacity: 0.6; } + .link { font-size: 0.9rem; color: var(--primary-accent-color); From 14927942e8f37b2135e378e9612cd367159143bf Mon Sep 17 00:00:00 2001 From: Botzy Date: Mon, 17 Feb 2025 18:25:21 +0200 Subject: [PATCH 57/99] fix(ConsentToggle): remove unused ConsentToggle component --- .../Intro/ConsentToggle/ConsentToggle.js | 56 ------------------- src/routes/Intro/ConsentToggle/index.js | 5 -- src/routes/Intro/ConsentToggle/styles.less | 43 -------------- 3 files changed, 104 deletions(-) delete mode 100644 src/routes/Intro/ConsentToggle/ConsentToggle.js delete mode 100644 src/routes/Intro/ConsentToggle/index.js delete mode 100644 src/routes/Intro/ConsentToggle/styles.less diff --git a/src/routes/Intro/ConsentToggle/ConsentToggle.js b/src/routes/Intro/ConsentToggle/ConsentToggle.js deleted file mode 100644 index 9a0210607..000000000 --- a/src/routes/Intro/ConsentToggle/ConsentToggle.js +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const React = require('react'); -const PropTypes = require('prop-types'); -const classnames = require('classnames'); -const { Button, Toggle } = require('stremio/components'); -const styles = require('./styles'); - -const ConsentToggle = React.forwardRef(({ className, label, link, href, onToggle, ...props }, ref) => { - const toggleOnClick = React.useCallback((event) => { - if (typeof props.onClick === 'function') { - props.onClick(event); - } - - if (!event.nativeEvent.togglePrevented && typeof onToggle === 'function') { - onToggle({ - type: 'toggle', - reactEvent: event, - nativeEvent: event.nativeEvent - }); - } - }, [onToggle, props.onClick]); - const linkOnClick = React.useCallback((event) => { - event.nativeEvent.togglePrevented = true; - }, []); - return ( - -
- {label} - {' '} - { - typeof link === 'string' && link.length > 0 && typeof href === 'string' && href.length > 0 ? - - : - null - } -
-
- ); -}); - -ConsentToggle.displayName = 'ConsentToggle'; - -ConsentToggle.propTypes = { - className: PropTypes.string, - checked: PropTypes.bool, - label: PropTypes.string, - link: PropTypes.string, - href: PropTypes.string, - onToggle: PropTypes.func, - onClick: PropTypes.func -}; - -module.exports = ConsentToggle; diff --git a/src/routes/Intro/ConsentToggle/index.js b/src/routes/Intro/ConsentToggle/index.js deleted file mode 100644 index 8edfe4a27..000000000 --- a/src/routes/Intro/ConsentToggle/index.js +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -const ConsentToggle = require('./ConsentToggle'); - -module.exports = ConsentToggle; diff --git a/src/routes/Intro/ConsentToggle/styles.less b/src/routes/Intro/ConsentToggle/styles.less deleted file mode 100644 index e8229e244..000000000 --- a/src/routes/Intro/ConsentToggle/styles.less +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (C) 2017-2023 Smart code 203358507 - -@import (reference) '~@stremio/stremio-colors/less/stremio-colors.less'; - -:import('~stremio/components/Toggle/styles.less') { - checkbox-icon: icon; -} - -.consent-toggle-container { - display: flex; - flex-direction: row; - align-items: center; - padding: 0.5rem 0; - border-radius: var(--border-radius); - - &:focus { - outline: none; - background-color: var(--overlay-color); - } - - &:global(.checked) { - .label { - opacity: 1; - } - } - - .label { - flex: 1; - margin-left: 1rem; - font-size: 0.9rem; - color: var(--primary-foreground-color); - opacity: 0.6; - - .link { - font-size: 0.9rem; - color: var(--primary-accent-color); - - &:hover { - text-decoration: underline; - } - } - } -} \ No newline at end of file From 878691fffbb9dc86834b37c153d1f037152121a8 Mon Sep 17 00:00:00 2001 From: Ivelin Megdanov Date: Mon, 17 Feb 2025 18:57:33 +0200 Subject: [PATCH 58/99] Removed margin block and convert padding to rem --- src/routes/Calendar/List/Item/Item.less | 4 ---- src/routes/Calendar/List/List.less | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/routes/Calendar/List/Item/Item.less b/src/routes/Calendar/List/Item/Item.less index 742cc1e5b..b11feda2a 100644 --- a/src/routes/Calendar/List/Item/Item.less +++ b/src/routes/Calendar/List/Item/Item.less @@ -10,10 +10,6 @@ border: 0.15rem solid transparent; transition: border-color 0.1s ease-out; - @supports (scroll-margin-block-start: 2px) { - scroll-margin-block-start: 2px; - } - .heading { flex: none; position: relative; diff --git a/src/routes/Calendar/List/List.less b/src/routes/Calendar/List/List.less index 768ac8c24..9f2dfd774 100644 --- a/src/routes/Calendar/List/List.less +++ b/src/routes/Calendar/List/List.less @@ -11,8 +11,8 @@ padding: 0 1rem; overflow-y: auto; - @supports (scroll-padding-block-start: 2px) { - scroll-padding-block-start: 2px; + @supports (scroll-padding-block-start: 0.15rem) { + scroll-padding-block-start: 0.15rem; } } From cc36befc9a996405c0f361969efa96b8581d052e Mon Sep 17 00:00:00 2001 From: Tim Date: Tue, 18 Feb 2025 15:24:20 +0100 Subject: [PATCH 59/99] refactor(Slider): simplify audio boost logic --- src/components/Slider/Slider.js | 8 +++---- src/components/Slider/styles.less | 40 +++++++++++++------------------ 2 files changed, 19 insertions(+), 29 deletions(-) diff --git a/src/components/Slider/Slider.js b/src/components/Slider/Slider.js index e29f31c1e..0e5c96c97 100644 --- a/src/components/Slider/Slider.js +++ b/src/components/Slider/Slider.js @@ -106,11 +106,9 @@ const Slider = ({ className, value, buffered, minimumValue, maximumValue, disabl
-
diff --git a/src/components/Slider/styles.less b/src/components/Slider/styles.less index 3acf79e62..2bdbbfe72 100644 --- a/src/components/Slider/styles.less +++ b/src/components/Slider/styles.less @@ -2,6 +2,12 @@ @import (reference) '~@stremio/stremio-colors/less/stremio-colors.less'; +@audio-boost-background: linear-gradient(to right, + var(--primary-foreground-color) 0%, + var(--primary-foreground-color) 50%, + var(--warning-accent-color) 75%, + var(--danger-accent-color) 100%) !important; + html.active-slider-within { cursor: grabbing; @@ -37,19 +43,14 @@ html.active-slider-within { .track { z-index: 0; flex: 1; + width: 100%; height: var(--track-size); border-radius: var(--track-size); - background-color: var(--primary-accent-color); - opacity: 0.2; + background-color: var(--overlay-color); &.audio-boost { - background: linear-gradient(to right, - var(--primary-foreground-color) 0%, - var(--primary-foreground-color) 50%, - var(--warning-accent-color) 75%, - var(--danger-accent-color) 100%) !important; opacity: 0.3; - filter: brightness(1.2); + background: @audio-boost-background; } } @@ -64,27 +65,18 @@ html.active-slider-within { .track-after { z-index: 2; flex: none; + width: 100%; height: var(--track-size); border-radius: var(--track-size); background-color: var(--primary-foreground-color); + mask-image: linear-gradient(to right, + black 0%, + black var(--mask-width), + transparent var(--mask-width) + ); &.audio-boost { - background: linear-gradient(to right, - var(--primary-foreground-color) 0%, - var(--primary-foreground-color) 50%, - var(--warning-accent-color) 75%, - var(--danger-accent-color) 100%) !important; - width: 100%; - mask-image: linear-gradient(to right, - black 0%, - black calc(var(--progress-width) - 2px), - transparent var(--progress-width) - ); - -webkit-mask-image: linear-gradient(to right, - black 0%, - black calc(var(--progress-width) - 2px), - transparent var(--progress-width) - ); + background: @audio-boost-background; } } From a4ee4db1b879fd2bcbce87add19cc33168b42722 Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 19 Feb 2025 11:05:09 +0100 Subject: [PATCH 60/99] feat: add quit on close setting for shell --- src/App/App.js | 12 ++++++++++-- src/routes/Settings/Settings.js | 14 ++++++++++++++ .../Settings/useProfileSettingsInputs.js | 18 ++++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/App/App.js b/src/App/App.js index 6dc2d6e0b..fa7e7a3e3 100644 --- a/src/App/App.js +++ b/src/App/App.js @@ -6,7 +6,7 @@ const { useTranslation } = require('react-i18next'); const { Router } = require('stremio-router'); const { Core, Shell, Chromecast, DragAndDrop, KeyboardShortcuts, ServicesProvider } = require('stremio/services'); const { NotFound } = require('stremio/routes'); -const { FileDropProvider, PlatformProvider, ToastProvider, TooltipProvider, CONSTANTS, withCoreSuspender } = require('stremio/common'); +const { FileDropProvider, PlatformProvider, ToastProvider, TooltipProvider, CONSTANTS, withCoreSuspender, useShell } = require('stremio/common'); const ServicesToaster = require('./ServicesToaster'); const DeepLinkHandler = require('./DeepLinkHandler'); const SearchParamsHandler = require('./SearchParamsHandler'); @@ -20,6 +20,7 @@ const RouterWithProtectedRoutes = withCoreSuspender(withProtectedRoutes(Router)) const App = () => { const { i18n } = useTranslation(); + const shell = useShell(); const onPathNotMatch = React.useCallback(() => { return NotFound; }, []); @@ -104,6 +105,9 @@ const App = () => { if (args && args.settings && typeof args.settings.interfaceLanguage === 'string') { i18n.changeLanguage(args.settings.interfaceLanguage); } + if (args?.settings) { + shell.send('update_settings', args.settings); + } break; } } @@ -112,6 +116,10 @@ const App = () => { if (state && state.profile && state.profile.settings && typeof state.profile.settings.interfaceLanguage === 'string') { i18n.changeLanguage(state.profile.settings.interfaceLanguage); } + + if (state?.profile?.settings) { + shell.send('update_settings', state.profile.settings); + } }; const onWindowFocus = () => { services.core.transport.dispatch({ @@ -146,7 +154,7 @@ const App = () => { services.core.transport .getState('ctx') .then(onCtxState) - .catch((e) => console.error(e)); + .catch(console.error); } return () => { if (services.core.active) { diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index 6ad15163a..312ad9e49 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -41,6 +41,7 @@ const Settings = () => { seekTimeDurationSelect, seekShortTimeDurationSelect, escExitFullscreenToggle, + quitOnCloseToggle, playInExternalPlayerSelect, nextVideoPopupDurationSelect, bingeWatchingToggle, @@ -322,6 +323,19 @@ const Settings = () => { {...interfaceLanguageSelect} />
+ { + shell.active && +
+
+
{ t('SETTINGS_QUIT_ON_CLOSE') }
+
+ +
+ }
{ t('SETTINGS_NAV_PLAYER') }
diff --git a/src/routes/Settings/useProfileSettingsInputs.js b/src/routes/Settings/useProfileSettingsInputs.js index d36b169f9..c193c6eaf 100644 --- a/src/routes/Settings/useProfileSettingsInputs.js +++ b/src/routes/Settings/useProfileSettingsInputs.js @@ -31,6 +31,23 @@ const useProfileSettingsInputs = (profile) => { }); } }), [profile.settings]); + + const quitOnCloseToggle = React.useMemo(() => ({ + checked: profile.settings.quitOnClose, + onClick: () => { + core.transport.dispatch({ + action: 'Ctx', + args: { + action: 'UpdateSettings', + args: { + ...profile.settings, + quitOnClose: !profile.settings.quitOnClose + } + } + }); + } + }), [profile.settings]); + const subtitlesLanguageSelect = React.useMemo(() => ({ options: Object.keys(languageNames).map((code) => ({ value: code, @@ -316,6 +333,7 @@ const useProfileSettingsInputs = (profile) => { audioLanguageSelect, surroundSoundToggle, escExitFullscreenToggle, + quitOnCloseToggle, seekTimeDurationSelect, seekShortTimeDurationSelect, playInExternalPlayerSelect, From 31121aab21098408726c6c54946a2a0a7b95b903 Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 19 Feb 2025 11:11:40 +0100 Subject: [PATCH 61/99] refactor(App): use dash for shell update settings message --- src/App/App.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/App/App.js b/src/App/App.js index fa7e7a3e3..92240aa0d 100644 --- a/src/App/App.js +++ b/src/App/App.js @@ -106,7 +106,7 @@ const App = () => { i18n.changeLanguage(args.settings.interfaceLanguage); } if (args?.settings) { - shell.send('update_settings', args.settings); + shell.send('update-settings', args.settings); } break; } @@ -118,7 +118,7 @@ const App = () => { } if (state?.profile?.settings) { - shell.send('update_settings', state.profile.settings); + shell.send('update-settings', state.profile.settings); } }; const onWindowFocus = () => { From 39e37b5875de0e54394c0d1d6be91dd21018a799 Mon Sep 17 00:00:00 2001 From: Botzy Date: Wed, 19 Feb 2025 18:22:10 +0200 Subject: [PATCH 62/99] refactor(Calendar): rename placeholder image with more generic name and fix import --- ...placeholder.png => not_loggedin_placeholder.png} | Bin src/routes/Calendar/Placeholder/Placeholder.tsx | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename images/{calendar_placeholder.png => not_loggedin_placeholder.png} (100%) diff --git a/images/calendar_placeholder.png b/images/not_loggedin_placeholder.png similarity index 100% rename from images/calendar_placeholder.png rename to images/not_loggedin_placeholder.png diff --git a/src/routes/Calendar/Placeholder/Placeholder.tsx b/src/routes/Calendar/Placeholder/Placeholder.tsx index 4b48ba3f2..1a8a412b8 100644 --- a/src/routes/Calendar/Placeholder/Placeholder.tsx +++ b/src/routes/Calendar/Placeholder/Placeholder.tsx @@ -16,7 +16,7 @@ const Placeholder = () => {
{'
From 64310c863f5cee3a0b1ee76fc03953df49eb774a Mon Sep 17 00:00:00 2001 From: Botzy Date: Thu, 20 Feb 2025 14:30:35 +0200 Subject: [PATCH 63/99] feat(Placeholder): added Placeholder component --- .../Library/Placeholder/Placeholder.less | 102 ++++++++++++++++++ .../Library/Placeholder/Placeholder.tsx | 32 ++++++ src/routes/Library/Placeholder/index.ts | 5 + 3 files changed, 139 insertions(+) create mode 100644 src/routes/Library/Placeholder/Placeholder.less create mode 100644 src/routes/Library/Placeholder/Placeholder.tsx create mode 100644 src/routes/Library/Placeholder/index.ts diff --git a/src/routes/Library/Placeholder/Placeholder.less b/src/routes/Library/Placeholder/Placeholder.less new file mode 100644 index 000000000..74908db66 --- /dev/null +++ b/src/routes/Library/Placeholder/Placeholder.less @@ -0,0 +1,102 @@ +// Copyright (C) 2017-2025 Smart code 203358507 + +@import (reference) '~stremio/common/screen-sizes.less'; + +.placeholder { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100%; + width: 100%; + overflow-y: auto; + + .title { + display: flex; + flex: 1; + align-items: flex-end; + font-size: 1.75rem; + font-weight: 400; + text-align: center; + color: var(--primary-foreground-color); + margin-bottom: 1rem; + opacity: 0.5; + } + + .image-container { + display: flex; + flex: 1; + align-items: center; + padding: 1.5rem 0; + + .image { + height: 100%; + max-height: 14rem; + object-fit: contain; + } + } + + .button-container { + display: flex; + flex: 1; + align-items: flex-start; + margin: 1rem 0; + + .button { + flex: none; + justify-content: center; + height: 4rem; + line-height: 4rem; + padding: 0 5rem; + font-size: 1.1rem; + color: var(--primary-foreground-color); + text-align: center; + border-radius: 3.5rem; + background-color: var(--overlay-color); + + &:hover { + outline: var(--focus-outline-size) solid var(--primary-foreground-color); + background-color: transparent; + } + } + } +} + +@media only screen and (max-width: @xsmall) { + .placeholder { + padding: 1rem 2rem; + + .title { + flex: 0.5; + } + + .image-container { + flex: 2; + padding: 1rem; + + .image { + max-height: 10rem; + } + } + + .button-container { + margin: 1rem 0 0; + } + } +} + +@media only screen and (max-width: @minimum) { + .placeholder { + + .image-container { + flex: 1; + } + + .button-container { + .button { + width: 100%; + } + } + } +} \ No newline at end of file diff --git a/src/routes/Library/Placeholder/Placeholder.tsx b/src/routes/Library/Placeholder/Placeholder.tsx new file mode 100644 index 000000000..d6332d2e6 --- /dev/null +++ b/src/routes/Library/Placeholder/Placeholder.tsx @@ -0,0 +1,32 @@ +// Copyright (C) 2017-2025 Smart code 203358507 + +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { Button, Image } from 'stremio/components'; +import styles from './Placeholder.less'; + +const Placeholder = () => { + const { t } = useTranslation(); + + return ( +
+
+ {t('LIBRARY_NOT_LOGGED_IN')} +
+
+ {' +
+
+ +
+
+ ); +}; + +export default Placeholder; diff --git a/src/routes/Library/Placeholder/index.ts b/src/routes/Library/Placeholder/index.ts new file mode 100644 index 000000000..b068f608e --- /dev/null +++ b/src/routes/Library/Placeholder/index.ts @@ -0,0 +1,5 @@ +// Copyright (C) 2017-2025 Smart code 203358507 + +import Placeholder from './Placeholder'; + +export default Placeholder; From 13c9ef986a2ca1c22a4916cb238fa0b8f82a338b Mon Sep 17 00:00:00 2001 From: Botzy Date: Thu, 20 Feb 2025 14:31:20 +0200 Subject: [PATCH 64/99] refactor(Library): reuse Placeholder component and remove unused styles --- src/routes/Library/Library.js | 15 +++------------ src/routes/Library/styles.less | 32 -------------------------------- 2 files changed, 3 insertions(+), 44 deletions(-) diff --git a/src/routes/Library/Library.js b/src/routes/Library/Library.js index 2871a9b3f..e1cea5995 100644 --- a/src/routes/Library/Library.js +++ b/src/routes/Library/Library.js @@ -5,7 +5,8 @@ const PropTypes = require('prop-types'); const classnames = require('classnames'); const NotFound = require('stremio/routes/NotFound'); const { useProfile, useNotifications, routesRegexp, useOnScrollToBottom, withCoreSuspender } = require('stremio/common'); -const { Button, DelayedRenderer, Chips, Image, MainNavBars, Multiselect, LibItem } = require('stremio/components'); +const { DelayedRenderer, Chips, Image, MainNavBars, Multiselect, LibItem } = require('stremio/components'); +const { default: Placeholder } = require('./Placeholder'); const useLibrary = require('./useLibrary'); const useSelectableInputs = require('./useSelectableInputs'); const styles = require('./styles'); @@ -76,17 +77,7 @@ const Library = ({ model, urlParams, queryParams }) => { } { model === 'library' && profile.auth === null ? -
- {' -
Library is only available for logged in users!
- -
+ : library.selected === null ? diff --git a/src/routes/Library/styles.less b/src/routes/Library/styles.less index 2bdbc13ec..76a16940e 100644 --- a/src/routes/Library/styles.less +++ b/src/routes/Library/styles.less @@ -66,38 +66,6 @@ padding: 4rem; } - &.no-user-message-container { - .login-button-container { - flex: none; - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - width: 20rem; - height: 3.5rem; - border-radius: 3.5rem; - padding: 0.5rem 1rem; - margin-bottom: 1rem; - background-color: var(--secondary-accent-color); - - &:hover { - outline: var(--focus-outline-size) solid var(--secondary-accent-color); - background-color: transparent; - } - - .label { - flex-grow: 0; - flex-shrink: 1; - flex-basis: auto; - max-height: 4.8em; - font-size: 1.2rem; - font-weight: 700; - color: var(--primary-foreground-color); - text-align: center; - } - } - } - .image { flex: none; width: 12rem; From e2c3e719ffd77eab4f98bbd1df682094ecddc302 Mon Sep 17 00:00:00 2001 From: Botzy Date: Thu, 20 Feb 2025 17:36:40 +0200 Subject: [PATCH 65/99] fix(Checkbox): remove transition on outline --- src/components/Checkbox/Checkbox.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Checkbox/Checkbox.less b/src/components/Checkbox/Checkbox.less index 718a7b129..a84244ce9 100644 --- a/src/components/Checkbox/Checkbox.less +++ b/src/components/Checkbox/Checkbox.less @@ -42,7 +42,7 @@ margin: 0 1rem 0 0.3rem; align-items: center; justify-content: center; - transition: all 0.2s ease-in-out; + transition: background-color 0.2s ease-in-out; cursor: pointer; outline: none; user-select: none; From 7b0c013dc08710e36760d3866a7072de5fb88bfd Mon Sep 17 00:00:00 2001 From: Botzy Date: Fri, 21 Feb 2025 13:41:59 +0200 Subject: [PATCH 66/99] fix(Placeholder): improve styles on mobile --- .../Calendar/Placeholder/Placeholder.less | 107 +++++++++++++----- .../Calendar/Placeholder/Placeholder.tsx | 20 ++-- 2 files changed, 93 insertions(+), 34 deletions(-) diff --git a/src/routes/Calendar/Placeholder/Placeholder.less b/src/routes/Calendar/Placeholder/Placeholder.less index a509ff79e..a37bd257d 100644 --- a/src/routes/Calendar/Placeholder/Placeholder.less +++ b/src/routes/Calendar/Placeholder/Placeholder.less @@ -13,7 +13,9 @@ overflow-y: auto; .title { - flex: none; + display: flex; + flex: 4; + align-items: flex-end; font-size: 1.75rem; font-weight: 400; text-align: center; @@ -22,19 +24,26 @@ opacity: 0.5; } - .image { - flex: none; - height: 14rem; - margin: 1.5rem 0; + .image-container { + display: flex; + flex: 4; + align-items: center; + padding: 1.5rem 0; + + .image { + height: 100%; + max-height: 14rem; + object-fit: contain; + } } .overview { - flex: none; + flex: 2; display: flex; flex-direction: row; align-items: center; gap: 4rem; - margin-bottom: 3rem; + margin-bottom: 1rem; .point { display: flex; @@ -61,21 +70,57 @@ } } - .button { - flex: none; - justify-content: center; - height: 4rem; - line-height: 4rem; - padding: 0 5rem; - font-size: 1.1rem; - color: var(--primary-foreground-color); - text-align: center; - border-radius: 3.5rem; - background-color: var(--overlay-color); + .button-container { + display: flex; + flex: 2; + align-items: flex-start; + margin: 1rem 0; + + .button { + display: flex; + justify-content: center; + height: 4rem; + line-height: 4rem; + padding: 0 5rem; + font-size: 1.1rem; + color: var(--primary-foreground-color); + text-align: center; + border-radius: 3.5rem; + background-color: var(--overlay-color); - &:hover { - outline: var(--focus-outline-size) solid var(--primary-foreground-color); - background-color: transparent; + &:hover { + outline: var(--focus-outline-size) solid var(--primary-foreground-color); + background-color: transparent; + } + } + } +} + +@media only screen and (max-width: @xsmall) { + .placeholder { + padding: 1rem 2rem; + + .title { + flex: 1; + margin-bottom: 0; + } + + .image-container { + flex: 3; + padding: 1rem; + + .image { + max-height: 10rem; + } + } + + .overview { + flex: 2; + } + + .button-container { + flex: 2; + margin: 1rem 0 0; } } } @@ -83,17 +128,27 @@ @media only screen and (max-width: @minimum) { .placeholder { padding: 1rem 2rem; - - .image { - height: 10rem; + .title { + flex: 2; } .overview { flex-direction: column; + flex: 2; + gap: 1rem; + + .point { + .text { + font-size: 1rem; + } + } } - .button { - width: 100%; + .button-container { + flex: 3; + .button { + width: 100%; + } } } } \ No newline at end of file diff --git a/src/routes/Calendar/Placeholder/Placeholder.tsx b/src/routes/Calendar/Placeholder/Placeholder.tsx index 4b48ba3f2..c84e7a1b8 100644 --- a/src/routes/Calendar/Placeholder/Placeholder.tsx +++ b/src/routes/Calendar/Placeholder/Placeholder.tsx @@ -14,11 +14,13 @@ const Placeholder = () => {
{t('CALENDAR_NOT_LOGGED_IN')}
- {' +
+ {' +
@@ -33,9 +35,11 @@ const Placeholder = () => {
- +
+ +
); }; From 97832d42a8bb1ea4c50a04c3edbb359ba8cf3a20 Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 21 Feb 2025 12:48:55 +0100 Subject: [PATCH 67/99] chore: update stremio-core-web --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index cd094aa9c..210c66388 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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.48.5", + "@stremio/stremio-core-web": "0.49.0", "@stremio/stremio-icons": "5.4.1", "@stremio/stremio-video": "0.0.48", "a-color-picker": "1.2.1", @@ -3371,9 +3371,9 @@ "integrity": "sha512-dYlPgu9W/H7c9s1zmW5tiDnRenaUa4Hg1QCyOg1lhOcgSfM/bVTi5nnqX+IfvGTTUNA0zgzh8hI3o3miwnZxTg==" }, "node_modules/@stremio/stremio-core-web": { - "version": "0.48.5", - "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.48.5.tgz", - "integrity": "sha512-oDTNBrv8zZi1VGbeV+1Bm6CliI2rF23ERdJpz+gv8EnbFjRIo78WIsoS0yO0EOg8HHXYsFytPq5+c0+YlxmBlA==", + "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==", "license": "MIT", "dependencies": { "@babel/runtime": "7.24.1" diff --git a/package.json b/package.json index e777dd091..6339eab06 100644 --- a/package.json +++ b/package.json @@ -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.48.5", + "@stremio/stremio-core-web": "0.49.0", "@stremio/stremio-icons": "5.4.1", "@stremio/stremio-video": "0.0.48", "a-color-picker": "1.2.1", From 755f0625bfd994125b50f1b6b36d31639c87b8b6 Mon Sep 17 00:00:00 2001 From: Botzy Date: Fri, 21 Feb 2025 13:53:11 +0200 Subject: [PATCH 68/99] fix(Placeholder): rename placeholder image --- ..._loggedin_placeholder.png => media_carousel.png} | Bin src/routes/Library/Placeholder/Placeholder.tsx | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename images/{not_loggedin_placeholder.png => media_carousel.png} (100%) diff --git a/images/not_loggedin_placeholder.png b/images/media_carousel.png similarity index 100% rename from images/not_loggedin_placeholder.png rename to images/media_carousel.png diff --git a/src/routes/Library/Placeholder/Placeholder.tsx b/src/routes/Library/Placeholder/Placeholder.tsx index d6332d2e6..d619611d8 100644 --- a/src/routes/Library/Placeholder/Placeholder.tsx +++ b/src/routes/Library/Placeholder/Placeholder.tsx @@ -16,7 +16,7 @@ const Placeholder = () => {
{'
From a050dd8d7679d8bb0106383f8739199c77ea1c32 Mon Sep 17 00:00:00 2001 From: Botzy Date: Fri, 21 Feb 2025 13:58:48 +0200 Subject: [PATCH 69/99] fix(Calendar): update placeholder image name --- src/routes/Calendar/Placeholder/Placeholder.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Calendar/Placeholder/Placeholder.tsx b/src/routes/Calendar/Placeholder/Placeholder.tsx index 1a8a412b8..3ec983f89 100644 --- a/src/routes/Calendar/Placeholder/Placeholder.tsx +++ b/src/routes/Calendar/Placeholder/Placeholder.tsx @@ -16,7 +16,7 @@ const Placeholder = () => {
{'
From a19ef95723d98000d21bc0f446b446a3564978ee Mon Sep 17 00:00:00 2001 From: Tim Date: Fri, 21 Feb 2025 13:02:53 +0100 Subject: [PATCH 70/99] chore: update stremio-core-web --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 642d0ea73..dadfc5ec8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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.48.5", + "@stremio/stremio-core-web": "0.49.0", "@stremio/stremio-icons": "5.4.1", "@stremio/stremio-video": "0.0.53", "a-color-picker": "1.2.1", @@ -3371,9 +3371,9 @@ "integrity": "sha512-dYlPgu9W/H7c9s1zmW5tiDnRenaUa4Hg1QCyOg1lhOcgSfM/bVTi5nnqX+IfvGTTUNA0zgzh8hI3o3miwnZxTg==" }, "node_modules/@stremio/stremio-core-web": { - "version": "0.48.5", - "resolved": "https://registry.npmjs.org/@stremio/stremio-core-web/-/stremio-core-web-0.48.5.tgz", - "integrity": "sha512-oDTNBrv8zZi1VGbeV+1Bm6CliI2rF23ERdJpz+gv8EnbFjRIo78WIsoS0yO0EOg8HHXYsFytPq5+c0+YlxmBlA==", + "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==", "license": "MIT", "dependencies": { "@babel/runtime": "7.24.1" diff --git a/package.json b/package.json index 9ccb0cee8..04a96a75e 100644 --- a/package.json +++ b/package.json @@ -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.48.5", + "@stremio/stremio-core-web": "0.49.0", "@stremio/stremio-icons": "5.4.1", "@stremio/stremio-video": "0.0.53", "a-color-picker": "1.2.1", From 039676afb5b375a8e2c36d18526caea441f6b476 Mon Sep 17 00:00:00 2001 From: Botzy Date: Mon, 24 Feb 2025 14:19:13 +0200 Subject: [PATCH 71/99] fix(MainNavBars): limit the content scroll area to not include navbar --- src/components/MainNavBars/MainNavBars.less | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/MainNavBars/MainNavBars.less b/src/components/MainNavBars/MainNavBars.less index a5495bc69..4eff455a5 100644 --- a/src/components/MainNavBars/MainNavBars.less +++ b/src/components/MainNavBars/MainNavBars.less @@ -29,8 +29,7 @@ .nav-content-container { position: absolute; - padding-top: calc(var(--horizontal-nav-bar-size) + var(--safe-area-inset-top)); - top: 0; + top: calc(var(--horizontal-nav-bar-size) + var(--safe-area-inset-top)); right: 0; bottom: 0; left: var(--vertical-nav-bar-size); From c5c7805d911c01f93ee94e60037ebb230e96aee6 Mon Sep 17 00:00:00 2001 From: Botzy Date: Mon, 24 Feb 2025 14:20:23 +0200 Subject: [PATCH 72/99] fix(Placeholder): improve styles and add scroll on mobile instead of squeezing in components --- .../Calendar/Placeholder/Placeholder.less | 24 +------------------ 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/src/routes/Calendar/Placeholder/Placeholder.less b/src/routes/Calendar/Placeholder/Placeholder.less index a37bd257d..456bcfd21 100644 --- a/src/routes/Calendar/Placeholder/Placeholder.less +++ b/src/routes/Calendar/Placeholder/Placeholder.less @@ -8,14 +8,11 @@ flex-direction: column; align-items: center; justify-content: center; - height: 100%; + min-height: 100%; width: 100%; overflow-y: auto; .title { - display: flex; - flex: 4; - align-items: flex-end; font-size: 1.75rem; font-weight: 400; text-align: center; @@ -25,9 +22,6 @@ } .image-container { - display: flex; - flex: 4; - align-items: center; padding: 1.5rem 0; .image { @@ -38,7 +32,6 @@ } .overview { - flex: 2; display: flex; flex-direction: row; align-items: center; @@ -71,9 +64,6 @@ } .button-container { - display: flex; - flex: 2; - align-items: flex-start; margin: 1rem 0; .button { @@ -101,12 +91,10 @@ padding: 1rem 2rem; .title { - flex: 1; margin-bottom: 0; } .image-container { - flex: 3; padding: 1rem; .image { @@ -114,12 +102,7 @@ } } - .overview { - flex: 2; - } - .button-container { - flex: 2; margin: 1rem 0 0; } } @@ -128,13 +111,9 @@ @media only screen and (max-width: @minimum) { .placeholder { padding: 1rem 2rem; - .title { - flex: 2; - } .overview { flex-direction: column; - flex: 2; gap: 1rem; .point { @@ -145,7 +124,6 @@ } .button-container { - flex: 3; .button { width: 100%; } From bf37815d14c90eaeb7bdde52ccb32ad366329db0 Mon Sep 17 00:00:00 2001 From: Botzy Date: Mon, 24 Feb 2025 14:51:09 +0200 Subject: [PATCH 73/99] fix(MainNavBars): limit content scroll on mobile to not go under bottom nav bar --- src/components/MainNavBars/MainNavBars.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MainNavBars/MainNavBars.less b/src/components/MainNavBars/MainNavBars.less index 4eff455a5..ca816a72f 100644 --- a/src/components/MainNavBars/MainNavBars.less +++ b/src/components/MainNavBars/MainNavBars.less @@ -42,7 +42,7 @@ .main-nav-bars-container { .nav-content-container { left: 0; - padding-bottom: var(--vertical-nav-bar-size); + bottom: var(--vertical-nav-bar-size); } .vertical-nav-bar { From 3bef434f42069a17c6960e37adb4264f0e2a926d Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 24 Feb 2025 14:35:39 +0100 Subject: [PATCH 74/99] refactor: update quit on close logic --- src/App/App.js | 24 +++++++++++---- src/common/useShell.ts | 68 ++++++++++++++++++++++++++++++++++++------ src/types/global.d.ts | 7 ++++- 3 files changed, 84 insertions(+), 15 deletions(-) diff --git a/src/App/App.js b/src/App/App.js index 92240aa0d..b6031be6e 100644 --- a/src/App/App.js +++ b/src/App/App.js @@ -21,6 +21,7 @@ const RouterWithProtectedRoutes = withCoreSuspender(withProtectedRoutes(Router)) const App = () => { const { i18n } = useTranslation(); const shell = useShell(); + const [windowHidden, setWindowHidden] = React.useState(false); const onPathNotMatch = React.useCallback(() => { return NotFound; }, []); @@ -98,6 +99,17 @@ const App = () => { services.chromecast.off('stateChanged', onChromecastStateChange); }; }, []); + + // Handle shell window visibility changed event + React.useEffect(() => { + const onWindowVisibilityChanged = (state) => { + setWindowHidden(state.visible === false && state.visibility === 0); + }; + + shell.on('win-visibility-changed', onWindowVisibilityChanged); + return () => shell.off('win-visibility-changed', onWindowVisibilityChanged); + }, []); + React.useEffect(() => { const onCoreEvent = ({ event, args }) => { switch (event) { @@ -105,9 +117,11 @@ const App = () => { if (args && args.settings && typeof args.settings.interfaceLanguage === 'string') { i18n.changeLanguage(args.settings.interfaceLanguage); } - if (args?.settings) { - shell.send('update-settings', args.settings); + + if (args?.settings?.quitOnClose && windowHidden) { + shell.send('quit'); } + break; } } @@ -117,8 +131,8 @@ const App = () => { i18n.changeLanguage(state.profile.settings.interfaceLanguage); } - if (state?.profile?.settings) { - shell.send('update-settings', state.profile.settings); + if (state?.profile?.settings?.quitOnClose && windowHidden) { + shell.send('quit'); } }; const onWindowFocus = () => { @@ -162,7 +176,7 @@ const App = () => { services.core.transport.off('CoreEvent', onCoreEvent); } }; - }, [initialized]); + }, [initialized, windowHidden]); return ( diff --git a/src/common/useShell.ts b/src/common/useShell.ts index 5e61bfe84..f4700d779 100644 --- a/src/common/useShell.ts +++ b/src/common/useShell.ts @@ -1,21 +1,71 @@ +import { useEffect } from 'react'; +import EventEmitter from 'eventemitter3'; + +const SHELL_EVENT_OBJECT = 'transport'; +const transport = globalThis?.qt?.webChannelTransport; +const events = new EventEmitter(); + +enum ShellEventType { + SIGNAL = 1, + INVOKE_METHOD = 6, +} + +type ShellEvent = { + id: number; + type: ShellEventType; + object: string; + args: string[]; +}; + + + const createId = () => Math.floor(Math.random() * 9999) + 1; const useShell = () => { - const transport = globalThis?.qt?.webChannelTransport; - const send = (method: string, ...args: (string | number)[]) => { - transport?.send(JSON.stringify({ - id: createId(), - type: 6, - object: 'transport', - method: 'onEvent', - args: [method, ...args], - })); + try { + transport?.send(JSON.stringify({ + id: createId(), + type: ShellEventType.INVOKE_METHOD, + object: SHELL_EVENT_OBJECT, + method: 'onEvent', + args: [method, ...args], + })); + } catch(e) { + console.error('Shell', 'Failed to send event', e); + } }; + const on = (name: string, listener: (arg: any) => void) => { + events.on(name, listener); + }; + + const off = (name: string, listener: (arg: any) => void) => { + events.off(name, listener); + }; + + useEffect(() => { + if (!transport) return; + + transport.onmessage = ({ data }) => { + try { + const { type, args } = JSON.parse(data) as ShellEvent; + + if (type === ShellEventType.SIGNAL) { + const [methodName, methodArg] = args; + events.emit(methodName, methodArg); + } + } catch (e) { + console.error('Shell', 'Failed to handle event', e); + } + }; + }, []); + return { active: !!transport, send, + on, + off, }; }; diff --git a/src/types/global.d.ts b/src/types/global.d.ts index 5effeffd4..7a50d7432 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -1,7 +1,12 @@ /* eslint-disable no-var */ +type QtTransportMessage = { + data: string; +}; + interface QtTransport { send: (message: string) => void, + onmessage: (message: QtTransportMessage) => void, } interface Qt { @@ -12,4 +17,4 @@ declare global { var qt: Qt | undefined; } -export { }; +export {} \ No newline at end of file From 4b56ac44c2bb4052c867cb4bbf489e73cd12e978 Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 24 Feb 2025 14:40:32 +0100 Subject: [PATCH 75/99] style: code format --- src/App/App.js | 2 +- src/common/useShell.ts | 20 +++++++++----------- src/types/global.d.ts | 2 +- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/App/App.js b/src/App/App.js index b6031be6e..d3a1ce188 100644 --- a/src/App/App.js +++ b/src/App/App.js @@ -100,7 +100,7 @@ const App = () => { }; }, []); - // Handle shell window visibility changed event + // Handle shell window visibility changed event React.useEffect(() => { const onWindowVisibilityChanged = (state) => { setWindowHidden(state.visible === false && state.visibility === 0); diff --git a/src/common/useShell.ts b/src/common/useShell.ts index f4700d779..7baab60bc 100644 --- a/src/common/useShell.ts +++ b/src/common/useShell.ts @@ -17,11 +17,17 @@ type ShellEvent = { args: string[]; }; - - const createId = () => Math.floor(Math.random() * 9999) + 1; const useShell = () => { + const on = (name: string, listener: (arg: any) => void) => { + events.on(name, listener); + }; + + const off = (name: string, listener: (arg: any) => void) => { + events.off(name, listener); + }; + const send = (method: string, ...args: (string | number)[]) => { try { transport?.send(JSON.stringify({ @@ -31,19 +37,11 @@ const useShell = () => { method: 'onEvent', args: [method, ...args], })); - } catch(e) { + } catch (e) { console.error('Shell', 'Failed to send event', e); } }; - const on = (name: string, listener: (arg: any) => void) => { - events.on(name, listener); - }; - - const off = (name: string, listener: (arg: any) => void) => { - events.off(name, listener); - }; - useEffect(() => { if (!transport) return; diff --git a/src/types/global.d.ts b/src/types/global.d.ts index 7a50d7432..d1d601d5e 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -17,4 +17,4 @@ declare global { var qt: Qt | undefined; } -export {} \ No newline at end of file +export {}; From 3890001085dadbf07f6702082e0107c9e15afc2a Mon Sep 17 00:00:00 2001 From: Botzy Date: Mon, 24 Feb 2025 16:24:55 +0200 Subject: [PATCH 76/99] fix(Library): align guest Placeholder with Calendar Placeholder layout and styles on mobile --- src/routes/Library/Library.js | 87 ++++++++++--------- .../Library/Placeholder/Placeholder.less | 64 ++++++++++---- .../Library/Placeholder/Placeholder.tsx | 17 +++- 3 files changed, 108 insertions(+), 60 deletions(-) diff --git a/src/routes/Library/Library.js b/src/routes/Library/Library.js index e1cea5995..8e19f123b 100644 --- a/src/routes/Library/Library.js +++ b/src/routes/Library/Library.js @@ -59,55 +59,58 @@ const Library = ({ model, urlParams, queryParams }) => { }, [hasNextPage, loadNextPage]); const onScroll = useOnScrollToBottom(onScrollToBottom, SCROLL_TO_BOTTOM_TRESHOLD); React.useLayoutEffect(() => { - if (profile.auth !== null && library.selected && library.selected.request.page === 1 && library.catalog.length !== 0 ) { + if (profile.auth !== null && library.selected && library.selected.request.page === 1 && library.catalog.length !== 0) { scrollContainerRef.current.scrollTop = 0; } }, [profile.auth, library.selected]); return ( -
- { - model === 'continue_watching' || profile.auth !== null ? -
- - -
- : - null - } - { - model === 'library' && profile.auth === null ? - - : - library.selected === null ? - -
- {' -
{model === 'library' ? 'Library' : 'Continue Watching'} not loaded!
-
-
- : - library.catalog.length === 0 ? -
- {' -
Empty {model === 'library' ? 'Library' : 'Continue Watching'}
+ { + profile.auth === null ? + + :
+ { + model === 'continue_watching' ? +
+ +
: -
- {library.catalog.map((libItem, index) => ( - - ))} -
- } -
+ null + } + { + model === 'library' ? + library.selected === null ? + +
+ {' +
{model === 'library' ? 'Library' : 'Continue Watching'} not loaded!
+
+
+ : + library.catalog.length === 0 ? +
+ {' +
Empty {model === 'library' ? 'Library' : 'Continue Watching'}
+
+ : +
+ {library.catalog.map((libItem, index) => ( + + ))} +
+ : null + } +
+ } ); }; diff --git a/src/routes/Library/Placeholder/Placeholder.less b/src/routes/Library/Placeholder/Placeholder.less index 74908db66..55de0356a 100644 --- a/src/routes/Library/Placeholder/Placeholder.less +++ b/src/routes/Library/Placeholder/Placeholder.less @@ -8,14 +8,11 @@ flex-direction: column; align-items: center; justify-content: center; - height: 100%; + min-height: 100%; width: 100%; overflow-y: auto; .title { - display: flex; - flex: 1; - align-items: flex-end; font-size: 1.75rem; font-weight: 400; text-align: center; @@ -25,9 +22,6 @@ } .image-container { - display: flex; - flex: 1; - align-items: center; padding: 1.5rem 0; .image { @@ -37,14 +31,43 @@ } } - .button-container { + .overview { display: flex; - flex: 1; - align-items: flex-start; - margin: 1rem 0; + flex-direction: row; + align-items: center; + gap: 4rem; + margin-bottom: 1rem; + .point { + display: flex; + flex-direction: row; + align-items: center; + gap: 1.5rem; + width: 18rem; + + .icon { + flex: none; + height: 3.25rem; + width: 3.25rem; + color: var(--primary-foreground-color); + opacity: 0.3; + } + + .text { + flex: auto; + font-size: 1.1rem; + font-size: 500; + color: var(--primary-foreground-color); + opacity: 0.9; + } + } + } + + .button-container { + margin: 1rem 0; + .button { - flex: none; + display: flex; justify-content: center; height: 4rem; line-height: 4rem; @@ -54,7 +77,7 @@ text-align: center; border-radius: 3.5rem; background-color: var(--overlay-color); - + &:hover { outline: var(--focus-outline-size) solid var(--primary-foreground-color); background-color: transparent; @@ -68,11 +91,10 @@ padding: 1rem 2rem; .title { - flex: 0.5; + margin-bottom: 0; } .image-container { - flex: 2; padding: 1rem; .image { @@ -88,9 +110,17 @@ @media only screen and (max-width: @minimum) { .placeholder { + padding: 1rem 2rem; - .image-container { - flex: 1; + .overview { + flex-direction: column; + gap: 1rem; + + .point { + .text { + font-size: 1rem; + } + } } .button-container { diff --git a/src/routes/Library/Placeholder/Placeholder.tsx b/src/routes/Library/Placeholder/Placeholder.tsx index d619611d8..d854a2d54 100644 --- a/src/routes/Library/Placeholder/Placeholder.tsx +++ b/src/routes/Library/Placeholder/Placeholder.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { useTranslation } from 'react-i18next'; +import Icon from '@stremio/stremio-icons/react'; import { Button, Image } from 'stremio/components'; import styles from './Placeholder.less'; @@ -16,10 +17,24 @@ const Placeholder = () => {
{'
+
+
+ +
+ {t('NOT_LOGGED_IN_CLOUD')} +
+
+
+ +
+ {t('NOT_LOGGED_IN_RECOMMENDATIONS')} +
+
+
: From 2b5df908271d23f8b690c3298c812afe44fc6b30 Mon Sep 17 00:00:00 2001 From: Botzy Date: Tue, 25 Feb 2025 11:40:34 +0200 Subject: [PATCH 81/99] feat(useWindowSize): added hook for screen size --- src/common/index.js | 2 ++ src/common/useWindowSize.js | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/common/useWindowSize.js diff --git a/src/common/index.js b/src/common/index.js index 4acf8b056..ab3723cd0 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -24,6 +24,7 @@ const { default: useShell } = require('./useShell'); const useStreamingServer = require('./useStreamingServer'); const useTorrent = require('./useTorrent'); const useTranslate = require('./useTranslate'); +const useWindowSize = require('./useWindowSize'); module.exports = { FileDropProvider, @@ -55,4 +56,5 @@ module.exports = { useStreamingServer, useTorrent, useTranslate, + useWindowSize, }; diff --git a/src/common/useWindowSize.js b/src/common/useWindowSize.js new file mode 100644 index 000000000..9f7285261 --- /dev/null +++ b/src/common/useWindowSize.js @@ -0,0 +1,18 @@ +// Copyright (C) 2017-2025 Smart code 203358507 + +const { useState, useEffect } = require('react'); + +const useWindowSize = () => { + const [size, setSize] = useState({ width: window.innerWidth, height: window.innerHeight }); + + useEffect(() => { + const handleResize = () => setSize({ width: window.innerWidth, height: window.innerHeight }); + + window.addEventListener('resize', handleResize); + return () => window.removeEventListener('resize', handleResize); + }, []); + + return size; +}; + +module.exports = useWindowSize; From b563ea1d10e24bc21f35af69cfec4fb98fed382e Mon Sep 17 00:00:00 2001 From: Botzy Date: Tue, 25 Feb 2025 11:45:48 +0200 Subject: [PATCH 82/99] fix(BottomSheet): hide BottomSheet when screen is resized --- src/components/BottomSheet/BottomSheet.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/BottomSheet/BottomSheet.tsx b/src/components/BottomSheet/BottomSheet.tsx index 7ebfb79d8..28e2f631a 100644 --- a/src/components/BottomSheet/BottomSheet.tsx +++ b/src/components/BottomSheet/BottomSheet.tsx @@ -4,6 +4,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { createPortal } from 'react-dom'; import classNames from 'classnames'; import useBinaryState from 'stremio/common/useBinaryState'; +import useWindowSize from 'stremio/common/useWindowSize'; import styles from './BottomSheet.less'; const CLOSE_THRESHOLD = 100; @@ -17,6 +18,7 @@ type Props = { const BottomSheet = ({ children, title, show, onClose }: Props) => { const containerRef = useRef(null); + const { width: windowWidth, height: windowHeight } = useWindowSize(); const [startOffset, setStartOffset] = useState(0); const [offset, setOffset] = useState(0); @@ -58,6 +60,10 @@ const BottomSheet = ({ children, title, show, onClose }: Props) => { !opened && onClose(); }, [opened]); + useEffect(() => { + opened && close(); + }, [windowWidth, windowHeight]); + return opened && createPortal((
From 9d17c82562aac8586f7b12441f85ffd01e7f300e Mon Sep 17 00:00:00 2001 From: Botsy Date: Tue, 25 Feb 2025 12:24:30 +0200 Subject: [PATCH 83/99] Update src/routes/Intro/styles.less Co-authored-by: Timothy Z. --- src/routes/Intro/styles.less | 1 - 1 file changed, 1 deletion(-) diff --git a/src/routes/Intro/styles.less b/src/routes/Intro/styles.less index b42a0b144..935b0fad1 100644 --- a/src/routes/Intro/styles.less +++ b/src/routes/Intro/styles.less @@ -291,7 +291,6 @@ } } - @media only screen and (max-width: @minimum) { .intro-container { .content-container { From e10c0312334ed550e4a8ea88fee9019222a473ea Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Tue, 25 Feb 2025 12:43:57 +0200 Subject: [PATCH 84/99] fix(Calendar): styles --- src/routes/Calendar/Calendar.less | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/Calendar/Calendar.less b/src/routes/Calendar/Calendar.less index 4763353f1..352514da4 100644 --- a/src/routes/Calendar/Calendar.less +++ b/src/routes/Calendar/Calendar.less @@ -13,7 +13,7 @@ gap: 0.5rem; width: 100%; height: 100%; - padding: 0 0 calc(1.5rem + var(--safe-area-inset-bottom)) 2rem; + padding: 0 0 2rem; .main { flex: auto; @@ -36,7 +36,7 @@ @media only screen and (max-width: @small) and (orientation: landscape) { .calendar { .content { - padding: 0 0 calc(1.5rem + var(--safe-area-inset-bottom)) 1rem; + padding: 0 0 1rem; } } } From fdda35841233c9bc8b72186dd2eb13a990e6f750 Mon Sep 17 00:00:00 2001 From: "Timothy Z." Date: Tue, 25 Feb 2025 12:56:40 +0200 Subject: [PATCH 85/99] refactor(Calendar): simplify the styles align the padding to other routes values --- src/routes/Calendar/Calendar.less | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/routes/Calendar/Calendar.less b/src/routes/Calendar/Calendar.less index 352514da4..63168360d 100644 --- a/src/routes/Calendar/Calendar.less +++ b/src/routes/Calendar/Calendar.less @@ -13,7 +13,7 @@ gap: 0.5rem; width: 100%; height: 100%; - padding: 0 0 2rem; + padding: 0 0 1.5rem 1.5rem; .main { flex: auto; @@ -31,12 +31,4 @@ padding: 0; } } -} - -@media only screen and (max-width: @small) and (orientation: landscape) { - .calendar { - .content { - padding: 0 0 1rem; - } - } -} +} \ No newline at end of file From 8733af871b2a694e92d676c127664d7c3ce34b94 Mon Sep 17 00:00:00 2001 From: Botzy Date: Tue, 25 Feb 2025 13:57:50 +0200 Subject: [PATCH 86/99] fix(BottomSheet): close BottomSheet on orientation change --- src/common/index.js | 4 +- src/common/useOrientation.ts | 63 ++++++++++++++++++++++ src/common/useWindowSize.js | 18 ------- src/components/BottomSheet/BottomSheet.tsx | 6 +-- 4 files changed, 68 insertions(+), 23 deletions(-) create mode 100644 src/common/useOrientation.ts delete mode 100644 src/common/useWindowSize.js diff --git a/src/common/index.js b/src/common/index.js index ab3723cd0..82f7a6a0c 100644 --- a/src/common/index.js +++ b/src/common/index.js @@ -24,7 +24,7 @@ const { default: useShell } = require('./useShell'); const useStreamingServer = require('./useStreamingServer'); const useTorrent = require('./useTorrent'); const useTranslate = require('./useTranslate'); -const useWindowSize = require('./useWindowSize'); +const { default: useOrientation } = require('./useOrientation'); module.exports = { FileDropProvider, @@ -56,5 +56,5 @@ module.exports = { useStreamingServer, useTorrent, useTranslate, - useWindowSize, + useOrientation, }; diff --git a/src/common/useOrientation.ts b/src/common/useOrientation.ts new file mode 100644 index 000000000..b92c7b394 --- /dev/null +++ b/src/common/useOrientation.ts @@ -0,0 +1,63 @@ +// Copyright (C) 2017-2025 Smart code 203358507 + +import { useState, useEffect } from 'react'; + +type DeviceOrientationData = { + alpha: number | null; + beta: number | null; + gamma: number | null; + absolute: boolean | null; + permissionGranted: boolean; +}; + +const useOrientation = () => { + const [orientation, setOrientation] = useState({ + alpha: null, + beta: null, + gamma: null, + absolute: null, + permissionGranted: false, + }); + + const requestPermission = async () => { + if ( + typeof DeviceOrientationEvent !== 'undefined' && + (DeviceOrientationEvent as any).requestPermission + ) { + try { + const permissionState = await (DeviceOrientationEvent as any).requestPermission(); + if (permissionState === 'granted') { + setOrientation((prev) => ({ ...prev, permissionGranted: true })); + } + } catch (error) { + console.error('Error requesting DeviceOrientation permission:', error); + } + } else { + setOrientation((prev) => ({ ...prev, permissionGranted: true })); + } + }; + + useEffect(() => { + const handleOrientationChange = (event: DeviceOrientationEvent) => { + setOrientation((prev) => ({ + ...prev, + alpha: event.alpha ?? null, + beta: event.beta ?? null, + gamma: event.gamma ?? null, + absolute: event.absolute ?? null, + })); + }; + + if (orientation.permissionGranted && window.DeviceOrientationEvent) { + window.addEventListener('deviceorientation', handleOrientationChange); + } + + return () => { + window.removeEventListener('deviceorientation', handleOrientationChange); + }; + }, [orientation.permissionGranted]); + + return { ...orientation, requestPermission }; +}; + +export default useOrientation; diff --git a/src/common/useWindowSize.js b/src/common/useWindowSize.js deleted file mode 100644 index 9f7285261..000000000 --- a/src/common/useWindowSize.js +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (C) 2017-2025 Smart code 203358507 - -const { useState, useEffect } = require('react'); - -const useWindowSize = () => { - const [size, setSize] = useState({ width: window.innerWidth, height: window.innerHeight }); - - useEffect(() => { - const handleResize = () => setSize({ width: window.innerWidth, height: window.innerHeight }); - - window.addEventListener('resize', handleResize); - return () => window.removeEventListener('resize', handleResize); - }, []); - - return size; -}; - -module.exports = useWindowSize; diff --git a/src/components/BottomSheet/BottomSheet.tsx b/src/components/BottomSheet/BottomSheet.tsx index 28e2f631a..d7dfe7130 100644 --- a/src/components/BottomSheet/BottomSheet.tsx +++ b/src/components/BottomSheet/BottomSheet.tsx @@ -4,7 +4,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { createPortal } from 'react-dom'; import classNames from 'classnames'; import useBinaryState from 'stremio/common/useBinaryState'; -import useWindowSize from 'stremio/common/useWindowSize'; +import useOrientation from 'stremio/common/useOrientation'; import styles from './BottomSheet.less'; const CLOSE_THRESHOLD = 100; @@ -18,7 +18,7 @@ type Props = { const BottomSheet = ({ children, title, show, onClose }: Props) => { const containerRef = useRef(null); - const { width: windowWidth, height: windowHeight } = useWindowSize(); + const orientation = useOrientation(); const [startOffset, setStartOffset] = useState(0); const [offset, setOffset] = useState(0); @@ -62,7 +62,7 @@ const BottomSheet = ({ children, title, show, onClose }: Props) => { useEffect(() => { opened && close(); - }, [windowWidth, windowHeight]); + }, [orientation]); return opened && createPortal((
From dc5c94b461c2d40f9891bbe0f6cc225b3b67965e Mon Sep 17 00:00:00 2001 From: Botzy Date: Tue, 25 Feb 2025 14:54:32 +0200 Subject: [PATCH 87/99] refactor(useOrientation): refactor hook to not ask for permissions --- src/common/useOrientation.ts | 61 ++++++++++-------------------------- 1 file changed, 16 insertions(+), 45 deletions(-) diff --git a/src/common/useOrientation.ts b/src/common/useOrientation.ts index b92c7b394..ec0eac293 100644 --- a/src/common/useOrientation.ts +++ b/src/common/useOrientation.ts @@ -1,63 +1,34 @@ // Copyright (C) 2017-2025 Smart code 203358507 -import { useState, useEffect } from 'react'; +import { useState, useEffect, useMemo } from 'react'; -type DeviceOrientationData = { - alpha: number | null; - beta: number | null; - gamma: number | null; - absolute: boolean | null; - permissionGranted: boolean; -}; +type DeviceOrientation = 'landscape' | 'portrait'; const useOrientation = () => { - const [orientation, setOrientation] = useState({ - alpha: null, - beta: null, - gamma: null, - absolute: null, - permissionGranted: false, - }); + const [windowHeight, setWindowHeight] = useState(window.innerHeight); + const [windowWidth, setWindowWidth] = useState(window.innerWidth); - const requestPermission = async () => { - if ( - typeof DeviceOrientationEvent !== 'undefined' && - (DeviceOrientationEvent as any).requestPermission - ) { - try { - const permissionState = await (DeviceOrientationEvent as any).requestPermission(); - if (permissionState === 'granted') { - setOrientation((prev) => ({ ...prev, permissionGranted: true })); - } - } catch (error) { - console.error('Error requesting DeviceOrientation permission:', error); - } + const orientation: DeviceOrientation = useMemo(() => { + if (windowHeight > windowWidth) { + return 'portrait'; } else { - setOrientation((prev) => ({ ...prev, permissionGranted: true })); + return 'landscape'; } - }; + }, [windowWidth, windowHeight]); useEffect(() => { - const handleOrientationChange = (event: DeviceOrientationEvent) => { - setOrientation((prev) => ({ - ...prev, - alpha: event.alpha ?? null, - beta: event.beta ?? null, - gamma: event.gamma ?? null, - absolute: event.absolute ?? null, - })); + const handleResize = () => { + setWindowHeight(window.innerHeight); + setWindowWidth(window.innerWidth); }; - if (orientation.permissionGranted && window.DeviceOrientationEvent) { - window.addEventListener('deviceorientation', handleOrientationChange); - } - + window.addEventListener('resize', handleResize); return () => { - window.removeEventListener('deviceorientation', handleOrientationChange); + window.removeEventListener('resize', handleResize); }; - }, [orientation.permissionGranted]); + }, [window.innerWidth, window.innerHeight]); - return { ...orientation, requestPermission }; + return { orientation }; }; export default useOrientation; From a2131393195445ce492d3af268351f06770c5818 Mon Sep 17 00:00:00 2001 From: Botzy Date: Tue, 25 Feb 2025 15:04:27 +0200 Subject: [PATCH 88/99] fix(useOrientation): fix hook return value --- src/common/useOrientation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/useOrientation.ts b/src/common/useOrientation.ts index ec0eac293..add8d1d40 100644 --- a/src/common/useOrientation.ts +++ b/src/common/useOrientation.ts @@ -28,7 +28,7 @@ const useOrientation = () => { }; }, [window.innerWidth, window.innerHeight]); - return { orientation }; + return orientation; }; export default useOrientation; From 7220635d79575a201826e5b5e8523238b58d8903 Mon Sep 17 00:00:00 2001 From: Ivelin Megdanov Date: Wed, 26 Feb 2025 12:05:17 +0200 Subject: [PATCH 89/99] Show catalog names while loading --- src/routes/Search/Search.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/routes/Search/Search.js b/src/routes/Search/Search.js index 4b052ed46..abfa99740 100644 --- a/src/routes/Search/Search.js +++ b/src/routes/Search/Search.js @@ -4,7 +4,7 @@ const React = require('react'); const PropTypes = require('prop-types'); const classnames = require('classnames'); const debounce = require('lodash.debounce'); -const { useTranslation } = require('react-i18next'); +const useTranslate = require('stremio/common/useTranslate'); const { default: Icon } = require('@stremio/stremio-icons/react'); const { withCoreSuspender, getVisibleChildrenRange } = require('stremio/common'); const { Image, MainNavBars, MetaItem, MetaRow } = require('stremio/components'); @@ -14,7 +14,7 @@ const styles = require('./styles'); const THRESHOLD = 100; const Search = ({ queryParams }) => { - const { t } = useTranslation(); + const t = useTranslate(); const [search, loadSearchRows] = useSearch(queryParams); const query = React.useMemo(() => { return search.selected !== null ? @@ -52,24 +52,24 @@ const Search = ({ queryParams }) => { query === null ?
-
{t('SEARCH_ANYTHING')}
+
{t.string('SEARCH_ANYTHING')}
-
{t('SEARCH_CATEGORIES')}
+
{t.string('SEARCH_CATEGORIES')}
-
{t('SEARCH_PERSONS')}
+
{t.string('SEARCH_PERSONS')}
-
{t('SEARCH_PROTOCOLS')}
+
{t.string('SEARCH_PROTOCOLS')}
-
{t('SEARCH_TYPES')}
+
{t.string('SEARCH_TYPES')}
@@ -81,7 +81,7 @@ const Search = ({ queryParams }) => { src={require('/images/empty.png')} alt={' '} /> -
{ t('STREMIO_TV_SEARCH_NO_ADDONS') }
+
{ t.string('STREMIO_TV_SEARCH_NO_ADDONS') }
: search.catalogs.map((catalog, index) => { @@ -110,11 +110,13 @@ const Search = ({ queryParams }) => { return null; } default: { + const loadingTitle = `${catalog.addon.manifest.name}: ${t.catalogTitle(catalog)}`; return ( ); } From 3d56023ffd662f9eb905eb3ea3ee2355f2ae0f38 Mon Sep 17 00:00:00 2001 From: Ivelin Megdanov Date: Wed, 26 Feb 2025 12:25:47 +0200 Subject: [PATCH 90/99] Added addon name to catalogTitle function --- src/common/useTranslate.js | 3 ++- src/routes/Search/Search.js | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/useTranslate.js b/src/common/useTranslate.js index 7214a4a1e..342b27dcf 100644 --- a/src/common/useTranslate.js +++ b/src/common/useTranslate.js @@ -21,10 +21,11 @@ const useTranslate = () => { if (addon && id && name) { const partialKey = `${addon.manifest.id.split('.').join('_')}_${id}`; const translatedName = stringWithPrefix(partialKey, 'CATALOG_', name); + const addonName = addon.manifest.name; if (type && withType) { const translatedType = stringWithPrefix(type, 'TYPE_'); - return `${translatedName} - ${translatedType}`; + return `${addonName}: ${translatedName} - ${translatedType}`; } return translatedName; diff --git a/src/routes/Search/Search.js b/src/routes/Search/Search.js index abfa99740..58e6e834b 100644 --- a/src/routes/Search/Search.js +++ b/src/routes/Search/Search.js @@ -110,13 +110,12 @@ const Search = ({ queryParams }) => { return null; } default: { - const loadingTitle = `${catalog.addon.manifest.name}: ${t.catalogTitle(catalog)}`; return ( ); } From 6420b5e0c95f82df3414e9949f100724cf1cd3fc Mon Sep 17 00:00:00 2001 From: Ivelin Megdanov Date: Wed, 26 Feb 2025 12:30:59 +0200 Subject: [PATCH 91/99] Added the loading title to the Board --- src/routes/Board/Board.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/routes/Board/Board.js b/src/routes/Board/Board.js index 9e721edf2..13acb4a86 100644 --- a/src/routes/Board/Board.js +++ b/src/routes/Board/Board.js @@ -3,7 +3,7 @@ const React = require('react'); const classnames = require('classnames'); const debounce = require('lodash.debounce'); -const { useTranslation } = require('react-i18next'); +const useTranslate = require('stremio/common/useTranslate'); const { useStreamingServer, useNotifications, withCoreSuspender, getVisibleChildrenRange, useProfile } = require('stremio/common'); const { ContinueWatchingItem, EventModal, MainNavBars, MetaItem, MetaRow } = require('stremio/components'); const useBoard = require('./useBoard'); @@ -14,7 +14,7 @@ const { default: StreamingServerWarning } = require('./StreamingServerWarning'); const THRESHOLD = 5; const Board = () => { - const { t } = useTranslation(); + const t = useTranslate(); const streamingServer = useStreamingServer(); const continueWatchingPreview = useContinueWatchingPreview(); const [board, loadBoardRows] = useBoard(); @@ -55,7 +55,7 @@ const Board = () => { continueWatchingPreview.items.length > 0 ? { key={index} className={classnames(styles['board-row'], styles['board-row-poster'], 'animation-fade-in')} catalog={catalog} + title={t.catalogTitle(catalog)} /> ); } From fef0a57ac719b721fca2571a1c0760257569ed91 Mon Sep 17 00:00:00 2001 From: Ivelin Megdanov Date: Thu, 27 Feb 2025 13:41:30 +0200 Subject: [PATCH 92/99] Removed addon name from catalog title --- src/common/useTranslate.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/common/useTranslate.js b/src/common/useTranslate.js index 342b27dcf..7214a4a1e 100644 --- a/src/common/useTranslate.js +++ b/src/common/useTranslate.js @@ -21,11 +21,10 @@ const useTranslate = () => { if (addon && id && name) { const partialKey = `${addon.manifest.id.split('.').join('_')}_${id}`; const translatedName = stringWithPrefix(partialKey, 'CATALOG_', name); - const addonName = addon.manifest.name; if (type && withType) { const translatedType = stringWithPrefix(type, 'TYPE_'); - return `${addonName}: ${translatedName} - ${translatedType}`; + return `${translatedName} - ${translatedType}`; } return translatedName; From faba70434286a98ca5635c05df77319754038fa4 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 27 Feb 2025 15:42:24 +0100 Subject: [PATCH 93/99] chore: v5.0.0-beta.19 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index dadfc5ec8..e862ca626 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "stremio", - "version": "5.0.0-beta.18", + "version": "5.0.0-beta.19", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "stremio", - "version": "5.0.0-beta.18", + "version": "5.0.0-beta.19", "license": "gpl-2.0", "dependencies": { "@babel/runtime": "7.26.0", diff --git a/package.json b/package.json index 04a96a75e..c0b375ab4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "stremio", "displayName": "Stremio", - "version": "5.0.0-beta.18", + "version": "5.0.0-beta.19", "author": "Smart Code OOD", "private": true, "license": "gpl-2.0", From 72053246cbda476c601131e79d0e666e194868a8 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 27 Feb 2025 22:55:23 +0100 Subject: [PATCH 94/99] fix(useShell): use chrome.webview instead of qt webChannelTransport --- src/common/useShell.ts | 10 ++++++---- src/types/global.d.ts | 11 +++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/common/useShell.ts b/src/common/useShell.ts index 7baab60bc..1a7bcb6ee 100644 --- a/src/common/useShell.ts +++ b/src/common/useShell.ts @@ -2,7 +2,7 @@ import { useEffect } from 'react'; import EventEmitter from 'eventemitter3'; const SHELL_EVENT_OBJECT = 'transport'; -const transport = globalThis?.qt?.webChannelTransport; +const transport = globalThis?.chrome?.webview; const events = new EventEmitter(); enum ShellEventType { @@ -30,7 +30,7 @@ const useShell = () => { const send = (method: string, ...args: (string | number)[]) => { try { - transport?.send(JSON.stringify({ + transport?.postMessage(JSON.stringify({ id: createId(), type: ShellEventType.INVOKE_METHOD, object: SHELL_EVENT_OBJECT, @@ -45,10 +45,9 @@ const useShell = () => { useEffect(() => { if (!transport) return; - transport.onmessage = ({ data }) => { + const onMessage = ({ data }: { data: string }) => { try { const { type, args } = JSON.parse(data) as ShellEvent; - if (type === ShellEventType.SIGNAL) { const [methodName, methodArg] = args; events.emit(methodName, methodArg); @@ -57,6 +56,9 @@ const useShell = () => { console.error('Shell', 'Failed to handle event', e); } }; + + transport.addEventListener('message', onMessage); + return () => transport.removeEventListener('message', onMessage); }, []); return { diff --git a/src/types/global.d.ts b/src/types/global.d.ts index d1d601d5e..3849b8914 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -13,8 +13,19 @@ interface Qt { webChannelTransport: QtTransport, } +interface ChromeWebView { + addEventListener: (type: 'message', listenenr: (event: any) => void) => void, + removeEventListener: (type: 'message', listenenr: (event: any) => void) => void, + postMessage: (message: string) => void, +} + +interface Chrome { + webview: ChromeWebView, +} + declare global { var qt: Qt | undefined; + var chrome: Chrome | undefined; } export {}; From 7ea8b18c59a24701e0acd6bc4745b62e9c3812f2 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 27 Feb 2025 23:13:16 +0100 Subject: [PATCH 95/99] fix(Settings): quit on close setting label --- src/routes/Settings/Settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/Settings/Settings.js b/src/routes/Settings/Settings.js index 312ad9e49..f238c1d02 100644 --- a/src/routes/Settings/Settings.js +++ b/src/routes/Settings/Settings.js @@ -341,7 +341,7 @@ const Settings = () => {
{ t('SETTINGS_NAV_PLAYER') }
-
{t('SETTINGS_SECTION_SUBTITLES')}
+
{t('SETTINGS_CLOSE_WINDOW')}
From 24d11b4cf942957a602d68f4667eadd509bfed49 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 27 Feb 2025 23:15:44 +0100 Subject: [PATCH 96/99] chore: v5.0.0-beta.20 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index e862ca626..0824f882f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "stremio", - "version": "5.0.0-beta.19", + "version": "5.0.0-beta.20", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "stremio", - "version": "5.0.0-beta.19", + "version": "5.0.0-beta.20", "license": "gpl-2.0", "dependencies": { "@babel/runtime": "7.26.0", diff --git a/package.json b/package.json index c0b375ab4..4cab1781f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "stremio", "displayName": "Stremio", - "version": "5.0.0-beta.19", + "version": "5.0.0-beta.20", "author": "Smart Code OOD", "private": true, "license": "gpl-2.0", From 28dbdaa20dd48e1cb669c3132d9b947a3c1b6fe5 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Fri, 28 Feb 2025 09:06:04 +0200 Subject: [PATCH 97/99] feat: MetaDetails selects appropriate season: - For non-watched series it choses 1st season - For watched series it uses the LibraryItem video to choose the same season Signed-off-by: Lachezar Lechev --- src/routes/MetaDetails/VideosList/VideosList.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/routes/MetaDetails/VideosList/VideosList.js b/src/routes/MetaDetails/VideosList/VideosList.js index 557b3df1f..00ee07924 100644 --- a/src/routes/MetaDetails/VideosList/VideosList.js +++ b/src/routes/MetaDetails/VideosList/VideosList.js @@ -20,6 +20,7 @@ const VideosList = ({ className, metaItem, libraryItem, season, seasonOnSelect, : []; }, [metaItem]); + // Orders season from 1 to X and 0 (special season) at the end const seasons = React.useMemo(() => { return videos .map(({ season }) => season) @@ -36,17 +37,27 @@ const VideosList = ({ className, metaItem, libraryItem, season, seasonOnSelect, return season; } + if (libraryItem?.state.video_id && videos) { + const video = videos?.find((video) => video.id === libraryItem.state.video_id); + + if (video && video.season && seasons.includes(video.season)) { + return video.season; + } + } + const nonSpecialSeasons = seasons.filter((season) => season !== 0); if (nonSpecialSeasons.length > 0) { - return nonSpecialSeasons[nonSpecialSeasons.length - 1]; + // default to 1st season + return nonSpecialSeasons[0]; } if (seasons.length > 0) { - return seasons[seasons.length - 1]; + // default to 1st season + return seasons[0]; } return null; - }, [seasons, season]); + }, [seasons, season, videos, libraryItem]); const videosForSeason = React.useMemo(() => { return videos .filter((video) => { From dba40169793aa6eaee8e0c55178bd4d53394ced9 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Fri, 28 Feb 2025 11:01:02 +0200 Subject: [PATCH 98/99] chore: VideoList - clean up Signed-off-by: Lachezar Lechev --- src/routes/MetaDetails/VideosList/VideosList.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/routes/MetaDetails/VideosList/VideosList.js b/src/routes/MetaDetails/VideosList/VideosList.js index 00ee07924..58614c9d9 100644 --- a/src/routes/MetaDetails/VideosList/VideosList.js +++ b/src/routes/MetaDetails/VideosList/VideosList.js @@ -20,7 +20,6 @@ const VideosList = ({ className, metaItem, libraryItem, season, seasonOnSelect, : []; }, [metaItem]); - // Orders season from 1 to X and 0 (special season) at the end const seasons = React.useMemo(() => { return videos .map(({ season }) => season) @@ -37,22 +36,18 @@ const VideosList = ({ className, metaItem, libraryItem, season, seasonOnSelect, return season; } - if (libraryItem?.state.video_id && videos) { - const video = videos?.find((video) => video.id === libraryItem.state.video_id); + const video = videos?.find((video) => video.id === libraryItem?.state.video_id); - if (video && video.season && seasons.includes(video.season)) { - return video.season; - } + if (video && video.season && seasons.includes(video.season)) { + return video.season; } const nonSpecialSeasons = seasons.filter((season) => season !== 0); if (nonSpecialSeasons.length > 0) { - // default to 1st season return nonSpecialSeasons[0]; } if (seasons.length > 0) { - // default to 1st season return seasons[0]; } From 1b70268b40772dac08172830cd7accaaa506b190 Mon Sep 17 00:00:00 2001 From: Botzy Date: Mon, 10 Mar 2025 17:52:02 +0200 Subject: [PATCH 99/99] fix(Player): handle touch events for context menu --- src/routes/Player/ControlBar/ControlBar.js | 6 +++- src/routes/Player/Player.js | 29 +++++++++++++++---- .../SideDrawerButton/SideDrawerButton.tsx | 8 +++-- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/routes/Player/ControlBar/ControlBar.js b/src/routes/Player/ControlBar/ControlBar.js index 60e3157a0..c81d0e38e 100644 --- a/src/routes/Player/ControlBar/ControlBar.js +++ b/src/routes/Player/ControlBar/ControlBar.js @@ -41,6 +41,8 @@ const ControlBar = ({ onToggleOptionsMenu, onToggleStatisticsMenu, onContextMenu, + onTouchStart, + onTouchEnd, ...props }) => { const { chromecast } = useServices(); @@ -104,7 +106,7 @@ const ControlBar = ({ }; }, []); return ( -
+
{ toggleFullscreen(); }, [toggleFullscreen]); - const onContextMenu = React.useCallback((e) => { - e.preventDefault(); - const { clientX, clientY } = e; + const handleContextMenuPosition = (clientX, clientY) => { const safeAreaTop = parseFloat(getComputedStyle(document.documentElement).getPropertyValue('env(safe-area-inset-top)')) || 0; const safeAreaRight = parseFloat(getComputedStyle(document.documentElement).getPropertyValue('env(safe-area-inset-right)')) || 0; const safeAreaBottom = parseFloat(getComputedStyle(document.documentElement).getPropertyValue('env(safe-area-inset-bottom)')) || 0; @@ -280,9 +278,24 @@ const Player = ({ urlParams, queryParams }) => { x: adjustedX, y: adjustedY, }); + }; + + const onContextMenu = React.useCallback((e) => { + e.preventDefault(); + const { clientX, clientY } = e; + handleContextMenuPosition(clientX, clientY); openContextMenu(); }, [contextMenuRef]); + const onTouchStart = (event) => { + const touch = event.touches[0]; + handleContextMenuPosition(touch.clientX, touch.clientY); + }; + + const onTouchEnd = () => { + openContextMenu(); + }; + React.useEffect(() => { if (!contextMenuOpen) { const menuSize = contextMenuRef?.current?.getBoundingClientRect(); @@ -689,7 +702,7 @@ const Player = ({ urlParams, queryParams }) => { /> { !video.state.loaded ? -
+
: @@ -697,7 +710,7 @@ const Player = ({ urlParams, queryParams }) => { } { (video.state.buffering || !video.state.loaded) && !error ? - + : null } @@ -755,6 +768,8 @@ const Player = ({ urlParams, queryParams }) => { onMouseMove={onBarMouseMove} onMouseOver={onBarMouseMove} onContextMenu={onContextMenu} + onTouchStart={onTouchStart} + onTouchEnd={onTouchEnd} /> { player.metaItem?.type === 'Ready' ? @@ -762,6 +777,8 @@ const Player = ({ urlParams, queryParams }) => { className={classnames(styles['layer'], styles['side-drawer-button-layer'])} onClick={toggleSideDrawer} onContextMenu={onContextMenu} + onTouchStart={onTouchStart} + onTouchEnd={onTouchEnd} /> : null @@ -797,6 +814,8 @@ const Player = ({ urlParams, queryParams }) => { onMouseMove={onBarMouseMove} onMouseOver={onBarMouseMove} onContextMenu={onContextMenu} + onTouchStart={onTouchStart} + onTouchEnd={onTouchEnd} /> { nextVideoPopupOpen ? diff --git a/src/routes/Player/SideDrawerButton/SideDrawerButton.tsx b/src/routes/Player/SideDrawerButton/SideDrawerButton.tsx index 5f5590476..9d5897548 100644 --- a/src/routes/Player/SideDrawerButton/SideDrawerButton.tsx +++ b/src/routes/Player/SideDrawerButton/SideDrawerButton.tsx @@ -1,6 +1,6 @@ // Copyright (C) 2017-2024 Smart code 203358507 -import React from 'react'; +import React, { BaseSyntheticEvent } from 'react'; import classNames from 'classnames'; import Icon from '@stremio/stremio-icons/react'; import styles from './SideDrawerButton.less'; @@ -9,11 +9,13 @@ type Props = { className: string, onClick: () => void, onContextMenu: () => void, + onTouchStart: (event: BaseSyntheticEvent) => void, + onTouchEnd: () => void, }; -const SideDrawerButton = ({ className, onClick, onContextMenu }: Props) => { +const SideDrawerButton = ({ className, onClick, onContextMenu, onTouchStart, onTouchEnd }: Props) => { return ( -
+
);