mirror of
https://github.com/Stremio/stremio-web.git
synced 2026-05-10 15:30:40 +00:00
Merge pull request #1258 from Stremio/refactor/core-logic
Some checks are pending
Build / build (push) Waiting to run
Some checks are pending
Build / build (push) Waiting to run
Dev: Move core logic to a provider
This commit is contained in:
commit
230be72e94
69 changed files with 471 additions and 496 deletions
|
|
@ -55,6 +55,7 @@
|
|||
"@types/hat": "^0.0.4",
|
||||
"@types/lodash.throttle": "^4.1.9",
|
||||
"@types/magnet-uri": "^5.1.5",
|
||||
"@types/node": "^25.6.0",
|
||||
"@types/react": "^18.3.28",
|
||||
"@types/react-dom": "^18.3.7",
|
||||
"babel-loader": "10.1.1",
|
||||
|
|
|
|||
|
|
@ -123,6 +123,9 @@ importers:
|
|||
'@types/lodash.throttle':
|
||||
specifier: ^4.1.9
|
||||
version: 4.1.9
|
||||
'@types/node':
|
||||
specifier: ^25.6.0
|
||||
version: 25.6.0
|
||||
'@types/magnet-uri':
|
||||
specifier: ^5.1.5
|
||||
version: 5.1.5
|
||||
|
|
@ -1494,6 +1497,9 @@ packages:
|
|||
'@types/mime@1.3.5':
|
||||
resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
|
||||
|
||||
'@types/node-forge@1.3.14':
|
||||
resolution: {integrity: sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==}
|
||||
|
||||
'@types/node@25.6.0':
|
||||
resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==}
|
||||
|
||||
|
|
|
|||
188
src/App/App.js
188
src/App/App.js
|
|
@ -3,24 +3,26 @@
|
|||
require('spatial-navigation-polyfill');
|
||||
const React = require('react');
|
||||
const { useTranslation } = require('react-i18next');
|
||||
const { useCore } = require('stremio/core');
|
||||
const { Router } = require('stremio-router');
|
||||
const { Core, Shell, Chromecast, DragAndDrop, KeyboardShortcuts, ServicesProvider, GamepadProvider } = require('stremio/services');
|
||||
const { Shell, Chromecast, DragAndDrop, KeyboardShortcuts, ServicesProvider, GamepadProvider } = require('stremio/services');
|
||||
const { NotFound } = require('stremio/routes');
|
||||
const { FileDropProvider, FullscreenProvider, PlatformProvider, ToastProvider, TooltipProvider, ShortcutsProvider, CONSTANTS, withCoreSuspender, useShell, useBinaryState } = require('stremio/common');
|
||||
const { FileDropProvider, FullscreenProvider, PlatformProvider, ToastProvider, TooltipProvider, ShortcutsProvider, CONSTANTS, useShell, useBinaryState, useProfile, withCoreSuspender } = 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 = withProtectedRoutes(Router);
|
||||
|
||||
const App = () => {
|
||||
const core = useCore();
|
||||
const profile = useProfile();
|
||||
const { i18n } = useTranslation();
|
||||
const shell = useShell();
|
||||
const [gamepadSupportEnabled, setGamepadSupportEnabled] = React.useState(false);
|
||||
|
|
@ -28,19 +30,13 @@ const App = () => {
|
|||
return NotFound;
|
||||
}, []);
|
||||
const services = React.useMemo(() => {
|
||||
const core = new Core({
|
||||
appVersion: process.env.VERSION,
|
||||
shellVersion: null
|
||||
});
|
||||
return {
|
||||
core,
|
||||
shell: new Shell(),
|
||||
chromecast: new Chromecast(),
|
||||
keyboardShortcuts: new KeyboardShortcuts(),
|
||||
dragAndDrop: new DragAndDrop({ core })
|
||||
};
|
||||
}, []);
|
||||
const [initialized, setInitialized] = React.useState(false);
|
||||
const [shortcutModalOpen,, closeShortcutsModal, toggleShortcutModal] = useBinaryState(false);
|
||||
const [gamepadModalOpen,, closeGamepadModal, toggleGamepadModal] = useBinaryState(false);
|
||||
|
||||
|
|
@ -58,12 +54,10 @@ const App = () => {
|
|||
React.useEffect(() => {
|
||||
let prevPath = window.location.hash.slice(1);
|
||||
const onLocationHashChange = () => {
|
||||
if (services.core.active) {
|
||||
services.core.transport.analytics({
|
||||
event: 'LocationPathChanged',
|
||||
args: { prevPath }
|
||||
});
|
||||
}
|
||||
core.transport.analytics({
|
||||
event: 'LocationPathChanged',
|
||||
args: { prevPath }
|
||||
});
|
||||
prevPath = window.location.hash.slice(1);
|
||||
};
|
||||
window.addEventListener('hashchange', onLocationHashChange);
|
||||
|
|
@ -71,19 +65,8 @@ const App = () => {
|
|||
window.removeEventListener('hashchange', onLocationHashChange);
|
||||
};
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
const onCoreStateChanged = () => {
|
||||
setInitialized(
|
||||
(services.core.active || services.core.error instanceof Error) &&
|
||||
(services.shell.active || services.shell.error instanceof Error)
|
||||
);
|
||||
};
|
||||
const onShellStateChanged = () => {
|
||||
setInitialized(
|
||||
(services.core.active || services.core.error instanceof Error) &&
|
||||
(services.shell.active || services.shell.error instanceof Error)
|
||||
);
|
||||
};
|
||||
const onChromecastStateChange = () => {
|
||||
if (services.chromecast.active) {
|
||||
services.chromecast.transport.setOptions({
|
||||
|
|
@ -95,23 +78,17 @@ const App = () => {
|
|||
});
|
||||
}
|
||||
};
|
||||
services.core.on('stateChanged', onCoreStateChanged);
|
||||
services.shell.on('stateChanged', onShellStateChanged);
|
||||
services.chromecast.on('stateChanged', onChromecastStateChange);
|
||||
services.core.start();
|
||||
services.shell.start();
|
||||
services.chromecast.start();
|
||||
services.keyboardShortcuts.start();
|
||||
services.dragAndDrop.start();
|
||||
window.services = services;
|
||||
return () => {
|
||||
services.core.stop();
|
||||
services.shell.stop();
|
||||
services.chromecast.stop();
|
||||
services.keyboardShortcuts.stop();
|
||||
services.dragAndDrop.stop();
|
||||
services.core.off('stateChanged', onCoreStateChanged);
|
||||
services.shell.off('stateChanged', onShellStateChanged);
|
||||
services.chromecast.off('stateChanged', onChromecastStateChange);
|
||||
};
|
||||
}, []);
|
||||
|
|
@ -142,124 +119,89 @@ const App = () => {
|
|||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
const onCoreEvent = ({ event, args }) => {
|
||||
switch (event) {
|
||||
case 'SettingsUpdated': {
|
||||
if (args && args.settings && typeof args.settings.interfaceLanguage === 'string') {
|
||||
i18n.changeLanguage(args.settings.interfaceLanguage);
|
||||
}
|
||||
if (typeof profile.settings?.interfaceLanguage === 'string') {
|
||||
i18n.changeLanguage(profile.settings.interfaceLanguage);
|
||||
}
|
||||
|
||||
if (args?.settings?.gamepadSupport !== undefined) {
|
||||
setGamepadSupportEnabled(args.settings.gamepadSupport);
|
||||
}
|
||||
if (typeof profile.settings?.gamepadSupport === 'boolean') {
|
||||
setGamepadSupportEnabled(profile.settings.gamepadSupport);
|
||||
}
|
||||
|
||||
if (args?.settings?.quitOnClose && shell.windowClosed) {
|
||||
shell.send('quit');
|
||||
}
|
||||
if (profile.settings?.quitOnClose && shell.windowClosed) {
|
||||
shell.send('quit');
|
||||
}
|
||||
}, [profile.settings, shell.windowClosed]);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
const onCtxState = (state) => {
|
||||
if (state && state.profile && state.profile.settings && typeof state.profile.settings.interfaceLanguage === 'string') {
|
||||
i18n.changeLanguage(state.profile.settings.interfaceLanguage);
|
||||
}
|
||||
|
||||
if (typeof state.profile.settings.gamepadSupport === 'boolean') {
|
||||
setGamepadSupportEnabled(state.profile.settings.gamepadSupport);
|
||||
}
|
||||
|
||||
if (state?.profile?.settings?.quitOnClose && shell.windowClosed) {
|
||||
shell.send('quit');
|
||||
}
|
||||
};
|
||||
React.useEffect(() => {
|
||||
const onWindowFocus = () => {
|
||||
services.core.transport.dispatch({
|
||||
core.transport.dispatch({
|
||||
action: 'Ctx',
|
||||
args: {
|
||||
action: 'PullAddonsFromAPI'
|
||||
}
|
||||
});
|
||||
services.core.transport.dispatch({
|
||||
core.transport.dispatch({
|
||||
action: 'Ctx',
|
||||
args: {
|
||||
action: 'PullUserFromAPI',
|
||||
args: {}
|
||||
}
|
||||
});
|
||||
services.core.transport.dispatch({
|
||||
core.transport.dispatch({
|
||||
action: 'Ctx',
|
||||
args: {
|
||||
action: 'SyncLibraryWithAPI'
|
||||
}
|
||||
});
|
||||
services.core.transport.dispatch({
|
||||
core.transport.dispatch({
|
||||
action: 'Ctx',
|
||||
args: {
|
||||
action: 'PullNotifications'
|
||||
}
|
||||
});
|
||||
};
|
||||
if (services.core.active) {
|
||||
onWindowFocus();
|
||||
window.addEventListener('focus', onWindowFocus);
|
||||
services.core.transport.on('CoreEvent', onCoreEvent);
|
||||
services.core.transport
|
||||
.getState('ctx')
|
||||
.then(onCtxState)
|
||||
.catch(console.error);
|
||||
}
|
||||
|
||||
onWindowFocus();
|
||||
window.addEventListener('focus', onWindowFocus);
|
||||
|
||||
return () => {
|
||||
if (services.core.active) {
|
||||
window.removeEventListener('focus', onWindowFocus);
|
||||
services.core.transport.off('CoreEvent', onCoreEvent);
|
||||
}
|
||||
window.removeEventListener('focus', onWindowFocus);
|
||||
};
|
||||
}, [initialized, shell.windowClosed]);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<React.StrictMode>
|
||||
<ServicesProvider services={services}>
|
||||
{
|
||||
initialized ?
|
||||
services.core.error instanceof Error ?
|
||||
<ErrorDialog className={styles['error-container']} />
|
||||
:
|
||||
<PlatformProvider>
|
||||
<ToastProvider className={styles['toasts-container']}>
|
||||
<TooltipProvider className={styles['tooltip-container']}>
|
||||
<FileDropProvider className={styles['file-drop-container']}>
|
||||
<GamepadProvider enabled={gamepadSupportEnabled} onGuide={toggleGamepadModal}>
|
||||
<ShortcutsProvider onShortcut={onShortcut}>
|
||||
<FullscreenProvider>
|
||||
{
|
||||
shortcutModalOpen && <ShortcutsModal onClose={closeShortcutsModal}/>
|
||||
}
|
||||
{
|
||||
gamepadModalOpen && <GamepadModal onClose={closeGamepadModal}/>
|
||||
}
|
||||
<ServicesToaster />
|
||||
<DeepLinkHandler />
|
||||
<SearchParamsHandler />
|
||||
<UpdaterBanner className={styles['updater-banner-container']} />
|
||||
<RouterWithProtectedRoutes
|
||||
className={styles['router']}
|
||||
viewsConfig={routerViewsConfig}
|
||||
onPathNotMatch={onPathNotMatch}
|
||||
/>
|
||||
</FullscreenProvider>
|
||||
</ShortcutsProvider>
|
||||
</GamepadProvider>
|
||||
</FileDropProvider>
|
||||
</TooltipProvider>
|
||||
</ToastProvider>
|
||||
</PlatformProvider>
|
||||
:
|
||||
<div className={styles['loader-container']} />
|
||||
}
|
||||
</ServicesProvider>
|
||||
</React.StrictMode>
|
||||
<ServicesProvider services={services}>
|
||||
<PlatformProvider>
|
||||
<ToastProvider className={styles['toasts-container']}>
|
||||
<TooltipProvider className={styles['tooltip-container']}>
|
||||
<FileDropProvider className={styles['file-drop-container']}>
|
||||
<GamepadProvider enabled={gamepadSupportEnabled} onGuide={toggleGamepadModal}>
|
||||
<ShortcutsProvider onShortcut={onShortcut}>
|
||||
<FullscreenProvider>
|
||||
{
|
||||
shortcutModalOpen && <ShortcutsModal onClose={closeShortcutsModal}/>
|
||||
}
|
||||
{
|
||||
gamepadModalOpen && <GamepadModal onClose={closeGamepadModal}/>
|
||||
}
|
||||
<ServicesToaster />
|
||||
<DeepLinkHandler />
|
||||
<SearchParamsHandler />
|
||||
<UpdaterBanner className={styles['updater-banner-container']} />
|
||||
<RouterWithProtectedRoutes
|
||||
className={styles['router']}
|
||||
viewsConfig={routerViewsConfig}
|
||||
onPathNotMatch={onPathNotMatch}
|
||||
/>
|
||||
</FullscreenProvider>
|
||||
</ShortcutsProvider>
|
||||
</GamepadProvider>
|
||||
</FileDropProvider>
|
||||
</TooltipProvider>
|
||||
</ToastProvider>
|
||||
</PlatformProvider>
|
||||
</ServicesProvider>
|
||||
);
|
||||
};
|
||||
|
||||
module.exports = App;
|
||||
module.exports = withCoreSuspender(App);
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const ErrorDialog = require('./ErrorDialog');
|
||||
|
||||
module.exports = ErrorDialog;
|
||||
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
const React = require('react');
|
||||
const { deepEqual } = require('fast-equals');
|
||||
const { useCore } = require('stremio/core');
|
||||
const { withCoreSuspender, useProfile, useToast } = require('stremio/common');
|
||||
const { useServices } = require('stremio/services');
|
||||
|
||||
const SearchParamsHandler = () => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const profile = useProfile();
|
||||
const toast = useToast();
|
||||
|
||||
|
|
|
|||
|
|
@ -2,38 +2,16 @@
|
|||
|
||||
const React = require('react');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { useCore } = require('stremio/core');
|
||||
const { useToast } = require('stremio/common');
|
||||
|
||||
const ServicesToaster = () => {
|
||||
const { core, dragAndDrop } = useServices();
|
||||
const { dragAndDrop } = useServices();
|
||||
const core = useCore();
|
||||
const toast = useToast();
|
||||
React.useEffect(() => {
|
||||
const onCoreEvent = ({ event, args }) => {
|
||||
switch (event) {
|
||||
case 'Error': {
|
||||
if (args.source.event === 'UserPulledFromAPI' && args.source.args.uid === null) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (args.source.event === 'LibrarySyncWithAPIPlanned' && args.source.args.uid === null) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (args.error.type === 'Other' && args.error.code === 3 && args.source.event === 'AddonInstalled' && args.source.args.transport_url.startsWith('https://www.strem.io/trakt/addon')) {
|
||||
break;
|
||||
}
|
||||
|
||||
toast.show({
|
||||
type: 'error',
|
||||
title: args.source.event,
|
||||
message: args.error.message,
|
||||
timeout: 4000,
|
||||
dataset: {
|
||||
type: 'CoreEvent'
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
const onCoreEvent = (name, data) => {
|
||||
switch (name) {
|
||||
case 'TorrentParsed': {
|
||||
toast.show({
|
||||
type: 'success',
|
||||
|
|
@ -53,13 +31,28 @@ const ServicesToaster = () => {
|
|||
case 'PlayingOnDevice': {
|
||||
toast.show({
|
||||
type: 'success',
|
||||
title: `Stream opened in ${args.device}`,
|
||||
title: `Stream opened in ${data.device}`,
|
||||
timeout: 4000
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
const onCoreError = (source, error) => {
|
||||
if (source.event === 'UserPulledFromAPI' && source.args.uid === null) return;
|
||||
if (source.event === 'LibrarySyncWithAPIPlanned' && source.args.uid === null) return;
|
||||
if (error.type === 'Other' && error.code === 3 && source.event === 'AddonInstalled' && source.args.transport_url.startsWith('https://www.strem.io/trakt/addon')) return;
|
||||
|
||||
toast.show({
|
||||
type: 'error',
|
||||
title: source.event,
|
||||
message: error.message,
|
||||
timeout: 4000,
|
||||
dataset: {
|
||||
type: 'CoreEvent'
|
||||
}
|
||||
});
|
||||
};
|
||||
const onDragAndDropError = (error) => {
|
||||
toast.show({
|
||||
type: 'error',
|
||||
|
|
@ -68,10 +61,12 @@ const ServicesToaster = () => {
|
|||
timeout: 4000
|
||||
});
|
||||
};
|
||||
core.transport.on('CoreEvent', onCoreEvent);
|
||||
core.on('event', onCoreEvent);
|
||||
core.on('error', onCoreError);
|
||||
dragAndDrop.on('error', onDragAndDropError);
|
||||
return () => {
|
||||
core.transport.off('CoreEvent', onCoreEvent);
|
||||
core.off('event', onCoreEvent);
|
||||
core.off('error', onCoreError);
|
||||
dragAndDrop.off('error', onDragAndDropError);
|
||||
};
|
||||
}, []);
|
||||
|
|
|
|||
|
|
@ -241,11 +241,6 @@ html {
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.loader-container, .error-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const React = require('react');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { useCore } = require('stremio/core');
|
||||
|
||||
const CoreSuspenderContext = React.createContext(null);
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ const useCoreSuspender = () => {
|
|||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
const withCoreSuspender = (Component, Fallback = () => { }) => {
|
||||
return function withCoreSuspender(props) {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const parentSuspender = useCoreSuspender();
|
||||
const [render, setRender] = React.useState(parentSuspender === null);
|
||||
const statesRef = React.useRef({});
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ const React = require('react');
|
|||
const throttle = require('lodash.throttle');
|
||||
const { deepEqual } = require('fast-equals');
|
||||
const intersection = require('lodash.intersection');
|
||||
const { useCore } = require('stremio/core');
|
||||
const { useCoreSuspender } = require('stremio/common/CoreSuspender');
|
||||
const { useRouteFocused } = require('stremio-router');
|
||||
const { useServices } = require('stremio/services');
|
||||
|
||||
const useModelState = ({ action, ...args }) => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const routeFocused = useRouteFocused();
|
||||
const mountedRef = React.useRef(false);
|
||||
const [model, timeout, map, deps] = React.useMemo(() => {
|
||||
|
|
@ -25,24 +25,21 @@ const useModelState = ({ action, ...args }) => {
|
|||
},
|
||||
undefined,
|
||||
() => {
|
||||
if (typeof map === 'function') {
|
||||
return map(getState(model));
|
||||
} else {
|
||||
return getState(model);
|
||||
}
|
||||
const state = getState(model);
|
||||
return typeof map === 'function' ? map(state) : state;
|
||||
}
|
||||
);
|
||||
React.useInsertionEffect(() => {
|
||||
React.useEffect(() => {
|
||||
if (action) {
|
||||
core.transport.dispatch(action, model);
|
||||
}
|
||||
}, [action]);
|
||||
React.useInsertionEffect(() => {
|
||||
React.useEffect(() => {
|
||||
return () => {
|
||||
core.transport.dispatch({ action: 'Unload' }, model);
|
||||
};
|
||||
}, []);
|
||||
React.useInsertionEffect(() => {
|
||||
React.useEffect(() => {
|
||||
const onNewState = async (models) => {
|
||||
if (models.indexOf(model) === -1 && (!Array.isArray(deps) || intersection(deps, models).length === 0)) {
|
||||
return;
|
||||
|
|
@ -57,17 +54,17 @@ const useModelState = ({ action, ...args }) => {
|
|||
};
|
||||
const onNewStateThrottled = throttle(onNewState, timeout);
|
||||
if (routeFocused) {
|
||||
core.transport.on('NewState', onNewStateThrottled);
|
||||
core.on('state', onNewStateThrottled);
|
||||
if (mountedRef.current) {
|
||||
onNewState([model]);
|
||||
}
|
||||
}
|
||||
return () => {
|
||||
onNewStateThrottled.cancel();
|
||||
core.transport.off('NewState', onNewStateThrottled);
|
||||
core.off('state', onNewStateThrottled);
|
||||
};
|
||||
}, [routeFocused]);
|
||||
React.useInsertionEffect(() => {
|
||||
React.useEffect(() => {
|
||||
mountedRef.current = true;
|
||||
}, []);
|
||||
return state;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useCallback } from 'react';
|
||||
import magnet from 'magnet-uri';
|
||||
import { useServices } from 'stremio/services';
|
||||
import { useCore } from 'stremio/core';
|
||||
import useToast from 'stremio/common/Toast/useToast';
|
||||
import useTorrent from 'stremio/common/useTorrent';
|
||||
import useStreamingServer from 'stremio/common/useStreamingServer';
|
||||
|
|
@ -8,7 +8,7 @@ import useStreamingServer from 'stremio/common/useStreamingServer';
|
|||
const HTTP_REGEX = /^https?:\/\/.+/i;
|
||||
|
||||
const usePlayUrl = () => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const toast = useToast();
|
||||
const { createTorrentFromMagnet } = useTorrent();
|
||||
const streamingServer = useStreamingServer();
|
||||
|
|
@ -24,7 +24,11 @@ const usePlayUrl = () => {
|
|||
timeout: 3000
|
||||
});
|
||||
try {
|
||||
const encoded = await core.transport.encodeStream({ url: trimmed });
|
||||
const encoded = await core.transport.encodeStream({
|
||||
name: '',
|
||||
description: '',
|
||||
url: trimmed,
|
||||
});
|
||||
if (typeof encoded === 'string') {
|
||||
window.location.hash = `#/player/${encodeURIComponent(encoded)}`;
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
// Copyright (C) 2017-2025 Smart code 203358507
|
||||
|
||||
import { useCallback } from 'react';
|
||||
import { useServices } from 'stremio/services';
|
||||
import useProfile from './useProfile';
|
||||
import { useCore } from 'stremio/core';
|
||||
|
||||
const useSettings = (): [Settings, (settings: Settings) => void] => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const profile = useProfile();
|
||||
|
||||
const updateSettings = useCallback((settings: Settings) => {
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@
|
|||
|
||||
const React = require('react');
|
||||
const magnet = require('magnet-uri');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { useCore } = require('stremio/core');
|
||||
const useToast = require('stremio/common/Toast/useToast');
|
||||
const useStreamingServer = require('stremio/common/useStreamingServer');
|
||||
|
||||
const CREATE_TORRENT_TIMEOUT = 20000;
|
||||
|
||||
const useTorrent = () => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const streamingServer = useStreamingServer();
|
||||
const toast = useToast();
|
||||
const createTorrentTimeout = React.useRef(null);
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
const React = require('react');
|
||||
const { useTranslation } = require('react-i18next');
|
||||
const PropTypes = require('prop-types');
|
||||
const { useCore } = require('stremio/core');
|
||||
const ModalDialog = require('stremio/components/ModalDialog');
|
||||
const { withCoreSuspender } = require('stremio/common/CoreSuspender');
|
||||
const { usePlatform } = require('stremio/common/Platform');
|
||||
const { useServices } = require('stremio/services');
|
||||
const AddonDetailsWithRemoteAndLocalAddon = withRemoteAndLocalAddon(require('./AddonDetails'));
|
||||
const useAddonDetails = require('./useAddonDetails');
|
||||
const styles = require('./styles');
|
||||
|
|
@ -45,7 +45,7 @@ function withRemoteAndLocalAddon(AddonDetails) {
|
|||
|
||||
const AddonDetailsModal = ({ transportUrl, onCloseRequest }) => {
|
||||
const { t } = useTranslation();
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const platform = usePlatform();
|
||||
const addonDetails = useAddonDetails(transportUrl);
|
||||
const modalButtons = React.useMemo(() => {
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
const React = require('react');
|
||||
const PropTypes = require('prop-types');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { useCore } = require('stremio/core');
|
||||
const LibItem = require('stremio/components/LibItem');
|
||||
|
||||
const ContinueWatchingItem = ({ _id, notifications, ...props }) => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
|
||||
const onDismissClick = React.useCallback((event) => {
|
||||
event.preventDefault();
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const { useCore } = require('stremio/core');
|
||||
const useModelState = require('stremio/common/useModelState');
|
||||
const { useServices } = require('stremio/services');
|
||||
|
||||
const map = (ctx) => ({
|
||||
...ctx.events,
|
||||
});
|
||||
|
||||
const useEvents = () => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
|
||||
const pullEvents = () => {
|
||||
core.transport.dispatch({
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const React = require('react');
|
||||
const { useServices } = require('stremio/services');
|
||||
const PropTypes = require('prop-types');
|
||||
const { useCore } = require('stremio/core');
|
||||
const MetaItem = require('stremio/components/MetaItem');
|
||||
const { t } = require('i18next');
|
||||
|
||||
const LibItem = ({ _id, removable, notifications, watched, ...props }) => {
|
||||
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
|
||||
const newVideos = React.useMemo(() => {
|
||||
const count = notifications.items?.[_id]?.length ?? 0;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (C) 2017-2025 Smart code 203358507
|
||||
|
||||
import { useMemo, useCallback } from 'react';
|
||||
import { useServices } from 'stremio/services';
|
||||
import { useCore } from 'stremio/core';
|
||||
|
||||
const useRating = (ratingInfo?: Loadable<RatingInfo>) => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
|
||||
const setRating = useCallback((status: Rating) => {
|
||||
core.transport.dispatch({
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ const PropTypes = require('prop-types');
|
|||
const classnames = require('classnames');
|
||||
const { useTranslation } = require('react-i18next');
|
||||
const { default: Icon } = require('@stremio/stremio-icons/react');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { useCore } = require('stremio/core');
|
||||
const { Button } = require('stremio/components');
|
||||
const { useFullscreen } = require('stremio/common/Fullscreen');
|
||||
const useProfile = require('stremio/common/useProfile');
|
||||
|
|
@ -18,7 +18,7 @@ const styles = require('./styles');
|
|||
|
||||
const NavMenuContent = ({ onClick }) => {
|
||||
const { t } = useTranslation();
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const profile = useProfile();
|
||||
const streamingServer = useStreamingServer();
|
||||
const { handlePlayUrl } = usePlayUrl();
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const React = require('react');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { useCore } = require('stremio/core');
|
||||
const useModelState = require('stremio/common/useModelState');
|
||||
|
||||
const useLocalSearch = () => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
|
||||
const action = React.useMemo(() => ({
|
||||
action: 'Load',
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const React = require('react');
|
||||
const { useCore } = require('stremio/core');
|
||||
const useModelState = require('stremio/common/useModelState');
|
||||
const { useServices } = require('stremio/services');
|
||||
|
||||
const useSearchHistory = () => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const { searchHistory: items } = useModelState({ model: 'ctx' });
|
||||
|
||||
const clear = React.useCallback(() => {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ const classnames = require('classnames');
|
|||
const { useTranslation } = require('react-i18next');
|
||||
const { default: Icon } = require('@stremio/stremio-icons/react');
|
||||
const { useRouteFocused } = require('stremio-router');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { useCore } = require('stremio/core');
|
||||
const { Button } = require('stremio/components');
|
||||
const { default: TextInput } = require('stremio/components/TextInput');
|
||||
const useToast = require('stremio/common/Toast/useToast');
|
||||
|
|
@ -14,7 +14,7 @@ const styles = require('./styles');
|
|||
|
||||
const SharePrompt = ({ className, url }) => {
|
||||
const { t } = useTranslation();
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const toast = useToast();
|
||||
const inputRef = React.useRef(null);
|
||||
const routeFocused = useRouteFocused();
|
||||
|
|
|
|||
15
src/core/CoreContext.ts
Normal file
15
src/core/CoreContext.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { createContext } from 'react';
|
||||
|
||||
interface CoreContext {
|
||||
transport: CoreTransport;
|
||||
on(name: 'state', listener: CoreStateListener): void;
|
||||
on(name: 'event', listener: CoreEventListener): void;
|
||||
on(name: 'error', listener: CoreErrorListener): void;
|
||||
off(name: 'state', listener: CoreStateListener): void;
|
||||
off(name: 'event', listener: CoreEventListener): void;
|
||||
off(name: 'error', listener: CoreErrorListener): void;
|
||||
}
|
||||
|
||||
const CoreContext = createContext<CoreContext>({} as CoreContext);
|
||||
|
||||
export default CoreContext;
|
||||
99
src/core/CoreProvider.tsx
Normal file
99
src/core/CoreProvider.tsx
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import CoreContext from './CoreContext';
|
||||
import createTransport from './createTransport';
|
||||
import Error from './Error';
|
||||
|
||||
type Props = {
|
||||
appInfo: object,
|
||||
children: React.ReactNode,
|
||||
};
|
||||
|
||||
const Core = (props: Props) => {
|
||||
const transport = createTransport();
|
||||
const [initialized, setInitialized] = useState(false);
|
||||
const [error, setError] = useState<Error | null>();
|
||||
|
||||
const stateListeners = useRef<CoreStateListener[]>([]);
|
||||
const eventListeners = useRef<CoreEventListener[]>([]);
|
||||
const errorListeners = useRef<CoreErrorListener[]>([]);
|
||||
|
||||
const on = (name: CoreListenerType, listener: CoreListener) => {
|
||||
if (name === 'state') stateListeners.current = [...stateListeners.current, listener as CoreStateListener];
|
||||
if (name === 'event') eventListeners.current = [...eventListeners.current, listener as CoreEventListener];
|
||||
if (name === 'error') errorListeners.current = [...errorListeners.current, listener as CoreErrorListener];
|
||||
};
|
||||
|
||||
const off = (name: CoreListenerType, listener: CoreListener) => {
|
||||
if (name === 'state') stateListeners.current = stateListeners.current.filter((l) => l !== listener);
|
||||
if (name === 'event') eventListeners.current = eventListeners.current.filter((l) => l !== listener);
|
||||
if (name === 'error') errorListeners.current = errorListeners.current.filter((l) => l !== listener);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const onCoreEvent = ({ name, args }: NewStateEvent | CoreEventEvent) => {
|
||||
switch (name) {
|
||||
case 'NewState':
|
||||
stateListeners.current.forEach((listener) => listener(args));
|
||||
break;
|
||||
|
||||
case 'CoreEvent': {
|
||||
switch (args.event) {
|
||||
case 'Error': {
|
||||
const { source, error } = args.args;
|
||||
errorListeners.current.forEach((listener) => listener(
|
||||
source,
|
||||
error,
|
||||
));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
eventListeners.current.forEach((listener) => listener(
|
||||
args.event,
|
||||
args.args,
|
||||
));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
if (!window.core) {
|
||||
transport
|
||||
.init(props.appInfo)
|
||||
.then(() => {
|
||||
window.core = transport;
|
||||
window.onCoreEvent = onCoreEvent;
|
||||
setInitialized(true);
|
||||
setError(null);
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
console.error('Failed to initialize core:', e);
|
||||
setInitialized(false);
|
||||
setError(e);
|
||||
});
|
||||
}
|
||||
|
||||
return () => {
|
||||
stateListeners.current = [];
|
||||
eventListeners.current = [];
|
||||
errorListeners.current = [];
|
||||
setInitialized(false);
|
||||
setError(null);
|
||||
window.onCoreEvent = null;
|
||||
window.core = null;
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<CoreContext.Provider value={{ transport, on, off }}>
|
||||
{ error && !initialized && <Error /> }
|
||||
{ initialized && !error && props.children }
|
||||
</CoreContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export default Core;
|
||||
|
|
@ -1,25 +1,27 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const React = require('react');
|
||||
const { useTranslation } = require('react-i18next');
|
||||
const PropTypes = require('prop-types');
|
||||
const classnames = require('classnames');
|
||||
const { Image, Button } = require('stremio/components');
|
||||
const styles = require('./styles');
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Image from 'stremio/components/Image';
|
||||
import Button from 'stremio/components/Button';
|
||||
import styles from './styles.less';
|
||||
|
||||
const ErrorDialog = ({ className }) => {
|
||||
const Error = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [dataCleared, setDataCleared] = React.useState(false);
|
||||
|
||||
const reload = React.useCallback(() => {
|
||||
window.location.reload();
|
||||
}, []);
|
||||
|
||||
const clearData = React.useCallback(() => {
|
||||
window.localStorage.clear();
|
||||
setDataCleared(true);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={classnames(className, styles['error-container'])}>
|
||||
<div className={styles['error-container']}>
|
||||
<Image
|
||||
className={styles['error-image']}
|
||||
src={require('/assets/images/empty.png')}
|
||||
|
|
@ -44,10 +46,5 @@ const ErrorDialog = ({ className }) => {
|
|||
);
|
||||
};
|
||||
|
||||
ErrorDialog.displayName = 'ErrorDialog';
|
||||
export default Error;
|
||||
|
||||
ErrorDialog.propTypes = {
|
||||
className: PropTypes.string
|
||||
};
|
||||
|
||||
module.exports = ErrorDialog;
|
||||
4
src/core/Error/index.ts
Normal file
4
src/core/Error/index.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
import Error from './Error';
|
||||
export default Error;
|
||||
|
|
@ -3,6 +3,9 @@
|
|||
@import (reference) '~@stremio/stremio-colors/less/stremio-colors.less';
|
||||
|
||||
.error-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
41
src/core/createTransport.ts
Normal file
41
src/core/createTransport.ts
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import Bridge from '@stremio/stremio-core-web/bridge';
|
||||
|
||||
const worker = new Worker(`${process.env.COMMIT_HASH}/scripts/worker.js`);
|
||||
const bridge = new Bridge(window, worker);
|
||||
|
||||
const createTransport = (): CoreTransport => {
|
||||
const init = async (args: object): Promise<void> => {
|
||||
return bridge.call(['init'], [args]);
|
||||
};
|
||||
|
||||
const getState = (model: string): Promise<object> => {
|
||||
return bridge.call(['getState'], [model]);
|
||||
};
|
||||
|
||||
const dispatch = (action: DispatchAction, model?: string): Promise<void> => {
|
||||
return bridge.call(['dispatch'], [action, model, location.hash]);
|
||||
};
|
||||
|
||||
const encodeStream = (stream: Stream): Promise<string> => {
|
||||
return bridge.call(['encodeStream'], [stream]);
|
||||
};
|
||||
|
||||
const decodeStream = (stream: string): Promise<Stream> => {
|
||||
return bridge.call(['decodeStream'], [stream]);
|
||||
};
|
||||
|
||||
const analytics = (event: object): Promise<void> => {
|
||||
return bridge.call(['analytics'], [event, location.hash]);
|
||||
};
|
||||
|
||||
return {
|
||||
init,
|
||||
getState,
|
||||
dispatch,
|
||||
encodeStream,
|
||||
decodeStream,
|
||||
analytics,
|
||||
};
|
||||
};
|
||||
|
||||
export default createTransport;
|
||||
8
src/core/global.d.ts
vendored
Normal file
8
src/core/global.d.ts
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
interface Window {
|
||||
core: CoreTransport | null | undefined,
|
||||
onCoreEvent: ((event: NewStateEvent | CoreEventEvent) => void) | null;
|
||||
}
|
||||
|
||||
interface Bridge {
|
||||
call(action: string[], args: any[]): Promise<any>,
|
||||
}
|
||||
7
src/core/index.ts
Normal file
7
src/core/index.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import CoreProvider from './CoreProvider';
|
||||
import useCore from './useCore';
|
||||
|
||||
export {
|
||||
CoreProvider,
|
||||
useCore,
|
||||
};
|
||||
54
src/core/types.d.ts
vendored
Normal file
54
src/core/types.d.ts
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
type DispatchAction = {
|
||||
action: string,
|
||||
args?: {
|
||||
model?: string,
|
||||
action?: string,
|
||||
args?: any,
|
||||
}
|
||||
};
|
||||
|
||||
type CoreTransport = {
|
||||
init: (args: object) => Promise<void>,
|
||||
getState: (model: string) => Promise<object>,
|
||||
dispatch: (action: DispatchAction, model?: string) => Promise<void>,
|
||||
encodeStream: (stream: Stream) => Promise<string>,
|
||||
decodeStream: (stream: string) => Promise<Stream>,
|
||||
analytics: (event: object) => Promise<void>,
|
||||
};
|
||||
|
||||
type CoreStateListener = (models: string[]) => void;
|
||||
type CoreEventListener = (name: string, data: object) => void;
|
||||
type CoreErrorListener = (source: CoreEvent, error: CoreEventError) => void;
|
||||
|
||||
type CoreListener = CoreStateListener | CoreEventListener | CoreErrorListener;
|
||||
type CoreListenerType = 'state' | 'event' | 'error';
|
||||
|
||||
type NewStateEvent = {
|
||||
name: 'NewState',
|
||||
args: string[],
|
||||
};
|
||||
|
||||
type CoreEvent = {
|
||||
event: 'UserPulledFromAPI' | 'UserLibraryMissing' | 'UserAuthenticated' | 'UserAddonsLocked' |
|
||||
'LibraryItemsPulledFromAPI' | 'LibraryItemsPushedToStorage' | 'LibrarySyncWithAPIPlanned',
|
||||
args: object,
|
||||
};
|
||||
|
||||
type CoreEventError = {
|
||||
code: number,
|
||||
type: string,
|
||||
message: string,
|
||||
};
|
||||
|
||||
type CoreError = {
|
||||
event: 'Error',
|
||||
args: {
|
||||
source: CoreEvent,
|
||||
error: CoreEventError,
|
||||
},
|
||||
};
|
||||
|
||||
type CoreEventEvent = {
|
||||
name: 'CoreEvent',
|
||||
args: CoreEvent | CoreError,
|
||||
};
|
||||
5
src/core/useCore.ts
Normal file
5
src/core/useCore.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
import { useContext } from 'react';
|
||||
import CoreContext from './CoreContext';
|
||||
|
||||
const useCore = () => useContext(CoreContext);
|
||||
export default useCore;
|
||||
12
src/index.js
12
src/index.js
|
|
@ -17,6 +17,7 @@ const i18n = require('i18next');
|
|||
const { initReactI18next } = require('react-i18next');
|
||||
const stremioTranslations = require('stremio-translations');
|
||||
const App = require('./App');
|
||||
const { CoreProvider } = require('./core');
|
||||
|
||||
const translations = Object.fromEntries(Object.entries(stremioTranslations()).map(([key, value]) => [key, {
|
||||
translation: value
|
||||
|
|
@ -33,8 +34,17 @@ i18n
|
|||
}
|
||||
});
|
||||
|
||||
const appInfo = {
|
||||
appVersion: process.env.VERSION,
|
||||
shellVersion: null
|
||||
};
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById('app'));
|
||||
root.render(<App />);
|
||||
root.render(
|
||||
<CoreProvider appInfo={appInfo}>
|
||||
<App />
|
||||
</CoreProvider>
|
||||
);
|
||||
|
||||
if (process.env.NODE_ENV === 'production' && process.env.SERVICE_WORKER_DISABLED !== 'true' && process.env.SERVICE_WORKER_DISABLED !== true && 'serviceWorker' in navigator) {
|
||||
window.addEventListener('load', () => {
|
||||
|
|
|
|||
2
src/modules.d.ts
vendored
2
src/modules.d.ts
vendored
|
|
@ -1,3 +1,5 @@
|
|||
declare module '@stremio/stremio-core-web/bridge';
|
||||
|
||||
declare module '*.less' {
|
||||
const resource: Record<string, string>;
|
||||
export = resource;
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ const PropTypes = require('prop-types');
|
|||
const classnames = require('classnames');
|
||||
const { useTranslation } = require('react-i18next');
|
||||
const { default: Icon } = require('@stremio/stremio-icons/react');
|
||||
const { useCore } = require('stremio/core');
|
||||
const { usePlatform, useBinaryState, withCoreSuspender } = require('stremio/common');
|
||||
const { AddonDetailsModal, Button, Image, MainNavBars, ModalDialog, SearchBar, SharePrompt, TextInput, MultiselectMenu } = require('stremio/components');
|
||||
const { useServices } = require('stremio/services');
|
||||
const useToast = require('stremio/common/Toast/useToast');
|
||||
const Addon = require('./Addon');
|
||||
const useInstalledAddons = require('./useInstalledAddons');
|
||||
|
|
@ -20,7 +20,7 @@ const { AddonPlaceholder } = require('./AddonPlaceholder');
|
|||
const Addons = ({ urlParams, queryParams }) => {
|
||||
const { t } = useTranslation();
|
||||
const platform = usePlatform();
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const toast = useToast();
|
||||
const installedAddons = useInstalledAddons(urlParams);
|
||||
const remoteAddons = useRemoteAddons(urlParams);
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
import React, { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import classnames from 'classnames';
|
||||
import { useServices } from 'stremio/services';
|
||||
import { Button } from 'stremio/components';
|
||||
import { useCore } from 'stremio/core';
|
||||
import useProfile from 'stremio/common/useProfile';
|
||||
import { withCoreSuspender } from 'stremio/common/CoreSuspender';
|
||||
import styles from './StreamingServerWarning.less';
|
||||
|
|
@ -15,7 +15,7 @@ type Props = {
|
|||
|
||||
const StreamingServerWarning = ({ className }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const profile = useProfile();
|
||||
|
||||
const createDismissalDate = (months: number, years = 0): Date => {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const React = require('react');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { useCore } = require('stremio/core');
|
||||
const { useModelState } = require('stremio/common');
|
||||
|
||||
const useBoard = () => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const action = React.useMemo(() => ({
|
||||
action: 'Load',
|
||||
args: {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ const { useTranslation } = require('react-i18next');
|
|||
const PropTypes = require('prop-types');
|
||||
const classnames = require('classnames');
|
||||
const { default: Icon } = require('@stremio/stremio-icons/react');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { useCore } = require('stremio/core');
|
||||
const { CONSTANTS, useBinaryState, useOnScrollToBottom, withCoreSuspender } = require('stremio/common');
|
||||
const { AddonDetailsModal, Button, DelayedRenderer, Image, MainNavBars, MetaItem, MetaPreview, ModalDialog, MultiselectMenu } = require('stremio/components');
|
||||
const useDiscover = require('./useDiscover');
|
||||
|
|
@ -16,7 +16,7 @@ const SCROLL_TO_BOTTOM_THRESHOLD = 400;
|
|||
|
||||
const Discover = ({ urlParams, queryParams }) => {
|
||||
const { t } = useTranslation();
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const [discover, loadNextPage] = useDiscover(urlParams, queryParams);
|
||||
const [selectInputs, hasNextPage] = useSelectableInputs(discover);
|
||||
const [inputsModalOpen, openInputsModal, closeInputsModal] = useBinaryState(false);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
const React = require('react');
|
||||
const UrlUtils = require('url');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { useCore } = require('stremio/core');
|
||||
const { useModelState } = require('stremio/common');
|
||||
|
||||
const map = (discover) => ({
|
||||
|
|
@ -23,7 +23,7 @@ const map = (discover) => ({
|
|||
});
|
||||
|
||||
const useDiscover = (urlParams, queryParams) => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const loadNextPage = React.useCallback(() => {
|
||||
core.transport.dispatch({
|
||||
action: 'CatalogWithFilters',
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ const PropTypes = require('prop-types');
|
|||
const classnames = require('classnames');
|
||||
const { default: Icon } = require('@stremio/stremio-icons/react');
|
||||
const { Modal, useRouteFocused } = require('stremio-router');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { useCore } = require('stremio/core');
|
||||
const { useBinaryState } = require('stremio/common');
|
||||
const { Button, Image, Checkbox } = require('stremio/components');
|
||||
const CredentialsTextInput = require('./CredentialsTextInput');
|
||||
|
|
@ -20,7 +20,7 @@ const SIGNUP_FORM = 'signup';
|
|||
const LOGIN_FORM = 'login';
|
||||
|
||||
const Intro = ({ queryParams }) => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const { t } = useTranslation();
|
||||
const routeFocused = useRouteFocused();
|
||||
const [startFacebookLogin, stopFacebookLogin] = useFacebookLogin();
|
||||
|
|
@ -268,27 +268,24 @@ const Intro = ({ queryParams }) => {
|
|||
}
|
||||
}, [state.form, routeFocused]);
|
||||
React.useEffect(() => {
|
||||
const onCoreEvent = ({ event, args }) => {
|
||||
switch (event) {
|
||||
case 'UserAuthenticated': {
|
||||
closeLoaderModal();
|
||||
if (routeFocused) {
|
||||
window.location = '#/';
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'Error': {
|
||||
if (args.source.event === 'UserAuthenticated') {
|
||||
closeLoaderModal();
|
||||
}
|
||||
|
||||
break;
|
||||
const onCoreEvent = (name) => {
|
||||
if (name === 'UserAuthenticated') {
|
||||
closeLoaderModal();
|
||||
if (routeFocused) {
|
||||
window.location = '#/';
|
||||
}
|
||||
}
|
||||
};
|
||||
core.transport.on('CoreEvent', onCoreEvent);
|
||||
const onCoreError = (source) => {
|
||||
if (source.event === 'UserAuthenticated') {
|
||||
closeLoaderModal();
|
||||
}
|
||||
};
|
||||
core.on('event', onCoreEvent);
|
||||
core.on('error', onCoreError);
|
||||
return () => {
|
||||
core.transport.off('CoreEvent', onCoreEvent);
|
||||
core.off('event', onCoreEvent);
|
||||
core.off('error', onCoreError);
|
||||
};
|
||||
}, [routeFocused]);
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const React = require('react');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { useCore } = require('stremio/core');
|
||||
const { useModelState } = require('stremio/common');
|
||||
|
||||
const useLibrary = (model, urlParams, queryParams) => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const loadNextPage = React.useCallback(() => {
|
||||
core.transport.dispatch({
|
||||
action: 'LibraryWithFilters',
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ const React = require('react');
|
|||
const { useTranslation } = require('react-i18next');
|
||||
const PropTypes = require('prop-types');
|
||||
const classnames = require('classnames');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { useCore } = require('stremio/core');
|
||||
const { useContentGamepadNavigation } = require('stremio/services/GamepadNavigation');
|
||||
const { withCoreSuspender } = require('stremio/common');
|
||||
const { VerticalNavBar, HorizontalNavBar, DelayedRenderer, Image, MetaPreview, ModalDialog } = require('stremio/components');
|
||||
|
|
@ -18,7 +18,7 @@ const styles = require('./styles');
|
|||
const MetaDetails = ({ urlParams, queryParams }) => {
|
||||
const contentRef = React.useRef(null);
|
||||
const { t } = useTranslation();
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const metaDetails = useMetaDetails(urlParams);
|
||||
const [season, setSeason] = useSeason(urlParams, queryParams);
|
||||
const [tabs, metaExtension, clearMetaExtension] = useMetaExtensionTabs(metaDetails.metaExtensions);
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ const PropTypes = require('prop-types');
|
|||
const classnames = require('classnames');
|
||||
const { default: Icon } = require('@stremio/stremio-icons/react');
|
||||
const { t } = require('i18next');
|
||||
const { useCore } = require('stremio/core');
|
||||
const { useProfile, usePlatform, useToast, useBinaryState } = require('stremio/common');
|
||||
const { Button, Image, Popup } = require('stremio/components');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { useRouteFocused } = require('stremio-router');
|
||||
const StreamPlaceholder = require('./StreamPlaceholder');
|
||||
const styles = require('./styles');
|
||||
|
|
@ -16,7 +16,7 @@ const Stream = ({ className, videoId, videoReleased, addonName, name, descriptio
|
|||
const profile = useProfile();
|
||||
const toast = useToast();
|
||||
const platform = usePlatform();
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const routeFocused = useRouteFocused();
|
||||
|
||||
const [menuOpen, , closeMenu, toggleMenu] = useBinaryState(false);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ const classnames = require('classnames');
|
|||
const { useTranslation } = require('react-i18next');
|
||||
const { default: Icon } = require('@stremio/stremio-icons/react');
|
||||
const { Button, Image, MultiselectMenu } = require('stremio/components');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { useCore } = require('stremio/core');
|
||||
const Stream = require('./Stream');
|
||||
const styles = require('./styles');
|
||||
const { usePlatform, useProfile } = require('stremio/common');
|
||||
|
|
@ -16,7 +16,7 @@ const ALL_ADDONS_KEY = 'ALL';
|
|||
|
||||
const StreamsList = ({ className, video, type, onEpisodeSearch, ...props }) => {
|
||||
const { t } = useTranslation();
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const platform = usePlatform();
|
||||
const profile = useProfile();
|
||||
const streamsContainerRef = React.useRef(null);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ const React = require('react');
|
|||
const PropTypes = require('prop-types');
|
||||
const classnames = require('classnames');
|
||||
const { t } = require('i18next');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { useCore } = require('stremio/core');
|
||||
const { useProfile } = require('stremio/common');
|
||||
const { Image, SearchBar, Toggle, Video } = require('stremio/components');
|
||||
const SeasonsBar = require('./SeasonsBar');
|
||||
|
|
@ -12,7 +12,7 @@ const { default: EpisodePicker } = require('../EpisodePicker');
|
|||
const styles = require('./styles');
|
||||
|
||||
const VideosList = ({ className, metaItem, libraryItem, season, seasonOnSelect, selectedVideoId, toggleNotifications }) => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const profile = useProfile();
|
||||
|
||||
const showNotificationsToggle = React.useMemo(() => {
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@ const React = require('react');
|
|||
const PropTypes = require('prop-types');
|
||||
const classnames = require('classnames');
|
||||
const { useTranslation } = require('react-i18next');
|
||||
const { useCore } = require('stremio/core');
|
||||
const { usePlatform, useToast } = require('stremio/common');
|
||||
const { useServices } = require('stremio/services');
|
||||
const Option = require('./Option');
|
||||
const styles = require('./styles');
|
||||
|
||||
const OptionsMenu = React.memo(React.forwardRef(({ className, stream, playbackDevices, extraSubtitlesTracks, selectedExtraSubtitlesTrackId }, ref) => {
|
||||
const { t } = useTranslation();
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const platform = usePlatform();
|
||||
const toast = useToast();
|
||||
const [streamingUrl, downloadUrl, magnetUrl] = React.useMemo(() => {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ const debounce = require('lodash.debounce');
|
|||
const langs = require('langs');
|
||||
const { useTranslation } = require('react-i18next');
|
||||
const { useRouteFocused } = require('stremio-router');
|
||||
const { useCore } = require('stremio/core');
|
||||
const { useServices, useGamepad } = require('stremio/services');
|
||||
const { useContentGamepadNavigation } = require('stremio/services/GamepadNavigation');
|
||||
const { useSettings, useProfile, useFullscreen, useBinaryState, useToast, useStreamingServer, withCoreSuspender, useShell, usePlatform, onShortcut } = require('stremio/common');
|
||||
|
|
@ -40,6 +41,7 @@ const GAMEPAD_HANDLER_ID = 'player';
|
|||
const Player = ({ urlParams, queryParams }) => {
|
||||
const { t } = useTranslation();
|
||||
const services = useServices();
|
||||
const core = useCore();
|
||||
const shell = useShell();
|
||||
const gamepad = useGamepad();
|
||||
const forceTranscoding = React.useMemo(() => {
|
||||
|
|
@ -506,19 +508,19 @@ const Player = ({ urlParams, queryParams }) => {
|
|||
);
|
||||
}
|
||||
};
|
||||
const onCoreEvent = ({ event }) => {
|
||||
if (event === 'PlayingOnDevice') {
|
||||
const onCoreEvent = (name) => {
|
||||
if (name === 'PlayingOnDevice') {
|
||||
playingOnExternalDevice.current = true;
|
||||
onPauseRequested();
|
||||
}
|
||||
};
|
||||
services.chromecast.on('stateChanged', onChromecastServiceStateChange);
|
||||
services.core.transport.on('CoreEvent', onCoreEvent);
|
||||
core.on('event', onCoreEvent);
|
||||
onChromecastServiceStateChange();
|
||||
return () => {
|
||||
toast.removeFilter(toastFilter);
|
||||
services.chromecast.off('stateChanged', onChromecastServiceStateChange);
|
||||
services.core.transport.off('CoreEvent', onCoreEvent);
|
||||
core.off('event', onCoreEvent);
|
||||
if (services.chromecast.active) {
|
||||
services.chromecast.transport.off(
|
||||
cast.framework.CastContextEventType.CAST_STATE_CHANGED,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import React, { useMemo, useCallback, useState, forwardRef, memo } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import Icon from '@stremio/stremio-icons/react';
|
||||
import { useServices } from 'stremio/services';
|
||||
import { useCore } from 'stremio/core';
|
||||
import { CONSTANTS } from 'stremio/common';
|
||||
import { MetaPreview, Video } from 'stremio/components';
|
||||
import SeasonsBar from 'stremio/routes/MetaDetails/VideosList/SeasonsBar';
|
||||
|
|
@ -19,7 +19,7 @@ type Props = {
|
|||
};
|
||||
|
||||
const SideDrawer = memo(forwardRef<HTMLDivElement, Props>(({ seriesInfo, className, closeSideDrawer, selected, ...props }: Props, ref) => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const [season, setSeason] = useState<number>(seriesInfo?.season);
|
||||
const [selectedVideoId, setSelectedVideoId] = useState<string | null>(null);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@
|
|||
const React = require('react');
|
||||
const PropTypes = require('prop-types');
|
||||
const classnames = require('classnames');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { useCore } = require('stremio/core');
|
||||
const { Video } = require('stremio/components');
|
||||
const styles = require('./styles');
|
||||
|
||||
const VideosMenu = ({ className, metaItem, seriesInfo }) => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
|
||||
const onMouseDown = React.useCallback((event) => {
|
||||
event.nativeEvent.videosMenuClosePrevented = true;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const React = require('react');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { useCore } = require('stremio/core');
|
||||
const { useModelState, useCoreSuspender } = require('stremio/common');
|
||||
|
||||
const map = (player) => ({
|
||||
|
|
@ -33,7 +33,7 @@ const map = (player) => ({
|
|||
});
|
||||
|
||||
const usePlayer = (urlParams) => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const { decodeStream } = useCoreSuspender();
|
||||
const stream = decodeStream(urlParams.stream);
|
||||
const action = React.useMemo(() => {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const React = require('react');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { useCore } = require('stremio/core');
|
||||
|
||||
const useStatistics = (player, streamingServer) => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
|
||||
const stream = React.useMemo(() => {
|
||||
if (player.stream?.type === 'Ready') {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const React = require('react');
|
||||
const { useCore } = require('stremio/core');
|
||||
const { useModelState } = require('stremio/common');
|
||||
const { useServices } = require('stremio/services');
|
||||
|
||||
const useSearch = (queryParams) => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
// TODO: refactor this to be in stremio-core-web
|
||||
// React.useEffect(() => {
|
||||
// let timerId = setTimeout(emitSearchEvent, 500);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { forwardRef, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useCore } from 'stremio/core';
|
||||
import { Button } from 'stremio/components';
|
||||
import { useServices } from 'stremio/services';
|
||||
import { usePlatform, useToast } from 'stremio/common';
|
||||
import { Section, Option, Link } from '../components';
|
||||
import User from './User';
|
||||
|
|
@ -14,7 +14,7 @@ type Props = {
|
|||
|
||||
const General = forwardRef<HTMLDivElement, Props>(({ profile }: Props, ref) => {
|
||||
const { t } = useTranslation();
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const platform = usePlatform();
|
||||
const toast = useToast();
|
||||
const [dataExport, loadDataExport] = useDataExport();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useServices } from 'stremio/services';
|
||||
import { useCore } from 'stremio/core';
|
||||
import { Link } from '../../components';
|
||||
import styles from './User.less';
|
||||
|
||||
|
|
@ -10,7 +10,7 @@ type Props = {
|
|||
|
||||
const User = ({ profile }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
|
||||
const avatar = useMemo(() => (
|
||||
!profile.auth ?
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const React = require('react');
|
||||
const { useServices } = require('stremio/services');
|
||||
const { useCore } = require('stremio/core');
|
||||
const { useModelState } = require('stremio/common');
|
||||
|
||||
const map = (dataExport) => ({
|
||||
|
|
@ -13,7 +13,7 @@ const map = (dataExport) => ({
|
|||
});
|
||||
|
||||
const useDataExport = () => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const loadDataExport = React.useCallback(() => {
|
||||
core.transport.dispatch({
|
||||
action: 'Load',
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { useMemo } from 'react';
|
||||
import { useCore } from 'stremio/core';
|
||||
import { interfaceLanguages, useLanguageSorting } from 'stremio/common';
|
||||
import { useServices } from 'stremio/services';
|
||||
|
||||
const useInterfaceOptions = (profile: Profile) => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
|
||||
const interfaceLanguageOptions = useMemo(() =>
|
||||
interfaceLanguages.map(({ name, codes }) => ({
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useCore } from 'stremio/core';
|
||||
import { CONSTANTS, languageNames, useLanguageSorting, usePlatform } from 'stremio/common';
|
||||
import { useServices } from 'stremio/services';
|
||||
|
||||
const LANGUAGES_NAMES: Record<string, string> = languageNames;
|
||||
|
||||
const usePlayerOptions = (profile: Profile) => {
|
||||
const { t } = useTranslation();
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const platform = usePlatform();
|
||||
|
||||
const languageOptions = useMemo(() => Object.keys(LANGUAGES_NAMES).map((code) => ({
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
// Copyright (C) 2017-2024 Smart code 203358507
|
||||
|
||||
import { useCallback } from 'react';
|
||||
import { useCore } from 'stremio/core';
|
||||
import { useModelState, useToast } from 'stremio/common';
|
||||
import useProfile from 'stremio/common/useProfile';
|
||||
import { useServices } from 'stremio/services';
|
||||
|
||||
const useStreamingServerUrls = () => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const profile = useProfile();
|
||||
const toast = useToast();
|
||||
const ctx = useModelState({ model: 'ctx' });
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { deepEqual } from 'fast-equals';
|
||||
import { useServices } from 'stremio/services';
|
||||
import { useCore } from 'stremio/core';
|
||||
|
||||
const CACHE_SIZES = [0, 2147483648, 5368709120, 10737418240, null];
|
||||
|
||||
|
|
@ -62,7 +62,7 @@ const TORRENT_PROFILES: Record<string, TorrentProfile> = {
|
|||
};
|
||||
|
||||
const useStreamingOptions = (streamingServer: StreamingServer) => {
|
||||
const { core } = useServices();
|
||||
const core = useCore();
|
||||
const { t } = useTranslation();
|
||||
// TODO combine those useMemo in one
|
||||
|
||||
|
|
|
|||
2
src/services/Core/Core.d.ts
vendored
2
src/services/Core/Core.d.ts
vendored
|
|
@ -1,2 +0,0 @@
|
|||
declare function Core(): Core;
|
||||
export = Core;
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const EventEmitter = require('eventemitter3');
|
||||
const CoreTransport = require('./CoreTransport');
|
||||
|
||||
function Core(args) {
|
||||
let active = false;
|
||||
let error = null;
|
||||
let starting = false;
|
||||
let transport = null;
|
||||
|
||||
const events = new EventEmitter();
|
||||
|
||||
function onTransportInit() {
|
||||
active = true;
|
||||
error = null;
|
||||
starting = false;
|
||||
onStateChanged();
|
||||
}
|
||||
function onTransportError(args) {
|
||||
console.error(args);
|
||||
active = false;
|
||||
error = new Error('Stremio Core Transport initialization failed', { cause: args });
|
||||
starting = false;
|
||||
onStateChanged();
|
||||
transport = null;
|
||||
}
|
||||
function onStateChanged() {
|
||||
events.emit('stateChanged');
|
||||
}
|
||||
|
||||
Object.defineProperties(this, {
|
||||
active: {
|
||||
configurable: false,
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return active;
|
||||
}
|
||||
},
|
||||
error: {
|
||||
configurable: false,
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return error;
|
||||
}
|
||||
},
|
||||
starting: {
|
||||
configurable: false,
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return starting;
|
||||
}
|
||||
},
|
||||
transport: {
|
||||
configurable: false,
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return transport;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.start = function() {
|
||||
if (active || error instanceof Error || starting) {
|
||||
return;
|
||||
}
|
||||
|
||||
starting = true;
|
||||
transport = new CoreTransport(args);
|
||||
transport.on('init', onTransportInit);
|
||||
transport.on('error', onTransportError);
|
||||
onStateChanged();
|
||||
};
|
||||
this.stop = function() {
|
||||
active = false;
|
||||
error = null;
|
||||
starting = false;
|
||||
onStateChanged();
|
||||
if (transport !== null) {
|
||||
transport.removeAllListeners();
|
||||
transport = null;
|
||||
}
|
||||
};
|
||||
this.on = function(name, listener) {
|
||||
events.on(name, listener);
|
||||
};
|
||||
this.off = function(name, listener) {
|
||||
events.off(name, listener);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = Core;
|
||||
2
src/services/Core/CoreTransport.d.ts
vendored
2
src/services/Core/CoreTransport.d.ts
vendored
|
|
@ -1,2 +0,0 @@
|
|||
declare function CoreTransport(): CoreTransport;
|
||||
export = CoreTransport;
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const EventEmitter = require('eventemitter3');
|
||||
const Bridge = require('@stremio/stremio-core-web/bridge');
|
||||
|
||||
function CoreTransport(args) {
|
||||
const events = new EventEmitter();
|
||||
const worker = new Worker(`${process.env.COMMIT_HASH}/scripts/worker.js`);
|
||||
const bridge = new Bridge(window, worker);
|
||||
|
||||
window.onCoreEvent = ({ name, args }) => {
|
||||
try {
|
||||
events.emit(name, args);
|
||||
} catch (error) {
|
||||
console.error('CoreTransport', error);
|
||||
}
|
||||
};
|
||||
|
||||
bridge.call(['init'], [args])
|
||||
.then(() => {
|
||||
try {
|
||||
events.emit('init');
|
||||
} catch (error) {
|
||||
console.error('CoreTransport', error);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
events.emit('error', error);
|
||||
});
|
||||
|
||||
this.on = function(name, listener) {
|
||||
events.on(name, listener);
|
||||
};
|
||||
this.off = function(name, listener) {
|
||||
events.off(name, listener);
|
||||
};
|
||||
this.removeAllListeners = function() {
|
||||
events.removeAllListeners();
|
||||
};
|
||||
this.getState = async function(field) {
|
||||
return bridge.call(['getState'], [field]);
|
||||
};
|
||||
this.getDebugState = async function() {
|
||||
return bridge.call(['getDebugState'], []);
|
||||
};
|
||||
this.dispatch = async function(action, field) {
|
||||
return bridge.call(['dispatch'], [action, field, location.hash]);
|
||||
};
|
||||
this.analytics = async function(event) {
|
||||
return bridge.call(['analytics'], [event, location.hash]);
|
||||
};
|
||||
this.decodeStream = async function(stream) {
|
||||
return bridge.call(['decodeStream'], [stream]);
|
||||
};
|
||||
this.encodeStream = async function(stream) {
|
||||
return bridge.call(['encodeStream'], [stream]);
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = CoreTransport;
|
||||
12
src/services/Core/globals.d.ts
vendored
12
src/services/Core/globals.d.ts
vendored
|
|
@ -1,12 +0,0 @@
|
|||
type CoreEvent = {
|
||||
name: string,
|
||||
args: any[],
|
||||
};
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
onCoreEvent: (event: CoreEvent) => void;
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const Core = require('./Core');
|
||||
|
||||
module.exports = Core;
|
||||
29
src/services/Core/types.d.ts
vendored
29
src/services/Core/types.d.ts
vendored
|
|
@ -1,29 +0,0 @@
|
|||
type Action = {
|
||||
action: string,
|
||||
args?: {
|
||||
model?: string,
|
||||
action?: string,
|
||||
args?: any,
|
||||
}
|
||||
};
|
||||
|
||||
type AnalyticsEvent = {
|
||||
event: string,
|
||||
args: object,
|
||||
};
|
||||
|
||||
interface CoreTransport {
|
||||
start: (args: object) => Promise<void>,
|
||||
getState: (model: string) => Promise<object>,
|
||||
dispatch: (action: Action, model?: string) => Promise<void>,
|
||||
decodeStream: (stream: string) => Promise<Stream>,
|
||||
encodeStream: (stream: object) => Promise<string>,
|
||||
analytics: (event: AnalyticsEvent) => Promise<void>,
|
||||
on: (name: string, listener: () => void) => void,
|
||||
off: (name: string, listener: () => void) => void,
|
||||
}
|
||||
|
||||
interface Core {
|
||||
active: boolean,
|
||||
transport: CoreTransport,
|
||||
}
|
||||
1
src/services/ServicesContext/types.d.ts
vendored
1
src/services/ServicesContext/types.d.ts
vendored
|
|
@ -1,5 +1,4 @@
|
|||
type ServicesContext = {
|
||||
core: Core,
|
||||
shell: any,
|
||||
chromecast: any,
|
||||
keyboardShortcuts: any,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
// Copyright (C) 2017-2023 Smart code 203358507
|
||||
|
||||
const Chromecast = require('./Chromecast');
|
||||
const Core = require('./Core');
|
||||
const DragAndDrop = require('./DragAndDrop');
|
||||
const KeyboardShortcuts = require('./KeyboardShortcuts');
|
||||
const { ServicesProvider, useServices } = require('./ServicesContext');
|
||||
|
|
@ -10,7 +9,6 @@ const Shell = require('./Shell');
|
|||
|
||||
module.exports = {
|
||||
Chromecast,
|
||||
Core,
|
||||
DragAndDrop,
|
||||
KeyboardShortcuts,
|
||||
ServicesProvider,
|
||||
|
|
|
|||
3
src/types/Stream.d.ts
vendored
3
src/types/Stream.d.ts
vendored
|
|
@ -10,8 +10,9 @@ type Stream = {
|
|||
description: string,
|
||||
infoHash?: string,
|
||||
fileIdx?: string,
|
||||
url?: string,
|
||||
externalUrl?: string,
|
||||
deepLinks: {
|
||||
deepLinks?: {
|
||||
player: string,
|
||||
externalPlayer: ExternalPlayerLinks,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
"outDir": "./dist",
|
||||
"module": "nodenext",
|
||||
"moduleResolution": "nodenext",
|
||||
"types": ["node"],
|
||||
"paths": {
|
||||
"stremio/*": ["./src/*"],
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue