jeff-downloader/app/Controllers/Http/DownloadController.js

297 lines
10 KiB
JavaScript
Raw Normal View History

2019-12-03 21:18:40 +01:00
'use strict'
const youtubedl = require('youtube-dl')
const fs = require('fs')
const ffmpeg = require('fluent-ffmpeg')
2019-12-24 16:19:04 +01:00
const { version } = require('../../../package.json');
2020-06-11 16:21:55 +02:00
const Ws = use('Ws');
const Antl = use('Antl');
2019-12-03 21:18:40 +01:00
let viewCounter = 0;
let files = [];
let day;
let month;
2020-01-24 01:58:43 +01:00
let announcementArray;
2020-06-11 16:21:55 +02:00
let announcement;
2020-01-23 18:38:51 +01:00
function formatBytes(bytes, decimals = 2) { // https://stackoverflow.com/a/18650828
if (bytes === 0) return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
}
2019-12-03 21:18:40 +01:00
class DownloadController {
2020-01-24 01:58:43 +01:00
async index ({ view, request, locale }) {
2019-12-24 16:19:04 +01:00
viewCounter++;
2020-01-24 01:58:43 +01:00
// Coudln't find a cleaner way to make it change with the browser locale
2020-06-11 16:21:55 +02:00
announcementArray = [Antl.forLocale(locale).formatMessage('announcement.1'), Antl.forLocale(locale).formatMessage('announcement.2'), Antl.forLocale(locale).formatMessage('announcement.3'), Antl.forLocale(locale).formatMessage('announcement.4'), Antl.forLocale(locale).formatMessage('announcement.5'), Antl.forLocale(locale).formatMessage('announcement.6'), 'Playlist download is experimental'];
// Get random announcement
announcement = announcementArray[Math.floor(Math.random() * announcementArray.length)];
2019-12-03 21:18:40 +01:00
// Get date for some event
let today = new Date();
day = today.getDay();
month = today.getMonth();
2019-12-24 16:19:04 +01:00
// If legacy link return
2020-01-24 22:03:21 +01:00
if (request.url() == '/legacy') return view.render('legacy', { version: version, viewCounter: viewCounter, day: day, month: month, announcement: announcement});
2020-06-11 16:21:55 +02:00
2019-12-03 21:18:40 +01:00
files = [];
2019-12-24 16:19:04 +01:00
let file = [];
2019-12-03 21:18:40 +01:00
for (let f of fs.readdirSync('./public/uploads')) {
file.push(f)
}
// get the 5 most recent files
2019-12-24 16:19:04 +01:00
file = file.sort((a, b) => {
2020-06-11 16:21:55 +02:00
if ((a || b).endsWith('.mp4') || (a || b).endsWith('.webm') || (a || b).endsWith('.mp3') || (a || b).endsWith('.flac') || (a || b).endsWith('.zip')) {
2019-12-03 21:18:40 +01:00
let time1 = fs.statSync(`./public/uploads/${b}`).ctime;
2020-06-11 16:21:55 +02:00
let time2 = fs.statSync(`./public/uploads/${a}`).ctime;
2019-12-03 21:18:40 +01:00
if (time1 < time2) return -1;
if (time1 > time2) return 1;
}
return 0;
}).slice(0, 5)
2020-06-11 16:21:55 +02:00
// Save space by deleting file that doesn't appear in the recent feed
2020-01-21 23:39:30 +01:00
for (let f of fs.readdirSync('./public/uploads')) {
2020-06-11 16:21:55 +02:00
if (!file.includes(f) && (f != 'hidden' && f != '.keep' && f != 'playlist')) {
2020-01-21 23:39:30 +01:00
fs.unlinkSync(`./public/uploads/${f}`);
}
}
2020-06-11 16:21:55 +02:00
for (let f of file) {
2019-12-24 16:19:04 +01:00
if (f.endsWith('.mp4') || f.endsWith('.webm')) {
// Send file name, file size in MB relative path for the file
2020-01-26 02:38:56 +01:00
let fileInfo = formatBytes(fs.statSync(`./public/uploads/${f}`).size).split(' ');
2020-01-26 03:15:22 +01:00
files.push({ name: f.split('.').slice(0, -1).join('.'), size: fileInfo[0], unit: fileInfo[1], date: fs.statSync(`./public/uploads/${f}`).ctime, location: `uploads/${f}`, ext: f.split('.').pop(), img: '' });
2019-12-24 16:19:04 +01:00
} else if (f.endsWith('.mp3') || f.endsWith('.flac')) {
2019-12-19 15:14:54 +01:00
// Send file name, file size in MB relative path for the file and relative path of music.png
2020-01-26 02:38:56 +01:00
let fileInfo = formatBytes(fs.statSync(`./public/uploads/${f}`).size).split(' ');
2020-01-26 03:15:22 +01:00
files.push({ name: f.split('.').slice(0, -1).join('.'), size: fileInfo[0], unit: fileInfo[1], date: fs.statSync(`./public/uploads/${f}`).ctime, location: `uploads/${f}`, ext: f.split('.').pop(), img: `/asset/music.png` });
2019-12-03 21:18:40 +01:00
}
2019-12-24 16:19:04 +01:00
}
2020-06-11 16:21:55 +02:00
2020-01-24 22:03:21 +01:00
return view.render('index', { version: version, viewCounter: viewCounter, file: files, day: day, month: month, announcement: announcement});
2019-12-03 21:18:40 +01:00
}
async download({ view, request, response }) {
2020-06-11 16:21:55 +02:00
const ws = Ws.getChannel('progress').topic('progress');
2019-12-03 21:18:40 +01:00
// To be honest i forgot what it does, but i think i need it
response.implicitEnd = false
let option, DLFile
// Get form input
let data = {
url: request.input('URL'),
quality: request.input('quality'),
format: request.input('format'),
alt: request.input('alt'),
feed: request.input('feed')
}
if (!data.url) {
2020-06-11 16:21:55 +02:00
if (ws) {
ws.socket.emit('error', 'bruh moment, you didin\'t input a link.');
}
return;
2019-12-03 21:18:40 +01:00
}
// Youtube-dl quality settings
if (data.quality == 'small')
option = 'worst'
else
option = 'best'
// If alt download ( Quality settings and file format option doesn't work here )
if (data.alt) {
2020-01-16 18:13:27 +01:00
let altFolder;
if (data.feed == 'on') {
altFolder = './public/uploads/hidden/alt.mp4';
} else {
altFolder = './public/uploads/alt.mp4'
}
if (fs.existsSync(altFolder)) {
fs.unlink(altFolder, (err) => {
2019-12-03 21:18:40 +01:00
if (err);
});
}
2020-06-11 16:21:55 +02:00
2020-01-16 18:13:27 +01:00
return youtubedl.exec(data.url, ['--format=mp4', '-o', altFolder], {}, function(err, output) {
2019-12-03 21:18:40 +01:00
if (err) {
2020-01-23 16:18:35 +01:00
console.error(err);
2020-06-11 16:21:55 +02:00
if (ws) {
ws.socket.emit('error', err.toString());
}
return;
2019-12-03 21:18:40 +01:00
}
2020-06-11 16:21:55 +02:00
console.log(altFolder.slice(17))
if (ws) {
ws.socket.emit('end', altFolder.slice(17));
}
return;
2019-12-03 21:18:40 +01:00
});
} else {
2020-06-11 16:21:55 +02:00
if (data.url.match( /^.*(youtu.be\/|list=)([^#\&\?]*).*/)) {
playlistDownload(data)
} else {
// Download as mp4 if possible
let video = youtubedl(data.url, ['--format=mp4', '-f', option]);
video.on('error', function(err) {
console.error(err);
if (ws) {
ws.socket.emit('error', err.toString());
}
return;
})
let ext;
let size = 0
video.on('info', function(info) {
size = info.size
// Set file name
ext = info.ext;
let title = info.title.slice(0,50);
DLFile = `${title.replace(/\s/g, '_')}.${ext}`;
DLFile = DLFile.replace(/[()]|[/]|[\\]|[?]|[!]/g, '_');
// If no title use the ID
if (title == '_') title = `_${info.id}`;
// If user want to hide from the feed
if (data.feed == 'on')
DLFile = `hidden/${title}.${ext}`;
video.pipe(fs.createWriteStream(`./public/uploads/${DLFile}`));
});
let pos = 0
video.on('data', function data(chunk) {
pos += chunk.length
// `size` should not be 0 here.
if (size) {
let percent = (pos / size * 100).toFixed(2)
if (ws) {
ws.socket.emit('progress', percent);
}
}
})
2019-12-03 21:18:40 +01:00
2020-06-11 16:21:55 +02:00
video.on('end', function() {
console.log('end');
if (ws) {
ws.socket.emit('message', 'end');
}
if (data.format == 'mp4' || data.format == 'webm') {
// If user requested mp4 directly attach the file
if (ws) {
ws.socket.emit('end', DLFile);
}
return;
} else {
// If user requested an audio format, convert it
ffmpeg(`./public/uploads/${DLFile}`)
.noVideo()
.audioChannels('2')
.audioFrequency('44100')
.audioBitrate('320k')
.format(data.format)
.save(`./public/uploads/${DLFile.replace(`.${ext}`, `.${data.format}`)}`)
.on('progress', (progress) => {
wb.broadcast(progress.percent)
})
.on('end', () => {
fs.unlinkSync(`./public/uploads/${DLFile}`);
if (ws) {
ws.socket.emit('end', DLFile.replace(`.${ext}`, `.${data.format}`));
}
});
}
});
}
}
function playlistDownload(data) {
const video = youtubedl(data.url)
video.on('error', function error(err) {
2020-01-23 16:18:35 +01:00
console.error(err);
2020-06-11 16:21:55 +02:00
if (ws) {
ws.socket.emit('error', err.toString());
}
return;
});
2019-12-03 21:18:40 +01:00
let ext;
2020-06-11 16:21:55 +02:00
let size = 0
2019-12-03 21:18:40 +01:00
video.on('info', function(info) {
2020-06-11 16:21:55 +02:00
console.log(info);
size = info.size
2019-12-03 21:18:40 +01:00
// Set file name
ext = info.ext;
2020-01-16 18:13:27 +01:00
let title = info.title.slice(0,50);
DLFile = `${title.replace(/\s/g, '_')}.${ext}`;
2020-06-11 16:21:55 +02:00
DLFile = DLFile.replace(/[()]|[/]|[\\]|[?]|[!]/g, '_');
2019-12-03 21:18:40 +01:00
// If no title use the ID
if (title == '_') title = `_${info.id}`;
2020-06-11 16:21:55 +02:00
// If user want to hide from the feed
if (data.feed == 'on')
DLFile = `hidden/playlist/${title}.${ext}`;
2019-12-03 21:18:40 +01:00
2020-06-11 16:21:55 +02:00
video.pipe(fs.createWriteStream(`./public/uploads/playlist/${DLFile}`));
});
let pos = 0
video.on('data', function data(chunk) {
pos += chunk.length
// `size` should not be 0 here.
if (size) {
let percent = (pos / size * 100).toFixed(2)
process.stdout.cursorTo(0)
process.stdout.clearLine(1)
if (ws) {
ws.socket.emit('progress', percent);
}
}
2019-12-03 21:18:40 +01:00
});
video.on('end', function() {
2020-06-11 16:21:55 +02:00
if (data.format == 'mp3' || data.format == 'flac') {
2019-12-03 21:18:40 +01:00
// If user requested an audio format, convert it
2020-06-11 16:21:55 +02:00
ffmpeg(`./public/uploads/playlist/${DLFile}`)
2019-12-03 21:18:40 +01:00
.noVideo()
.audioChannels('2')
.audioFrequency('44100')
.audioBitrate('320k')
.format(data.format)
2020-06-11 16:21:55 +02:00
.save(`./public/uploads/playlist/${DLFile.replace(`.${ext}`, `.${data.format}`)}`)
.on('progress', (progress) => {
ws.socket.emit(progress.percent)
2019-12-03 21:18:40 +01:00
})
2020-06-11 16:21:55 +02:00
.on('end', () => {
fs.unlinkSync(`./public/uploads/playlist/${DLFile}`);
if (ws) {
ws.socket.emit('end', `./public/uploads/playlist/${DLFile.replace(`.${ext}`, `.${data.format}`)}`);
}
});
} else {
if (ws) {
ws.socket.emit('end', `./public/uploads/playlist/${DLFile}`);
}
2019-12-03 21:18:40 +01:00
}
});
2020-06-11 16:21:55 +02:00
video.on('next', playlistDownload);
2019-12-03 21:18:40 +01:00
}
}
}
module.exports = DownloadController