mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-09-30 17:40:53 -07:00
feat(youtube): add YouTube browser window and Whisper subtitle source
- Add `subminer youtube`/`yt` and tray "Browse YouTube" window that plays or queues picked videos in mpv - Add `youtube.subtitleSource` (`youtube` | `whisper`) to transcribe YouTube audio via subtitle generation - Allow the subtitle generation modal on YouTube videos - Pick the real Japanese track over machine-translated ones and fall back to yt-dlp on HTTP 429 - Remove legacy launcher youtubeSubgen/whisper/AI args and `--youtube-mode` - Fix EPIPE crash when the launching terminal is closed with Ctrl+C - Thin media timing review handles with orange original-boundary bars - Update docs and change fragments
This commit is contained in:
@@ -393,12 +393,6 @@
|
||||
<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"
|
||||
|
||||
@@ -449,8 +449,8 @@ export function createMediaTimingReviewModal(
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves an untouched clip end back to where the line's dialogue ends. The Line end
|
||||
* rail keeps marking the subtitle timing, and Reset restores it.
|
||||
* Moves an untouched clip end back to where the line's dialogue ends. The orange
|
||||
* end bar keeps marking the subtitle timing, and Reset restores it.
|
||||
*/
|
||||
function trimTrailingSilence(peaks: readonly number[]): void {
|
||||
if (!payload || !trailingTrimPending || previewPlaying || previewRequest.isInFlight()) {
|
||||
|
||||
@@ -88,7 +88,7 @@ export function createSubtitleGenerationModal(
|
||||
const vad = snapshot ? describeGenerationVad(snapshot.vad) : null;
|
||||
const tools = snapshot ? describeGenerationTools(snapshot.tools) : null;
|
||||
const readyMessage = !snapshot?.mediaPath
|
||||
? 'Open local media to generate subtitles.'
|
||||
? 'Open a local file or a YouTube video to generate subtitles.'
|
||||
: !tools?.ready
|
||||
? 'Install the missing tools or set their paths in Settings, then click Check again.'
|
||||
: !model?.ready
|
||||
@@ -96,7 +96,8 @@ export function createSubtitleGenerationModal(
|
||||
: !vad?.ready
|
||||
? 'Download the speech detection model or uncheck Focus on spoken dialogue.'
|
||||
: 'Ready when you are.';
|
||||
dom.media.textContent = snapshot?.mediaPath ?? 'Open a local media file in the player first.';
|
||||
dom.media.textContent =
|
||||
snapshot?.mediaPath ?? 'Open a local file or a YouTube video in the player first.';
|
||||
dom.tools.textContent = tools?.text ?? 'Checking local tools...';
|
||||
dom.model.textContent = model?.text ?? 'Checking local models...';
|
||||
dom.modelPicker.classList.toggle('hidden', !snapshot || Boolean(snapshot.externalModelPath));
|
||||
|
||||
+20
-47
@@ -1763,34 +1763,6 @@ body:focus-visible,
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.media-timing-review-original-label {
|
||||
position: absolute;
|
||||
z-index: 7;
|
||||
padding: 3px 5px;
|
||||
border: 1px solid color-mix(in srgb, var(--ctp-crust) 35%, transparent);
|
||||
border-radius: 4px;
|
||||
background: var(--ctp-peach);
|
||||
box-shadow: 0 2px 6px color-mix(in srgb, var(--ctp-crust) 55%, transparent);
|
||||
color: var(--ctp-crust);
|
||||
font-size: 8px;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.06em;
|
||||
line-height: 1;
|
||||
pointer-events: none;
|
||||
white-space: nowrap;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.media-timing-review-original-label.is-start {
|
||||
top: 5px;
|
||||
left: calc(var(--original-start) + 7px);
|
||||
}
|
||||
|
||||
.media-timing-review-original-label.is-end {
|
||||
right: calc(100% - var(--original-end) + 7px);
|
||||
bottom: 5px;
|
||||
}
|
||||
|
||||
.media-timing-review-track.is-loading::after {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
@@ -1856,61 +1828,62 @@ body:focus-visible,
|
||||
}
|
||||
}
|
||||
|
||||
/* A thin line centered on the clip edge, so the line itself is the trim boundary. */
|
||||
.media-timing-review-handle {
|
||||
position: absolute;
|
||||
z-index: 6;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 14px;
|
||||
border: 1px solid var(--ctp-teal);
|
||||
background: linear-gradient(
|
||||
180deg,
|
||||
var(--ctp-teal),
|
||||
color-mix(in srgb, var(--ctp-teal) 74%, var(--ctp-crust))
|
||||
);
|
||||
width: 3px;
|
||||
background: var(--ctp-teal);
|
||||
cursor: ew-resize;
|
||||
touch-action: none;
|
||||
transform: translateX(-50%);
|
||||
transition: box-shadow 130ms ease;
|
||||
}
|
||||
|
||||
/* Widens the grab area past the visible bracket without moving the clip edge. */
|
||||
/* Widens the grab area past the visible line without moving the clip edge. */
|
||||
.media-timing-review-handle::before {
|
||||
position: absolute;
|
||||
inset: 0 -7px;
|
||||
inset: 0 -8px;
|
||||
content: '';
|
||||
}
|
||||
|
||||
/* Grip knob, symmetric about the line so it never reads as a separate edge. */
|
||||
.media-timing-review-handle::after {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 6px;
|
||||
height: 18px;
|
||||
width: 7px;
|
||||
height: 16px;
|
||||
content: '';
|
||||
border-inline: 1px solid color-mix(in srgb, var(--ctp-crust) 55%, transparent);
|
||||
border: 1px solid color-mix(in srgb, var(--ctp-crust) 55%, transparent);
|
||||
border-radius: 4px;
|
||||
background: var(--ctp-teal);
|
||||
transform: translate(-50%, -50%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.media-timing-review-handle-start {
|
||||
left: var(--selection-start);
|
||||
border-radius: 5px 0 0 5px;
|
||||
}
|
||||
|
||||
.media-timing-review-handle-end {
|
||||
left: var(--selection-end);
|
||||
border-radius: 0 5px 5px 0;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
.media-timing-review-handle:hover {
|
||||
box-shadow: 0 0 16px color-mix(in srgb, var(--ctp-teal) 60%, transparent);
|
||||
box-shadow: 0 0 10px color-mix(in srgb, var(--ctp-teal) 70%, transparent);
|
||||
}
|
||||
|
||||
.media-timing-review-handle:focus-visible {
|
||||
outline: 2px solid transparent;
|
||||
box-shadow:
|
||||
inset 0 0 0 2px var(--ctp-yellow),
|
||||
0 0 16px color-mix(in srgb, var(--ctp-yellow) 55%, transparent);
|
||||
background: var(--ctp-yellow);
|
||||
box-shadow: 0 0 12px color-mix(in srgb, var(--ctp-yellow) 60%, transparent);
|
||||
}
|
||||
|
||||
.media-timing-review-handle:focus-visible::after {
|
||||
background: var(--ctp-yellow);
|
||||
}
|
||||
|
||||
.media-timing-review-expand-row span {
|
||||
|
||||
Reference in New Issue
Block a user