}>;
};
- return c.json(result.result ?? []);
+ return c.json(
+ (result.result ?? []).map((note) => ({
+ ...note,
+ preview: buildAnkiNotePreview(note.fields, options?.ankiConnectConfig),
+ })),
+ );
} catch {
return c.json([], 502);
}
@@ -710,6 +754,7 @@ export function createStatsApp(
if (imageResult.status === 'rejected')
errors.push(`image: ${(imageResult.reason as Error).message}`);
+ const wordFieldName = getConfiguredWordFieldName(ankiConfig);
const sentenceFieldName = ankiConfig.fields?.sentence ?? 'Sentence';
const translationFieldName = ankiConfig.fields?.translation ?? 'SelectionText';
const audioFieldName = ankiConfig.fields?.audio ?? 'ExpressionAudio';
@@ -726,7 +771,7 @@ export function createStatsApp(
if (ankiConfig.isLapis?.enabled || ankiConfig.isKiku?.enabled) {
if (word) {
- fields['Expression'] = word;
+ fields[wordFieldName] = word;
}
if (mode === 'sentence') {
fields['IsSentenceCard'] = 'x';
@@ -831,6 +876,7 @@ export function startStatsServer(config: StatsServerConfig): { close: () => void
mpvSocketPath: config.mpvSocketPath,
ankiConnectConfig: config.ankiConnectConfig,
addYomitanNote: config.addYomitanNote,
+ resolveAnkiNoteId: config.resolveAnkiNoteId,
});
const server = serve({
diff --git a/stats/src/components/anime/AnimeCardsList.tsx b/stats/src/components/anime/AnimeCardsList.tsx
index 739a0d7..4a157dc 100644
--- a/stats/src/components/anime/AnimeCardsList.tsx
+++ b/stats/src/components/anime/AnimeCardsList.tsx
@@ -51,7 +51,7 @@ export function AnimeCardsList({ episodes, totalCards }: AnimeCardsListProps) {
{ep.canonicalTitle}
- |
+ |
{formatNumber(ep.totalCards)}
|
diff --git a/stats/src/components/anime/AnimeDetailView.tsx b/stats/src/components/anime/AnimeDetailView.tsx
index bbb299c..d321b4f 100644
--- a/stats/src/components/anime/AnimeDetailView.tsx
+++ b/stats/src/components/anime/AnimeDetailView.tsx
@@ -163,10 +163,7 @@ export function AnimeDetailView({
anilistEntries={anilistEntries ?? []}
onChangeAnilist={() => setShowAnilistSelector(true)}
/>
-
+
onOpenEpisodeDetail(videoId) : undefined}
diff --git a/stats/src/components/anime/EpisodeDetail.tsx b/stats/src/components/anime/EpisodeDetail.tsx
index 9502db9..da3daf7 100644
--- a/stats/src/components/anime/EpisodeDetail.tsx
+++ b/stats/src/components/anime/EpisodeDetail.tsx
@@ -37,12 +37,7 @@ export function EpisodeDetail({ videoId, onSessionDeleted }: EpisodeDetailProps)
if (cancelled) return;
const map = new Map();
for (const note of notes) {
- const expr =
- note.fields?.Expression?.value ??
- note.fields?.expression?.value ??
- note.fields?.Word?.value ??
- note.fields?.word?.value ??
- '';
+ const expr = note.preview?.word ?? '';
map.set(note.noteId, { noteId: note.noteId, expression: expr });
}
setNoteInfos(map);
diff --git a/stats/src/components/library/LibraryTab.tsx b/stats/src/components/library/LibraryTab.tsx
index 55b9595..217fbec 100644
--- a/stats/src/components/library/LibraryTab.tsx
+++ b/stats/src/components/library/LibraryTab.tsx
@@ -22,7 +22,13 @@ export function LibraryTab({ onNavigateToSession }: LibraryTabProps) {
const totalMs = media.reduce((sum, m) => sum + m.totalActiveMs, 0);
if (selectedVideoId !== null) {
- return setSelectedVideoId(null)} onNavigateToSession={onNavigateToSession} />;
+ return (
+ setSelectedVideoId(null)}
+ onNavigateToSession={onNavigateToSession}
+ />
+ );
}
if (loading) return Loading... ;
diff --git a/stats/src/components/overview/HeroStats.tsx b/stats/src/components/overview/HeroStats.tsx
index 68266e5..9c11f18 100644
--- a/stats/src/components/overview/HeroStats.tsx
+++ b/stats/src/components/overview/HeroStats.tsx
@@ -22,7 +22,7 @@ export function HeroStats({ summary, sessions }: HeroStatsProps) {
Cards this week
- {weekCards}
+ {weekCards}
diff --git a/stats/src/components/sessions/SessionDetail.tsx b/stats/src/components/sessions/SessionDetail.tsx
index ddf8f45..6128d32 100644
--- a/stats/src/components/sessions/SessionDetail.tsx
+++ b/stats/src/components/sessions/SessionDetail.tsx
@@ -19,7 +19,9 @@ import type { KnownWordsTimelinePoint } from '../../hooks/useSessions';
import { CHART_THEME } from '../../lib/chart-theme';
import {
buildSessionChartEvents,
- extractSessionEventNoteInfo,
+ collectPendingSessionEventNoteIds,
+ getSessionEventCardRequest,
+ mergeSessionEventNoteInfos,
resolveActiveSessionMarkerKey,
type SessionChartMarker,
type SessionEventNoteInfo,
@@ -119,7 +121,7 @@ export function SessionDetail({ session }: SessionDetailProps) {
const [pinnedMarkerKey, setPinnedMarkerKey] = useState(null);
const [noteInfos, setNoteInfos] = useState |