Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
84e5f23
feat: added react-router dependency
Botsy Apr 16, 2025
f7c1c82
feat(dependencies): added react-router-dom
Botsy Apr 29, 2025
3c5e754
feat(Router): added HashRouter to manage routes in app
Botsy Apr 29, 2025
90d5401
fix: cycle dependency with useRouteFocused
Botsy Apr 29, 2025
b15ff42
fix(App): clean up unused code
Botsy Apr 29, 2025
91c363c
Merge branch 'development' into feat/react-router
Botsy Apr 29, 2025
95a3965
fix(Discover): parse correct url and query params
Botsy Apr 29, 2025
d0891ad
fix(Library): parse correct url and query params and model type
Botsy Apr 29, 2025
0951ef3
fix(Calendar): parse correct url params
Botsy Apr 29, 2025
ed65bed
fix(Addons): parse correct url and search params
Botsy Apr 29, 2025
f87ef3d
fix(MetaDetails): parse correct url and search params
Botsy Apr 29, 2025
f026175
fix(Player): parse correct url and search params
Botsy Apr 29, 2025
0e75a6c
fix(Search): parse correct url and search params
Botsy Apr 29, 2025
2fbddee
fix(Intro): parse correct query params
Botsy Apr 29, 2025
e633ba3
fix(Search): linting
Botsy Apr 29, 2025
271f8c9
fix(ModalDialog): fix issue with cycle dependencies in ModalDialog
Botsy May 12, 2025
8ca47ac
feat(withProtectedRoutes): use navigate instead of window location
Botsy May 13, 2025
9a3ac82
feat(ContinueWatching): use navigate instead window location
Botsy May 13, 2025
1737450
feat(LibItem): use navigate instead window location
Botsy May 13, 2025
6b35568
feat(SearchBar): use navigate instead window location
Botsy May 14, 2025
3c012fc
feat(Video): use navigate instead window location
Botsy May 14, 2025
ba652b8
feat(useSelectableInputs): use navigate instead window location
Botsy May 14, 2025
e2830ef
feat(Library): use navigate instead window location
Botsy May 14, 2025
d1c9514
feat(Calendar): use navigate instead window location
Botsy May 14, 2025
2a82371
feat(MetaDetails): use navigate instead window location
Botsy May 14, 2025
ee11a3d
fix: linting
Botsy May 14, 2025
c116df2
feat(EpisodePicker): use location from react router instead window.lo…
Botsy May 15, 2025
86c54bf
feat(Player): use navigate from react router instead window.location
Botsy May 15, 2025
7b92a11
feat: use navigate instead of window.history
Botsy May 15, 2025
a06737a
Merge branch 'development' into feat/react-router
Botsy May 19, 2025
d9ac72f
fix(useModelState): fix issue with infinite datastoreGet requests on …
Botsy May 19, 2025
bd8e407
fix(Player): remove unused import
Botsy May 19, 2025
31c89c6
fix(Intro): fix Modal circular dependency import
Botsy May 20, 2025
efe6171
refactor(profile): login/logout button logic
Botsy May 20, 2025
4fbdd64
refactor(withProtectedRoutes): remove unused HOC and improved the red…
Botsy May 20, 2025
c439503
revert(useModelState): revert changes on dispatching actions for diff…
Botsy May 22, 2025
3cabd4a
Merge branch 'development' into feat/react-router
Botsy Jun 18, 2025
604a1ca
fix: issue with infinite api calls on meta details
Botsy Jun 18, 2025
1457d12
fix typo
Botsy Jun 19, 2025
d33f78e
Merge branch 'development' of https://github.com/Stremio/stremio-web …
tymmesyde Jun 20, 2025
6d0136e
fix(Discover): flashing on tab switch
Botsy Jun 24, 2025
bb45004
fix: memoize url params
Botsy Jun 24, 2025
ec4c6ef
Merge branch 'development' into feat/react-router
kKaskak Jun 24, 2025
e30b33c
chore: fix builds
kKaskak Jun 24, 2025
2776367
chore: remove unnecessary change
kKaskak Jun 24, 2025
fc320e0
fix: replace route when going back in streams list or changing season
Botsy Jul 21, 2025
75f0820
fix(MetaItem): horizontal nav - go back to main origin instead using …
Botsy Jul 21, 2025
8876cea
fix: season search replace url
Botsy Jul 22, 2025
cf69505
fix: stop replacing routes in meta details video if on mobile
Botsy Jul 22, 2025
457e168
fix: issue with opening trailer
Botsy Aug 18, 2025
95a7f8a
Merge branch 'development' into feat/react-router
Botsy Aug 19, 2025
9205761
fix: use window location replace on next episode for complete compone…
Botsy Aug 25, 2025
41422eb
Merge branch 'development' into feat/react-router
Botsy Aug 26, 2025
b4b8e0a
fix: race condition with updating player time
Botsy Aug 26, 2025
7547348
Merge branch 'development' into feat/react-router
Botsy Apr 30, 2026
29058c5
chore: update pnpm-lock file
Botsy Apr 30, 2026
79c9fa4
fix: apply suggested fixes
Botsy Apr 30, 2026
ee24776
feat: toPath helper
Botsy Apr 30, 2026
4ce255c
refactor: reorganise code to use navigate from react router
Botsy Apr 30, 2026
3166fc3
chore: clean up leftover window.location and window.history and use n…
Botsy Apr 30, 2026
5fc7c5f
fix: use toPath helper in navigating
Botsy Apr 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
"react-focus-lock": "2.13.2",
"react-i18next": "^15.1.3",
"react-is": "18.3.1",
"react-router": "6.30.0",
"react-router-dom": "6.30.0",
"spatial-navigation-polyfill": "github:Stremio/spatial-navigation#64871b1422466f5f45d24ebc8bbd315b2ebab6a6",
"stremio-translations": "github:Stremio/stremio-translations#176c69f3bdede824f37979a046ee27cef355affc",
"url": "0.11.4",
Expand Down
37 changes: 37 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 1 addition & 36 deletions src/App/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,21 @@ const React = require('react');
const { useTranslation } = require('react-i18next');
const { Router } = require('stremio-router');
const { Core, Shell, Chromecast, DragAndDrop, KeyboardShortcuts, ServicesProvider, GamepadProvider } = require('stremio/services');
const { NotFound } = require('stremio/routes');
const { FileDropProvider, PlatformProvider, ToastProvider, TooltipProvider, ShortcutsProvider, CONSTANTS, withCoreSuspender, useShell, useBinaryState } = require('stremio/common');
const ServicesToaster = require('./ServicesToaster');
const DeepLinkHandler = require('./DeepLinkHandler');
const SearchParamsHandler = require('./SearchParamsHandler');
const { default: UpdaterBanner } = require('./UpdaterBanner');
const { default: ShortcutsModal } = require('./ShortcutsModal');
const { default: GamepadModal } = require('./GamepadModal');
const ErrorDialog = require('./ErrorDialog');
const withProtectedRoutes = require('./withProtectedRoutes');
const routerViewsConfig = require('./routerViewsConfig');
const styles = require('./styles');

const RouterWithProtectedRoutes = withCoreSuspender(withProtectedRoutes(Router));
const RouterWithProtectedRoutes = withCoreSuspender(Router);

const App = () => {
const { i18n } = useTranslation();
const shell = useShell();
const [gamepadSupportEnabled, setGamepadSupportEnabled] = React.useState(false);
const onPathNotMatch = React.useCallback(() => {
return NotFound;
}, []);
const services = React.useMemo(() => {
const core = new Core({
appVersion: process.env.VERSION,
Expand Down Expand Up @@ -116,31 +109,6 @@ const App = () => {
};
}, []);

// Handle shell events
React.useEffect(() => {
const onOpenMedia = (data) => {
try {
const { protocol, hostname, pathname, searchParams } = new URL(data);
if (protocol === CONSTANTS.PROTOCOL) {
if (hostname.length) {
const transportUrl = `https://${hostname}${pathname}`;
window.location.href = `#/addons?addon=${encodeURIComponent(transportUrl)}`;
} else {
window.location.href = `#${pathname}?${searchParams.toString()}`;
}
}
} catch (e) {
console.error('Failed to open media:', e);
}
};

shell.on('open-media', onOpenMedia);

return () => {
shell.off('open-media', onOpenMedia);
};
}, []);

React.useEffect(() => {
const onCoreEvent = ({ event, args }) => {
switch (event) {
Expand Down Expand Up @@ -238,13 +206,10 @@ const App = () => {
gamepadModalOpen && <GamepadModal onClose={closeGamepadModal}/>
}
<ServicesToaster />
<DeepLinkHandler />
<SearchParamsHandler />
<UpdaterBanner className={styles['updater-banner-container']} />
<RouterWithProtectedRoutes
className={styles['router']}
viewsConfig={routerViewsConfig}
onPathNotMatch={onPathNotMatch}
/>
</ShortcutsProvider>
</GamepadProvider>
Expand Down
5 changes: 4 additions & 1 deletion src/App/DeepLinkHandler.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
// Copyright (C) 2017-2023 Smart code 203358507

const React = require('react');
const { useNavigate } = require('react-router');
const { withCoreSuspender, useStreamingServer } = require('stremio/common');
const { default: toPath } = require('stremio/common/toPath');

const DeepLinkHandler = () => {
const navigate = useNavigate();
const streamingServer = useStreamingServer();
React.useEffect(() => {
if (streamingServer.torrent !== null) {
const [, { type, content }] = streamingServer.torrent;
if (type === 'Ready') {
const [, deepLinks] = content;
if (typeof deepLinks.metaDetailsVideos === 'string') {
window.location = deepLinks.metaDetailsVideos;
navigate(toPath(deepLinks.metaDetailsVideos));
}
}
}
Expand Down
35 changes: 35 additions & 0 deletions src/App/OpenMediaHandler.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (C) 2017-2026 Smart code 203358507

import { useEffect } from 'react';
import { useNavigate } from 'react-router';
import { useShell, CONSTANTS } from 'stremio/common';

const OpenMediaHandler = () => {
const navigate = useNavigate();
const shell = useShell();

useEffect(() => {
const onOpenMedia = (data: string) => {
try {
const { protocol, hostname, pathname, searchParams } = new URL(data);
if (protocol === CONSTANTS.PROTOCOL) {
if (hostname.length) {
const transportUrl = `https://${hostname}${pathname}`;
navigate(`/addons?addon=${encodeURIComponent(transportUrl)}`);
} else {
navigate(`${pathname}?${searchParams.toString()}`);
}
}
} catch (e) {
console.error('Failed to open media:', e);
}
};

shell.on('open-media', onOpenMedia);
return () => shell.off('open-media', onOpenMedia);
}, [navigate, shell]);

return null;
};

export default OpenMediaHandler;
29 changes: 0 additions & 29 deletions src/App/withProtectedRoutes.js

This file was deleted.

2 changes: 2 additions & 0 deletions src/common/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const useModelState = require('./useModelState');
const useNotifications = require('./useNotifications');
const useOnScrollToBottom = require('./useOnScrollToBottom');
const useProfile = require('./useProfile');
const { default: useRouteFocused } = require('./useRouteFocused');
const { default: useSettings } = require('./useSettings');
const { default: useShell } = require('./useShell');
const useStreamingServer = require('./useStreamingServer');
Expand Down Expand Up @@ -60,6 +61,7 @@ module.exports = {
useNotifications,
useOnScrollToBottom,
useProfile,
useRouteFocused,
useSettings,
useShell,
useStreamingServer,
Expand Down
59 changes: 59 additions & 0 deletions src/common/routerPaths.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (C) 2017-2025 Smart code 203358507

import React from 'react';
import routes from 'stremio/routes';

export const routerPaths = [
{
path: '/intro',
element: <routes.Intro />,
},
{
path: '/discover/:transportUrl?/:type?/:catalogId?',
element: <routes.Discover />,
},
{
path: '/library/:type?',
element: <routes.Library />,
},
{
path: '/calendar/:year?/:month?',
element: <routes.Calendar />,
},
{
path: '/continuewatching/:type?',
element: <routes.Library />,
},
{
path: '/search',
element: <routes.Search />,
},
{
path: '/metadetails/:type?/:id?/:videoId?',
element: <routes.MetaDetails />,
},
{
path: '/detail/:type?/:id?/:videoId?',
element: <routes.MetaDetails />,
},
{
path: '/addons/:type?/:transportUrl?/:catalogId?',
element: <routes.Addons />,
},
{
path: '/settings',
element: <routes.Settings />,
},
{
path: '/player/:stream?/:streamTransportUrl?/:metaTransportUrl?/:type?/:id?/:videoId?',
element: <routes.Player />,
},
{
path: '/',
element: <routes.Board />,
},
{
path: '*',
element: <routes.NotFound />,
},
];
5 changes: 5 additions & 0 deletions src/common/toPath.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright (C) 2017-2026 Smart code 203358507

const toPath = (link: string): string => link.startsWith('#') ? link.slice(1) : link;

export default toPath;
10 changes: 5 additions & 5 deletions src/common/useModelState.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const throttle = require('lodash.throttle');
const { deepEqual } = require('fast-equals');
const intersection = require('lodash.intersection');
const { useCoreSuspender } = require('stremio/common/CoreSuspender');
const { useRouteFocused } = require('stremio-router');
const { default: useRouteFocused } = require('stremio/common/useRouteFocused');
const { useServices } = require('stremio/services');

const useModelState = ({ action, ...args }) => {
Expand All @@ -32,17 +32,17 @@ const useModelState = ({ action, ...args }) => {
}
}
);
React.useInsertionEffect(() => {
React.useLayoutEffect(() => {
if (action) {
core.transport.dispatch(action, model);
}
}, [action]);
React.useInsertionEffect(() => {
React.useLayoutEffect(() => {
return () => {
core.transport.dispatch({ action: 'Unload' }, model);
};
}, []);
React.useInsertionEffect(() => {
React.useLayoutEffect(() => {
const onNewState = async (models) => {
if (models.indexOf(model) === -1 && (!Array.isArray(deps) || intersection(deps, models).length === 0)) {
return;
Expand All @@ -67,7 +67,7 @@ const useModelState = ({ action, ...args }) => {
core.transport.off('NewState', onNewStateThrottled);
};
}, [routeFocused]);
React.useInsertionEffect(() => {
React.useLayoutEffect(() => {
mountedRef.current = true;
}, []);
return state;
Expand Down
Loading
Loading