diff --git a/.Dockerfile.kate-swp b/.Dockerfile.kate-swp new file mode 100644 index 0000000..5aa81cf Binary files /dev/null and b/.Dockerfile.kate-swp differ diff --git a/src/bot.js b/src/bot.js index 126799d..e06122c 100644 --- a/src/bot.js +++ b/src/bot.js @@ -50,6 +50,19 @@ try { const ytLinkRegexp = /^https:\/\/www\.youtube\.com/m; +async function getFileSize(pathname) { + const stream = fs.createReadStream(pathname); + let size = 0; + return await new Promise((resolve, reject) => { + stream.on("data", data => size += data.length); + stream.on("end", () => resolve(size)); + stream.on("error", reject); + }); +} + +// Check if download process +const tgChatsDownloaded = new Object(); + class TgBotSender { constructor(parent, bot, msg, memory = {}) { this.parent = parent; @@ -90,15 +103,25 @@ class TgBotSender { const filename = `${(new Date()).getTime()}.${quality.exc}`; const isStream = path.join(__dirname, `tmp/${filename}`); + let uploadFileInterval = null; const finallyHandler = (result) => { - if (isStream) { + clearInterval(uploadFileInterval); + //delete tgChatsDownloaded[msg.chat.id]; + if (isStream && isStream !== true) { fs.rm(isStream, { recursive: true, force: true }, () => {}); if (result) fs.rm(result, { recursive: true, force: true }, () => {}); } }; - video + const errHandler = (err) => { + console.error(err.stack); + //this.bot.sendMessage(msg.chat.id, "Download failed"); + sent.text("Download failed"); + finallyHandler(); + } + + await video .download(({ percent, downloaded, fine, msg }) => { //console.debug({ percent, fine, downloaded, msg }); const now = new Date(); @@ -111,41 +134,47 @@ class TgBotSender { }, isStream) .then(async (downloaded) => { console.debug("downloaded:", downloaded); - if (downloaded.format.type === "video") { - await this.bot.sendChatAction(msg.chat.id, 'upload_document'); - const uploadFileInterval = setInterval(() => { - this.bot.sendChatAction(msg.chat.id, 'upload_document'); - }, 4250); - await new Promise(r => setTimeout(r, 3000)); - await this.bot.sendVideo( - msg.chat.id, - downloaded.data, - { caption: info.title }, - { - filename, - contentType: isStream === true ? "application/octet-stream" : downloaded.format.mime, - //contentType: downloaded.format.mime, - }, - ); - clearInterval(uploadFileInterval); - } else if (downloaded.format.type === "audio") { - await this.bot.sendAudio( - msg.chat.id, - downloaded.data, - { caption: info.title }, - { - filename: `downloaded.${downloaded.format.exc}`, - contentType: downloaded.format.mime, - }, - ); + try { + if (downloaded.format.type === "video") { + const filesize = typeof isStream !== "string" ? 0 : await getFileSize(downloaded.data); + //console.debug("filesize:", filesize); + if (filesize < 50 * 1024 * 1024) { + await this.bot.sendChatAction(msg.chat.id, 'upload_document'); + uploadFileInterval = setInterval(() => { + this.bot.sendChatAction(msg.chat.id, 'upload_document'); + }, 4250); + await new Promise(r => setTimeout(r, 3000)); + await this.bot.sendVideo( + msg.chat.id, + downloaded.data, + { caption: info.title }, + { + filename, + contentType: isStream === true ? "application/octet-stream" : downloaded.format.mime, + //contentType: downloaded.format.mime, + }, + ); + } else { + return await sent.text(`Maximum filesize reached. Try any types (Current file: ${ + ((filesize / (1024 * 1024))+"").split(".")[0] + } MB)`); + } + } else if (downloaded.format.type === "audio") { + await this.bot.sendAudio( + msg.chat.id, + downloaded.data, + { caption: info.title }, + { + filename: `downloaded.${downloaded.format.exc}`, + contentType: downloaded.format.mime, + }, + ); + } + } catch (err) { + return errHandler(err); } finallyHandler(downloaded.data); - }) - .catch((err) => { - console.error(err.stack); - this.bot.sendMessage(msg.chat.id, "Download failed"); - finallyHandler(); - }); + }).catch(errHandler); } } @@ -202,7 +231,12 @@ class TgBot { async cbHandler(query) { const key = query.from.id + ":" + query.data; //console.debug(query, this.videosGC.actions[key], key); - this.videosGC.actions[key]?.(); + if (!this.videosGC.actions[key]) + return this.bot.answerCallbackQuery(query.id, { + text: "Resend me video link, please", + show_alert: true + }); + this.videosGC.actions[key](query.id); } async send(msg, txt) { @@ -270,12 +304,23 @@ class TgBot { const qualityItem = qualities[quality]; const actKey = msg.from.id + ":" + quality + "_" + msg.message_id; - this.videosGC.register(actKey, () => { + this.videosGC.register(actKey, async (queryId) => { //console.debug("ACT btn:", actKey); + if (tgChatsDownloaded[msg.from.id]) + return this.bot.answerCallbackQuery(queryId, { + text: 'Wait until download was not finished', + show_alert: true + }); + tgChatsDownloaded[msg.from.id] = true; sent .download(video, qualityItem) - .then(() => {}) - .catch(errHandler); + .then(() => { + delete tgChatsDownloaded[msg.from.id]; + }) + .catch((err) => { + errHandler(err); + delete tgChatsDownloaded[msg.from.id]; + }); }, video); /*this.videosGC.actions[actKey] = () => { sent diff --git a/src/download.js b/src/download.js index 51ab7d6..b2e7c9e 100644 --- a/src/download.js +++ b/src/download.js @@ -223,7 +223,8 @@ class DownloadVideo { exc: f.ext, // <- расширение resolution, filesize: f.filesize || null, - mime: mimeType, type: !mimeType ? null : type + mime: mimeType, type: !mimeType ? null : type, + forceAll: () => f }; }); if (withDefaults) { @@ -268,29 +269,48 @@ class DownloadVideo { [this.quality.flag] : this.quality.flag; const params = [ "--cookies", "cookies.txt", + "--user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", + //"--extractor-args", "youtube:player-client=default,mweb;po_token=mweb.gvs+XXX", + "--extractor-args", "youtube:player_client=default,mweb", "-f", ...flags, "-o", !isPath ? "-" : isStream, this.url, ]; d("yt-dlp " + params.join(" ")); - const child = spawn("yt-dlp", params); + //console.debug({ HOME: process.env.HOME }); + const child = spawn("yt-dlp", params, { + env: { + ...process.env, + //HOME: process.env.HOME, + LANG: "en_US.UTF-8", + }, + stdio: ["pipe","pipe","pipe"], + //stdio: ["pipe","inherit","pipe"], + //stdio: ["inherit", "inherit", "inherit"], + }); let downloaded = 0; let percent = 0; let sizeTg = 0; let fine = false; const getDwnld = () => `Real size: ${downloaded}, total: ${sizeTg}`; - - child.stderr.on("data", (data) => { + + const stderrHandler = (data) => { const str = data.toString(); + //console.debug("DEBUG >>>>>>", str); //console.debug(str); const match = str.match(/(\d+\.\d+)%/); if (match && cb) { percent = parseFloat(match[1]); cb({ percent, downloaded: !isPath ? getDwnld() : "Processing", fine }); } - }); + }; + + child.stderr.on("data", stderrHandler); if (isPath) { + child.stdout.on("data", stderrHandler); + child.on("close", (code) => { + //console.debug(">>>>>>>>>>>>>FINISHED"); signal.emit("finish"); fine = true; if (code !== 0) { diff --git a/src/tmp/1761390915442.mp4 b/src/tmp/1761390915442.mp4 new file mode 100644 index 0000000..76d7755 Binary files /dev/null and b/src/tmp/1761390915442.mp4 differ diff --git a/src/tmp/1761390915442.mp4.converted.mp4 b/src/tmp/1761390915442.mp4.converted.mp4 new file mode 100644 index 0000000..3e8091f Binary files /dev/null and b/src/tmp/1761390915442.mp4.converted.mp4 differ