From 517f45e8fdae938771a095291b5be891015c60a0 Mon Sep 17 00:00:00 2001 From: cottongin Date: Tue, 22 Sep 2026 10:35:22 -0400 Subject: [PATCH] feat(captions): use font, shadow, dimmed color, bg toggle in preview captions Co-authored-by: Cursor --- src/lib/components/VideoPlayer.svelte | 371 +++++++++++++++++++++++++- 1 file changed, 358 insertions(+), 13 deletions(-) diff --git a/src/lib/components/VideoPlayer.svelte b/src/lib/components/VideoPlayer.svelte index c444a27..36842e3 100644 --- a/src/lib/components/VideoPlayer.svelte +++ b/src/lib/components/VideoPlayer.svelte @@ -1,12 +1,122 @@
- {#if session.status === 'ready' && session.streamUrl} + {#if session.status === 'ready' && session.previewStatus === 'complete' && videoSrc} + onerror={handleError} + onloadeddata={handleLoadedData} + preload="metadata" + playsinline + > + {#if activeCues.length > 0} +
+ {#each activeCues as cue} + {#if preferences.captionSettings.wordHighlight && cue.words}{#each getActiveWords(cue, session.currentTime) as word}{word.text}{' '}{/each}{:else}{cue.text}{/if} + {/each} +
+ {/if} + {#if parsedCues.length > 0} +
+ + +
+ {/if} + {#if showCaptionSettings} + (showCaptionSettings = false)} /> + {/if} + {#if session.showUpgradeToast} +
+ Higher quality preview available + + +
+ {/if} + {#if videoError} +
{videoError}
+ {/if} + {:else if session.status === 'ready' && session.previewStatus === 'downloading'} +
+
Downloading preview…
+
+
+
+
{Math.round(session.previewProgress * 100)}%
+
{:else if session.status === 'resolving'}
Loading video…
{:else if session.status === 'error'}
{session.error ?? 'Failed to load video.'}
+ {:else if session.status === 'ready' && session.previewStatus === 'idle'} +
Preparing download…
{:else}
Paste a URL above to load a video
{/if} @@ -74,8 +267,9 @@ align-items: center; justify-content: center; background: #000; - min-height: 200px; + min-height: 0; position: relative; + overflow: hidden; } video { @@ -84,6 +278,77 @@ object-fit: contain; } + .caption-overlay { + position: absolute; + left: 0; + right: 0; + display: flex; + flex-direction: column; + align-items: center; + gap: 2px; + pointer-events: none; + z-index: 5; + padding: 0 10%; + } + + .caption-text { + display: inline-block; + padding: 4px 10px; + border-radius: 3px; + line-height: 1.4; + text-align: center; + white-space: pre-wrap; + max-width: 80%; + } + + .caption-word { + transition: opacity 0.1s ease; + } + + .caption-word.spoken { + opacity: 1; + } + + .cc-controls { + position: absolute; + bottom: 12px; + right: 12px; + display: flex; + gap: 4px; + z-index: 10; + } + + .cc-toggle, + .cc-settings-btn { + background: rgba(0, 0, 0, 0.7); + color: #ccc; + border: 1px solid rgba(255, 255, 255, 0.3); + border-radius: 4px; + padding: 4px 8px; + font-size: 12px; + font-weight: 700; + cursor: pointer; + letter-spacing: 0.5px; + transition: background 0.15s, color 0.15s, border-color 0.15s; + } + + .cc-toggle:hover, + .cc-settings-btn:hover { + background: rgba(0, 0, 0, 0.9); + color: #fff; + } + + .cc-toggle.active { + background: rgba(255, 255, 255, 0.9); + color: #000; + border-color: rgba(255, 255, 255, 0.9); + } + + .cc-settings-btn { + font-weight: 400; + font-size: 14px; + } + .placeholder { color: var(--text-muted); font-size: 16px; @@ -92,4 +357,84 @@ .placeholder.error { color: var(--danger); } + + .video-overlay-error { + position: absolute; + bottom: 8px; + left: 8px; + right: 8px; + padding: 6px 10px; + background: rgba(0, 0, 0, 0.8); + color: var(--danger); + font-size: 12px; + border-radius: 4px; + z-index: 20; + } + + .progress-bar { + width: 200px; + height: 6px; + background: var(--bg-tertiary); + border-radius: 3px; + margin: 12px auto 6px; + overflow: hidden; + } + + .progress-fill { + height: 100%; + background: var(--accent, #89b4fa); + border-radius: 3px; + transition: width 0.3s ease; + } + + .progress-text { + font-size: 13px; + color: var(--text-secondary); + } + + .upgrade-toast { + position: absolute; + top: 10px; + right: 10px; + display: flex; + align-items: center; + gap: 8px; + background: var(--bg-primary, #1e1e2e); + border: 1px solid var(--border, #353550); + border-radius: 6px; + padding: 8px 12px; + font-size: 12px; + color: var(--text-primary, #cdd6f4); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4); + z-index: 15; + } + + .upgrade-btn { + background: #89b4fa; + color: #1e1e2e; + border: none; + border-radius: 4px; + padding: 4px 10px; + font-size: 11px; + font-weight: 600; + cursor: pointer; + } + + .upgrade-btn:hover { + background: #b4d0fb; + } + + .dismiss-btn { + background: none; + border: none; + color: var(--text-secondary, #6c7086); + cursor: pointer; + font-size: 14px; + padding: 2px 4px; + line-height: 1; + } + + .dismiss-btn:hover { + color: var(--text-primary, #cdd6f4); + }