From a47c8bb83a09c8a0196a168c2630160839cd5de5 Mon Sep 17 00:00:00 2001 From: FullGreaM Date: Sun, 9 Nov 2025 14:51:51 +0300 Subject: [PATCH] Add thumb fix + configure empty preview image --- src/bot.js | 2 +- src/config.js | 1 + src/download.js | 65 +++++++++++-------------------------------------- src/utils.js | 58 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 52 deletions(-) create mode 100644 src/utils.js diff --git a/src/bot.js b/src/bot.js index dfd83b0..fa90c8b 100644 --- a/src/bot.js +++ b/src/bot.js @@ -420,7 +420,7 @@ class TgBot { { type: "photo", //media: info.thumbnail, - media: "https://placekitten.com/500/350", + media: config.emptyImage, caption: info.title, }, { diff --git a/src/config.js b/src/config.js index 8cf7d61..3c58f4d 100644 --- a/src/config.js +++ b/src/config.js @@ -8,6 +8,7 @@ const config = { session: process.env.API_SESSION, chatId: +process.env.CHAT_ID, }, + emptyImage: process.env.EMPTY_IMAGE_URL ?? "https://placekitten.com/500/350", }; config.whitelist = [].concat( process.env.WHITELIST?.split(/\s*,\s*/g).map((x) => +x) ?? [], diff --git a/src/download.js b/src/download.js index 532011c..e7c08bf 100644 --- a/src/download.js +++ b/src/download.js @@ -3,59 +3,16 @@ const { Readable } = require("stream"); const EventEmitter = require("events"); const mime = require("mime"); const path = require("path"); -const http = require("http"); -const https = require("https"); const { URL } = require("url"); const fs = require("fs"); const FFMPEG = require("./ffmpeg"); +const config = require("./config"); +const { downloadFile, verifyThumbUrl } = require("./utils"); const formatsCache = new Map(); const infoCache = new Map(); const d = r => console.debug("DEBUG:", r) || r; - -async function downloadFile(fileUrl) { - return new Promise((resolve, reject) => { - try { - const url = new URL(fileUrl); - const protocol = url.protocol === "https:" ? https : http; - - const extMatch = path.extname(url.pathname).split("?")[0]; - const extension = extMatch ? extMatch.replace(".", "") : "tmp"; - - const filename = `${Date.now()}.${extension}`; - const savePath = path.join(__dirname, "tmp", filename); - - fs.mkdirSync(path.dirname(savePath), { recursive: true }); - - const file = fs.createWriteStream(savePath); - - protocol.get(fileUrl, (response) => { - if (response.statusCode !== 200) { - return reject( - new Error(`Failed to get '${fileUrl}' (${response.statusCode})`) - ); - } - - response.pipe(file); - - file.on("finish", () => { - file.close(); - /*setTimeout(() => { - fs.rm(savePath, () => {}); - }, 60000);*/ - resolve(savePath); - }); - }).on("error", (err) => { - fs.unlinkSync(savePath); - reject(err); - }); - } catch (err) { - reject(err); - } - }); -} - class YtdlUpdater extends EventEmitter { constructor () { super(); @@ -172,12 +129,19 @@ class DownloadVideo { console.error("yt-dlp error:", err.toString()); }); - child.on("close", code => { + child.on("close", async code => { if (code !== 0) return reject(new Error("yt-dlp failed to get info")); try { const info = JSON.parse(data); - + + const thumbnails = + (await Promise.all(info.thumbnails.map(async thumbnail => { + const verified = await verifyThumbUrl(thumbnail.url); + if (!verified) return null; + return thumbnail; + }))).filter(x => x !== null); + resolve({ id: info.id, title: info.title, @@ -185,10 +149,10 @@ class DownloadVideo { uploader: info.uploader, duration: info.duration, thumbnail: - info.thumbnails?.[info.thumbnails.length - 1]?.url || - info.thumbnail, + (thumbnails?.[thumbnails.length - 1]?.url || + info.thumbnail) || config.emptyImage, url: info.webpage_url, - thumbnails: info.thumbnails + thumbnails }); } catch (e) { reject(e); @@ -314,7 +278,6 @@ class DownloadVideo { "-f", ...flags, "-o", !isPath ? "-" : isStream, this.url, ]; - d("yt-dlp " + params.join(" ")); const child = spawn("yt-dlp", params, { env: { ...process.env, diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..558cbd3 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,58 @@ +const http = require("http"); +const https = require("https"); +const path = require("path"); +const fs = require("fs"); + +async function downloadFile (fileUrl) { + return new Promise((resolve, reject) => { + try { + const url = new URL(fileUrl); + const protocol = url.protocol === "https:" ? https : http; + + const extMatch = path.extname(url.pathname).split("?")[0]; + const extension = extMatch ? extMatch.replace(".", "") : "tmp"; + + const filename = `${Date.now()}.${extension}`; + const savePath = path.join(__dirname, "tmp", filename); + + fs.mkdirSync(path.dirname(savePath), { recursive: true }); + + const file = fs.createWriteStream(savePath); + + protocol.get(fileUrl, (response) => { + if (response.statusCode !== 200) { + return reject( + new Error(`Failed to get '${fileUrl}' (${response.statusCode})`) + ); + } + + response.pipe(file); + + file.on("finish", () => { + file.close(); + /*setTimeout(() => { + fs.rm(savePath, () => {}); + }, 60000);*/ + resolve(savePath); + }); + }).on("error", (err) => { + fs.unlinkSync(savePath); + reject(err); + }); + } catch (err) { + reject(err); + } + }); +} + +async function verifyThumbUrl (fileUrl) { + try { + if (/\.webp$/m.test(fileUrl)) return false; + await downloadFile(fileUrl); + return true; + } catch (_) { + return false; + } +} + +module.exports = { downloadFile, verifyThumbUrl };