2020-06-17 18:42:52 +02:00
const { Command } = require ( 'discord-akairo' ) ;
const downloader = require ( '../../utils/download' ) ;
const compress = require ( '../../utils/compress' ) ;
2021-03-16 16:20:03 +01:00
const checkHapi = require ( '../../utils/checkHapi' ) ;
2021-02-04 17:14:52 +01:00
const { proxy , Hapi } = require ( '../../config.json' ) ;
2020-06-17 18:42:52 +02:00
const os = require ( 'os' ) ;
const fs = require ( 'fs' ) ;
2021-02-04 17:14:52 +01:00
const fetch = require ( 'node-fetch' ) ;
2020-06-17 18:42:52 +02:00
class DownloadCommand extends Command {
constructor ( ) {
2020-06-18 01:36:09 +02:00
super ( 'download' , {
2020-06-18 00:36:48 +02:00
aliases : [ 'download' , 'dl' ] ,
2020-06-17 18:42:52 +02:00
category : 'utility' ,
clientPermissions : [ 'SEND_MESSAGES' , 'EMBED_LINKS' , 'ATTACH_FILES' ] ,
args : [
{
id : 'link' ,
2020-07-16 09:23:50 +02:00
type : 'url' ,
2020-06-17 18:42:52 +02:00
prompt : {
2020-07-16 09:23:50 +02:00
start : 'Please send the URL of which video you want to download. Say `cancel` to stop the command' ,
2020-08-25 03:11:01 +02:00
retry : 'Please send a valid URL of the video you want to download. Say `cancel` to stop the command' ,
optional : true
2020-07-16 09:23:50 +02:00
} ,
2020-06-17 18:42:52 +02:00
} ,
{
id : 'caption' ,
type : 'string' ,
match : 'rest'
} ,
{
id : 'spoiler' ,
match : 'flag' ,
flag : [ '--spoil' , '--spoiler' , '-s' ]
2020-08-25 02:09:16 +02:00
} ,
{
id : 'proxy' ,
2020-08-25 03:11:01 +02:00
match : 'option' ,
flag : [ '--proxy' ] ,
} ,
{
id : 'listproxy' ,
2020-08-25 02:09:16 +02:00
match : 'flag' ,
2020-08-25 03:11:01 +02:00
flag : [ '--listproxy' , '--proxylist' ]
2020-06-17 18:42:52 +02:00
}
] ,
description : {
2020-09-06 22:53:17 +02:00
content : 'Download videos from different website from the link you provided\n`-s` to make the video as a spoiler\n`--proxy #` to select a proxy\n`--listproxy` to see a list of proxy' ,
2020-06-17 18:42:52 +02:00
usage : '[link] [caption]' ,
2020-08-25 17:21:01 +02:00
examples : [ 'https://www.youtube.com/watch?v=6n3pFFPSlW4 Look at this funny gnome' , 'https://www.youtube.com/watch?v=6n3pFFPSlW4 --proxy 1' , '--listproxy' ]
2020-06-17 18:42:52 +02:00
}
} ) ;
}
async exec ( message , args ) {
2021-07-23 04:23:43 +02:00
if ( args . link === null ) {
let urlRE = new RegExp ( '([a-zA-Z0-9]+://)?([a-zA-Z0-9_]+:[a-zA-Z0-9_]+@)?([a-zA-Z0-9.-]+\\.[A-Za-z]{2,4})(:[0-9]+)?([^ ])+' ) ;
await message . channel . messages . fetch ( { limit : 10 } ) . then ( messages => {
messages . map ( m => {
if ( m . content . match ( urlRE ) ) {
args . link = new URL ( m . content . match ( urlRE ) [ 0 ] ) ;
}
} ) ;
} ) ;
}
2021-03-16 16:20:03 +01:00
if ( ! args . link ) return message . channel . send ( 'Please try again with a valid URL.' ) ;
if ( args . listproxy ) {
let proxys = [ ] ;
let i = 0 ;
proxy . forEach ( proxy => {
i ++ ;
proxys . push ( ` [ ${ i } ] ${ proxy . hideip ? '[IP HIDDEN]' : proxy . ip . substring ( 0 , proxy . ip . length - 5 ) } - ${ proxy . country } ` ) ;
} ) ;
const Embed = this . client . util . embed ( )
. setColor ( message . member ? message . member . displayHexColor : 'NAVY' )
. setTitle ( 'List of available proxy' )
. setDescription ( proxys . join ( '\n' ) )
. setFooter ( 'You can help me get more proxy by either donating to me or providing a proxy for me' ) ;
return message . channel . send ( Embed ) ;
}
2021-02-04 17:17:38 +01:00
let Embed = this . client . util . embed ( )
. setColor ( message . member ? message . member . displayHexColor : 'NAVY' )
. setAuthor ( ` Downloaded by ${ message . author . username } ` , message . author . displayAvatarURL ( ) , args . link )
. setDescription ( args . caption ? args . caption : '' )
. setFooter ( ` You can get the original video by clicking on the "downloaded by ${ message . author . username } " message! ` ) ;
let compressEmbed = this . client . util . embed ( )
. setColor ( message . member ? message . member . displayHexColor : 'NAVY' )
. setTitle ( 'This one will need compression!' )
. setDescription ( 'Starting compression now!' )
. setFooter ( 'Want it to go faster? Donate to the dev with the donate command, so i can get a better server and do it faster!' ) ;
let loadingmsg = await message . channel . send ( 'Downloading <a:loadingmin:527579785212329984>' ) ;
2021-03-16 16:20:03 +01:00
const spoiler = args . spoiler ;
let filePath = ` ${ os . tmpdir ( ) } / ${ message . id } .mp4 ` ;
if ( spoiler )
filePath = ` SPOILER_ ${ filePath } ` ;
const isHapiOnline = await checkHapi ( ) ;
if ( isHapiOnline ) { // I should move that into the download utility file
console . log ( ` [Download] Hapi server is online at: ${ Hapi } ` ) ;
Embed . setFooter ( ` Using Hapi | ${ Embed . footer . text } ` ) ;
compressEmbed . setFooter ( ` Using Hapi | ${ compressEmbed . footer . text } ` ) ;
2021-02-04 17:17:38 +01:00
const params = new URLSearchParams ( ) ;
params . append ( 'url' , args . link . href ) ;
2021-03-16 16:20:03 +01:00
2021-02-04 17:17:38 +01:00
fetch ( ` ${ Hapi } /download ` , { method : 'POST' , body : params } )
. then ( async res => {
2021-03-16 16:20:03 +01:00
console . log ( ` status is ${ res . status } ` ) ;
if ( res . status !== 200 ) {
console . log ( 'Status is not 200. Abort' ) ;
return message . channel . send ( 'An error has occurred.' ) ;
}
2021-02-04 17:25:51 +01:00
2021-03-16 16:20:03 +01:00
if ( res . headers . get ( 'content-type' ) === 'application/json; charset=utf-8' ) { // If we receive JSON it mean it started compressing the video
console . log ( 'Compressing' ) ;
2021-02-04 17:17:38 +01:00
let json = await res . json ( ) ;
let compressmsg = await message . channel . send ( compressEmbed ) ;
2021-03-16 16:20:03 +01:00
console . log ( ` Got json! \n ${ json } ` ) ;
2021-02-04 17:17:38 +01:00
2021-03-16 16:20:03 +01:00
// Edit compression embed progress
2021-02-04 17:17:38 +01:00
let editmsg = setInterval ( ( ) => {
fetch ( json . status )
. then ( res => res . json ( ) )
. then ( json => {
compressEmbed . setDescription ( ` Ready in ${ json . eta === '' ? 'soon enough' : json . eta } . ${ json . percent } % complete. ` ) ;
compressmsg . edit ( compressEmbed ) ;
} )
. catch ( e => {
console . error ( e ) ;
clearInterval ( editmsg ) ;
return message . channel . send ( 'Hapi server returned an error.' ) ;
} ) ;
} , 5000 ) ;
2021-03-16 16:20:03 +01:00
// Check if the file is at the final location ( end result once it get compressed ) give up after 100 try
2021-02-04 17:17:38 +01:00
let retry = 0 ;
let interval = setInterval ( ( ) => {
fetch ( ` ${ json . final } ` )
. then ( res => {
2021-03-16 16:20:03 +01:00
if ( res . status !== 200 ) {
console . log ( ` try # ${ retry } status ${ res . status } ` ) ;
retry ++ ;
if ( retry >= 100 ) {
clearInterval ( editmsg ) ;
clearInterval ( interval ) ;
return message . channel . send ( 'Timed out, your video was probably too big to get compressed.' ) ;
}
} else {
2021-02-04 17:17:38 +01:00
clearInterval ( editmsg ) ;
clearInterval ( interval ) ;
2021-03-16 16:20:03 +01:00
const dest = fs . createWriteStream ( filePath ) ;
2021-02-04 17:17:38 +01:00
res . body . pipe ( dest ) ;
2021-03-16 16:20:03 +01:00
2021-02-04 17:17:38 +01:00
dest . on ( 'finish' , ( ) => {
compressmsg . delete ( ) ;
2021-03-16 16:20:03 +01:00
loadingmsg . delete ( ) ;
message . delete ( ) ;
2021-02-04 17:17:38 +01:00
message . channel . send ( {
embed : Embed ,
2021-03-16 16:20:03 +01:00
files : [ filePath ]
2021-03-04 13:34:49 +01:00
} )
. catch ( err => {
console . error ( err ) ;
return message . channel . send ( ` ${ err . name } : ${ err . message } ${ err . message === 'Request entity too large' ? 'The file size is too big' : '' } ` ) ;
} ) ;
2021-02-04 17:17:38 +01:00
} ) ;
}
} )
. catch ( e => {
console . error ( e ) ;
clearInterval ( interval ) ;
return message . channel . send ( 'Hapi server returned an error.' ) ;
} ) ;
} , 5000 ) ;
2021-03-16 16:20:03 +01:00
2021-02-04 17:17:38 +01:00
} else {
2021-03-16 16:20:03 +01:00
console . log ( 'finished download' ) ;
2021-03-16 16:22:10 +01:00
loadingmsg . delete ( ) ;
message . delete ( ) ;
2021-03-16 16:20:03 +01:00
const dest = fs . createWriteStream ( filePath ) ;
2021-02-04 17:17:38 +01:00
res . body . pipe ( dest ) ;
dest . on ( 'finish' , ( ) => {
2021-03-16 16:20:03 +01:00
message . channel . send ( { embed : Embed , files : [ filePath ] } ) ;
2021-02-04 17:17:38 +01:00
} ) ;
}
} ) ;
2021-03-16 16:20:03 +01:00
} else { // No Hapi server, let the bot download it
if ( args . proxy && ! args . proxyAuto ) { // args.proxyAuto is only provided when the command is run after a error 429
args . proxy = args . proxy - 1 ;
if ( ! proxy [ args . proxy ] ) args . proxy = 0 ;
}
2021-02-04 17:25:51 +01:00
2021-03-16 16:20:03 +01:00
downloader ( args . link . href , args . proxy != null ? [ '--proxy' , proxy [ args . proxy ] . ip ] : null , filePath )
. on ( 'error' , async err => {
if ( err . includes ( 'HTTP Error 429: Too Many Requests' ) ) {
if ( args . proxy != null ) {
args . proxy = args . proxy + 1 ;
} else {
args . proxy = 0 ;
args . proxyAuto = true ;
}
2020-08-25 03:11:01 +02:00
2021-03-16 16:20:03 +01:00
if ( ! proxy [ args . proxy ] ) return message . channel . send ( '`HTTP Error 429: Too Many Requests.`\nThe website you tried to download from probably has the bot blocked along with its proxy' ) ;
2020-06-17 18:42:52 +02:00
2021-03-16 16:20:03 +01:00
loadingmsg . delete ( ) ;
return this . client . commandHandler . runCommand ( message , this . client . commandHandler . findCommand ( 'download' ) , args ) ;
2020-09-14 15:37:28 +02:00
}
2021-03-16 16:20:03 +01:00
if ( err . includes ( 'Error: status code 403' ) ) return message . channel . send ( '`HTTP Error 403: Forbidden.`\nThe video you tried to download is not publicly available therefor the bot can\'t download it.' ) ;
2020-09-14 15:37:28 +02:00
2021-03-16 16:20:03 +01:00
return message . channel . send ( err , { code : true } ) ;
} )
. on ( 'end' , async output => {
let file = fs . statSync ( output ) ;
let fileSize = file . size / 1000000.0 ;
2020-06-17 18:42:52 +02:00
2021-03-16 16:20:03 +01:00
if ( fileSize > 8 ) { // File bigger than 8 mb, it need compressing
filePath = ` ${ filePath . substring ( 0 , filePath . length - 4 ) } compressed.mp4 ` ;
loadingmsg . delete ( ) ;
2020-06-17 18:42:52 +02:00
2021-03-16 16:20:03 +01:00
let compressmsg = await message . channel . send ( compressEmbed ) ;
2020-06-17 18:42:52 +02:00
2021-03-16 16:20:03 +01:00
let handbrake = compress ( output , filePath ) ;
2020-06-17 18:42:52 +02:00
2021-03-16 16:20:03 +01:00
let percentComplete ;
let eta ;
2020-06-17 18:42:52 +02:00
2021-03-16 16:20:03 +01:00
handbrake . on ( 'progress' , progress => {
percentComplete = progress . percentComplete ;
eta = progress . eta ;
} ) ;
2020-06-17 18:42:52 +02:00
2021-03-16 16:20:03 +01:00
// Every 5 seconds update the compress message with the %
let editmsg = setInterval ( ( ) => {
compressEmbed . setDescription ( ` Ready in ${ eta === '' ? 'soon enough' : eta } . ${ percentComplete } % complete. ` ) ;
compressmsg . edit ( compressEmbed ) ;
} , 5000 ) ;
2020-06-17 18:42:52 +02:00
2021-03-16 16:20:03 +01:00
handbrake . on ( 'err' , ( err ) => {
clearInterval ( editmsg ) ;
compressmsg . delete ( ) ;
return message . channel . send ( err , { code : true } ) ;
} ) ;
2020-06-17 18:42:52 +02:00
2021-03-16 16:20:03 +01:00
handbrake . on ( 'end' , ( output ) => {
clearInterval ( editmsg ) ;
file = fs . statSync ( output ) ;
fileSize = file . size / 1000000.0 ;
2020-06-17 18:42:52 +02:00
2021-03-16 16:20:03 +01:00
if ( fileSize > 8 ) return message . channel . send ( 'End results is too big for discord.' ) ;
2020-06-17 18:42:52 +02:00
2021-03-16 16:20:03 +01:00
return message . channel . send ( { embed : Embed , files : [ output ] } )
. catch ( err => {
compressmsg . delete ( ) ;
console . error ( err ) ;
return message . channel . send ( ` ${ err . name } : ${ err . message } ${ err . message === 'Request entity too large' ? 'The file size is too big' : '' } ` ) ;
} )
. then ( ( ) => {
compressmsg . delete ( ) ;
// Delete file after it has been sent
fs . unlinkSync ( output ) ;
message . delete ( ) ;
} ) ;
} ) ;
} else {
2020-06-17 18:42:52 +02:00
return message . channel . send ( { embed : Embed , files : [ output ] } )
. catch ( err => {
2021-03-16 16:20:03 +01:00
loadingmsg . delete ( ) ;
2020-06-17 18:42:52 +02:00
console . error ( err ) ;
2020-07-16 09:23:50 +02:00
return message . channel . send ( ` ${ err . name } : ${ err . message } ${ err . message === 'Request entity too large' ? 'The file size is too big' : '' } ` ) ;
2020-06-17 18:42:52 +02:00
} )
. then ( ( ) => {
2021-03-16 16:20:03 +01:00
loadingmsg . delete ( ) ;
2020-06-17 18:42:52 +02:00
// Delete file after it has been sent
fs . unlinkSync ( output ) ;
message . delete ( ) ;
} ) ;
2021-03-16 16:20:03 +01:00
}
} ) ;
}
2020-06-17 18:42:52 +02:00
}
}
2021-03-16 16:20:03 +01:00
2020-06-17 18:42:52 +02:00
module . exports = DownloadCommand ;