# Stremio Web Stremio Web is a modern media center web application built with React that provides a one-stop solution for video entertainment. Users can discover, watch, and organize video content from easy-to-install addons. The application uses a modular architecture with a core transport layer communicating via Web Workers with the stremio-core-web Rust/WASM backend for performance-critical operations. The application features a hash-based routing system, comprehensive player controls with Chromecast support, addon management, library organization, content discovery, and calendar tracking for series. It supports multiple platforms including web browsers, desktop (via Electron shell), and mobile devices with platform-specific features like external player integration. ## Core Services ### Core Service Initialization The Core service manages the connection to the stremio-core-web backend through a Web Worker bridge. It handles state synchronization, user authentication, library management, and addon communication. ```javascript // Initialize core service with app version const services = { core: new Core({ appVersion: process.env.VERSION, shellVersion: null }), shell: new Shell(), chromecast: new Chromecast(), keyboardShortcuts: new KeyboardShortcuts(), dragAndDrop: new DragAndDrop({ core }) }; // Start all services services.core.start(); services.shell.start(); services.chromecast.start(); // Listen for state changes services.core.on('stateChanged', () => { if (services.core.active) { console.log('Core is ready'); } else if (services.core.error) { console.error('Core failed to initialize:', services.core.error); } }); // Dispatch actions to core services.core.transport.dispatch({ action: 'Ctx', args: { action: 'PullAddonsFromAPI' } }); // Get state from core const ctx = await services.core.transport.getState('ctx'); console.log('User profile:', ctx.profile); ``` ### CoreTransport API The CoreTransport provides the bridge interface for communicating with the stremio-core-web WASM module running in a Web Worker. ```javascript // CoreTransport methods available via services.core.transport // Get model state const playerState = await core.transport.getState('player'); const libraryState = await core.transport.getState('library'); const ctxState = await core.transport.getState('ctx'); // Dispatch actions await core.transport.dispatch({ action: 'Load', args: { model: 'CatalogsWithExtra', args: { extra: [['search', 'matrix']] } } }, 'catalog'); // Send analytics events await core.transport.analytics({ event: 'LocationPathChanged', args: { prevPath: '/board' } }); // Decode stream for playback const decodedStream = await core.transport.decodeStream(streamData); // Listen for core events core.transport.on('CoreEvent', ({ event, args }) => { if (event === 'SettingsUpdated') { console.log('Settings changed:', args.settings); } }); // Listen for state updates core.transport.on('NewState', (models) => { console.log('Updated models:', models); }); ``` ## React Hooks ### useModelState Hook The useModelState hook subscribes to core state models and automatically updates when the model changes. It handles state mapping, throttling, and cleanup. ```javascript const useModelState = require('stremio/common/useModelState'); // Basic usage - subscribe to streaming server state const useStreamingServer = () => { return useModelState({ model: 'streaming_server' }); }; // With state mapping - transform ctx state to profile const useProfile = () => { const map = (ctx) => ({ ...ctx.profile, settings: { ...ctx.profile.settings, streamingServerWarningDismissed: new Date( ctx.profile.settings.streamingServerWarningDismissed ) } }); return useModelState({ model: 'ctx', map }); }; // With action dispatch on mount const usePlayer = (urlParams) => { return useModelState({ model: 'player', action: { action: 'Load', args: { model: 'Player', args: { stream: urlParams.stream } } } }); }; // Usage in component const MyComponent = () => { const profile = useProfile(); const streamingServer = useStreamingServer(); return (

User: {profile.auth?.user?.email}

Server: {streamingServer.baseUrl}

); }; ``` ### useBinaryState Hook A simple hook for managing boolean state with explicit on/off/toggle functions. ```javascript const useBinaryState = require('stremio/common/useBinaryState'); const MyComponent = () => { const [isOpen, open, close, toggle] = useBinaryState(false); return (
{isOpen && }
); }; // Multiple binary states const Player = () => { const [optionsMenuOpen, , closeOptionsMenu, toggleOptionsMenu] = useBinaryState(false); const [subtitlesMenuOpen, , closeSubtitlesMenu, toggleSubtitlesMenu] = useBinaryState(false); const [audioMenuOpen, , closeAudioMenu, toggleAudioMenu] = useBinaryState(false); const closeAllMenus = () => { closeOptionsMenu(); closeSubtitlesMenu(); closeAudioMenu(); }; return (
{optionsMenuOpen && } {subtitlesMenuOpen && }
); }; ``` ### useToast Hook Displays toast notifications with automatic timeout and filtering capabilities. ```javascript const { useToast } = require('stremio/common'); const MyComponent = () => { const toast = useToast(); // Show success toast const onSuccess = () => { toast.show({ type: 'success', title: 'Addon Installed', message: 'The addon was successfully installed', timeout: 3000 }); }; // Show error toast const onError = (error) => { toast.show({ type: 'error', title: 'Error', message: error.message, timeout: 5000, dataset: { type: 'PlayerError' } }); }; // Add filter to suppress certain toasts useEffect(() => { const filter = (item) => item?.dataset?.type === 'CoreEvent'; toast.addFilter(filter); return () => toast.removeFilter(filter); }, []); // Clear all toasts const clearAll = () => toast.clear(); return ( ); }; ``` ## Router System ### Routes Configuration The router uses hash-based navigation with regex pattern matching for route parameters. ```javascript // Route definitions with regex patterns const routesRegexp = { intro: { regexp: /^\/intro$/, urlParamsNames: [] }, board: { regexp: /^\/?(?:board)?$/, urlParamsNames: [] }, discover: { regexp: /^\/discover(?:\/([^/]*)\/([^/]*)\/([^/]*))?$/, urlParamsNames: ['transportUrl', 'type', 'catalogId'] }, library: { regexp: /^\/library(?:\/([^/]*))?$/, urlParamsNames: ['type'] }, metadetails: { regexp: /^\/(?:metadetails|detail)\/([^/]*)\/([^/]*)(?:\/([^/]*))?$/, urlParamsNames: ['type', 'id', 'videoId'] }, player: { regexp: /^\/player\/([^/]*)(?:\/([^/]*)\/([^/]*)\/([^/]*)\/([^/]*)\/([^/]*))?$/, urlParamsNames: ['stream', 'streamTransportUrl', 'metaTransportUrl', 'type', 'id', 'videoId'] }, addons: { regexp: /^\/addons(?:\/([^/]*)(?:\/([^/]*)\/([^/]*))?)?$/, urlParamsNames: ['type', 'transportUrl', 'catalogId'] }, settings: { regexp: /^\/settings$/, urlParamsNames: [] } }; // Router views configuration const routerViewsConfig = [ [{ ...routesRegexp.board, component: Board }], [ { ...routesRegexp.intro, component: Intro }, { ...routesRegexp.discover, component: Discover }, { ...routesRegexp.library, component: Library }, { ...routesRegexp.search, component: Search } ], [{ ...routesRegexp.metadetails, component: MetaDetails }], [ { ...routesRegexp.addons, component: Addons }, { ...routesRegexp.settings, component: Settings } ], [{ ...routesRegexp.player, component: Player }] ]; // Navigate programmatically window.location.href = '#/discover/https%3A%2F%2Fv3-cinemeta.strem.io%2Fmanifest.json/movie/top'; window.location.href = '#/metadetails/movie/tt0111161'; window.location.href = '#/player/encoded-stream-data'; window.history.back(); ``` ## Components ### Button Component A versatile button component supporting links, long press, and keyboard navigation. ```tsx import Button from 'stremio/components/Button'; // Basic button // Link button // Button with long press // Disabled button // External link ``` ### Video Player Controls The Player component provides comprehensive video playback controls with subtitle support, audio tracks, and streaming server integration. ```javascript // Player route receives urlParams const Player = ({ urlParams, queryParams }) => { const [player, videoParamsChanged, timeChanged, seek, pausedChanged, ended, nextVideo] = usePlayer(urlParams); const video = useVideo(); const streamingServer = useStreamingServer(); // Load video stream useEffect(() => { if (player.selected && player.stream?.type === 'Ready') { video.load({ stream: player.stream.content, autoplay: true, time: player.libraryItem?.state?.timeOffset || 0, forceTranscoding: false, streamingServerURL: streamingServer.baseUrl }); } }, [player.selected, player.stream]); // Control playback const onPlayRequested = () => video.setProp('paused', false); const onPauseRequested = () => video.setProp('paused', true); const onSeekRequested = (time) => { video.setProp('time', time); seek(time, video.state.duration); }; const onVolumeChange = (volume) => video.setProp('volume', volume); // Subtitle controls const onSubtitlesTrackSelected = (id) => video.setSubtitlesTrack(id); const onExtraSubtitlesTrackSelected = (id) => video.setExtraSubtitlesTrack(id); // Audio track selection const onAudioTrackSelected = (id) => video.setProp('selectedAudioTrackId', id); // Playback speed const onPlaybackSpeedChanged = (rate) => video.setProp('playbackSpeed', rate); return (
); }; ``` ## Addon Management ### Installing and Managing Addons Addons extend Stremio's functionality by providing catalogs, streams, and metadata from various sources. ```javascript const { useServices } = require('stremio/services'); const AddonsManager = () => { const { core } = useServices(); // Install addon const installAddon = (addon) => { core.transport.dispatch({ action: 'Ctx', args: { action: 'InstallAddon', args: addon } }); }; // Uninstall addon const uninstallAddon = (addon) => { core.transport.dispatch({ action: 'Ctx', args: { action: 'UninstallAddon', args: addon } }); }; // Example addon object const addon = { transportUrl: 'https://v3-cinemeta.strem.io/manifest.json', manifest: { id: 'com.stremio.cinemeta', name: 'Cinemeta', version: '3.0.0', description: 'Movie and TV metadata', types: ['movie', 'series'], catalogs: [ { type: 'movie', id: 'top', name: 'Popular Movies' } ] } }; return (
); }; // Navigate to addon details via URL window.location.href = '#/addons?addon=' + encodeURIComponent('https://example.com/manifest.json'); ``` ## Application Constants ### Configuration Constants Global constants used throughout the application for configuration and UI options. ```javascript const CONSTANTS = require('stremio/common/CONSTANTS'); // Streaming server default URL console.log(CONSTANTS.DEFAULT_STREAMING_SERVER_URL); // 'http://127.0.0.1:11470/' // Chromecast configuration console.log(CONSTANTS.CHROMECAST_RECEIVER_APP_ID); // '1634F54B' // Subtitle customization options console.log(CONSTANTS.SUBTITLES_SIZES); // [75, 100, 125, 150, 175, 200, 250] console.log(CONSTANTS.SUBTITLES_FONTS); // ['PlusJakartaSans', 'Arial', ...] // Player settings console.log(CONSTANTS.SEEK_TIME_DURATIONS); // [3000, 5000, 10000, ...] console.log(CONSTANTS.NEXT_VIDEO_POPUP_DURATIONS); // [0, 5000, 10000, ...] // Catalog pagination console.log(CONSTANTS.CATALOG_PREVIEW_SIZE); // 10 console.log(CONSTANTS.CATALOG_PAGE_SIZE); // 100 // Content type priorities for sorting console.log(CONSTANTS.TYPE_PRIORITIES); // { movie: 10, series: 9, channel: 8, tv: 7, music: 6, ... } // External player options by platform const externalPlayers = CONSTANTS.EXTERNAL_PLAYERS.filter( player => player.platforms.includes('android') ); // VLC, MX Player, Just Player, etc. // Supported local subtitle formats console.log(CONSTANTS.SUPPORTED_LOCAL_SUBTITLES); // ['application/x-subrip', 'text/vtt'] // Deep link protocol console.log(CONSTANTS.PROTOCOL); // 'stremio:' ``` ## Summary Stremio Web is designed for building rich media experiences with a focus on extensibility through addons and cross-platform compatibility. The architecture separates concerns between the React UI layer and the Rust/WASM core, communicating through a Web Worker bridge for optimal performance. Key patterns include the useModelState hook for reactive state management, hash-based routing for deep linking support, and the services layer for platform-specific functionality like Chromecast and shell integration. Developers extending Stremio Web should focus on the addon system for adding new content sources, the component library for UI consistency, and the core dispatch/state pattern for data flow. The application supports multiple deployment targets including standalone web, Electron desktop, and mobile webviews, with platform detection enabling conditional features. The toast and tooltip systems provide consistent user feedback, while the router supports complex navigation patterns with parameter extraction and view stacking.