Created
January 16, 2026 17:01
-
-
Save weskerty/b66265b7d941c8f3717f3830d669b17d to your computer and use it in GitHub Desktop.
TelegramDownLoader Go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const fs = require('fs').promises; | |
| const {createReadStream, existsSync, statSync} = require('fs'); | |
| const path = require('path'); | |
| const {exec, spawn} = require('child_process'); | |
| const {promisify} = require('util'); | |
| const {execSync} = require('child_process'); | |
| const {bot, logger} = require('../lib'); | |
| const eP = promisify(exec); | |
| const LTO = 300000; | |
| const FT = { | |
| video: { | |
| ex: new Set(['mp4', 'mkv', 'avi', 'webm', 'mov', 'flv', 'm4v']), | |
| mt: 'video/mp4', | |
| }, | |
| image: { | |
| ex: new Set(['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'tiff', 'svg']), | |
| mt: 'image/jpeg', | |
| }, | |
| document: { | |
| ex: new Set(['pdf', 'epub', 'docx', 'txt', 'apk', 'apks', 'zip', 'rar', 'iso', 'ini', 'cbr', 'cbz', 'torrent', 'json', 'xml', 'html', 'css', 'js', 'csv', 'xls', 'xlsx', 'ppt', 'pptx']), | |
| mts: new Map([ | |
| ['pdf', 'application/pdf'], | |
| ['epub', 'application/epub+zip'], | |
| ['docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'], | |
| ['txt', 'text/plain'], | |
| ['apk', 'application/vnd.android.package-archive'], | |
| ['apks', 'application/vnd.android.package-archive'], | |
| ['zip', 'application/zip'], | |
| ['rar', 'application/x-rar-compressed'], | |
| ['iso', 'application/x-iso9660-image'], | |
| ['ini', 'text/plain'], | |
| ['cbr', 'application/x-cbr'], | |
| ['cbz', 'application/x-cbz'], | |
| ['torrent', 'application/x-bittorrent'], | |
| ['json', 'application/json'], | |
| ['xml', 'application/xml'], | |
| ['html', 'text/html'], | |
| ['css', 'text/css'], | |
| ['js', 'application/javascript'], | |
| ['csv', 'text/csv'], | |
| ['xls', 'application/vnd.ms-excel'], | |
| ['xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'], | |
| ['ppt', 'application/vnd.ms-powerpoint'], | |
| ['pptx', 'application/vnd.openxmlformats-officedocument.presentationml.presentation'], | |
| ]), | |
| dmt: 'application/octet-stream', | |
| }, | |
| audio: { | |
| ex: new Set(['mp3', 'wav', 'ogg', 'flac', 'm4a', 'aac', 'wma']), | |
| mt: 'audio/mpeg', | |
| }, | |
| }; | |
| function gFD(fP) { | |
| const e = path.extname(fP).slice(1).toLowerCase(); | |
| for (const [ct, tI] of Object.entries(FT)) { | |
| if (tI.ex.has(e)) { | |
| return { | |
| category: ct, | |
| mimetype: ct === 'document' | |
| ? tI.mts.get(e) || tI.dmt | |
| : tI.mt, | |
| }; | |
| } | |
| } | |
| return { | |
| category: 'document', | |
| mimetype: FT.document.dmt, | |
| }; | |
| } | |
| function fFS(bt) { | |
| if (bt < 1024) return bt + ' B'; | |
| if (bt < 1048576) return (bt / 1024).toFixed(2) + ' KB'; | |
| if (bt < 1073741824) return (bt / 1048576).toFixed(2) + ' MB'; | |
| return (bt / 1073741824).toFixed(2) + ' GB'; | |
| } | |
| function sWO(cmd, arg) { | |
| return new Promise((res, rej) => { | |
| const ch = spawn(cmd, arg, { | |
| stdio: ['ignore', 'inherit', 'inherit'] | |
| }); | |
| ch.on('error', (er) => { | |
| logger.error(`[T]Spw: ${er.message}`); | |
| rej(er); | |
| }); | |
| ch.on('close', (cd) => { | |
| if (cd === 0) { | |
| res(); | |
| } else { | |
| logger.error(`[T]X ${cd}`); | |
| rej(new Error(`Exit ${cd}`)); | |
| } | |
| }); | |
| }); | |
| } | |
| function sLg(cmd, arg) { | |
| return new Promise((res, rej) => { | |
| const ch = spawn(cmd, arg, { | |
| stdio: ['ignore', 'inherit', 'inherit'] | |
| }); | |
| const to = setTimeout(() => { | |
| logger.info('[T]Tmt'); | |
| ch.kill(); | |
| rej(new Error('Timeout')); | |
| }, LTO); | |
| ch.on('error', (er) => { | |
| clearTimeout(to); | |
| logger.error(`[T]LogE: ${er.message}`); | |
| rej(er); | |
| }); | |
| ch.on('close', (cd) => { | |
| clearTimeout(to); | |
| if (cd === 0) { | |
| res(); | |
| } else { | |
| logger.error(`[T]LogF: ${cd}`); | |
| rej(new Error(`LogX ${cd}`)); | |
| } | |
| }); | |
| }); | |
| } | |
| async function sEx(cmd, sE = false) { | |
| try { | |
| return await eP(cmd); | |
| } catch (er) { | |
| if (!sE) { | |
| logger.error(`[T]ExeE: ${er.message}`); | |
| } | |
| throw new Error('ExeF'); | |
| } | |
| } | |
| class RQ { | |
| constructor(mC = 1) { | |
| this.q = []; | |
| this.aR = 0; | |
| this.mC = mC; | |
| } | |
| async aRq(tp, tk, m) { | |
| return new Promise((res, rej) => { | |
| this.q.push({tp, tk, m, res, rej}); | |
| this.pN(); | |
| }); | |
| } | |
| async pN() { | |
| if (this.aR >= this.mC || this.q.length === 0) { | |
| return; | |
| } | |
| this.aR++; | |
| const {tk, res, rej} = this.q.shift(); | |
| try { | |
| const rt = await tk(); | |
| res(rt); | |
| } catch (er) { | |
| rej(er); | |
| } finally { | |
| this.aR--; | |
| this.pN(); | |
| } | |
| } | |
| } | |
| class TDLDownloader { | |
| constructor() { | |
| this.cx = null; | |
| this.rQ = null; | |
| this.sTd = null; | |
| this.sR = new Map(); | |
| this.fNM = new Map(); | |
| this.cDF = new Set(); | |
| this.cSD = null; | |
| this.miniSearch = null; | |
| this.fI = false; | |
| } | |
| setContext(cx) { | |
| this.cx = cx; | |
| const jsonBaseDir = cx.AMULEDOWNLOADS || | |
| cx.TEMP_DOWNLOAD_DIR || | |
| path.join(process.cwd(), 'tmp'); | |
| this.cf = { | |
| tempDir: cx.TEMP_DOWNLOAD_DIR || path.join(process.cwd(), 'tmp'), | |
| jsonDir: path.join(jsonBaseDir, 'tdl_exports'), | |
| indexPath: path.join(jsonBaseDir, 'tdl_exports', 'search_index.json'), | |
| tdlPath: path.join(process.cwd(), 'media', 'bin', 'tdl'), | |
| chatIds: (cx.CHATSTELEGRAMID || '1143692078').split(',').map(id => id.trim()), | |
| shouldDeleteTempFiles: cx.DELETE_TEMP_FILE !== 'false', | |
| maxConcurrent: parseInt(cx.MAXSOLICITUD, 10) || 1 | |
| }; | |
| this.rQ = new RQ(this.cf.maxConcurrent); | |
| } | |
| async cIF() { | |
| try { | |
| require.resolve('minisearch'); | |
| this.fI = true; | |
| logger.info('[T] MiniSearch ya instalado'); | |
| return true; | |
| } catch (er) { | |
| try { | |
| logger.info('[T] Instalando MiniSearch...'); | |
| await eP('npm install minisearch --force --no-save --ignore-peer-deps', { | |
| cwd: process.cwd() | |
| }); | |
| delete require.cache[require.resolve('minisearch')]; | |
| this.fI = true; | |
| logger.info('[T] β MiniSearch instalado'); | |
| return true; | |
| } catch (iE) { | |
| logger.error('[T]MiniF:', iE.message); | |
| this.fI = false; | |
| return false; | |
| } | |
| } | |
| } | |
| async eD() { | |
| await Promise.all([ | |
| fs.mkdir(this.cf.jsonDir, {recursive: true}), | |
| fs.mkdir(this.cf.tempDir, {recursive: true}), | |
| fs.mkdir(path.dirname(this.cf.tdlPath), {recursive: true}) | |
| ]); | |
| } | |
| async fST() { | |
| try { | |
| await eP('tdl version'); | |
| this.sTd = 'tdl'; | |
| return true; | |
| } catch { | |
| return false; | |
| } | |
| } | |
| async gTP() { | |
| if (!this.sTd && await this.fST()) { | |
| return this.sTd; | |
| } | |
| if (this.sTd) return this.sTd; | |
| try { | |
| await fs.access(this.cf.tdlPath); | |
| return this.cf.tdlPath; | |
| } catch { | |
| return this.dTd(); | |
| } | |
| } | |
| async dTd() { | |
| const dU = 'https://github.com/iyear/tdl/releases/latest/download/tdl_Linux_64bit.tar.gz'; | |
| const tD = path.dirname(this.cf.tdlPath); | |
| const tP = path.join(tD, 'tdl_Linux_64bit.tar.gz'); | |
| await fs.mkdir(tD, {recursive: true}); | |
| try { | |
| await sEx(`curl -L -o "${tP}" "${dU}"`); | |
| } catch { | |
| try { | |
| const fetch = (await import('node-fetch')).default; | |
| const rp = await fetch(dU); | |
| if (!rp.ok) throw new Error(`DlF: ${rp.statusText}`); | |
| const bf = Buffer.from(await rp.arrayBuffer()); | |
| await fs.writeFile(tP, bf); | |
| } catch (er) { | |
| throw new Error(`DlE: ${er.message}`); | |
| } | |
| } | |
| await sEx(`tar -xzf "${tP}" -C "${tD}"`); | |
| await fs.chmod(this.cf.tdlPath, '755'); | |
| await fs.unlink(tP).catch(() => {}); | |
| return this.cf.tdlPath; | |
| } | |
| async lTd() { | |
| const tP = await this.gTP(); | |
| await sLg(tP, ['login', '-T', 'qr']); | |
| } | |
| mkD() { | |
| const sI = `tdl_${Date.now()}`; | |
| this.cSD = path.join(this.cf.tempDir, 'tdl', sI); | |
| return this.cSD; | |
| } | |
| async sCl(tg, rt = 3) { | |
| if (!tg) return; | |
| for (let i = 0; i < rt; i++) { | |
| try { | |
| const st = await fs.stat(tg); | |
| if (st.isDirectory()) { | |
| await fs.rm(tg, {recursive: true, force: true}); | |
| } else { | |
| await fs.unlink(tg); | |
| } | |
| return; | |
| } catch (er) { | |
| if (er.code === 'ENOENT') { | |
| return; | |
| } | |
| if (i === rt - 1) { | |
| logger.error(`[T]ClF ${tg}: ${er.message}`); | |
| return; | |
| } | |
| await new Promise(r => setTimeout(r, 1000 * (i + 1))); | |
| } | |
| } | |
| } | |
| async cF() { | |
| if (!this.cf.shouldDeleteTempFiles) return; | |
| try { | |
| if (this.cSD) { | |
| await this.sCl(this.cSD); | |
| } | |
| this.cDF.clear(); | |
| this.cSD = null; | |
| } catch (er) { | |
| logger.error('[T]Cl:', er); | |
| } | |
| } | |
| async cAF() { | |
| if (!this.cf.shouldDeleteTempFiles) return; | |
| try { | |
| const jF = await fs.readdir(this.cf.jsonDir); | |
| for (const fl of jF) { | |
| if (fl.startsWith('selected_') || fl.startsWith('temp_')) { | |
| await this.sCl(path.join(this.cf.jsonDir, fl)); | |
| } | |
| } | |
| } catch (er) { | |
| logger.error('[T]ClAll:', er); | |
| } | |
| } | |
| async dTL(m, url) { | |
| return this.rQ.aRq('download', async () => { | |
| const tP = await this.gTP(); | |
| const sD = this.mkD(); | |
| try { | |
| await this.eD(); | |
| await fs.mkdir(sD, {recursive: true}); | |
| await this.cF(); | |
| this.cDF.clear(); | |
| const ag = ['dl', '--skip-same', '--template', '{{ filenamify .FileName }}', '-d', sD]; | |
| for (const u of url) { | |
| ag.push('-u', u); | |
| } | |
| await sWO(tP, ag); | |
| await this.pDF(m, sD); | |
| } catch (er) { | |
| throw new Error(`Err dl: ${er.message}`); | |
| } finally { | |
| if (this.cf.shouldDeleteTempFiles) { | |
| await this.cF(); | |
| } | |
| } | |
| }, m); | |
| } | |
| async eAC() { | |
| const tP = await this.gTP(); | |
| await this.eD(); | |
| const rt = []; | |
| for (const cI of this.cf.chatIds) { | |
| const eF = path.join(this.cf.jsonDir, `export_${cI}.json`); | |
| if (existsSync(eF)) { | |
| rt.push({chatId: cI, file: eF, success: true, skipped: true}); | |
| continue; | |
| } | |
| try { | |
| await sWO(tP, ['chat', 'export', '-c', cI, '-o', eF]); | |
| rt.push({chatId: cI, file: eF, success: true, skipped: false}); | |
| } catch (er) { | |
| logger.error(`[T]ExpF ${cI}: ${er.message}`); | |
| rt.push({chatId: cI, error: er.message, success: false, skipped: false}); | |
| } | |
| } | |
| this.miniSearch = null; | |
| try { | |
| await fs.unlink(this.cf.indexPath); | |
| logger.info('[T] Γndice invalidado'); | |
| } catch {} | |
| return rt; | |
| } | |
| async cDA() { | |
| try { | |
| const jF = await fs.readdir(this.cf.jsonDir); | |
| for (const fl of jF) { | |
| if (fl.startsWith('export_') && fl.endsWith('.json')) { | |
| const fP = path.join(this.cf.jsonDir, fl); | |
| const st = await fs.stat(fP); | |
| const sM = new Date(); | |
| sM.setMonth(sM.getMonth() - 6); | |
| if (st.mtime < sM) return true; | |
| } | |
| } | |
| return false; | |
| } catch { | |
| return false; | |
| } | |
| } | |
| async loadOrCreateIndex() { | |
| try { | |
| if (existsSync(this.cf.indexPath)) { | |
| const indexData = await fs.readFile(this.cf.indexPath, 'utf8'); | |
| const MiniSearch = require('minisearch'); | |
| this.miniSearch = MiniSearch.loadJSON(indexData, { | |
| fields: ['fileName'], | |
| storeFields: ['id', 'chatId', 'messageId', 'fileName', 'from', 'file_size'] | |
| }); | |
| logger.info('[T] Γndice cargado desde disco'); | |
| return; | |
| } | |
| } catch (err) { | |
| logger.warn('[T] Error cargando Γndice, recreando...', err.message); | |
| } | |
| await this.buildAndSaveIndex(); | |
| } | |
| async buildAndSaveIndex() { | |
| if (!this.fI) { | |
| throw new Error('MiniSearch no estΓ‘ instalado'); | |
| } | |
| const MiniSearch = require('minisearch'); | |
| this.miniSearch = new MiniSearch({ | |
| fields: ['fileName'], | |
| storeFields: ['id', 'chatId', 'messageId', 'fileName', 'from', 'file_size'], | |
| processTerm: (term) => term | |
| .toLowerCase() | |
| .normalize('NFD') | |
| .replace(/[\u0300-\u036f]/g, '') | |
| .replace(/[^a-z0-9]/g, ' ') | |
| .trim(), | |
| searchOptions: { | |
| prefix: true, | |
| fuzzy: 0.2, | |
| combineWith: 'AND' | |
| } | |
| }); | |
| let totalDocs = 0; | |
| const allFiles = await fs.readdir(this.cf.jsonDir); | |
| const exportFiles = allFiles.filter(f => f.startsWith('export_') && f.endsWith('.json')); | |
| logger.info(`[T] Indexando ${exportFiles.length} archivos JSON...`); | |
| for (const fileName of exportFiles) { | |
| const jF = path.join(this.cf.jsonDir, fileName); | |
| const chatIdMatch = fileName.match(/^export_(.+)\.json$/); | |
| if (!chatIdMatch) continue; | |
| const cI = chatIdMatch[1]; | |
| try { | |
| const fC = await fs.readFile(jF, 'utf8'); | |
| const jD = JSON.parse(fC); | |
| if (jD?.messages && Array.isArray(jD.messages)) { | |
| const docs = jD.messages | |
| .filter(mg => mg.file_name || mg.file) | |
| .map(mg => ({ | |
| id: `${cI}_${mg.id}`, | |
| chatId: cI, | |
| messageId: mg.id, | |
| fileName: mg.file_name || mg.file, | |
| from: mg.from || null, | |
| file_size: mg.file_size | |
| })); | |
| if (docs.length > 0) { | |
| this.miniSearch.addAll(docs); | |
| totalDocs += docs.length; | |
| logger.info(`[T] ${fileName}: ${docs.length} archivos`); | |
| } | |
| } | |
| } catch (pE) { | |
| logger.error(`[T]PaF ${jF}: ${pE.message}`); | |
| } | |
| } | |
| const indexData = JSON.stringify(this.miniSearch); | |
| await fs.writeFile(this.cf.indexPath, indexData); | |
| logger.info(`[T] Γndice creado con ${totalDocs} documentos de ${exportFiles.length} chats`); | |
| } | |
| async sIC(m, sQ) { | |
| return this.rQ.aRq('search', async () => { | |
| await this.eD(); | |
| this.sR.clear(); | |
| this.fNM.clear(); | |
| let nE = false; | |
| try { | |
| for (const cI of this.cf.chatIds) { | |
| const eF = path.join(this.cf.jsonDir, `export_${cI}.json`); | |
| if (!existsSync(eF)) { | |
| nE = true; | |
| break; | |
| } | |
| } | |
| if (nE) { | |
| await this.eAC(); | |
| } | |
| if (!this.miniSearch) { | |
| await this.loadOrCreateIndex(); | |
| } | |
| const iO = await this.cDA(); | |
| const results = this.miniSearch.search(sQ, { | |
| prefix: true, | |
| fuzzy: 0.2, | |
| combineWith: 'AND' | |
| }); | |
| if (results.length === 0) { | |
| const T1 = iO ? | |
| `DB antigua\nSin res: "${sQ}"` : | |
| `Sin res: "${sQ}"`; | |
| await m.send(T1, {quoted: m.data}); | |
| return; | |
| } | |
| const chatResults = new Map(); | |
| results.forEach((result, index) => { | |
| const rI = index + 1; | |
| const cI = result.chatId; | |
| if (!chatResults.has(cI)) { | |
| chatResults.set(cI, { | |
| chatId: cI, | |
| name: `Chat ${cI}`, | |
| results: [] | |
| }); | |
| } | |
| const fM = { | |
| from: result.from, | |
| size: result.file_size ? fFS(result.file_size) : null | |
| }; | |
| chatResults.get(cI).results.push({ | |
| id: result.messageId, | |
| file: result.fileName, | |
| resultIndex: rI, | |
| metadata: fM | |
| }); | |
| this.sR.set(rI, { | |
| chatId: cI, | |
| messageId: result.messageId, | |
| file: result.fileName, | |
| metadata: fM | |
| }); | |
| this.fNM.set(`${result.messageId}_${this.sFN(result.fileName)}`, result.fileName); | |
| }); | |
| let rM = iO ? "DB antigua\n" : ""; | |
| rM += `${results.length} βππππππΆπΉππ\n> _Usa tdl dd 1,2,etc_\n`; | |
| for (const cRs of chatResults.values()) { | |
| for (const rs of cRs.results) { | |
| rM += `\`${rs.resultIndex}\` ${rs.file}\n`; | |
| if (rs.metadata) { | |
| const mI = []; | |
| if (rs.metadata.from) mI.push(`*De:* _${rs.metadata.from}_`); | |
| if (rs.metadata.size) mI.push(`*Peso:* _${rs.metadata.size}_`); | |
| if (mI.length > 0) { | |
| rM += `> ${mI.join(', ')}\n`; | |
| } | |
| } | |
| rM += '\n'; | |
| } | |
| } | |
| await m.send(rM, {quoted: m.data}); | |
| } catch (er) { | |
| throw new Error(`Err bus: ${er.message}`); | |
| } | |
| }, m); | |
| } | |
| sFN(fN) { | |
| return fN.replace(/[<>:"/\\|?*]/g, '_'); | |
| } | |
| async cSJ(idx) { | |
| const sI = new Map(); | |
| for (const ix of idx) { | |
| const it = this.sR.get(parseInt(ix)); | |
| if (it) { | |
| if (!sI.has(it.chatId)) { | |
| sI.set(it.chatId, []); | |
| } | |
| sI.get(it.chatId).push({ | |
| id: it.messageId, | |
| type: "message", | |
| file: it.file | |
| }); | |
| } | |
| } | |
| const jF = []; | |
| for (const [cI, mg] of sI.entries()) { | |
| const jC = { | |
| id: parseInt(cI), | |
| messages: mg | |
| }; | |
| const jP = path.join(this.cf.jsonDir, `selected_${cI}_${Date.now()}.json`); | |
| await fs.writeFile(jP, JSON.stringify(jC)); | |
| jF.push(jP); | |
| } | |
| return jF; | |
| } | |
| async dSI(m, idx) { | |
| return this.rQ.aRq('download', async () => { | |
| const tP = await this.gTP(); | |
| const sD = this.mkD(); | |
| try { | |
| await this.eD(); | |
| await fs.mkdir(sD, {recursive: true}); | |
| await this.cF(); | |
| this.cDF.clear(); | |
| if (this.sR.size === 0) { | |
| throw new Error('Sin res'); | |
| } | |
| const sI = idx | |
| .map(ix => parseInt(ix.trim())) | |
| .filter(ix => !isNaN(ix) && this.sR.has(ix)); | |
| if (sI.length === 0) { | |
| throw new Error('Sin sel'); | |
| } | |
| const jF = await this.cSJ(sI); | |
| if (jF.length === 0) { | |
| throw new Error('Err sel'); | |
| } | |
| await m.send(`Descargando ${sI.length} archivos...`, {quoted: m.data}); | |
| const ag = ['dl', '--skip-same', '--template', '{{ filenamify .FileName }}', '-d', sD]; | |
| for (const jFl of jF) { | |
| ag.push('-f', jFl); | |
| } | |
| await sWO(tP, ag); | |
| await this.pDF(m, sD); | |
| } catch (er) { | |
| throw new Error(`Err dl: ${er.message}`); | |
| } finally { | |
| await this.cAF(); | |
| if (this.cf.shouldDeleteTempFiles) { | |
| await this.cF(); | |
| } | |
| } | |
| }, m); | |
| } | |
| async pDF(m, sD) { | |
| try { | |
| const fl = await fs.readdir(sD); | |
| if (fl.length === 0) { | |
| await m.send("Sin archivos", {quoted: m.data}); | |
| return; | |
| } | |
| for (const f of fl) { | |
| const fP = path.join(sD, f); | |
| try { | |
| const st = await fs.stat(fP); | |
| if (st.isDirectory()) { | |
| continue; | |
| } | |
| const {category, mimetype} = gFD(fP); | |
| const fB = await fs.readFile(fP); | |
| const bn = path.basename(fP); | |
| const mt = bn.match(/^(\d+)_(.+)$/); | |
| let fN = bn; | |
| if (mt && mt.length >= 3) { | |
| const mI = parseInt(mt[1]); | |
| for (const [ky, oN] of this.fNM.entries()) { | |
| if (ky.startsWith(`${mI}_`)) { | |
| fN = oN; | |
| break; | |
| } | |
| } | |
| } | |
| await m.send(fB, { | |
| fileName: fN, | |
| mimetype: mimetype, | |
| quoted: m.data | |
| }, category); | |
| } catch (er) { | |
| logger.error(`[T]EnvF ${f}: ${er.message}`); | |
| } | |
| } | |
| } catch (er) { | |
| logger.error(`[T]ProcE: ${er.message}`); | |
| await m.send(`Error: ${er.message}`, {quoted: m.data}); | |
| } | |
| } | |
| } | |
| const tdlDownloader = new TDLDownloader(); | |
| bot( | |
| { | |
| pattern: 'tdl ?(.*)', | |
| fromMe: true, | |
| desc: 'Buscar y descargar archivos de chats de Telegram usando TDL.', | |
| type: 'download', | |
| }, | |
| async (message, match, ctx) => { | |
| tdlDownloader.setContext(ctx); | |
| if (!tdlDownloader.fI) { | |
| try { | |
| await tdlDownloader.cIF(); | |
| } catch (error) { | |
| return await message.send(`β Error instalando MiniSearch: ${error.message}`, {quoted: message.data}); | |
| } | |
| if (!tdlDownloader.fI) { | |
| return await message.send('β MiniSearch es requerido pero no se pudo instalar', {quoted: message.data}); | |
| } | |
| } | |
| const inp = match.trim() || message.reply_message?.text || ''; | |
| if (!inp) { | |
| await message.send( | |
| '> π Buscar: `tdl` <busqueda>\n' + | |
| '> π₯ Descargar: `tdl dd` <indices>\n' + | |
| '> π Enlace: `tdl` <https://t.me/...>\n' + | |
| '> π Login: `tdl login`\n' + | |
| '> πΎ Exportar: `tdl export`\n' + | |
| '> π Actualizar: `tdl update`', | |
| {quoted: message.data} | |
| ); | |
| return; | |
| } | |
| try { | |
| const arg = inp.split(' '); | |
| if (arg[0].toLowerCase() === 'login') { | |
| await message.send('Escanea QR en terminal', {quoted: message.data}); | |
| await tdlDownloader.lTd(); | |
| await message.send('Login exitoso', {quoted: message.data}); | |
| return; | |
| } | |
| if (arg[0].toLowerCase() === 'update') { | |
| const tP = await tdlDownloader.dTd(); | |
| await message.send(`TDL actualizado: ${tP}`, {quoted: message.data}); | |
| return; | |
| } | |
| if (arg[0].toLowerCase() === 'export') { | |
| await message.send(`Exportando chats...`, {quoted: message.data}); | |
| const rt = await tdlDownloader.eAC(); | |
| const sC = rt.filter(r => r.success).length; | |
| await message.send(`Exportados ${sC}/${rt.length} chats`, {quoted: message.data}); | |
| return; | |
| } | |
| if (arg[0].toLowerCase() === 'dd') { | |
| const idx = arg.slice(1).join('').split(/[,\s]+/); | |
| await tdlDownloader.dSI(message, idx); | |
| return; | |
| } | |
| const tL = arg.filter(a => /^https?:\/\/(t\.me|telegram\.me)\//i.test(a)); | |
| if (tL.length > 0) { | |
| await tdlDownloader.dTL(message, tL); | |
| return; | |
| } | |
| await tdlDownloader.sIC(message, inp); | |
| } catch (er) { | |
| await message.send(`Error: ${er.message}`, {quoted: message.data}); | |
| } | |
| } | |
| ); | |
| module.exports = {tdlDownloader}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment