WIP 184-2 보충: generic 추출기 (직접 파일 · .unknown_video) 이고 합치지 않은 경우만 일반 파일로 - 사이트 추출기의 후처리 실패는 그대로 실패 (검토 대기)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
backup_묶음6_d46e089
RyuJongJin 2026-10-12 08:34:13 +09:00
parent 2d2bd40824
commit 354798c0e7
2 changed files with 32 additions and 1 deletions

View File

@ -177,7 +177,11 @@ class YtDlpBackend implements DownloadBackend {
// 영상 · 음성을 따로 받아도 하나의 진행률 · 크기로 보이게 합친다
final totals = YtDlpTotals();
var files = 0;
// 184-2: 사이트 추출기가 아닌 "generic" (직접 파일 등) 으로 받았는지 · 영상 · 음성을 합쳤는지
var generic = false, merged = false;
void onLine(String line) {
if (line.startsWith('[generic]')) generic = true;
if (line.startsWith('[Merger]')) merged = true;
final prog = parseYtDlpProgress(line);
if (prog != null) {
totals.update(prog);
@ -246,7 +250,9 @@ class YtDlpBackend implements DownloadBackend {
}
// 184-2: 동영상이 아닌 직접 파일 (확장자로 미리 알 수 없던 주소) 을 다 받았는데 후처리에서 실패 -
// 받은 파일을 원래 이름으로 남기고 "완료" (예전에는 다 받고도 "실패 · 받지 못했습니다" 와 "… [id].unknown_video")
if (isNonVideoPostprocessError(err) && await _keepAsPlainFile(t)) {
// 사이트 추출기 (youtube 등) 나 합치기 실패는 진짜 동영상이 망가진 것일 수 있어 실패 그대로 (이유를 보인다)
final plain = !merged && (generic || t.files.any((f) => f.endsWith('.unknown_video')));
if (plain && isNonVideoPostprocessError(err) && await _keepAsPlainFile(t)) {
changed();
return;
}

View File

@ -32,6 +32,7 @@ a = sys.argv[1:]
d = a[a.index('-P') + 1]
f = os.path.join(d, 'download [download].unknown_video')
open(f, 'w').write('PK')
print('[generic] Extracting URL: ' + a[-1], flush=True)
print('[download] Destination: ' + f, flush=True)
sys.stderr.write('ERROR: Postprocessing: Error opening input files: Invalid data found when processing input\n')
sys.exit(1)
@ -49,6 +50,30 @@ sys.exit(1)
expect(File(p.join(out.path, 'download [download].unknown_video')).existsSync(), isFalse);
});
test('사이트 추출기 (youtube 등) 의 후처리 실패는 바꾸지 않는다 - 망가진 동영상을 "완료" 로 두지 않음', () async {
final dir = Directory.systemTemp.createTempSync('jj_plain_');
addTearDown(() => dir.deleteSync(recursive: true));
final script = File(p.join(dir.path, 'fake_ytdlp.py'))
..writeAsStringSync(r'''
import os, sys
a = sys.argv[1:]
d = a[a.index('-P') + 1]
f = os.path.join(d, 'clip [abc].f137.mp4')
open(f, 'w').write('V')
print('[youtube] Extracting URL: ' + a[-1], flush=True)
print('[download] Destination: ' + f, flush=True)
sys.stderr.write('ERROR: Postprocessing: Error opening input files: Invalid data found when processing input\n')
sys.exit(1)
''');
final backend = YtDlpBackend(ytdlp: 'python', prefixArgs: [script.path], deno: '');
final t = DownloadTask(
id: '1', kind: DownloadKind.video, source: 'https://www.youtube.com/watch?v=abc&file=a.zip', dir: dir.path);
await backend.start(t, () {});
expect(t.state, DownloadState.failed);
expect(t.error, contains('Postprocessing'));
expect(File(p.join(dir.path, 'clip [abc].f137.mp4')).existsSync(), isTrue, reason: '이름도 바꾸지 않음');
});
test('받은 파일이 없으면 그대로 실패', () async {
final dir = Directory.systemTemp.createTempSync('jj_plain_');
addTearDown(() => dir.deleteSync(recursive: true));