refactor: fold discord service into provider

This commit is contained in:
Timothy Z. 2026-06-15 12:34:18 +03:00
parent 4a04b6d7a2
commit 6e76f9d051
6 changed files with 26 additions and 123 deletions

View file

@ -5,7 +5,7 @@ const React = require('react');
const { useTranslation } = require('react-i18next');
const { useCore } = require('stremio/core');
const { Router } = require('stremio-router');
const { Chromecast, Discord, ServicesProvider, GamepadProvider } = require('stremio/services');
const { Chromecast, ServicesProvider, GamepadProvider } = require('stremio/services');
const { FullscreenProvider, ToastProvider, TooltipProvider, ShortcutsProvider, DiscordProvider, CONSTANTS, useBinaryState, useProfile, withCoreSuspender, onFileDrop, usePlatform } = require('stremio/common');
const ServicesToaster = require('./ServicesToaster');
const SearchParamsHandler = require('./SearchParamsHandler');
@ -24,7 +24,6 @@ const App = () => {
const [gamepadSupportEnabled, setGamepadSupportEnabled] = React.useState(false);
const services = React.useMemo(() => {
return {
discord: new Discord(),
chromecast: new Chromecast(),
};
}, []);
@ -81,13 +80,11 @@ const App = () => {
};
services.chromecast.on('stateChanged', onChromecastStateChange);
services.chromecast.start();
services.discord.init(shell);
window.services = services;
return () => {
services.chromecast.stop();
services.chromecast.off('stateChanged', onChromecastStateChange);
services.discord.destroy();
};
}, []);

View file

@ -1,5 +1,5 @@
import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
import { useServices } from 'stremio/services';
import { usePlatform } from '../Platform';
import useProfile from '../useProfile';
import type { DiscordActivity as Activity } from './activity';
@ -27,38 +27,34 @@ type Props = {
};
const DiscordProvider = ({ children }: Props) => {
const { discord } = useServices();
const { shell } = usePlatform();
const profile = useProfile();
const enabled = profile.settings?.discordRpcEnabled === true;
const [available, setAvailable] = useState(discord?.available === true);
const available = shell.active === true;
const [connected, setConnected] = useState(false);
const [activity, setActivityState] = useState<Activity | null>(null);
const sentActivity = useRef<Activity | null>(null);
const connectRequested = useRef(false);
const shellRef = useRef(shell);
shellRef.current = shell;
useEffect(() => {
if (!discord) return;
if (!available) return;
const onStatusChanged = (isConnected: boolean) => {
const onStatus = (data: { connected: boolean }) => {
connectRequested.current = false;
setConnected(isConnected);
};
const onAvailabilityChanged = (isAvailable: boolean) => {
setAvailable(isAvailable);
setConnected(data.connected === true);
};
discord.on('statusChanged', onStatusChanged);
discord.on('availabilityChanged', onAvailabilityChanged);
setAvailable(discord.available === true);
shellRef.current.on('discord-status', onStatus);
return () => {
discord.off('statusChanged', onStatusChanged);
discord.off('availabilityChanged', onAvailabilityChanged);
shellRef.current.off('discord-status', onStatus);
};
}, [discord]);
}, [available]);
useEffect(() => {
if (!discord || !available) {
if (!available) {
connectRequested.current = false;
setConnected(false);
sentActivity.current = null;
@ -68,7 +64,7 @@ const DiscordProvider = ({ children }: Props) => {
if (!enabled) {
connectRequested.current = false;
if (connected) {
discord.disconnect();
shellRef.current.send('discord-disconnect', {});
}
sentActivity.current = null;
return;
@ -79,7 +75,7 @@ const DiscordProvider = ({ children }: Props) => {
const requestConnect = () => {
if (!connectRequested.current) {
connectRequested.current = true;
discord.connect();
shellRef.current.send('discord-connect', {});
}
};
@ -89,14 +85,14 @@ const DiscordProvider = ({ children }: Props) => {
return () => {
window.clearInterval(interval);
};
}, [available, connected, discord, enabled]);
}, [available, connected, enabled]);
useEffect(() => {
if (!discord || !available || !enabled || !connected) return;
if (!available || !enabled || !connected) return;
if (activity === null) {
if (sentActivity.current !== null) {
discord.clearActivity();
shellRef.current.send('discord-clear-activity', {});
sentActivity.current = null;
}
return;
@ -104,15 +100,15 @@ const DiscordProvider = ({ children }: Props) => {
if (sameActivity(sentActivity.current, activity)) return;
discord.setActivity(
activity.state,
activity.details || '',
activity.image || null,
activity.startTimestamp || null,
activity.endTimestamp || null
);
shellRef.current.send('discord-set-activity', {
state: activity.state,
details: activity.details || '',
image: activity.image || null,
startTimestamp: activity.startTimestamp || null,
endTimestamp: activity.endTimestamp || null,
});
sentActivity.current = activity;
}, [activity, available, connected, discord, enabled]);
}, [activity, available, connected, enabled]);
const setActivity = useCallback((nextActivity: Activity | null) => {
setActivityState((currentActivity) => sameActivity(currentActivity, nextActivity) ? currentActivity : nextActivity);

View file

@ -1,82 +0,0 @@
// Copyright (C) 2017-2025 Smart code 203358507
import EventEmitter from 'eventemitter3';
type DiscordStatusData = {
connected: boolean;
};
class Discord {
private events: EventEmitter;
private shell: any;
private onDiscordStatus: ((data: DiscordStatusData) => void) | null = null;
constructor() {
this.events = new EventEmitter();
this.shell = null;
}
init(shellService: any): void {
this.shell = shellService;
if (this.shell) {
this.onDiscordStatus = (data: DiscordStatusData) => {
this.events.emit('availabilityChanged', this.available);
this.events.emit('statusChanged', data.connected);
};
this.shell.on('discord-status', this.onDiscordStatus);
}
}
destroy(): void {
if (this.shell && this.onDiscordStatus) {
this.shell.off('discord-status', this.onDiscordStatus);
this.onDiscordStatus = null;
}
this.shell = null;
}
connect(): void {
if (this.shell && this.shell.active) {
this.shell.send('discord-connect', {});
}
}
disconnect(): void {
if (this.shell && this.shell.active) {
this.shell.send('discord-disconnect', {});
}
}
setActivity(state: string, details: string, image?: string | null, startTimestamp?: number | null, endTimestamp?: number | null): void {
if (this.shell && this.shell.active) {
this.shell.send('discord-set-activity', {
state,
details,
image: image || null,
startTimestamp: startTimestamp || null,
endTimestamp: endTimestamp || null
});
}
}
clearActivity(): void {
if (this.shell && this.shell.active) {
this.shell.send('discord-clear-activity', {});
}
}
get available(): boolean {
return this.shell && this.shell.active;
}
on(name: string, listener: (data: any) => void): void {
this.events.on(name, listener);
}
off(name: string, listener: (data: any) => void): void {
this.events.off(name, listener);
}
}
export default Discord;

View file

@ -1,5 +0,0 @@
// Copyright (C) 2017-2025 Smart code 203358507
import Discord from './Discord';
export default Discord;

View file

@ -1,4 +1,3 @@
type ServicesContext = {
chromecast: any,
discord: any,
};

View file

@ -1,13 +1,11 @@
// Copyright (C) 2017-2023 Smart code 203358507
const Chromecast = require('./Chromecast');
const { default: Discord } = require('./Discord');
const { ServicesProvider, useServices } = require('./ServicesContext');
const { GamepadProvider, useGamepad } = require('./GamepadContext');
module.exports = {
Chromecast,
Discord,
ServicesProvider,
useServices,
GamepadProvider,