Files
SubMiner/src/renderer/index.html
T

1061 lines
44 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!--
SubMiner - All-in-one sentence mining overlay
Copyright (C) 2024 sudacode
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self' 'unsafe-inline' chrome-extension:; script-src 'self' 'unsafe-inline' chrome-extension:; style-src 'self' 'unsafe-inline' chrome-extension:; img-src 'self' data: blob: chrome-extension:; worker-src 'self' blob:;"
/>
<title>SubMiner</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<!-- Programmatic focus fallback target for Electron/window focus management. -->
<div id="overlay" tabindex="-1">
<div
id="controllerStatusToast"
class="controller-status-toast hidden"
role="status"
aria-live="polite"
></div>
<div
id="overlayErrorToast"
class="overlay-error-toast hidden"
role="status"
aria-live="polite"
></div>
<div
id="overlayNotificationStack"
class="overlay-notification-stack position-top-right hidden"
aria-live="polite"
aria-atomic="false"
></div>
<aside
id="overlayNotificationHistory"
class="notification-history side-right"
role="dialog"
aria-label="Notification history"
aria-hidden="true"
>
<header class="notification-history-header">
<span class="notification-history-title">Notifications</span>
<div class="notification-history-header-actions">
<button class="notification-history-clear" type="button">Clear</button>
<button
class="notification-history-close"
type="button"
aria-label="Close notification history"
>
×
</button>
</div>
</header>
<div class="notification-history-body">
<ul class="notification-history-list"></ul>
<div class="notification-history-empty">No notifications yet</div>
</div>
</aside>
<div id="secondarySubContainer" class="secondary-sub-hidden">
<div id="secondarySubRoot"></div>
</div>
<div id="subtitleContainer">
<div id="subtitleRoot"></div>
</div>
<div id="jimakuModal" class="modal hidden" aria-hidden="true">
<div class="modal-content">
<div class="modal-header">
<div class="modal-title">Jimaku Subtitles</div>
<button id="jimakuClose" class="modal-close" type="button">Close</button>
</div>
<div class="modal-body">
<div class="jimaku-tabs" role="tablist">
<button
id="jimakuTabAnime"
class="jimaku-tab active"
type="button"
role="tab"
aria-selected="true"
>
Anime
</button>
<button
id="jimakuTabLiveAction"
class="jimaku-tab"
type="button"
role="tab"
aria-selected="false"
>
Live action
</button>
</div>
<div class="jimaku-form">
<label class="jimaku-field">
<span>Title</span>
<input id="jimakuTitle" type="text" placeholder="Title" />
</label>
<label class="jimaku-field">
<span>Season</span>
<input id="jimakuSeason" type="number" min="1" placeholder="1" />
</label>
<label class="jimaku-field">
<span>Episode</span>
<input id="jimakuEpisode" type="number" min="1" placeholder="1" />
</label>
<button id="jimakuSearch" class="jimaku-button" type="button">Search</button>
</div>
<div id="jimakuStatus" class="jimaku-status"></div>
<div id="jimakuEntriesSection" class="jimaku-section hidden">
<div class="jimaku-section-title">Entries</div>
<ul id="jimakuEntries" class="jimaku-list"></ul>
</div>
<div id="jimakuFilesSection" class="jimaku-section hidden">
<div class="jimaku-section-title">Files</div>
<ul id="jimakuFiles" class="jimaku-list"></ul>
<button id="jimakuBroaden" class="jimaku-link hidden" type="button">
Broaden search (all files)
</button>
</div>
</div>
</div>
</div>
<div id="tsukihimeModal" class="modal hidden" aria-hidden="true">
<div class="modal-content">
<div class="modal-header">
<div class="modal-title">TsukiHime Subtitles</div>
<button id="tsukihimeClose" class="modal-close" type="button">Close</button>
</div>
<div class="modal-body">
<div class="tsukihime-tabs" role="tablist">
<button
id="tsukihimeTabSecondary"
class="tsukihime-tab active"
type="button"
role="tab"
aria-selected="true"
>
English
</button>
<button
id="tsukihimeTabPrimary"
class="tsukihime-tab"
type="button"
role="tab"
aria-selected="false"
>
Japanese
</button>
</div>
<div class="jimaku-form">
<label class="jimaku-field">
<span>Title</span>
<input id="tsukihimeTitle" type="text" placeholder="Anime title" />
</label>
<label class="jimaku-field">
<span>Episode</span>
<input id="tsukihimeEpisode" type="number" min="1" placeholder="1" />
</label>
<button id="tsukihimeSearch" class="jimaku-button" type="button">Search</button>
</div>
<div id="tsukihimeStatus" class="jimaku-status"></div>
<div id="tsukihimeEntriesSection" class="jimaku-section hidden">
<div class="jimaku-section-title">Releases</div>
<ul id="tsukihimeEntries" class="jimaku-list"></ul>
</div>
<div id="tsukihimeFilesSection" class="jimaku-section hidden">
<div class="jimaku-section-title">Subtitle tracks</div>
<ul id="tsukihimeFiles" class="jimaku-list"></ul>
</div>
</div>
</div>
</div>
<div id="youtubePickerModal" class="modal hidden" aria-hidden="true">
<div class="modal-content youtube-picker-content">
<div class="modal-header">
<div class="modal-title">YouTube Subtitle Tracks</div>
<button id="youtubePickerCloseButton" class="modal-close" type="button">
Continue without subtitles
</button>
</div>
<div class="modal-body youtube-picker-body">
<div id="youtubePickerTitle" class="youtube-picker-title"></div>
<div class="youtube-picker-grid">
<label class="youtube-picker-field">
<span>Primary subtitle</span>
<select id="youtubePickerPrimarySelect"></select>
</label>
<label class="youtube-picker-field">
<span>Secondary subtitle</span>
<select id="youtubePickerSecondarySelect"></select>
</label>
</div>
<div id="youtubePickerStatus" class="youtube-picker-status"></div>
<ul id="youtubePickerTracks" class="youtube-picker-tracks"></ul>
<div class="youtube-picker-footer">
<button id="youtubePickerContinueButton" class="kiku-confirm-button" type="button">
Use selected subtitles
</button>
</div>
</div>
</div>
</div>
<div
id="mediaTimingReviewModal"
class="modal media-timing-review-modal hidden"
aria-hidden="true"
>
<div
class="modal-content media-timing-review-content"
role="dialog"
aria-modal="true"
aria-labelledby="mediaTimingReviewTitle"
>
<div class="media-timing-review-header">
<div class="media-timing-review-heading">
<div id="mediaTimingReviewTitle" class="media-timing-review-title">
Review media timing
</div>
<div id="mediaTimingReviewKind" class="media-timing-review-kind">Sentence card</div>
</div>
<button
id="mediaTimingReviewCancel"
class="media-timing-review-quiet-button"
type="button"
>
Cancel
</button>
</div>
<div id="mediaTimingReviewEditor" class="media-timing-review-editor">
<div class="media-timing-review-sentence-header">
<div class="media-timing-review-sentence-heading">
<span class="media-timing-review-sentence-label">Sentence on card</span>
<span id="mediaTimingReviewLineCount" class="media-timing-review-line-count">
1 line
</span>
</div>
<div
id="mediaTimingReviewLineControls"
class="media-timing-review-line-controls hidden"
>
<div class="media-timing-review-line-stepper">
<span>Prev</span>
<button
id="mediaTimingReviewPrevRemove"
type="button"
aria-label="Remove the earliest added previous subtitle line from the card sentence"
title="Remove the earliest previous line (Shift+P)"
>
&minus;
</button>
<button
id="mediaTimingReviewPrevAdd"
type="button"
aria-label="Add the previous subtitle line to the card sentence"
title="Add the previous line (P)"
>
+
</button>
</div>
<div class="media-timing-review-line-stepper">
<span>Next</span>
<button
id="mediaTimingReviewNextRemove"
type="button"
aria-label="Remove the latest added next subtitle line from the card sentence"
title="Remove the latest next line (Shift+N)"
>
&minus;
</button>
<button
id="mediaTimingReviewNextAdd"
type="button"
aria-label="Add the next subtitle line to the card sentence"
title="Add the next line (N)"
>
+
</button>
</div>
</div>
</div>
<blockquote id="mediaTimingReviewText" class="media-timing-review-text"></blockquote>
<div id="mediaTimingReviewFramePicker" class="media-timing-frame-picker hidden">
<div class="media-timing-frame-image-shell">
<img
id="mediaTimingReviewFrameImage"
class="hidden"
alt="Selected card screenshot"
/>
</div>
<div class="media-timing-frame-controls">
<div class="media-timing-frame-heading">
<label for="mediaTimingReviewFrameSlider">Card screenshot</label>
<output id="mediaTimingReviewFrameTime" for="mediaTimingReviewFrameSlider"
></output
>
</div>
<input
id="mediaTimingReviewFrameSlider"
type="range"
min="0"
max="1"
step="0.001"
value="0"
aria-label="Screenshot time"
/>
<div class="media-timing-frame-buttons">
<button
id="mediaTimingReviewFramePrevious"
type="button"
aria-label="Previous video frame"
>
← Frame
</button>
<button
id="mediaTimingReviewFrameNext"
type="button"
aria-label="Next video frame"
>
Frame →
</button>
<button
id="mediaTimingReviewFrameReset"
type="button"
aria-label="Reset screenshot"
>
Reset
</button>
</div>
<p id="mediaTimingReviewFrameStatus" role="status"></p>
</div>
</div>
<div class="media-timing-review-readout" aria-live="polite">
<div>
<span>Starts</span>
<strong id="mediaTimingReviewStartValue">00:00.000</strong>
</div>
<div class="media-timing-review-duration">
<span>Clip length</span>
<strong id="mediaTimingReviewDuration">0.00s</strong>
</div>
<div>
<span>Ends</span>
<strong id="mediaTimingReviewEndValue">00:00.000</strong>
</div>
</div>
<div class="media-timing-review-timeline-shell">
<div class="media-timing-review-timeline-labels">
<span id="mediaTimingReviewTimelineStart">00:00</span>
<span id="mediaTimingReviewWaveformLabel">speech-weighted waveform</span>
<span id="mediaTimingReviewTimelineEnd">00:00</span>
</div>
<div id="mediaTimingReviewSelectionTrack" class="media-timing-review-track">
<svg
class="media-timing-review-waveform"
viewBox="0 0 1000 100"
preserveAspectRatio="none"
aria-hidden="true"
>
<defs>
<linearGradient id="mediaTimingReviewWaveformFill" x1="0" y1="0" x2="0" y2="1">
<stop class="media-timing-review-waveform-edge-stop" offset="0%" />
<stop class="media-timing-review-waveform-core-stop" offset="50%" />
<stop class="media-timing-review-waveform-edge-stop" offset="100%" />
</linearGradient>
</defs>
<path id="mediaTimingReviewWaveformPath"></path>
</svg>
<div
class="media-timing-review-original-range"
title="Mined subtitle timing"
aria-hidden="true"
>
<span class="media-timing-review-original-boundary is-start"></span>
<span class="media-timing-review-original-boundary is-end"></span>
</div>
<span class="media-timing-review-original-label is-start" aria-hidden="true">
Line start
</span>
<span class="media-timing-review-original-label is-end" aria-hidden="true">
Line end
</span>
<div
id="mediaTimingReviewSelectedRange"
class="media-timing-review-selected-range"
aria-hidden="true"
></div>
<div class="media-timing-review-playhead" aria-hidden="true"></div>
<div
id="mediaTimingReviewStartHandle"
class="media-timing-review-handle media-timing-review-handle-start"
role="slider"
tabindex="0"
aria-label="Clip start"
aria-orientation="horizontal"
></div>
<div
id="mediaTimingReviewEndHandle"
class="media-timing-review-handle media-timing-review-handle-end"
role="slider"
tabindex="0"
aria-label="Clip end"
aria-orientation="horizontal"
></div>
</div>
<div class="media-timing-review-expand-row">
<button
id="mediaTimingReviewShowEarlier"
class="media-timing-review-expand-button"
type="button"
aria-label="Show two more seconds before the visible timeline without moving the selected clip"
title="Show 2 more seconds before the visible timeline. The selected clip does not move."
>
Earlier &minus;2s
</button>
<span>Drag an edge to trim, or drag the highlighted clip to move it.</span>
<button
id="mediaTimingReviewShowLater"
class="media-timing-review-expand-button"
type="button"
aria-label="Show two more seconds after the visible timeline without moving the selected clip"
title="Show 2 more seconds after the visible timeline. The selected clip does not move."
>
Later +2s
</button>
</div>
</div>
<div class="media-timing-review-fine-grid">
<div class="media-timing-review-fine-control">
<span>Start</span>
<button
id="mediaTimingReviewStartBack"
type="button"
aria-label="Move start backward 100 milliseconds"
>
&minus;0.1s
</button>
<button
id="mediaTimingReviewStartForward"
type="button"
aria-label="Move start forward 100 milliseconds"
>
+0.1s
</button>
</div>
<div class="media-timing-review-fine-control">
<span>End</span>
<button
id="mediaTimingReviewEndBack"
type="button"
aria-label="Move end backward 100 milliseconds"
>
&minus;0.1s
</button>
<button
id="mediaTimingReviewEndForward"
type="button"
aria-label="Move end forward 100 milliseconds"
>
+0.1s
</button>
</div>
</div>
<div
id="mediaTimingReviewStatus"
class="media-timing-review-status"
role="status"
aria-live="polite"
></div>
<div class="media-timing-review-footer">
<div class="media-timing-review-preview-actions">
<button
id="mediaTimingReviewPlay"
class="media-timing-review-play-button"
type="button"
>
<span class="media-timing-review-play-glyph" aria-hidden="true"></span>
<span id="mediaTimingReviewPlayLabel">Play selection</span>
</button>
<button
id="mediaTimingReviewReset"
class="media-timing-review-quiet-button"
type="button"
>
Reset timing
</button>
</div>
<button
id="mediaTimingReviewConfirm"
class="media-timing-review-confirm-button"
type="button"
>
Use this timing
</button>
</div>
<div class="media-timing-review-hints" aria-hidden="true">
<span><kbd>Space</kbd> preview</span>
<span><kbd>&larr;</kbd><kbd>&rarr;</kbd> nudge focused edge</span>
<span><kbd>P</kbd>/<kbd>N</kbd> add prev/next line</span>
<span><kbd>Enter</kbd> confirm</span>
<span><kbd>Esc</kbd> cancel</span>
</div>
</div>
<div id="mediaTimingReviewCancelStep" class="media-timing-review-cancel-step hidden">
<div class="media-timing-review-cancel-mark" aria-hidden="true">?</div>
<h2>Stop reviewing?</h2>
<p id="mediaTimingReviewCancelMessage">Choose what should happen to this card.</p>
<div class="media-timing-review-cancel-actions">
<button
id="mediaTimingReviewCancelBack"
class="media-timing-review-quiet-button"
type="button"
>
Keep editing
</button>
<button
id="mediaTimingReviewUseOriginal"
class="media-timing-review-original-button"
type="button"
>
Use original timing
</button>
<button
id="mediaTimingReviewSkipMedia"
class="media-timing-review-skip-button"
type="button"
title="Keep this card but do not add audio or an image."
>
Keep without media
</button>
<button
id="mediaTimingReviewDiscard"
class="media-timing-review-discard-button"
type="button"
>
Delete card
</button>
</div>
</div>
</div>
</div>
<div id="kikuFieldGroupingModal" class="modal hidden" aria-hidden="true">
<div class="modal-content">
<div class="modal-header">
<div class="modal-title">Duplicate Card Detected</div>
</div>
<div class="modal-body">
<div id="kikuSelectionStep">
<div class="kiku-info-text">
A card with the same expression already exists. Select which card to keep. The other
card's content will be merged using field grouping. You can choose whether to delete
the duplicate.
</div>
<div class="kiku-cards-container">
<div id="kikuCard1" class="kiku-card active" tabindex="0">
<div class="kiku-card-label">1 &mdash; Original Card</div>
<div class="kiku-card-expression" id="kikuCard1Expression"></div>
<div class="kiku-card-sentence" id="kikuCard1Sentence"></div>
<div class="kiku-card-meta" id="kikuCard1Meta"></div>
</div>
<div id="kikuCard2" class="kiku-card" tabindex="0">
<div class="kiku-card-label">2 &mdash; New Card</div>
<div class="kiku-card-expression" id="kikuCard2Expression"></div>
<div class="kiku-card-sentence" id="kikuCard2Sentence"></div>
<div class="kiku-card-meta" id="kikuCard2Meta"></div>
</div>
</div>
<div class="kiku-footer">
<label class="kiku-delete-toggle">
<input id="kikuDeleteDuplicate" type="checkbox" checked />
Delete duplicate card after merge
</label>
<button id="kikuConfirmButton" class="kiku-confirm-button" type="button">
Continue
</button>
<button id="kikuCancelButton" class="kiku-cancel-button" type="button">
Cancel
</button>
</div>
</div>
<div id="kikuPreviewStep" class="hidden">
<div class="kiku-preview-header">
<div class="kiku-preview-title">Final Merge Preview</div>
<div class="kiku-preview-toggle">
<button id="kikuPreviewCompact" type="button">Compact</button>
<button id="kikuPreviewFull" type="button">Full</button>
</div>
</div>
<div id="kikuPreviewError" class="kiku-preview-error hidden"></div>
<pre id="kikuPreviewJson" class="kiku-preview-json"></pre>
<div class="kiku-footer">
<button id="kikuBackButton" class="kiku-cancel-button" type="button">Back</button>
<button id="kikuFinalConfirmButton" class="kiku-confirm-button" type="button">
Confirm Merge
</button>
<button id="kikuFinalCancelButton" class="kiku-cancel-button" type="button">
Cancel
</button>
</div>
</div>
<div id="kikuHint" class="kiku-hint">
Press 1 or 2 to select &middot; Enter to confirm &middot; Esc to cancel
</div>
</div>
</div>
</div>
<div id="runtimeOptionsModal" class="modal hidden" aria-hidden="true">
<div class="modal-content runtime-modal-content">
<div class="modal-header">
<div class="modal-title">Runtime Options</div>
<button id="runtimeOptionsClose" class="modal-close" type="button">Close</button>
</div>
<div class="modal-body">
<div id="runtimeOptionsHint" class="runtime-options-hint">
Arrow keys: select/change · Enter or double-click: apply · Esc: close
</div>
<ul id="runtimeOptionsList" class="runtime-options-list"></ul>
<div id="runtimeOptionsStatus" class="runtime-options-status"></div>
</div>
</div>
</div>
<div id="characterDictionaryModal" class="modal hidden" aria-hidden="true">
<div class="modal-content character-dictionary-content">
<div class="modal-header">
<div class="modal-title">Character Dictionary Management</div>
<button id="characterDictionaryClose" class="modal-close" type="button">Close</button>
</div>
<div class="modal-body">
<div
class="character-dictionary-tabs"
role="tablist"
aria-label="Character dictionary views"
>
<button
id="characterDictionaryOverrideTab"
class="character-dictionary-tab active"
type="button"
role="tab"
aria-selected="true"
>
Override
</button>
<button
id="characterDictionaryManageTab"
class="character-dictionary-tab"
type="button"
role="tab"
aria-selected="false"
>
Manage
</button>
</div>
<div id="characterDictionarySummary" class="runtime-options-hint"></div>
<div id="characterDictionarySearchPanel">
<div class="character-dictionary-search">
<input
id="characterDictionarySearchInput"
class="character-dictionary-search-input"
type="text"
aria-label="Search character dictionary"
autocomplete="off"
/>
<button
id="characterDictionarySearchButton"
class="character-dictionary-use"
type="button"
>
Search
</button>
</div>
<div id="characterDictionaryCurrent" class="character-dictionary-current"></div>
<ul id="characterDictionaryCandidates" class="character-dictionary-candidates"></ul>
</div>
<div id="characterDictionaryManagerPanel" class="hidden">
<ul
id="characterDictionaryManagedEntries"
class="character-dictionary-candidates character-dictionary-managed-entries"
></ul>
</div>
<div id="characterDictionaryStatus" class="runtime-options-status"></div>
</div>
</div>
</div>
<div
id="subtitleGenerationModal"
class="modal hidden"
aria-hidden="true"
role="dialog"
aria-modal="true"
aria-labelledby="subtitleGenerationTitle"
>
<div class="modal-content subtitle-generation-content">
<div class="modal-header">
<div id="subtitleGenerationTitle" class="modal-title">Generate Japanese subtitles</div>
<button id="subtitleGenerationClose" class="modal-close" type="button">Close</button>
</div>
<div class="modal-body subtitle-generation-body">
<p class="subtitle-generation-intro">
Turn the current audio track into timed Japanese subtitles. Audio stays on this
device.
</p>
<div class="subtitle-generation-detail">
<span class="subtitle-generation-label">Current media</span>
<div id="subtitleGenerationMedia">Checking current media...</div>
</div>
<div class="subtitle-generation-detail">
<span class="subtitle-generation-label">Local tools</span>
<div id="subtitleGenerationTools">Checking local tools...</div>
<p class="subtitle-generation-hint">
SubMiner downloads models, not whisper.cpp or FFmpeg. Install them, or set their
paths in Settings → Integrations → Japanese Subtitle Generation.
</p>
</div>
<div class="subtitle-generation-detail">
<span class="subtitle-generation-label">Speech model</span>
<div id="subtitleGenerationModel">Checking local models...</div>
<div
id="subtitleGenerationModelPicker"
class="subtitle-generation-model-picker hidden"
>
<label for="subtitleGenerationModelSelect">Model</label>
<select
id="subtitleGenerationModelSelect"
aria-describedby="subtitleGenerationModelDescription subtitleGenerationModelRecommendation"
></select>
<p id="subtitleGenerationModelDescription" class="subtitle-generation-hint"></p>
<p id="subtitleGenerationModelRecommendation" class="subtitle-generation-hint">
Start with small for a balance of accuracy and CPU time. Larger models need more
memory; speed depends on your hardware. Sizes shown are downloads.
</p>
<p class="subtitle-generation-hint">
This choice lasts for this SubMiner session. Set the default model in Settings.
</p>
</div>
<p class="subtitle-generation-hint">
Use your own model in Settings → Integrations → Japanese Subtitle Generation → Model
Path.
</p>
<button
id="subtitleGenerationDownload"
class="kiku-cancel-button hidden"
type="button"
>
Download model
</button>
</div>
<div class="subtitle-generation-detail">
<label class="subtitle-generation-vad-toggle" for="subtitleGenerationVadEnabled">
<input
id="subtitleGenerationVadEnabled"
type="checkbox"
aria-describedby="subtitleGenerationVadHint"
/>
Focus on spoken dialogue <span class="subtitle-generation-hint">Optional</span>
</label>
<div id="subtitleGenerationVadModel" class="subtitle-generation-hint"></div>
<p id="subtitleGenerationVadHint" class="subtitle-generation-hint">
Keeps uncertain audio to avoid losing dialogue under music. Songs may also be
transcribed. Requires whisper.cpp's speech detector.
</p>
<p class="subtitle-generation-hint">
Applies for this session. Set VAD Model Path in Settings to enable it by default.
</p>
<button
id="subtitleGenerationVadDownload"
class="kiku-cancel-button hidden"
type="button"
>
Download speech detection model
</button>
</div>
<div id="subtitleGenerationActivity" class="subtitle-generation-activity hidden">
<div class="subtitle-generation-progress-heading">
<span id="subtitleGenerationStage">Preparing</span>
<span id="subtitleGenerationPercent"></span>
</div>
<progress
id="subtitleGenerationProgress"
max="100"
aria-label="Subtitle generation progress"
></progress>
</div>
<div
id="subtitleGenerationStatus"
class="runtime-options-status"
role="status"
aria-live="polite"
></div>
<div class="subtitle-generation-actions">
<button id="subtitleGenerationRefresh" class="kiku-cancel-button" type="button">
Check again
</button>
<button id="subtitleGenerationCancel" class="kiku-cancel-button hidden" type="button">
Cancel
</button>
<button
id="subtitleGenerationStart"
class="kiku-confirm-button"
type="button"
disabled
>
Generate subtitles
</button>
</div>
<p class="subtitle-generation-hint">
The generated SRT will be saved locally and loaded into the player. You can close this
window while it runs.
</p>
</div>
</div>
</div>
<div id="subtitleSelectionModal" class="modal hidden" aria-hidden="true">
<div
class="modal-content subsync-modal-content"
role="dialog"
aria-modal="true"
aria-labelledby="subtitleSelectionTitle"
>
<div class="modal-header">
<h2 id="subtitleSelectionTitle">Select subtitles</h2>
<button id="subtitleSelectionClose" class="modal-close" type="button">Close</button>
</div>
<div class="modal-body">
<div class="subsync-form">
<label class="subsync-field">
<span>Primary subtitle</span>
<select id="subtitleSelectionPrimary"></select>
</label>
<label class="subsync-field">
<span>Secondary subtitle</span>
<select id="subtitleSelectionSecondary"></select>
</label>
</div>
<div
id="subtitleSelectionStatus"
class="runtime-options-status"
role="status"
aria-live="polite"
></div>
<div class="subsync-footer">
<button id="subtitleSelectionApply" class="kiku-confirm-button" type="button">
Apply
</button>
</div>
</div>
</div>
</div>
<div id="subsyncModal" class="modal hidden" aria-hidden="true">
<div class="modal-content subsync-modal-content">
<div class="modal-header">
<div class="modal-title">Subtitle Sync</div>
<button id="subsyncClose" class="modal-close" type="button">Close</button>
</div>
<div class="modal-body">
<div class="subsync-form">
<div class="subsync-field">
<span>Engine</span>
<label class="subsync-radio">
<input id="subsyncEngineAlass" type="radio" name="subsyncEngine" checked />
alass
</label>
<label class="subsync-radio">
<input id="subsyncEngineFfsubsync" type="radio" name="subsyncEngine" />
ffsubsync
</label>
</div>
<label id="subsyncReferenceLabel" class="subsync-field">
<span>Reference (correct timing, for alass)</span>
<select id="subsyncReferenceSelect"></select>
</label>
<label id="subsyncTargetLabel" class="subsync-field">
<span>Out-of-sync Subtitle (gets retimed)</span>
<select id="subsyncTargetSelect"></select>
</label>
</div>
<div id="subsyncStatus" class="runtime-options-status"></div>
<div class="subsync-footer">
<button id="subsyncRun" class="kiku-confirm-button" type="button">Run Sync</button>
</div>
</div>
</div>
</div>
<div id="controllerSelectModal" class="modal hidden" aria-hidden="true">
<div class="modal-content runtime-modal-content">
<div class="modal-header">
<div class="modal-title">Controller Configuration</div>
<button id="controllerSelectClose" class="modal-close" type="button">Close</button>
</div>
<div class="modal-body">
<label class="controller-select-field">
<span>Preferred Controller</span>
<select id="controllerSelectPicker"></select>
</label>
<div id="controllerSelectSummary" class="controller-select-summary"></div>
<div id="controllerConfigList" class="controller-config-list"></div>
<div id="controllerSelectStatus" class="runtime-options-status"></div>
<div class="subsync-footer">
<button id="controllerSelectSave" class="kiku-confirm-button" type="button">
Save Controller
</button>
</div>
</div>
</div>
</div>
<div id="controllerDebugModal" class="modal hidden" aria-hidden="true">
<div class="modal-content runtime-modal-content controller-debug-content">
<div
id="controllerDebugToast"
class="controller-debug-toast hidden"
aria-live="polite"
></div>
<div class="modal-header">
<div class="modal-title">Controller Debug</div>
<button id="controllerDebugClose" class="modal-close" type="button">Close</button>
</div>
<div class="modal-body">
<div id="controllerDebugStatus" class="runtime-options-status"></div>
<div id="controllerDebugSummary" class="controller-debug-summary"></div>
<div class="controller-debug-grid">
<div>
<div class="jimaku-section-title">Axes</div>
<pre id="controllerDebugAxes" class="controller-debug-pre"></pre>
</div>
<div>
<div class="jimaku-section-title">Buttons</div>
<pre id="controllerDebugButtons" class="controller-debug-pre"></pre>
</div>
<div class="controller-debug-span">
<div class="controller-debug-section-header">
<div class="jimaku-section-title">Config</div>
<button id="controllerDebugCopy" class="kiku-cancel-button" type="button">
Copy
</button>
</div>
<pre id="controllerDebugButtonIndices" class="controller-debug-pre"></pre>
</div>
</div>
</div>
</div>
</div>
<div id="subtitleSidebarModal" class="modal hidden subtitle-sidebar-modal" aria-hidden="true">
<div id="subtitleSidebarContent" class="modal-content subtitle-sidebar-content">
<div class="modal-header">
<div class="modal-title">Subtitle Sidebar</div>
<button id="subtitleSidebarCopy" class="modal-close" type="button" hidden>Copy</button>
<button id="subtitleSidebarClose" class="modal-close" type="button">Close</button>
</div>
<div class="modal-body subtitle-sidebar-body">
<button
id="subtitleGenerationOpen"
class="kiku-cancel-button subtitle-generation-open"
type="button"
>
Generate Japanese subtitles
</button>
<div id="subtitleSidebarStatus" class="runtime-options-status"></div>
<ul id="subtitleSidebarList" class="subtitle-sidebar-list"></ul>
</div>
</div>
</div>
<div id="sessionHelpModal" class="modal hidden" aria-hidden="true">
<div class="modal-content session-help-content">
<div class="modal-header">
<div class="modal-title">Session Help</div>
<button id="sessionHelpClose" class="modal-close" type="button">Close</button>
</div>
<div class="modal-body">
<div id="sessionHelpShortcut" class="session-help-shortcut"></div>
<div id="sessionHelpWarning" class="session-help-warning"></div>
<div id="sessionHelpStatus" class="session-help-status"></div>
<input
id="sessionHelpFilter"
class="session-help-filter"
type="text"
placeholder="Type / to search shortcuts"
autocomplete="off"
spellcheck="false"
/>
<div id="sessionHelpContent" class="session-help-content-list"></div>
</div>
</div>
</div>
<div id="changelogModal" class="modal hidden" aria-hidden="true">
<div class="modal-content changelog-content">
<div class="modal-header">
<div class="modal-title">Changelog</div>
<div class="changelog-header-actions">
<button id="changelogRefresh" class="changelog-refresh" type="button">Refresh</button>
<button id="changelogClose" class="modal-close" type="button">Close</button>
</div>
</div>
<div class="modal-body">
<div class="changelog-meta">
<span id="changelogInstalled" class="changelog-installed"></span>
<span id="changelogSource" class="changelog-source"></span>
</div>
<div id="changelogWarning" class="changelog-warning"></div>
<div id="changelogStatus" class="changelog-status"></div>
<div id="changelogList" class="changelog-list"></div>
</div>
</div>
</div>
<div id="playlistBrowserModal" class="modal hidden" aria-hidden="true">
<div class="modal-content playlist-browser-content">
<div class="modal-header">
<div class="modal-title">Playlist Browser</div>
<button id="playlistBrowserClose" class="modal-close" type="button">Close</button>
</div>
<div class="modal-body playlist-browser-body">
<div id="playlistBrowserTitle" class="playlist-browser-title"></div>
<div id="playlistBrowserStatus" class="playlist-browser-status"></div>
<div class="playlist-browser-grid">
<div class="playlist-browser-pane">
<div class="playlist-browser-pane-title">Directory</div>
<ul id="playlistBrowserDirectoryList" class="playlist-browser-list"></ul>
</div>
<div class="playlist-browser-pane">
<div class="playlist-browser-pane-title">Playlist</div>
<ul id="playlistBrowserPlaylistList" class="playlist-browser-list"></ul>
</div>
</div>
<div class="playlist-browser-footer">
<span>Tab switch pane</span>
<span>Enter activate</span>
<span>Delete remove</span>
<span>Ctrl/Cmd+Arrows reorder</span>
<span>Esc close</span>
</div>
</div>
</div>
</div>
</div>
<script type="module" src="renderer.js"></script>
</body>
</html>