fix(ytdlp): keep valid downloaded outputs
This commit is contained in:
1 parent
03bb21c951
commit
b9d988b379
3 files changed
+91
-23
No files matched your search
Vendored
+15
-8
@@ -11032,15 +11032,22 @@ function safeRmDir(dir) {
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
function isYtDlpSidecarOrTemporaryFile(fileName) {
|
||||
const lower = fileName.toLowerCase();
|
||||
return lower.endsWith(".part") || lower.endsWith(".ytdl") || lower.endsWith(".tmp") || lower.endsWith(".info.json") || lower.endsWith(".live_chat.json") || lower.endsWith(".description") || lower.endsWith(".annotations.xml");
|
||||
}
|
||||
function selectPrimaryOutputFile(taskDir) {
|
||||
const entries = fs10.readdirSync(taskDir, { withFileTypes: true });
|
||||
const files = entries.filter((e) => e.isFile()).map((e) => ({
|
||||
name: e.name,
|
||||
fullPath: path15.join(taskDir, e.name)
|
||||
})).filter((f) => !f.name.endsWith(".part") && !f.name.endsWith(".ytdl") && !f.name.endsWith(".json") && !f.name.endsWith(".tmp")).map((f) => ({
|
||||
...f,
|
||||
size: fs10.existsSync(f.fullPath) ? fs10.statSync(f.fullPath).size : 0
|
||||
})).filter((f) => f.size > 0).sort((a, b) => b.size - a.size);
|
||||
const collectFiles = (dir) => {
|
||||
const entries = fs10.readdirSync(dir, { withFileTypes: true });
|
||||
return entries.flatMap((entry) => {
|
||||
const fullPath = path15.join(dir, entry.name);
|
||||
if (entry.isDirectory()) return collectFiles(fullPath);
|
||||
if (!entry.isFile() || isYtDlpSidecarOrTemporaryFile(entry.name)) return [];
|
||||
const size = fs10.existsSync(fullPath) ? fs10.statSync(fullPath).size : 0;
|
||||
return size > 0 ? [{ name: entry.name, fullPath, size }] : [];
|
||||
});
|
||||
};
|
||||
const files = collectFiles(taskDir).sort((a, b) => b.size - a.size);
|
||||
if (files.length === 0) return null;
|
||||
return { filePath: files[0].fullPath, fileName: files[0].name, size: files[0].size };
|
||||
}
|
||||
|
||||
@@ -70,22 +70,30 @@ function safeRmDir(dir: string) {
|
||||
}
|
||||
}
|
||||
|
||||
function selectPrimaryOutputFile(taskDir: string): { filePath: string; fileName: string; size: number } | null {
|
||||
const entries = fs.readdirSync(taskDir, { withFileTypes: true });
|
||||
const files = entries
|
||||
.filter(e => e.isFile())
|
||||
.map(e => ({
|
||||
name: e.name,
|
||||
fullPath: path.join(taskDir, e.name),
|
||||
}))
|
||||
.filter(f => !f.name.endsWith('.part') && !f.name.endsWith('.ytdl') && !f.name.endsWith('.json') && !f.name.endsWith('.tmp'))
|
||||
.map(f => ({
|
||||
...f,
|
||||
size: fs.existsSync(f.fullPath) ? fs.statSync(f.fullPath).size : 0
|
||||
}))
|
||||
.filter(f => f.size > 0)
|
||||
.sort((a, b) => b.size - a.size);
|
||||
function isYtDlpSidecarOrTemporaryFile(fileName: string): boolean {
|
||||
const lower = fileName.toLowerCase();
|
||||
return lower.endsWith('.part')
|
||||
|| lower.endsWith('.ytdl')
|
||||
|| lower.endsWith('.tmp')
|
||||
|| lower.endsWith('.info.json')
|
||||
|| lower.endsWith('.live_chat.json')
|
||||
|| lower.endsWith('.description')
|
||||
|| lower.endsWith('.annotations.xml');
|
||||
}
|
||||
|
||||
export function selectPrimaryOutputFile(taskDir: string): { filePath: string; fileName: string; size: number } | null {
|
||||
const collectFiles = (dir: string): Array<{ name: string; fullPath: string; size: number }> => {
|
||||
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
||||
return entries.flatMap(entry => {
|
||||
const fullPath = path.join(dir, entry.name);
|
||||
if (entry.isDirectory()) return collectFiles(fullPath);
|
||||
if (!entry.isFile() || isYtDlpSidecarOrTemporaryFile(entry.name)) return [];
|
||||
const size = fs.existsSync(fullPath) ? fs.statSync(fullPath).size : 0;
|
||||
return size > 0 ? [{ name: entry.name, fullPath, size }] : [];
|
||||
});
|
||||
};
|
||||
|
||||
const files = collectFiles(taskDir).sort((a, b) => b.size - a.size);
|
||||
if (files.length === 0) return null;
|
||||
return { filePath: files[0].fullPath, fileName: files[0].name, size: files[0].size };
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { selectPrimaryOutputFile } from './ytDlpDownload.js';
|
||||
|
||||
function makeTaskDir(): string {
|
||||
return fs.mkdtempSync(path.join(os.tmpdir(), 'tg-vault-ytdlp-select-'));
|
||||
}
|
||||
|
||||
function writeFile(filePath: string, content: string) {
|
||||
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
||||
fs.writeFileSync(filePath, content);
|
||||
}
|
||||
|
||||
function testSelectsRealOutputFromNestedDirectories() {
|
||||
const dir = makeTaskDir();
|
||||
writeFile(path.join(dir, 'video.info.json'), '{"metadata":true}');
|
||||
writeFile(path.join(dir, 'tmp.part'), 'partial');
|
||||
writeFile(path.join(dir, 'nested', 'small-thumb.jpg'), 'x');
|
||||
writeFile(path.join(dir, 'nested', 'video.mp4'), 'real-media-output');
|
||||
|
||||
const selected = selectPrimaryOutputFile(dir);
|
||||
|
||||
assert.equal(selected?.fileName, 'video.mp4');
|
||||
assert.equal(selected?.filePath, path.join(dir, 'nested', 'video.mp4'));
|
||||
assert.equal(selected?.size, Buffer.byteLength('real-media-output'));
|
||||
}
|
||||
|
||||
function testDoesNotDiscardJsonWhenItIsTheOnlyRealOutput() {
|
||||
const dir = makeTaskDir();
|
||||
writeFile(path.join(dir, 'result.json'), '{"download":"payload"}');
|
||||
|
||||
const selected = selectPrimaryOutputFile(dir);
|
||||
|
||||
assert.equal(selected?.fileName, 'result.json');
|
||||
assert.equal(selected?.filePath, path.join(dir, 'result.json'));
|
||||
}
|
||||
|
||||
function testReturnsNullWhenOnlyTemporarySidecarsExist() {
|
||||
const dir = makeTaskDir();
|
||||
writeFile(path.join(dir, 'video.part'), 'partial');
|
||||
writeFile(path.join(dir, 'video.ytdl'), 'state');
|
||||
writeFile(path.join(dir, 'video.info.json'), '{"metadata":true}');
|
||||
writeFile(path.join(dir, 'video.tmp'), 'tmp');
|
||||
|
||||
assert.equal(selectPrimaryOutputFile(dir), null);
|
||||
}
|
||||
|
||||
testSelectsRealOutputFromNestedDirectories();
|
||||
testDoesNotDiscardJsonWhenItIsTheOnlyRealOutput();
|
||||
testReturnsNullWhenOnlyTemporarySidecarsExist();
|
||||
console.log('yt-dlp output selection ok');
|
||||
Reference in new issue
Block a user