tuna-agent 0.1.156 → 0.1.157
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -144,6 +144,22 @@ function detectPlatform(url) {
|
|
|
144
144
|
return 'facebook';
|
|
145
145
|
return 'other';
|
|
146
146
|
}
|
|
147
|
+
// yt-dlp `%(title)s` is a clean title on YouTube but the full post caption
|
|
148
|
+
// on TikTok/Douyin/Facebook (often 200+ chars, prefixed with engagement
|
|
149
|
+
// stats). Strip the social-stats prefix, keep the first segment, and cap
|
|
150
|
+
// to a sane title length so the cloned idea doesn't get a paragraph title.
|
|
151
|
+
function cleanSourceTitle(raw) {
|
|
152
|
+
let t = (raw || '').trim().split('\n')[0].trim();
|
|
153
|
+
// Drop leading "1K views · 51 reactions | " / "230 likes, 12 comments - " noise.
|
|
154
|
+
t = t.replace(/^\s*(?:[\d.,]+\s*[KMB]?\s*(?:views?|likes?|reactions?|comments?|shares?|followers?)\b\s*[·,|–\-:]*\s*)+/i, '').trim();
|
|
155
|
+
// FB/TikTok pack "title | extra | hashtags" — keep the first real segment.
|
|
156
|
+
const seg = t.split(/\s*[|·]\s*/)[0].trim();
|
|
157
|
+
if (seg.length >= 8)
|
|
158
|
+
t = seg;
|
|
159
|
+
if (t.length > 90)
|
|
160
|
+
t = t.slice(0, 90).replace(/\s+\S*$/, '').trim() + '…';
|
|
161
|
+
return t.slice(0, 120);
|
|
162
|
+
}
|
|
147
163
|
// Download a source video across YouTube / TikTok / Douyin / Facebook.
|
|
148
164
|
// yt-dlp supports all of them, but a single rigid `-f` that works for
|
|
149
165
|
// YouTube fails on the others, so try a tolerant 720p-capped format then
|
|
@@ -153,6 +169,10 @@ async function downloadSourceVideo(url, dest) {
|
|
|
153
169
|
const platform = detectPlatform(url);
|
|
154
170
|
const common = [
|
|
155
171
|
'--no-playlist', '--no-warnings', '--retries', '3', '--fragment-retries', '3',
|
|
172
|
+
// dest ends in .mp4 — force merged/odd containers to mp4 so the file
|
|
173
|
+
// lands EXACTLY at `dest` (else fs.rename → ENOENT, e.g. YouTube shorts
|
|
174
|
+
// where bv*+ba merges to .mkv/.webm).
|
|
175
|
+
'--merge-output-format', 'mp4', '--remux-video', 'mp4',
|
|
156
176
|
'--user-agent', SRC_UA, ...cookieArgs(), '-o', dest, url,
|
|
157
177
|
];
|
|
158
178
|
const attempts = [
|
|
@@ -522,7 +542,7 @@ export async function analyzeVideo(url, onProgress) {
|
|
|
522
542
|
let source_title = '';
|
|
523
543
|
try {
|
|
524
544
|
const t = await run(YT_DLP, ['--skip-download', '--no-warnings', '--no-playlist', '--user-agent', SRC_UA, ...cookieArgs(), '--print', '%(title)s', url]);
|
|
525
|
-
source_title = (t.out
|
|
545
|
+
source_title = cleanSourceTitle(t.out);
|
|
526
546
|
}
|
|
527
547
|
catch { /* title is best-effort — analysis still proceeds without it */ }
|
|
528
548
|
progress('Đang tách audio...');
|