fix: SSE bez nazwanych zdarzen (postep stal na 0); usun tryb testowy; opcja napisow (osadz/.srt)
All checks were successful
deploy / deploy (push) Successful in 28s
All checks were successful
deploy / deploy (push) Successful in 28s
- jobs.controller: usun pole type z MessageEvent — onmessage w EventSource reaguje tylko na domyslne 'message', przez co front nie dostawal zdarzen - usun trial (health, compose, deploy.yml, UI, zmienne Gitea) - napisy: wybor osadzania w wideo lub osobnego pliku .srt (--convert-subs srt) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -79,10 +79,10 @@ export default function App() {
|
||||
const [mode, setMode] = useState<Mode>('mp3');
|
||||
const [format, setFormat] = useState('320');
|
||||
const [subtitles, setSubtitles] = useState(false);
|
||||
const [subsMode, setSubsMode] = useState<'embed' | 'file'>('embed');
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [log, setLog] = useState<string[]>(['OK: wszystko gotowe do pobierania.']);
|
||||
const [trial, setTrial] = useState<{ daysLeft: number | null; expires: string | null } | null>(null);
|
||||
const esRef = useRef<EventSource | null>(null);
|
||||
const jobRef = useRef<string | null>(null);
|
||||
const logEndRef = useRef<HTMLDivElement | null>(null);
|
||||
@@ -94,15 +94,6 @@ export default function App() {
|
||||
setFormat(MODES.find((m) => m.key === mode)!.formats[0].value);
|
||||
}, [mode]);
|
||||
|
||||
useEffect(() => {
|
||||
fetch('/api/health')
|
||||
.then((r) => r.json())
|
||||
.then((h) => {
|
||||
if (h?.trial?.enabled) setTrial({ daysLeft: h.trial.daysLeft, expires: h.trial.expires });
|
||||
})
|
||||
.catch(() => {});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
logEndRef.current?.scrollIntoView({ block: 'end' });
|
||||
}, [log]);
|
||||
@@ -139,7 +130,7 @@ export default function App() {
|
||||
const res = await fetch('/api/jobs', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ url: url.trim(), mode, format, subtitles }),
|
||||
body: JSON.stringify({ url: url.trim(), mode, format, subtitles, subsMode }),
|
||||
});
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
const { id } = await res.json();
|
||||
@@ -262,21 +253,34 @@ export default function App() {
|
||||
</select>
|
||||
</div>
|
||||
<div className="col">
|
||||
<label className="field-label">Zapisz do:</label>
|
||||
<label className="field-label">Napisy:</label>
|
||||
<div className="save-to">
|
||||
<span>Pobranie przez przeglądarkę (folder „Pobrane”)</span>
|
||||
<label className="subs">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={subtitles}
|
||||
checked={subtitles && mode !== 'mp3'}
|
||||
onChange={(e) => setSubtitles(e.target.checked)}
|
||||
disabled={mode === 'mp3'}
|
||||
/>
|
||||
Napisy
|
||||
Pobierz napisy
|
||||
</label>
|
||||
<select
|
||||
className="select subs-select"
|
||||
value={subsMode}
|
||||
onChange={(e) => setSubsMode(e.target.value as 'embed' | 'file')}
|
||||
disabled={!subtitles || mode === 'mp3'}
|
||||
>
|
||||
<option value="embed">Osadź w pliku wideo</option>
|
||||
<option value="file">Osobny plik (.srt)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p className="hint">
|
||||
Napisy dotyczą tylko faktycznie dostępnych napisów — nie obejmują
|
||||
automatycznie generowanych napisów YouTube. Gotowy plik pobiera się przez
|
||||
przeglądarkę (folder „Pobrane”).
|
||||
</p>
|
||||
|
||||
<div className="actions">
|
||||
<button
|
||||
@@ -298,12 +302,6 @@ export default function App() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{trial && (
|
||||
<div className="trial">
|
||||
Tryb testowy: zostało {trial.daysLeft} dni. Wygasa: {trial.expires}.
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="logbox">
|
||||
<div className="logbox-title">Log</div>
|
||||
<div className="logbox-body">
|
||||
|
||||
Reference in New Issue
Block a user