chore: update docs and demo media assets
|
Before Width: | Height: | Size: 4.3 MiB |
|
Before Width: | Height: | Size: 12 MiB After Width: | Height: | Size: 23 MiB |
|
Before Width: | Height: | Size: 523 KiB |
BIN
assets/minecard.webp
Normal file
|
After Width: | Height: | Size: 21 MiB |
@@ -69,6 +69,7 @@ export default {
|
|||||||
{ text: 'Launcher Script', link: '/launcher-script' },
|
{ text: 'Launcher Script', link: '/launcher-script' },
|
||||||
{ text: 'Usage', link: '/usage' },
|
{ text: 'Usage', link: '/usage' },
|
||||||
{ text: 'Mining Workflow', link: '/mining-workflow' },
|
{ text: 'Mining Workflow', link: '/mining-workflow' },
|
||||||
|
// { text: 'Feature Demos', link: '/demos' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
72
docs/demos.md
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# Feature Demos
|
||||||
|
|
||||||
|
Short recordings of SubMiner's key features and integrations from real playback sessions.
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const v = '20260301-1';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
## Anki Card Mining & Enrichment
|
||||||
|
|
||||||
|
Mine vocabulary cards from Yomitan or directly from subtitle lines. SubMiner automatically attaches the sentence, a timing-accurate audio clip, a screenshot, and a translation.
|
||||||
|
|
||||||
|
<video controls playsinline preload="metadata" :poster="`/assets/minecard-poster.jpg?v=${demoAssetVersion}`">
|
||||||
|
<source :src="`/assets/minecard.webm?v=${demoAssetVersion}`" type="video/webm" />
|
||||||
|
<source :src="`/assets/minecard.mp4?v=${demoAssetVersion}`" type="video/mp4" />
|
||||||
|
<a :href="`/assets/minecard.webm?v=${demoAssetVersion}`" target="_blank" rel="noreferrer">
|
||||||
|
<img :src="`/assets/minecard.webp?v=${demoAssetVersion}`" alt="SubMiner demo Animated fallback" style="width: 100%; height: auto;" />
|
||||||
|
</a>
|
||||||
|
</video>
|
||||||
|
|
||||||
|
::: info VIDEO COMING SOON
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Subtitle Download & Sync
|
||||||
|
|
||||||
|
Search and download subtitles from Jimaku, then automatically synchronize them with alass or ffsubsync — all from within SubMiner.
|
||||||
|
|
||||||
|
<!-- <video controls playsinline preload="metadata" :poster="`/assets/demos/subtitle-sync-poster.jpg?v=${v}`">
|
||||||
|
<source :src="`/assets/demos/subtitle-sync.webm?v=${v}`" type="video/webm" />
|
||||||
|
<source :src="`/assets/demos/subtitle-sync.mp4?v=${v}`" type="video/mp4" />
|
||||||
|
</video> -->
|
||||||
|
|
||||||
|
::: info VIDEO COMING SOON
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Jellyfin Integration
|
||||||
|
|
||||||
|
Browse your Jellyfin library, cast to devices, and launch playback directly from SubMiner. Watch progress syncs back to your Jellyfin server.
|
||||||
|
|
||||||
|
<!-- <video controls playsinline preload="metadata" :poster="`/assets/demos/jellyfin-poster.jpg?v=${v}`">
|
||||||
|
<source :src="`/assets/demos/jellyfin.webm?v=${v}`" type="video/webm" />
|
||||||
|
<source :src="`/assets/demos/jellyfin.mp4?v=${v}`" type="video/mp4" />
|
||||||
|
</video> -->
|
||||||
|
|
||||||
|
::: info VIDEO COMING SOON
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Texthooker
|
||||||
|
|
||||||
|
Open subtitles in an external texthooker page for use with browser-based tools and extensions alongside the overlay.
|
||||||
|
|
||||||
|
<!-- <video controls playsinline preload="metadata" :poster="`/assets/demos/texthooker-poster.jpg?v=${v}`">
|
||||||
|
<source :src="`/assets/demos/texthooker.webm?v=${v}`" type="video/webm" />
|
||||||
|
<source :src="`/assets/demos/texthooker.mp4?v=${v}`" type="video/mp4" />
|
||||||
|
</video> -->
|
||||||
|
|
||||||
|
::: info VIDEO COMING SOON
|
||||||
|
:::
|
||||||
|
|
||||||
|
<style>
|
||||||
|
video {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid var(--vp-c-divider);
|
||||||
|
box-shadow: 0 18px 44px rgba(0, 0, 0, 0.28);
|
||||||
|
margin: 0.75rem 0 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin-top: 2.5rem !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -19,6 +19,6 @@ test('docs demo media uses shared cache-busting asset version token', () => {
|
|||||||
'<a :href="`/assets/minecard.webm?v=${demoAssetVersion}`" target="_blank" rel="noreferrer">',
|
'<a :href="`/assets/minecard.webm?v=${demoAssetVersion}`" target="_blank" rel="noreferrer">',
|
||||||
);
|
);
|
||||||
expect(docsIndexContents).toContain(
|
expect(docsIndexContents).toContain(
|
||||||
'<img :src="`/assets/minecard.gif?v=${demoAssetVersion}`" alt="SubMiner demo GIF fallback" style="width: 100%; height: auto;" />',
|
'<img :src="`/assets/minecard.webp?v=${demoAssetVersion}`" alt="SubMiner demo Animated fallback" style="width: 100%; height: auto;" />',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ const demoAssetVersion = '20260223-2';
|
|||||||
<source :src="`/assets/minecard.webm?v=${demoAssetVersion}`" type="video/webm" />
|
<source :src="`/assets/minecard.webm?v=${demoAssetVersion}`" type="video/webm" />
|
||||||
<source :src="`/assets/minecard.mp4?v=${demoAssetVersion}`" type="video/mp4" />
|
<source :src="`/assets/minecard.mp4?v=${demoAssetVersion}`" type="video/mp4" />
|
||||||
<a :href="`/assets/minecard.webm?v=${demoAssetVersion}`" target="_blank" rel="noreferrer">
|
<a :href="`/assets/minecard.webm?v=${demoAssetVersion}`" target="_blank" rel="noreferrer">
|
||||||
<img :src="`/assets/minecard.gif?v=${demoAssetVersion}`" alt="SubMiner demo GIF fallback" style="width: 100%; height: auto;" />
|
<img :src="`/assets/minecard.webp?v=${demoAssetVersion}`" alt="SubMiner demo Animated fallback" style="width: 100%; height: auto;" />
|
||||||
</a>
|
</a>
|
||||||
</video>
|
</video>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 4.3 MiB |
|
Before Width: | Height: | Size: 12 MiB After Width: | Height: | Size: 23 MiB |
BIN
docs/public/assets/minecard.webp
Normal file
|
After Width: | Height: | Size: 21 MiB |
@@ -141,7 +141,7 @@
|
|||||||
"bandedColors": ["#ed8796", "#f5a97f", "#f9e2af", "#a6e3a1", "#8aadf4"], // Five colors used for rank bands when mode is `banded` (from most common to least within topX).
|
"bandedColors": ["#ed8796", "#f5a97f", "#f9e2af", "#a6e3a1", "#8aadf4"], // Five colors used for rank bands when mode is `banded` (from most common to least within topX).
|
||||||
}, // Frequency dictionary setting.
|
}, // Frequency dictionary setting.
|
||||||
"secondary": {
|
"secondary": {
|
||||||
"fontFamily": "Manrope, Inter", // Font family setting.
|
"fontFamily": "Inter, Noto Sans, Helvetica Neue, sans-serif", // Font family setting.
|
||||||
"fontSize": 24, // Font size setting.
|
"fontSize": 24, // Font size setting.
|
||||||
"fontColor": "#cad3f5", // Font color setting.
|
"fontColor": "#cad3f5", // Font color setting.
|
||||||
"lineHeight": 1.35, // Line height setting.
|
"lineHeight": 1.35, // Line height setting.
|
||||||
|
|||||||
@@ -11,11 +11,12 @@ Description:
|
|||||||
Generates two browser-friendly files next to the input file:
|
Generates two browser-friendly files next to the input file:
|
||||||
- <name>.mp4 (H.264 + AAC, prefers NVIDIA GPU if available)
|
- <name>.mp4 (H.264 + AAC, prefers NVIDIA GPU if available)
|
||||||
- <name>.webm (AV1/VP9 + Opus, prefers NVIDIA GPU if available)
|
- <name>.webm (AV1/VP9 + Opus, prefers NVIDIA GPU if available)
|
||||||
- <name>.gif (palette-optimised, 15 fps)
|
|
||||||
- <name>-poster.jpg (single frame for video poster fallback)
|
- <name>-poster.jpg (single frame for video poster fallback)
|
||||||
|
- <name>.webp (animated, only when --webp is provided)
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-f, --force Overwrite existing output files
|
-f, --force Overwrite existing output files
|
||||||
|
-w, --webp Generate animated WebP preview
|
||||||
|
|
||||||
Encoding profile:
|
Encoding profile:
|
||||||
- Crop: 1920x1080 at x=760 y=200
|
- Crop: 1920x1080 at x=760 y=200
|
||||||
@@ -25,6 +26,7 @@ USAGE
|
|||||||
}
|
}
|
||||||
|
|
||||||
force=0
|
force=0
|
||||||
|
generate_webp=0
|
||||||
input=""
|
input=""
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
@@ -36,6 +38,9 @@ while [[ $# -gt 0 ]]; do
|
|||||||
-f | --force)
|
-f | --force)
|
||||||
force=1
|
force=1
|
||||||
;;
|
;;
|
||||||
|
-w | --webp)
|
||||||
|
generate_webp=1
|
||||||
|
;;
|
||||||
-*)
|
-*)
|
||||||
echo "Error: unknown option: $1" >&2
|
echo "Error: unknown option: $1" >&2
|
||||||
usage
|
usage
|
||||||
@@ -74,7 +79,7 @@ base="${filename%.*}"
|
|||||||
|
|
||||||
mp4_out="$dir/$base.mp4"
|
mp4_out="$dir/$base.mp4"
|
||||||
webm_out="$dir/$base.webm"
|
webm_out="$dir/$base.webm"
|
||||||
gif_out="$dir/$base.gif"
|
webp_out="$dir/$base.webp"
|
||||||
poster_out="$dir/$base-poster.jpg"
|
poster_out="$dir/$base-poster.jpg"
|
||||||
|
|
||||||
overwrite_flag="-n"
|
overwrite_flag="-n"
|
||||||
@@ -83,7 +88,11 @@ if [[ "$force" -eq 1 ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$force" -eq 0 ]]; then
|
if [[ "$force" -eq 0 ]]; then
|
||||||
for output in "$mp4_out" "$webm_out" "$gif_out" "$poster_out"; do
|
outputs=("$mp4_out" "$webm_out" "$poster_out")
|
||||||
|
if [[ "$generate_webp" -eq 1 ]]; then
|
||||||
|
outputs+=("$webp_out")
|
||||||
|
fi
|
||||||
|
for output in "${outputs[@]}"; do
|
||||||
if [[ -e "$output" ]]; then
|
if [[ -e "$output" ]]; then
|
||||||
echo "Error: output exists: $output (use --force to overwrite)" >&2
|
echo "Error: output exists: $output (use --force to overwrite)" >&2
|
||||||
exit 1
|
exit 1
|
||||||
@@ -98,7 +107,6 @@ has_encoder() {
|
|||||||
|
|
||||||
crop_vf="crop=1920:1080:760:205"
|
crop_vf="crop=1920:1080:760:205"
|
||||||
webm_vf="${crop_vf},fps=30"
|
webm_vf="${crop_vf},fps=30"
|
||||||
gif_vf="${crop_vf},fps=15,scale=960:-1:flags=lanczos,split[s0][s1];[s0]palettegen=max_colors=128[p];[s1][p]paletteuse=dither=bayer:bayer_scale=3"
|
|
||||||
|
|
||||||
echo "Generating MP4: $mp4_out"
|
echo "Generating MP4: $mp4_out"
|
||||||
if has_encoder "h264_nvenc"; then
|
if has_encoder "h264_nvenc"; then
|
||||||
@@ -159,10 +167,20 @@ else
|
|||||||
"$webm_out"
|
"$webm_out"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Generating GIF: $gif_out"
|
if [[ "$generate_webp" -eq 1 ]]; then
|
||||||
|
if ! has_encoder "libwebp"; then
|
||||||
|
echo "Error: encoder not found: libwebp" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Generating animated WebP: $webp_out"
|
||||||
ffmpeg "$overwrite_flag" -i "$input" \
|
ffmpeg "$overwrite_flag" -i "$input" \
|
||||||
-vf "$gif_vf" \
|
-vf "${crop_vf},fps=24,scale=960:-1:flags=lanczos" \
|
||||||
"$gif_out"
|
-c:v libwebp \
|
||||||
|
-q:v 80 \
|
||||||
|
-loop 0 \
|
||||||
|
-an \
|
||||||
|
"$webp_out"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Generating poster: $poster_out"
|
echo "Generating poster: $poster_out"
|
||||||
ffmpeg "$overwrite_flag" -ss 00:00:05 -i "$input" \
|
ffmpeg "$overwrite_flag" -ss 00:00:05 -i "$input" \
|
||||||
@@ -174,5 +192,7 @@ ffmpeg "$overwrite_flag" -ss 00:00:05 -i "$input" \
|
|||||||
echo "Done."
|
echo "Done."
|
||||||
echo "MP4: $mp4_out"
|
echo "MP4: $mp4_out"
|
||||||
echo "WebM: $webm_out"
|
echo "WebM: $webm_out"
|
||||||
echo "GIF: $gif_out"
|
if [[ "$generate_webp" -eq 1 ]]; then
|
||||||
|
echo "WebP: $webp_out"
|
||||||
|
fi
|
||||||
echo "Poster: $poster_out"
|
echo "Poster: $poster_out"
|
||||||
|
|||||||