feat(discord): support show reading status with Discord Rich Presence, closes #1538 (#2998)

This commit is contained in:
Huang Xin
2026-01-19 17:42:19 +01:00
committed by GitHub
parent 1704736bc8
commit d9a6cffe78
50 changed files with 794 additions and 85 deletions
@@ -53,6 +53,7 @@ import { transformContent } from '@/services/transformService';
import { lockScreenOrientation } from '@/utils/bridge';
import { useTextTranslation } from '../hooks/useTextTranslation';
import { useBookCoverAutoSave } from '../hooks/useAutoSaveBookCover';
import { useDiscordPresence } from '@/hooks/useDiscordPresence';
import { manageSyntaxHighlighting } from '@/utils/highlightjs';
import { getViewInsets } from '@/utils/insets';
import { removeTabIndex } from '@/utils/a11y';
@@ -85,6 +86,7 @@ const FoliateViewer: React.FC<{
const { getBookData } = useBookDataStore();
const { applyBackgroundTexture } = useBackgroundTexture();
const { applyEinkMode } = useEinkMode();
const bookData = getBookData(bookKey);
const viewState = getViewState(bookKey);
const viewSettings = getViewSettings(bookKey);
@@ -98,6 +100,12 @@ const FoliateViewer: React.FC<{
useAutoFocus<HTMLDivElement>({ ref: containerRef });
useDiscordPresence(
bookData?.book || null,
!!viewState?.isPrimary,
settings.discordRichPresenceEnabled,
);
useEffect(() => {
const timer = setTimeout(() => setToastMessage(''), 2000);
return () => clearTimeout(timer);
@@ -20,6 +20,7 @@ import { uniqueId } from '@/utils/misc';
import { throttle } from '@/utils/throttle';
import { eventDispatcher } from '@/utils/event';
import { navigateToLibrary } from '@/utils/nav';
import { clearDiscordPresence } from '@/utils/discord';
import { BOOK_IDS_SEPARATOR } from '@/services/constants';
import { BookDetailModal } from '@/components/metadata';
@@ -136,6 +137,12 @@ const ReaderContent: React.FC<{ ids?: string; settings: SystemSettings }> = ({ i
const saveConfigAndCloseBook = async (bookKey: string) => {
console.log('Closing book', bookKey);
const viewState = getViewState(bookKey);
if (viewState?.isPrimary && appService?.isDesktopApp) {
await clearDiscordPresence(appService);
}
try {
getView(bookKey)?.close();
getView(bookKey)?.remove();
@@ -3,7 +3,9 @@ import React from 'react';
import Image from 'next/image';
import { MdCheck } from 'react-icons/md';
import { useRouter } from 'next/navigation';
import { useEnv } from '@/context/EnvContext';
import { useAuth } from '@/context/AuthContext';
import { useReaderStore } from '@/store/readerStore';
import { useLibraryStore } from '@/store/libraryStore';
import { useSidebarStore } from '@/store/sidebarStore';
@@ -14,6 +16,8 @@ import { isWebAppPlatform } from '@/services/environment';
import { eventDispatcher } from '@/utils/event';
import { FIXED_LAYOUT_FORMATS } from '@/types/book';
import { DOWNLOAD_READEST_URL } from '@/services/constants';
import { navigateToLogin } from '@/utils/nav';
import { saveSysSettings } from '@/helpers/settings';
import { setKOSyncSettingsWindowVisible } from '@/app/reader/components/KOSyncSettings';
import { setProofreadRulesVisibility } from '@/app/reader/components/ProofreadRules';
import { setAboutDialogVisible } from '@/components/AboutWindow';
@@ -28,7 +32,9 @@ interface BookMenuProps {
const BookMenu: React.FC<BookMenuProps> = ({ menuClassName, setIsDropdownOpen }) => {
const _ = useTranslation();
const { envConfig } = useEnv();
const router = useRouter();
const { envConfig, appService } = useEnv();
const { user } = useAuth();
const { settings } = useSettingsStore();
const { bookKeys, recreateViewer, getViewSettings, setViewSettings } = useReaderStore();
const { getVisibleLibrary } = useLibraryStore();
@@ -93,6 +99,14 @@ const BookMenu: React.FC<BookMenuProps> = ({ menuClassName, setIsDropdownOpen })
eventDispatcher.dispatch('push-kosync', { bookKey: sideBarBookKey });
setIsDropdownOpen?.(false);
};
const toggleDiscordPresence = () => {
const discordRichPresenceEnabled = !settings.discordRichPresenceEnabled;
saveSysSettings(envConfig, 'discordRichPresenceEnabled', discordRichPresenceEnabled);
setIsDropdownOpen?.(false);
if (discordRichPresenceEnabled && !user) {
navigateToLogin(router);
}
};
return (
<Menu
@@ -153,6 +167,17 @@ const BookMenu: React.FC<BookMenuProps> = ({ menuClassName, setIsDropdownOpen })
<MenuItem label={_('Pull Progress')} onClick={handlePullKOSync} />
</>
)}
{appService?.isDesktopApp && (
<>
<hr className='border-base-200 my-1' />
<MenuItem
label={_('Show on Discord')}
tooltip={_("Display what I'm reading on Discord")}
toggled={settings.discordRichPresenceEnabled}
onClick={toggleDiscordPresence}
/>
</>
)}
<hr className='border-base-200 my-1' />
<MenuItem label={_('Proofread')} onClick={showProofreadRulesWindow} />
<hr className='border-base-200 my-1' />