release: 5.0.6 — streamlink stdout-Capture + CSS select+checkbox fixes
Streamlink Diagnose:
- stdout-Buffer wird jetzt zusaetzlich zu stderr gesammelt; einige
streamlink-Builds schreiben 'error:'-Lines auf stdout statt stderr,
was bisher zu leerem stderrTail + 'Streamlink exit code 1' ohne
Detail-Info gefuehrt hat.
- download-part-failed Debug-Log enthaelt jetzt stderrTail UND
stdoutTail (jeweils letzte 2000 chars), plus User-facing-Error wird
aus beiden Streams kombiniert gesucht.
CSS:
- .form-group select: 'background: ...' Shorthand wurde durch
'background-color: ...' ersetzt — Shorthand hatte background-image
(Chevron-SVG), background-repeat, background-position, background-size
aus der globalen select-Regel resettet, was zu tiled Chevrons im
Dropdown gefuehrt hat ('Best (default) ▼▼▼▼▼▼...').
- input[type='checkbox']:checked: rotated-border-Trick durch inline-
SVG-Checkmark ersetzt — die rotated borders renderten in mstsc/RDP-
Sessions teilweise als Pfeile statt Haken (DPI-Skalierungs-Artefakt).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e270e1ec12
commit
5e78068169
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "twitch-vod-manager",
|
||||
"version": "5.0.5",
|
||||
"version": "5.0.6",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "twitch-vod-manager",
|
||||
"version": "5.0.5",
|
||||
"version": "5.0.6",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"axios": "^1.6.0",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "twitch-vod-manager",
|
||||
"version": "5.0.5",
|
||||
"version": "5.0.6",
|
||||
"description": "Twitch VOD Manager - Download Twitch VODs easily",
|
||||
"main": "dist/main.js",
|
||||
"author": "xRangerDE",
|
||||
|
||||
48
src/main.ts
48
src/main.ts
@ -3139,13 +3139,24 @@ function downloadVODPart(
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
const stdoutBuffer: string[] = [];
|
||||
proc.stdout?.on('data', (data: Buffer) => {
|
||||
const line = data.toString();
|
||||
// No per-line stdout — streamlink emits 10-100 lines/sec during
|
||||
// an active download, which floods the terminal in dev and the
|
||||
// electron-launched console in prod. Progress + tag parsing
|
||||
// below extracts everything we need; failures get logged via
|
||||
// appendDebugLog from the consumer side.
|
||||
// Capture non-progress lines auch fuer Diagnose — streamlink-Windows-
|
||||
// Builds schreiben einige Errors auf stdout statt stderr (z.B. "error:
|
||||
// No playable streams found on this URL"). Wenn stderr leer bleibt,
|
||||
// greift der close-handler auf stdout zurueck.
|
||||
stdoutBuffer.push(line);
|
||||
if (stdoutBuffer.length > 200) stdoutBuffer.shift();
|
||||
const lower = line.toLowerCase();
|
||||
if (lower.includes('error:') || lower.includes('warning:')) {
|
||||
appendDebugLog('download-part-stdout-err', { itemId, message: line.trim() });
|
||||
if (lower.includes('error:')) {
|
||||
// Letzte echte streamlink-Errorzeile, auch wenn auf stdout
|
||||
const errLine = line.split('\n').map(l => l.trim()).filter(l => l.toLowerCase().includes('error:')).pop();
|
||||
if (errLine) lastErrorLine = errLine;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse progress
|
||||
const match = line.match(/(\d+\.\d+)%/);
|
||||
@ -3227,17 +3238,30 @@ function downloadVODPart(
|
||||
return;
|
||||
}
|
||||
|
||||
// Volle stderr-History im Debug-Log (kollabiert) — fuer Forensik
|
||||
// wenn der User schreibt "es funktioniert nicht". User-facing
|
||||
// genericError ist die echte streamlink-Fehlerzeile, nicht nur
|
||||
// "Streamlink Fehlercode 1".
|
||||
// Volle stderr+stdout-History im Debug-Log fuer Forensik.
|
||||
// Streamlink-Windows-Builds schreiben Errors gelegentlich auf
|
||||
// stdout statt stderr ("No playable streams found on this URL"
|
||||
// war historisch ein stdout-Error). Wir mergen beide Streams
|
||||
// damit immer SICHTBAR ist was passiert.
|
||||
const fullStderr = stderrBuffer.join('').trim();
|
||||
const userFacingError = lastErrorLine
|
||||
|| (fullStderr.split('\n').filter(l => l.trim()).pop() || '').trim()
|
||||
|| tBackend('streamlinkExitCode', { code: String(code ?? -1) });
|
||||
const fullStdout = stdoutBuffer.join('').trim();
|
||||
// Letzte Error-/Warning-Zeile aus beiden Streams suchen, falls
|
||||
// lastErrorLine noch leer ist (z.B. weil streamlink ohne Output
|
||||
// mit Code 1 exited — was bei pre-flight-Auth-Fails passiert).
|
||||
let userFacingError = lastErrorLine;
|
||||
if (!userFacingError) {
|
||||
const combined = (fullStderr + '\n' + fullStdout).split('\n').map(l => l.trim()).filter(Boolean);
|
||||
userFacingError = combined.filter(l => l.toLowerCase().includes('error:')).pop()
|
||||
|| combined.filter(l => !l.startsWith('[')).pop()
|
||||
|| '';
|
||||
}
|
||||
if (!userFacingError) {
|
||||
userFacingError = tBackend('streamlinkExitCode', { code: String(code ?? -1) });
|
||||
}
|
||||
appendDebugLog('download-part-failed', {
|
||||
itemId, filename, code, error: userFacingError,
|
||||
stderrTail: fullStderr.slice(-2000),
|
||||
stdoutTail: fullStdout.slice(-2000),
|
||||
});
|
||||
resolve({ success: false, error: userFacingError });
|
||||
});
|
||||
|
||||
@ -756,20 +756,21 @@ input[type="checkbox"]:hover:not(:disabled) {
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked {
|
||||
background: var(--accent);
|
||||
/* Inline-SVG-Checkmark statt rotated-border-Trick — robuster ueber
|
||||
DPI-Skalierungen und Remote-Desktop-Renderings (RDP / mstsc), wo
|
||||
die kleinen border-rotation-Pseudo-Elemente teilweise als
|
||||
Dreiecke / Pfeile gerendert wurden. */
|
||||
background-color: var(--accent);
|
||||
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23ffffff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='3.5 8.5 6.5 11.5 12.5 5'/%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 12px;
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 4px;
|
||||
top: 0.5px;
|
||||
width: 5px;
|
||||
height: 9px;
|
||||
border: solid #fff;
|
||||
border-width: 0 2px 2px 0;
|
||||
transform: rotate(45deg);
|
||||
/* Pseudo-Element nicht mehr noetig — Checkmark kommt aus background. */
|
||||
content: none;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:focus-visible {
|
||||
@ -1761,7 +1762,11 @@ select option {
|
||||
|
||||
.form-group input:not([type="checkbox"]):not([type="radio"]), .form-group select {
|
||||
width: 100%;
|
||||
background: var(--bg-main);
|
||||
/* background-color (nicht background shorthand) — sonst wuerden
|
||||
background-image (Chevron-SVG), background-repeat, background-size
|
||||
und background-position aus der globalen `select`-Regel resettet,
|
||||
was zu tiled Chevrons im Dropdown gefuehrt hat. */
|
||||
background-color: var(--bg-main);
|
||||
border: 1px solid rgba(255,255,255,0.1);
|
||||
border-radius: 4px;
|
||||
padding: 10px 12px;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user