diff --git a/dev.moku.app.yml b/dev.moku.app.yml index dbdcd02..d27a957 100644 --- a/dev.moku.app.yml +++ b/dev.moku.app.yml @@ -181,7 +181,7 @@ modules: path: . - type: file path: packaging/frontend-dist.tar.gz - sha256: 3f18e4cc9153e28fd9020f7de22aac6dad1891034833b683c4bc0f5d0e04fc2b + sha256: 9e9590cf8c98b07ca774382491b1d8cfcc1f2151afadbf8e23e2abda0c086c11 - packaging/cargo-sources.json - type: inline dest: src-tauri/.cargo diff --git a/packaging/cargo-sources.json b/packaging/cargo-sources.json index ea953c2..48a38f4 100644 --- a/packaging/cargo-sources.json +++ b/packaging/cargo-sources.json @@ -2225,14 +2225,14 @@ { "type": "archive", "archive-type": "tar-gzip", - "url": "https://static.crates.io/crates/iri-string/iri-string-0.7.11.crate", - "sha256": "d8e7418f59cc01c88316161279a7f665217ae316b388e58a0d10e29f54f1e5eb", - "dest": "cargo/vendor/iri-string-0.7.11" + "url": "https://static.crates.io/crates/iri-string/iri-string-0.7.12.crate", + "sha256": "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20", + "dest": "cargo/vendor/iri-string-0.7.12" }, { "type": "inline", - "contents": "{\"package\": \"d8e7418f59cc01c88316161279a7f665217ae316b388e58a0d10e29f54f1e5eb\", \"files\": {}}", - "dest": "cargo/vendor/iri-string-0.7.11", + "contents": "{\"package\": \"25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20\", \"files\": {}}", + "dest": "cargo/vendor/iri-string-0.7.12", "dest-filename": ".cargo-checksum.json" }, { @@ -4198,6 +4198,19 @@ "dest": "cargo/vendor/ring-0.17.14", "dest-filename": ".cargo-checksum.json" }, + { + "type": "archive", + "archive-type": "tar-gzip", + "url": "https://static.crates.io/crates/rpcdiscord/rpcdiscord-0.2.6.crate", + "sha256": "71aa9a2097dc0176805e24debcb5d3ea5a17b796cd1d28e76b29f78fb49d7d5d", + "dest": "cargo/vendor/rpcdiscord-0.2.6" + }, + { + "type": "inline", + "contents": "{\"package\": \"71aa9a2097dc0176805e24debcb5d3ea5a17b796cd1d28e76b29f78fb49d7d5d\", \"files\": {}}", + "dest": "cargo/vendor/rpcdiscord-0.2.6", + "dest-filename": ".cargo-checksum.json" + }, { "type": "archive", "archive-type": "tar-gzip", @@ -5238,6 +5251,19 @@ "dest": "cargo/vendor/tauri-plugin-2.5.4", "dest-filename": ".cargo-checksum.json" }, + { + "type": "archive", + "archive-type": "tar-gzip", + "url": "https://static.crates.io/crates/tauri-plugin-drpc/tauri-plugin-drpc-0.1.6.crate", + "sha256": "7b291669b7dbc05471fba380eeecf31e3f733ae6013aaa5216a43ca376027e5a", + "dest": "cargo/vendor/tauri-plugin-drpc-0.1.6" + }, + { + "type": "inline", + "contents": "{\"package\": \"7b291669b7dbc05471fba380eeecf31e3f733ae6013aaa5216a43ca376027e5a\", \"files\": {}}", + "dest": "cargo/vendor/tauri-plugin-drpc-0.1.6", + "dest-filename": ".cargo-checksum.json" + }, { "type": "archive", "archive-type": "tar-gzip", @@ -6018,6 +6044,19 @@ "dest": "cargo/vendor/utf8_iter-1.0.4", "dest-filename": ".cargo-checksum.json" }, + { + "type": "archive", + "archive-type": "tar-gzip", + "url": "https://static.crates.io/crates/uuid/uuid-0.8.2.crate", + "sha256": "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7", + "dest": "cargo/vendor/uuid-0.8.2" + }, + { + "type": "inline", + "contents": "{\"package\": \"bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7\", \"files\": {}}", + "dest": "cargo/vendor/uuid-0.8.2", + "dest-filename": ".cargo-checksum.json" + }, { "type": "archive", "archive-type": "tar-gzip", diff --git a/src/components/pages/Home.svelte b/src/components/pages/Home.svelte index 9e574dd..c0e632a 100644 --- a/src/components/pages/Home.svelte +++ b/src/components/pages/Home.svelte @@ -173,7 +173,11 @@ const d = await gql<{ chapters: { nodes: Chapter[] } }>(GET_CHAPTERS, { mangaId: heroMangaId }); all = [...d.chapters.nodes].sort((a, b) => a.sourceOrder - b.sourceOrder); } - openReader(chapter, all); + if (all.length) { + const manga = heroManga ?? { id: heroMangaId, title: heroTitle, thumbnailUrl: heroManga?.thumbnailUrl ?? "" } as any; + store.activeManga = manga; + openReader(chapter, all); + } } catch { store.activeManga = { id: heroMangaId, title: heroTitle, thumbnailUrl: heroManga?.thumbnailUrl ?? "" } as any; } finally { resuming = false; } } @@ -188,8 +192,10 @@ const d = await gql<{ chapters: { nodes: Chapter[] } }>(GET_CHAPTERS, { mangaId: heroEntry.mangaId }); const chapters = [...d.chapters.nodes].sort((a, b) => a.sourceOrder - b.sourceOrder); const ch = chapters.find(c => c.id === heroEntry!.chapterId) ?? chapters[0]; - if (ch) openReader(ch, chapters); - else store.activeManga = { id: heroEntry.mangaId, title: heroEntry.mangaTitle, thumbnailUrl: heroEntry.thumbnailUrl } as any; + if (ch) { + store.activeManga = heroManga ?? { id: heroEntry.mangaId, title: heroEntry.mangaTitle, thumbnailUrl: heroEntry.thumbnailUrl } as any; + openReader(ch, chapters); + } } catch { store.activeManga = { id: heroEntry.mangaId, title: heroEntry.mangaTitle, thumbnailUrl: heroEntry.thumbnailUrl } as any; } finally { resuming = false; } } @@ -199,8 +205,10 @@ const d = await gql<{ chapters: { nodes: Chapter[] } }>(GET_CHAPTERS, { mangaId: entry.mangaId }); const chapters = [...d.chapters.nodes].sort((a, b) => a.sourceOrder - b.sourceOrder); const ch = chapters.find(c => c.id === entry.chapterId) ?? chapters[0]; - if (ch) openReader(ch, chapters); - else store.activeManga = { id: entry.mangaId, title: entry.mangaTitle, thumbnailUrl: entry.thumbnailUrl } as any; + if (ch) { + store.activeManga = { id: entry.mangaId, title: entry.mangaTitle, thumbnailUrl: entry.thumbnailUrl } as any; + openReader(ch, chapters); + } else store.activeManga = { id: entry.mangaId, title: entry.mangaTitle, thumbnailUrl: entry.thumbnailUrl } as any; } catch { store.activeManga = { id: entry.mangaId, title: entry.mangaTitle, thumbnailUrl: entry.thumbnailUrl } as any; } } diff --git a/src/lib/discord.ts b/src/lib/discord.ts index b6a821a..17b300a 100644 --- a/src/lib/discord.ts +++ b/src/lib/discord.ts @@ -5,6 +5,8 @@ import type { Manga, Chapter } from "./types"; const APP_ID = "1487894643613106298"; const FALLBACK_IMAGE = "moku_logo"; +let sessionStart: number | null = null; // ← captured once on init + function isPublicUrl(url: string | null | undefined): boolean { return typeof url === "string" && url.startsWith("https://"); } @@ -22,12 +24,17 @@ function formatChapter(chapter: Chapter): string { return `Chapter ${Number.isInteger(n) ? n : n.toFixed(1)}`; } +function getTimestamps(): Timestamps { + return new Timestamps(sessionStart ?? Date.now()); +} + const BUTTONS = [ new Button("GitHub", "https://github.com/Youwes09/Moku"), new Button("Discord", "https://discord.gg/Jq3pwuNqPp"), ]; export async function initRpc(): Promise { + sessionStart = Date.now(); // ← set once here await start(APP_ID) .then(() => console.log("[discord] RPC started")) .catch((e) => console.error("[discord] initRpc failed:", e)); @@ -44,7 +51,7 @@ export async function setReading(manga: Manga, chapter: Chapter): Promise .setDetails(trunc(manga.title)) .setState(`${formatChapter(chapter)} · Reading`) .setAssets(assets) - .setTimestamps(new Timestamps(Date.now())); + .setTimestamps(getTimestamps()); // ← reuses session start activity.setButton(BUTTONS); await setActivity(activity) @@ -60,7 +67,7 @@ export async function setIdle(): Promise { const activity = new Activity() .setDetails("Browsing") .setAssets(assets) - .setTimestamps(new Timestamps(Date.now())); + .setTimestamps(getTimestamps()); // ← reuses session start activity.setButton(BUTTONS); await setActivity(activity) @@ -75,7 +82,8 @@ export async function clearReading(): Promise { } export async function destroyRpc(): Promise { + sessionStart = null; // ← clean up on stop await stop() .then(() => console.log("[discord] RPC stopped")) .catch((e) => console.error("[discord] destroyRpc failed:", e)); -} +} \ No newline at end of file