mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-11-13 04:46:08 -08:00
feat(plugins): add JavaScript plugin system with overlay panel (#303)
This commit is contained in:
1 parent
90fc7cf940
commit
a9a4c4f083
110 files changed
+5897
-344
No files matched your search
@@ -1,5 +1,6 @@
|
||||
import http, { IncomingMessage, ServerResponse } from 'node:http';
|
||||
import axios, { AxiosInstance } from 'axios';
|
||||
import type { PluginMiningProvenance } from '../plugin-api';
|
||||
|
||||
interface StartProxyOptions {
|
||||
host: string;
|
||||
@@ -13,9 +14,13 @@ interface AnkiConnectEnvelope {
|
||||
}
|
||||
|
||||
export interface AnkiConnectProxyServerDeps {
|
||||
captureMiningProvenance?: () => PluginMiningProvenance | null;
|
||||
onNotesAdded?: (noteIds: number[], provenance: PluginMiningProvenance | null) => void;
|
||||
shouldAutoUpdateNewCards: () => boolean;
|
||||
processNewCard: (noteId: number) => Promise<void>;
|
||||
recordCardsAdded?: (count: number, noteIds: number[]) => void;
|
||||
/** Called once SubMiner is done with an added note: after enrichment, or right away when it is off. */
|
||||
onCardsReady?: (noteIds: number[]) => void;
|
||||
trackAddedDuplicateNoteIds?: (noteId: number, duplicateNoteIds: number[]) => void;
|
||||
getDeck?: () => string | undefined;
|
||||
findNotes?: (
|
||||
@@ -186,6 +191,12 @@ export class AnkiConnectProxyServer {
|
||||
typeof req.headers['content-type'] === 'string'
|
||||
? req.headers['content-type']
|
||||
: 'application/json';
|
||||
const action = requestJson?.action;
|
||||
const provenance =
|
||||
typeof action === 'string' &&
|
||||
['addNote', 'addNotes', 'multi', 'updateNoteFields'].includes(action)
|
||||
? (this.deps.captureMiningProvenance?.() ?? null)
|
||||
: null;
|
||||
const upstreamResponse = await this.client.request<ArrayBuffer>({
|
||||
url: targetUrl,
|
||||
method: req.method,
|
||||
@@ -203,7 +214,7 @@ export class AnkiConnectProxyServer {
|
||||
res.end(responseBody);
|
||||
|
||||
if (req.method === 'POST') {
|
||||
this.maybeEnqueueFromRequest(requestJson, responseBody);
|
||||
this.maybeEnqueueFromRequest(requestJson, responseBody, provenance);
|
||||
}
|
||||
} catch (error) {
|
||||
this.deps.logWarn('[anki-proxy] Failed to forward request:', (error as Error).message);
|
||||
@@ -215,16 +226,19 @@ export class AnkiConnectProxyServer {
|
||||
private maybeEnqueueFromRequest(
|
||||
requestJson: Record<string, unknown> | null,
|
||||
responseBody: Buffer,
|
||||
provenance: PluginMiningProvenance | null = null,
|
||||
): void {
|
||||
if (!requestJson || !this.deps.shouldAutoUpdateNewCards()) {
|
||||
if (!requestJson) {
|
||||
return;
|
||||
}
|
||||
const autoUpdate = this.deps.shouldAutoUpdateNewCards();
|
||||
|
||||
const action =
|
||||
typeof requestJson.action === 'string'
|
||||
? requestJson.action
|
||||
: String(requestJson.action ?? '');
|
||||
if (action === 'updateNoteFields') {
|
||||
if (!autoUpdate) return;
|
||||
const params = requestJson.params;
|
||||
if (
|
||||
!params ||
|
||||
@@ -246,6 +260,7 @@ export class AnkiConnectProxyServer {
|
||||
response.result !== null
|
||||
)
|
||||
return;
|
||||
this.deps.onNotesAdded?.(this.collectSingleResultId(note.id), provenance);
|
||||
this.enqueueNotes(this.collectSingleResultId(note.id), false);
|
||||
return;
|
||||
}
|
||||
@@ -277,9 +292,16 @@ export class AnkiConnectProxyServer {
|
||||
params.subminerEnrich === false
|
||||
) {
|
||||
// Stats owns the saved sentence and media; the live mpv context is unrelated.
|
||||
if (noteIds.length > 0) this.deps.recordCardsAdded?.(noteIds.length, noteIds);
|
||||
if (autoUpdate && noteIds.length > 0) this.deps.recordCardsAdded?.(noteIds.length, noteIds);
|
||||
return;
|
||||
}
|
||||
if (!autoUpdate) {
|
||||
// Nothing to enrich, so the added notes are already in their final state.
|
||||
this.deps.onNotesAdded?.(noteIds, provenance);
|
||||
if (noteIds.length > 0) this.deps.onCardsReady?.(noteIds);
|
||||
return;
|
||||
}
|
||||
this.deps.onNotesAdded?.(noteIds, provenance);
|
||||
this.maybeTrackDuplicateNoteIds(requestJson, action, responseResult);
|
||||
if (noteIds.length === 0 && shouldFallbackToLatestAdded) {
|
||||
void this.enqueueMostRecentAddedNote();
|
||||
@@ -534,6 +556,7 @@ export class AnkiConnectProxyServer {
|
||||
this.pendingNoteIdSet.delete(noteId);
|
||||
|
||||
if (!this.deps.shouldAutoUpdateNewCards()) {
|
||||
this.deps.onCardsReady?.([noteId]);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -547,6 +570,7 @@ export class AnkiConnectProxyServer {
|
||||
);
|
||||
} finally {
|
||||
this.inFlightNoteIds.delete(noteId);
|
||||
this.deps.onCardsReady?.([noteId]);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
|
||||
Reference in new issue
Block a user