2026-09-21 10:57:43 -04:00
|
|
|
<script lang="ts">
|
|
|
|
|
import { resolveUrl } from '$lib/bindings/video';
|
2026-09-21 11:00:46 -04:00
|
|
|
import {
|
|
|
|
|
session,
|
|
|
|
|
setMetadata,
|
|
|
|
|
setError,
|
|
|
|
|
setResolving,
|
|
|
|
|
beginDownload,
|
|
|
|
|
} from '$lib/stores/videoSession.svelte';
|
2026-09-21 10:57:43 -04:00
|
|
|
|
|
|
|
|
let inputValue = $state('');
|
chore: stage all pending work — caption styling, media server, processing modal, docs, summaries
Includes:
- Extended caption styling (font, shadow, dimmed color, bg toggle)
- Media server, subtitle downloader, VTT parser, processing modal
- Waveform tiers, thumbnail/timeline improvements, transport controls
- Hybrid download model, dependency management, clip export enhancements
- 21 chat summaries, 2 implementation plans, 2 design specs
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 10:48:16 -04:00
|
|
|
let inputEl = $state<HTMLInputElement | null>(null);
|
|
|
|
|
|
|
|
|
|
function blurInput() {
|
|
|
|
|
inputEl?.blur();
|
|
|
|
|
}
|
2026-09-21 10:57:43 -04:00
|
|
|
|
|
|
|
|
async function handleSubmit() {
|
|
|
|
|
const trimmed = inputValue.trim();
|
|
|
|
|
if (!trimmed) return;
|
|
|
|
|
|
chore: stage all pending work — caption styling, media server, processing modal, docs, summaries
Includes:
- Extended caption styling (font, shadow, dimmed color, bg toggle)
- Media server, subtitle downloader, VTT parser, processing modal
- Waveform tiers, thumbnail/timeline improvements, transport controls
- Hybrid download model, dependency management, clip export enhancements
- 21 chat summaries, 2 implementation plans, 2 design specs
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 10:48:16 -04:00
|
|
|
blurInput();
|
2026-09-21 10:57:43 -04:00
|
|
|
setResolving();
|
|
|
|
|
try {
|
|
|
|
|
const meta = await resolveUrl(trimmed);
|
|
|
|
|
setMetadata(meta);
|
2026-09-21 11:00:46 -04:00
|
|
|
void beginDownload();
|
2026-09-21 10:57:43 -04:00
|
|
|
} catch (e) {
|
|
|
|
|
setError(String(e));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleKeydown(e: KeyboardEvent) {
|
|
|
|
|
if (e.key === 'Enter') {
|
|
|
|
|
handleSubmit();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handlePaste(e: ClipboardEvent) {
|
|
|
|
|
const text = e.clipboardData?.getData('text')?.trim();
|
|
|
|
|
if (text && (text.startsWith('http://') || text.startsWith('https://'))) {
|
2026-09-21 11:57:08 -04:00
|
|
|
e.preventDefault();
|
2026-09-21 10:57:43 -04:00
|
|
|
inputValue = text;
|
|
|
|
|
setTimeout(handleSubmit, 50);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
2026-09-21 11:57:08 -04:00
|
|
|
<div class="url-input-wrapper">
|
|
|
|
|
<div class="url-input">
|
|
|
|
|
<input
|
chore: stage all pending work — caption styling, media server, processing modal, docs, summaries
Includes:
- Extended caption styling (font, shadow, dimmed color, bg toggle)
- Media server, subtitle downloader, VTT parser, processing modal
- Waveform tiers, thumbnail/timeline improvements, transport controls
- Hybrid download model, dependency management, clip export enhancements
- 21 chat summaries, 2 implementation plans, 2 design specs
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-22 10:48:16 -04:00
|
|
|
bind:this={inputEl}
|
2026-09-21 11:57:08 -04:00
|
|
|
type="text"
|
|
|
|
|
placeholder="Paste a video URL and press Enter…"
|
|
|
|
|
bind:value={inputValue}
|
|
|
|
|
onkeydown={handleKeydown}
|
|
|
|
|
onpaste={handlePaste}
|
|
|
|
|
disabled={session.status === 'resolving'}
|
|
|
|
|
/>
|
|
|
|
|
{#if session.status === 'resolving'}
|
|
|
|
|
<span class="spinner">⏳</span>
|
|
|
|
|
{/if}
|
|
|
|
|
</div>
|
2026-09-21 10:57:43 -04:00
|
|
|
{#if session.error}
|
2026-09-21 11:57:08 -04:00
|
|
|
<div class="error-bar" title={session.error}>⚠ {session.error}</div>
|
2026-09-21 10:57:43 -04:00
|
|
|
{/if}
|
2026-09-21 10:45:53 -04:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<style>
|
2026-09-21 11:57:08 -04:00
|
|
|
.url-input-wrapper {
|
2026-09-21 10:45:53 -04:00
|
|
|
flex: 1;
|
2026-09-21 11:57:08 -04:00
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
gap: 4px;
|
|
|
|
|
}
|
|
|
|
|
.url-input {
|
2026-09-21 10:57:43 -04:00
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
gap: 8px;
|
2026-09-21 10:45:53 -04:00
|
|
|
}
|
|
|
|
|
.url-input input {
|
|
|
|
|
width: 100%;
|
|
|
|
|
}
|
2026-09-21 10:57:43 -04:00
|
|
|
.spinner {
|
|
|
|
|
animation: pulse 1s ease-in-out infinite;
|
|
|
|
|
}
|
2026-09-21 11:57:08 -04:00
|
|
|
.error-bar {
|
2026-09-21 10:57:43 -04:00
|
|
|
color: var(--danger);
|
2026-09-21 11:57:08 -04:00
|
|
|
font-size: 12px;
|
|
|
|
|
line-height: 1.3;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
white-space: nowrap;
|
2026-09-21 10:57:43 -04:00
|
|
|
cursor: help;
|
|
|
|
|
}
|
|
|
|
|
@keyframes pulse {
|
|
|
|
|
0%,
|
|
|
|
|
100% {
|
|
|
|
|
opacity: 1;
|
|
|
|
|
}
|
|
|
|
|
50% {
|
|
|
|
|
opacity: 0.4;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-09-21 10:45:53 -04:00
|
|
|
</style>
|