Spaces:
Paused
Paused
- lib/twt.js +52 -45
lib/twt.js
CHANGED
|
@@ -1,54 +1,61 @@
|
|
| 1 |
-
const {
|
| 2 |
const path = require("path");
|
| 3 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
/**
|
| 5 |
* Mengambil metadata video Twitter menggunakan yt-dlp.
|
| 6 |
* @param {string} url - URL tweet yang berisi video.
|
| 7 |
* @returns {Promise<Object>} - Metadata video dalam format JSON.
|
| 8 |
*/
|
| 9 |
async function getTwitterVideoInfo(url) {
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
bitrate: a.abr,
|
| 41 |
-
url: a.url
|
| 42 |
-
}))
|
| 43 |
-
};
|
| 44 |
-
|
| 45 |
-
resolve(res);
|
| 46 |
-
} catch (parseError) {
|
| 47 |
-
return { status: 500, message: e.message}
|
| 48 |
-
}
|
| 49 |
-
});
|
| 50 |
-
});
|
| 51 |
}
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
module.exports = getTwitterVideoInfo
|
|
|
|
| 1 |
+
const { spawn } = require("child_process");
|
| 2 |
const path = require("path");
|
| 3 |
|
| 4 |
+
const ytdlp = "yt-dlp"; // Asumsi yt-dlp sudah terinstall global di Docker
|
| 5 |
+
const cookiesPath = path.join(__dirname, "./cookies/twt.txt");
|
| 6 |
+
|
| 7 |
+
function runYtDlp(args) {
|
| 8 |
+
return new Promise((resolve, reject) => {
|
| 9 |
+
const process = spawn(ytdlp, args, { stdio: ["ignore", "pipe", "pipe"] });
|
| 10 |
+
let stdout = "";
|
| 11 |
+
let stderr = "";
|
| 12 |
+
|
| 13 |
+
process.stdout.on("data", (data) => (stdout += data.toString()));
|
| 14 |
+
process.stderr.on("data", (data) => (stderr += data.toString()));
|
| 15 |
+
|
| 16 |
+
process.on("close", (code) => {
|
| 17 |
+
if (code === 0) resolve(stdout.trim());
|
| 18 |
+
else reject(new Error(stderr.trim() || `yt-dlp exited with code ${code}`));
|
| 19 |
+
});
|
| 20 |
+
});
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
/**
|
| 24 |
* Mengambil metadata video Twitter menggunakan yt-dlp.
|
| 25 |
* @param {string} url - URL tweet yang berisi video.
|
| 26 |
* @returns {Promise<Object>} - Metadata video dalam format JSON.
|
| 27 |
*/
|
| 28 |
async function getTwitterVideoInfo(url) {
|
| 29 |
+
try {
|
| 30 |
+
const result = await runYtDlp(["-j", "--cookies", cookiesPath, url]);
|
| 31 |
+
const info = JSON.parse(result);
|
| 32 |
+
|
| 33 |
+
// Pastikan `formats` ada, jika tidak buat array kosong
|
| 34 |
+
const videoFormats = (info.formats || []).filter(
|
| 35 |
+
(f) => (f.video_ext !== "none" && f.audio_ext !== "none") || f.url.includes(".mp4")
|
| 36 |
+
);
|
| 37 |
+
|
| 38 |
+
const audioFormats = (info.formats || []).filter((f) => f.video_ext === "none" && f.audio_ext !== "none");
|
| 39 |
+
|
| 40 |
+
return {
|
| 41 |
+
status: 200,
|
| 42 |
+
title: info.title || "No Title",
|
| 43 |
+
description: info.description || "",
|
| 44 |
+
thumbnail: info.thumbnail || "",
|
| 45 |
+
video: videoFormats.map((v) => ({
|
| 46 |
+
format_id: v.format_id,
|
| 47 |
+
resolution: v.resolution || `${v.width}x${v.height}`,
|
| 48 |
+
url: v.url,
|
| 49 |
+
})),
|
| 50 |
+
audio: audioFormats.map((a) => ({
|
| 51 |
+
format_id: a.format_id,
|
| 52 |
+
bitrate: a.abr,
|
| 53 |
+
url: a.url,
|
| 54 |
+
})),
|
| 55 |
+
};
|
| 56 |
+
} catch (err) {
|
| 57 |
+
throw new Error(`Failed to get video info: ${err.message}`);
|
| 58 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
}
|
| 60 |
+
|
| 61 |
+
module.exports = getTwitterVideoInfo;
|
|
|