mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-10-21 05:01:26 -07:00
clean up and add new showcase videos
This commit is contained in:
20 files changed
+206
-13
No files matched your search
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 21 MiB After Width: | Height: | Size: 3.0 MiB |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+15
-8
@@ -1,10 +1,11 @@
|
||||
---
|
||||
id: TASK-133
|
||||
title: Improve AniList character dictionary parity with upstream guide
|
||||
status: To Do
|
||||
assignee: []
|
||||
status: In Progress
|
||||
assignee:
|
||||
- OpenCode
|
||||
created_date: '2026-03-08 21:06'
|
||||
updated_date: '2026-03-08 21:35'
|
||||
updated_date: '2026-03-10 06:18'
|
||||
labels:
|
||||
- dictionary
|
||||
- anilist
|
||||
@@ -28,15 +29,11 @@ priority: high
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
|
||||
Plan and implement guide-faithful parity improvements for the AniList character dictionary flow inside SubMiner's current single-media generation path. Scope includes AniList first/last name hints, hint-aware reading generation for kanji/native names, expanded honorific coverage, 160x200 JPEG thumbnail handling, and AniList 429 retry/backoff behavior.
|
||||
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
<!-- AC:BEGIN -->
|
||||
|
||||
- [ ] #1 AniList character queries include first/last name fields and preserve them through runtime data models.
|
||||
- [ ] #2 Dictionary generation uses hint-aware name splitting and reading generation for kanji and mixed native names, not only kana-only readings.
|
||||
- [ ] #3 Honorific generation is expanded substantially toward upstream coverage and is covered by regression tests.
|
||||
@@ -44,10 +41,20 @@ Plan and implement guide-faithful parity improvements for the AniList character
|
||||
- [ ] #5 AniList requests handle 429 responses with bounded exponential backoff and tests cover retry behavior.
|
||||
<!-- AC:END -->
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
<!-- SECTION:PLAN:BEGIN -->
|
||||
1. Add targeted regression tests in `src/main/character-dictionary-runtime.test.ts` for AniList 429 retry behavior and thumbnail conversion/fallback image paths before changing runtime code.
|
||||
2. Update `fetchAniList` in `src/main/character-dictionary-runtime.ts` to retry 429 responses with bounded exponential backoff or `Retry-After` delays, while preserving existing request pacing hook behavior.
|
||||
3. Update `downloadCharacterImage` to run downloaded bytes through `convertImageToThumbnail`, returning `.jpg` paths when conversion succeeds and preserving original bytes/extensions on fallback.
|
||||
4. Run focused character-dictionary tests first, then broader required verification commands if the focused lane passes.
|
||||
5. Record progress against acceptance criteria #4 and #5 in TASK-133 notes/final checklist once verified.
|
||||
<!-- SECTION:PLAN:END -->
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
|
||||
Approved design and implementation plan captured on 2026-03-08. Scope stays within current single-media AniList dictionary flow; excludes username-driven CURRENT-list fetching and Yomitan auto-update schema work.
|
||||
|
||||
Resumed TASK-133 to finish remaining AC #4 image thumbnail wiring and AC #5 AniList 429 retry handling. Existing code already contains helper constants/functions; next work is wiring plus regression coverage.
|
||||
<!-- SECTION:NOTES:END -->
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
---
|
||||
id: TASK-151
|
||||
title: Keep JLPT underline color stable during Yomitan text selection
|
||||
status: Done
|
||||
assignee:
|
||||
- OpenCode
|
||||
created_date: '2026-03-10 06:42'
|
||||
updated_date: '2026-03-10 07:54'
|
||||
labels: []
|
||||
dependencies: []
|
||||
references:
|
||||
- src/renderer/style.css
|
||||
- src/renderer/subtitle-render.test.ts
|
||||
documentation:
|
||||
- ../subminer-docs/development.md
|
||||
- ../subminer-docs/architecture.md
|
||||
priority: medium
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
Fix the subtitle overlay so JLPT underlines keep their JLPT color when Yomitan lookups trigger hover/selection styling on tokens that are also known, N+1, or frequency-highlighted.
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
<!-- AC:BEGIN -->
|
||||
- [x] #1 JLPT-tagged subtitle tokens keep their JLPT underline color during hover/selection states used by Yomitan lookup.
|
||||
- [x] #2 Tokens that combine JLPT with known, N+1, name-match, or frequency styling preserve their primary text color while keeping the JLPT underline color.
|
||||
- [x] #3 Renderer regression coverage verifies the JLPT underline color remains explicit in the stylesheet for combined styling states.
|
||||
<!-- AC:END -->
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
<!-- SECTION:PLAN:BEGIN -->
|
||||
1. Revert the temporary box-shadow JLPT marker experiment and restore native JLPT underline styling in `src/renderer/style.css`.
|
||||
2. Add explicit JLPT hover/selection color rules with higher specificity so Yomitan lookup highlight states cannot repaint the underline to the token hover color.
|
||||
3. Update `src/renderer/subtitle-render.test.ts` to verify JLPT hover/selection rules keep the predefined JLPT underline color, then rerun focused and relevant verification commands.
|
||||
|
||||
4. Add JLPT-specific `text-decoration-color` overrides directly on child `.c` spans and their hover/selection states, since Yomitan lookup likely paints the decorated child text runs rather than only the parent token span.
|
||||
<!-- SECTION:PLAN:END -->
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
Added a renderer regression test that asserts JLPT underline color stays explicit through hover and selection styling.
|
||||
|
||||
Updated `src/renderer/style.css` to route JLPT underline color through `--subtitle-jlpt-underline-color` and re-apply it on word/character hover and selection states.
|
||||
|
||||
Verification: `bun test src/renderer/subtitle-render.test.ts`, `bun run typecheck`, `bun run test:fast`, `bun run build`, `bun run changelog:lint`, `bunx prettier --check src/renderer/style.css src/renderer/subtitle-render.test.ts changes/jlpt-underline-yomitan.md`. `bun run format:check:src` still fails because of unrelated existing formatting issues in `src/main-entry-runtime.test.ts` and `src/main-entry-runtime.ts`.
|
||||
|
||||
User verified the original CSS variable propagation fix did not resolve the live issue; continuing investigation and reopening the task.
|
||||
|
||||
Confirmed Chromium was repainting native `text-decoration` underlines with the selected text color; reproduced it in a temporary browser repro and verified that switching the JLPT marker to an inset box-shadow keeps the JLPT color stable during selection.
|
||||
|
||||
Replaced the previous native underline approach with a fragment-safe JLPT marker using `box-shadow` plus `box-decoration-break`, then updated stylesheet regression coverage to match the new implementation.
|
||||
|
||||
Verification: `bun test src/renderer/subtitle-render.test.ts`, `bunx prettier --check src/renderer/style.css src/renderer/subtitle-render.test.ts`, `bun run typecheck`, `bun run test:fast`, `bun run build`.
|
||||
|
||||
User requested reverting the box-shadow marker experiment. Narrowing the fix to preserve native JLPT underline color during Yomitan hover/selection instead of changing the underline rendering method.
|
||||
|
||||
Reverted the box-shadow experiment per user request. Restored native JLPT underline styling and added explicit JLPT hover/selection rules so Yomitan lookup states keep the predefined JLPT underline color with `!important`.
|
||||
|
||||
Verification after revert/fix: `bun test src/renderer/subtitle-render.test.ts`, `bunx prettier --check src/renderer/style.css src/renderer/subtitle-render.test.ts`, `bun run typecheck`, `bun run build`.
|
||||
|
||||
Issue still reproduces specifically during Shift-held Yomitan lookup. Investigating decoration propagation onto child `.c` spans during lookup-triggered hover/selection states.
|
||||
|
||||
Added JLPT-specific `text-decoration-color` overrides directly to child `.c` spans and their hover/selection states, in addition to the token span itself, so lookup-triggered decoration painting on child runs keeps the JLPT color.
|
||||
|
||||
Verification: `bun test src/renderer/subtitle-render.test.ts`, `bunx prettier --check src/renderer/style.css src/renderer/subtitle-render.test.ts`, `bun run typecheck`, `bun run build`.
|
||||
|
||||
Added a final high-specificity combined-state JLPT override after the annotation hover/selection rules. It targets tokens that are both JLPT-tagged and known/N+1/name-match/frequency-highlighted, forcing `text-decoration-color` back to the JLPT variable after the later annotation state blocks.
|
||||
|
||||
Verification: `bun test src/renderer/subtitle-render.test.ts`, `bunx prettier --check src/renderer/style.css src/renderer/subtitle-render.test.ts`, `bun run build`.
|
||||
|
||||
Switched the JLPT underline from native `text-decoration` to a separate painted underline layer using `background-image` on JLPT tokens. Also changed hover token highlight rules to use `background-color` so the JLPT underline layer survives Shift+Yomitan hover/lookup interactions.
|
||||
|
||||
Verification: `bun test src/renderer/subtitle-render.test.ts`, `bunx prettier --check src/renderer/style.css src/renderer/subtitle-render.test.ts`, `bun run build`.
|
||||
|
||||
User reports the latest background-image JLPT underline change introduced grey-looking token highlights. Investigating the interaction between the new underline layer and hover background styling.
|
||||
|
||||
The background-image underline layer interacts poorly with hover fills and makes highlighted tokens look grey. Switching the separate JLPT underline layer to an inset box-shadow so hover background color and JLPT underline paint can coexist cleanly.
|
||||
|
||||
Adjusted the separate JLPT underline layer from `background-image` to inset `box-shadow`. This keeps the underline decoupled from Yomitan hover color while avoiding the grey-looking underline artifact introduced by the background-image approach.
|
||||
|
||||
User reports the separate underline layer still disappears/greys out during lookup. Switching strategy again: use a dedicated `border-bottom` JLPT marker instead of box-shadow/background so the underline stays independent from Yomitan hover paint without blending artifacts.
|
||||
|
||||
Replaced the separate JLPT underline layer with `border-bottom` plus a small bottom padding. This keeps the underline visually separate from Yomitan hover paint and avoids the disappearing/grey artifact seen with background-image and box-shadow.
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
||||
## Final Summary
|
||||
|
||||
<!-- SECTION:FINAL_SUMMARY:BEGIN -->
|
||||
Switched the JLPT underline layer in `src/renderer/style.css` to `border-bottom` plus `padding-bottom`, keeping it independent from Yomitan hover/selection repainting while avoiding the disappearing or grey artifact seen with the background-image and box-shadow approaches.
|
||||
|
||||
Updated `src/renderer/subtitle-render.test.ts` to assert the border-bottom-based JLPT underline layer.
|
||||
|
||||
Verification: `bun test src/renderer/subtitle-render.test.ts`, `bunx prettier --check src/renderer/style.css src/renderer/subtitle-render.test.ts`, `bun run build`.
|
||||
<!-- SECTION:FINAL_SUMMARY:END -->
|
||||
+1
-1
@@ -50,7 +50,7 @@
|
||||
"test:launcher": "bun run test:launcher:src",
|
||||
"test:core": "bun run test:core:src",
|
||||
"test:subtitle": "bun run test:subtitle:src",
|
||||
"test:fast": "bun run test:config:src && bun run test:core:src && bun test src/main-entry-runtime.test.ts src/anki-integration/anki-connect-proxy.test.ts src/release-workflow.test.ts src/ci-workflow.test.ts scripts/build-changelog.test.ts && bun run tsc && bun test dist/main/runtime/registry.test.js",
|
||||
"test:fast": "bun run test:config:src && bun run test:core:src && bun test src/main-entry-runtime.test.ts src/anki-integration/anki-connect-proxy.test.ts src/release-workflow.test.ts src/ci-workflow.test.ts scripts/build-changelog.test.ts scripts/mkv-to-readme-video.test.ts && bun run tsc && bun test dist/main/runtime/registry.test.js",
|
||||
"generate:config-example": "bun run build && bun dist/generate-config-example.js",
|
||||
"start": "bun run build && electron . --start",
|
||||
"dev": "bun run build && electron . --start --dev",
|
||||
|
||||
@@ -102,7 +102,19 @@ fi
|
||||
|
||||
has_encoder() {
|
||||
local encoder="$1"
|
||||
ffmpeg -hide_banner -encoders 2> /dev/null | grep -qE "[[:space:]]${encoder}[[:space:]]"
|
||||
ffmpeg -hide_banner -encoders 2> /dev/null | awk -v encoder="$encoder" '$2 == encoder { found = 1 } END { exit(found ? 0 : 1) }'
|
||||
}
|
||||
|
||||
pick_webp_encoder() {
|
||||
if has_encoder "libwebp_anim"; then
|
||||
echo "libwebp_anim"
|
||||
return 0
|
||||
fi
|
||||
if has_encoder "libwebp"; then
|
||||
echo "libwebp"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
crop_vf="crop=1920:1080:760:205"
|
||||
@@ -168,14 +180,14 @@ else
|
||||
fi
|
||||
|
||||
if [[ "$generate_webp" -eq 1 ]]; then
|
||||
if ! has_encoder "libwebp"; then
|
||||
if ! webp_encoder="$(pick_webp_encoder)"; then
|
||||
echo "Error: encoder not found: libwebp" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Generating animated WebP: $webp_out"
|
||||
echo "Generating animated WebP with $webp_encoder: $webp_out"
|
||||
ffmpeg "$overwrite_flag" -i "$input" \
|
||||
-vf "${crop_vf},fps=24,scale=960:-1:flags=lanczos" \
|
||||
-c:v libwebp \
|
||||
-c:v "$webp_encoder" \
|
||||
-q:v 80 \
|
||||
-loop 0 \
|
||||
-an \
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import test from 'node:test';
|
||||
|
||||
function withTempDir<T>(fn: (dir: string) => T): T {
|
||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'subminer-mkv-to-readme-video-test-'));
|
||||
try {
|
||||
return fn(dir);
|
||||
} finally {
|
||||
fs.rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
function writeExecutable(filePath: string, contents: string): void {
|
||||
fs.writeFileSync(filePath, contents, 'utf8');
|
||||
fs.chmodSync(filePath, 0o755);
|
||||
}
|
||||
|
||||
test('mkv-to-readme-video accepts libwebp_anim when libwebp is unavailable', () => {
|
||||
withTempDir((root) => {
|
||||
const binDir = path.join(root, 'bin');
|
||||
const inputPath = path.join(root, 'sample.mkv');
|
||||
const ffmpegLogPath = path.join(root, 'ffmpeg-args.log');
|
||||
|
||||
fs.mkdirSync(binDir, { recursive: true });
|
||||
fs.writeFileSync(inputPath, 'fake-video', 'utf8');
|
||||
|
||||
writeExecutable(
|
||||
path.join(binDir, 'ffmpeg'),
|
||||
`#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ "$#" -ge 2 && "$1" == "-hide_banner" && "$2" == "-encoders" ]]; then
|
||||
cat <<'EOF'
|
||||
V....D libx264 libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (codec h264)
|
||||
V....D libvpx-vp9 libvpx VP9 (codec vp9)
|
||||
V....D libwebp_anim libwebp WebP image (codec webp)
|
||||
A....D aac AAC (Advanced Audio Coding)
|
||||
A....D libopus libopus Opus (codec opus)
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
printf '%s\\n' "$*" >> "${ffmpegLogPath}"
|
||||
output=""
|
||||
for arg in "$@"; do
|
||||
output="$arg"
|
||||
done
|
||||
mkdir -p "$(dirname "$output")"
|
||||
touch "$output"
|
||||
`,
|
||||
);
|
||||
|
||||
const result = spawnSync('bash', ['scripts/mkv-to-readme-video.sh', '--webp', inputPath], {
|
||||
cwd: process.cwd(),
|
||||
env: {
|
||||
...process.env,
|
||||
PATH: `${binDir}:${process.env.PATH || ''}`,
|
||||
},
|
||||
encoding: 'utf8',
|
||||
});
|
||||
|
||||
assert.equal(result.status, 0, result.stderr || result.stdout);
|
||||
assert.equal(fs.existsSync(path.join(root, 'sample.mp4')), true);
|
||||
assert.equal(fs.existsSync(path.join(root, 'sample.webm')), true);
|
||||
assert.equal(fs.existsSync(path.join(root, 'sample.webp')), true);
|
||||
assert.equal(fs.existsSync(path.join(root, 'sample-poster.jpg')), true);
|
||||
|
||||
const ffmpegLog = fs.readFileSync(ffmpegLogPath, 'utf8');
|
||||
assert.match(ffmpegLog, /-c:v libwebp_anim/);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user