import { cfg } from "../cfg"; import sql from "../sql"; import fs from "fs"; import path from "path"; import crypto from "crypto"; import uuid from "uuid"; import cloudscraper from "cloudscraper"; import readChunk from "read-chunk"; import ytdl from "ytdl-core"; import request from "request"; import fileType from "file-type"; import { Readable } from "stream"; const checkRepost = (url, cbcr) => { sql.exec("select count(id) as count, id from `f0ck`.`items` where `src` = ?", url).then(rows => { cbcr((rows[0].count == 0)?true:rows[0].id); }); }; const checkRepostCheckSum = (cs, cbcrcs) => { sql.exec("select count(id) as count, id from `f0ck`.`items` where `checksum` = ?", cs).then(rows => { cbcrcs((rows[0].count == 0)?true:rows[0].id); }); }; const formatSize = size => { const i = ~~(Math.log(size) / Math.log(1024)); return (size / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i]; }; const getCheckSum = (file, cbcs) => { var sha256sum = crypto.createHash('sha256'); fs.ReadStream(file) .on('data', d => sha256sum.update(d)) .on('end', () => cbcs(sha256sum.digest('hex'))); }; export default bot => { bot._trigger.set("parser", new bot.trigger({ call: /https?:\/\/[\w-]+(\.[\w-]+)+\.?(:\d+)?(\/\S*)?/gi, f: e => { if(e.channel === "#kbot-dev" || e.message.match(/(!|-)f0ck/i)) { if(!e.message.match(/(!|-)ignore/)) { const tmp = e.message.match(/https?:\/\/[\w-]+(\.[\w-]+)+\.?(:\d+)?(\/\S*)?/gi); // get links tmp.forEach((entry,i,a) => { if(!entry.match(/f0ck\.me/i) && !entry.match(/\.onion/i)) { getLink(entry, ((e.message.match(/(!|-)force/i) && e.user.level.level >= 100)?true:false), e.user.level.level, cb => { if(cb.success === true) { fs.rename(cb.file, cb.file + '.' + cb.info.ext, (err) => { if(!err) { sql.exec("insert into `f0ck`.`items` (`src`,`dest`,`mime`,`size`,`checksum`,`username`,`userchannel`,`usernetwork`,`stamp`,`active`,`thumb`) values (?,?,?,?,?,?,?,?,?,?,?)", [ entry, cb.file + '.' + cb.info.ext, cb.info.mime, cb.size, cb.checksum, e.user.nick, e.channel, e.network, ~~(new Date() / 1000), 0, cb.info.thumb ? cb.info.thumb : '' ]).then(result => { //lib.generateThumbs(); e.reply(cfg.main.url.val+"/"+result.insertId+" - "+cb.info.title+" ("+cb.info.mime+", ~"+formatSize(cb.size)+") by "+e.user.nick+" ("+e.user.prefix+")"); }).catch(msg => { e.reply("ups", msg); }); } else { e.reply("Datei konnte nicht verschoben werden D:"); e.reply(`${cb.file} -> ${cb.file}.${cb.info.ext}`); } }); } else { e.reply(JSON.stringify(cb)); fs.stat(process.cwd() + '/b/' + cb.file, (err, stat) => { if(cb.msg !== '') e.reply(cb.msg); if(!err && stat.isFile()) fs.unlinkSync(process.cwd() + '/b/' + cb.file); }); } }); } }); } else e.reply("ignored"); } else e.reply("ignore"); } })); }; const getLink = (url, force, userlevel, cb) => { const yt = /https?:\/\/(www\.)?youtu(\.be\/|be\.com\/)((.+\/)?(watch(\?v=|.+&v=))?(v=)?)([\w_-]{11})(&.+)?/gi; const sc = /https?:\/\/(www\.)?(soundcloud\.com|snd\.sc)(\/\S*)(\/\S*)/gi; checkRepost(url, cbcr => { var tmpdest = uuid.v1().split('-')[0]; if(cbcr === true) { var dat = fs.createWriteStream(process.cwd() + '/b/' + tmpdest); var info; if(url.match(yt)) { // ytdl ytdl.getInfo(url, (err, inf) => { if(!err) { var title = inf.title; var iurl = inf.thumbnail_url; //JSON.parse(inf.player_response).videoDetails.thumbnail.thumbnails[0].url.split('?')[0]; try { dlformat = { filter: (format) => { return format.container === 'webm'; } }; ytdl.downloadFromInfo(inf, dlformat) .on('response', (res) => { if( ( res.headers['content-length'] <= cfg.main.maxFileSize.val ) || force || ( userlevel >= 60 && res.headers['content-length'] <= (cfg.main.maxFileSize.val * 2) ) ) { info = { type: 'youtube', title: title, mime: 'video/webm', ext: 'webm', thumb: iurl }; } else { res.destroy(); dat.end(); return cb({ success: false, file: tmpdest, msg: 'f0ck! your file is too big (~'+formatSize(res.headers['content-length'])+'), max '+formatSize( ( userlevel >= 60?(cfg.main.maxFileSize.val*2):cfg.main.maxFileSize.val ) )+' allowed' }); } }) .on('error', (err) => { dat.end(); return cb({ success: false, file: tmpdest, msg: err.message }); }) .pipe(dat); } catch(ex) { dat.end(); return cb({ success: false, file: tmpdest, msg: ex.message }); } } }); } else if(url.match(sc)) { // scdl request('https://api.soundcloud.com/resolve.json?client_id=' + cfg.main.scclientid.val + '&url=' + url, (err, res, body) => { if(!err && res.statusCode === 200) { var data = JSON.parse(body); request(data.stream_url + ((data.stream_url.indexOf('?') === -1)?'?':'&') + 'client_id=' + cfg.main.scclientid.val) .pipe(dat); info = { type: 'soundcloud', title: data.title, mime: 'audio/mpeg', ext: 'mp3', thumb: (data.artwork_url !== null)?data.artwork_url.replace('large.jpg', 't300x300.jpg'):null }; } else { dat.end(); return cb({ success: false, file: tmpdest, msg: 'f0ck sc-api' }); } }); } else { // various cloudscraper.request({ method: 'GET', url: url, encoding: null, }, (err, res, data) => { if(!err) { var type = res.headers['content-type'].split(";")[0]; if(cfg.main.allowedMimes.val.hasOwnProperty(type)) { if( ( data.length <= cfg.main.maxFileSize.val ) || force || ( userlevel >= 60 && data.length <= (cfg.main.maxFileSize.val * 2) ) ) { var s = new Readable; s.push(data); s.push(null); s.pipe(dat); info = { type: 'other', title: path.parse(url).base, mime: type, ext: cfg.main.allowedMimes[type], thumb: null }; } else { dat.end(); return cb({ success: false, file: tmpdest, msg: 'f0ck! your file is too big (~'+formatSize(data.length)+'), max '+formatSize( ( userlevel >= 60?(cfg.main.maxFileSize.val*2):cfg.main.maxFileSize.val ) )+' allowed' }); } } else { dat.end(); return cb({ success: false, file: tmpdest, msg: 'irgendwas mit mime oder so.' }); } } else { dat.end(); return cb({ success: false, file: tmpdest, msg: 'nope.' }); } }); } dat .on('finish', () => { var size = dat.bytesWritten; dat.end(); if( ( size <= cfg.main.maxFileSize.val ) || force || ( userlevel >= 60 && size <= (cfg.main.maxFileSize.val * 2) ) ) { fs.stat(process.cwd() + '/b/' + tmpdest, (err, stat) => { if(!err && stat.isFile() && stat.size > 300) { getCheckSum(process.cwd() + '/b/' + tmpdest, (cbcs) => { checkRepostCheckSum(cbcs, (cbcrcs) => { if(cbcrcs === true) { var mime = fileType(readChunk.sync(process.cwd() + '/b/' + tmpdest, 0, 262)); info.ext = mime.ext; info.mime = mime.mime; if(cfg.main.allowedMimes.val.hasOwnProperty(mime.mime) || info.type === 'soundcloud') return cb({ success: true, info: info, size: size, file: process.cwd() + '/b/' + tmpdest, checksum: cbcs }); else return cb({ success: false, file: tmpdest, msg: 'lol, go f0ck yourself ('+mime.mime+')' }); } else return cb({ success: false, file: tmpdest, msg: 'repost motherf0cker: '+cfg.main.url.val+'/'+cbcrcs }); }); }); } else return cb({ success: false, file: tmpdest, msg: 'nope' }); }); } else return cb({ success: false, file: tmpdest, msg: 'f0ck! your file is too big (~'+formatSize(size)+'), max '+formatSize( ( userlevel >= 60?(cfg.main.maxFileSize.val*2):cfg.main.maxFileSize.val ) )+' allowed' }); }) .on('error', err => { return cb({ success: false, file: tmpdest, msg: err }); }); } else return cb({ success: false, file: tmpdest, msg: 'repost motherf0cker: '+cfg.main.url.val+'/'+cbcr }); }); };