Last active
August 4, 2016 05:09
-
-
Save emsifa/c78cecbf7b734f7210d3bdaf7aef0f1a to your computer and use it in GitHub Desktop.
Simple node.js command line vidio.com downloader
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
{ | |
"dependencies": { | |
"bluebird": "^3.3.5", | |
"chalk": "^1.1.3", | |
"concat-files": "^0.1.0", | |
"inquirer": "^1.0.2", | |
"progress": "^1.1.8" | |
} | |
} |
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
var url = process.argv[2]; | |
// url harus dari vidio.com | |
if (!url) { | |
return console.error("URL cannot be empty"); | |
} | |
if (!(/^http(s)?:\/\/www\.vidio\.com\/watch\//).test(url)) { | |
return console.error("URL is not vidio.com video page"); | |
} | |
var Promise = require('bluebird'); | |
var ProgressBar = require('progress'); | |
var inquirer = require('inquirer'); | |
var https = require('https'); | |
var fs = require('fs'); | |
var chalk = require('chalk'); | |
var concat = require('concat-files'); | |
var video_resolutions = {}; | |
var temp_files = []; | |
var result_filename; | |
function grab(url, message) { | |
return new Promise(function(resolve, reject) { | |
var req = https.request(url); | |
var result = ''; | |
req.on('response', function(res) { | |
if (res.statusCode < 200 || res.statusCode >= 300) { | |
reject(new Error("Cannot grab content from statusCode " + res.statusCode)); | |
} | |
if (message) { | |
var len = parseInt(res.headers['content-length'], 10); | |
var bar = new ProgressBar(message, { | |
complete: chalk.green('.'), | |
incomplete: ' ', | |
width: 3, | |
total: len | |
}); | |
} | |
res.on('data', function(chunk) { | |
if (message) { | |
bar.tick(chunk.length); | |
} | |
result += chunk; | |
}); | |
res.on('end', function() { | |
resolve(result); | |
}); | |
}); | |
req.end(); | |
}); | |
} | |
function download(url, file_stream, message) { | |
return new Promise(function(resolve, reject) { | |
var req = https.request(url); | |
req.on('response', function(res) { | |
if (res.statusCode < 200 || res.statusCode >= 300) { | |
reject(new Error("Cannot download file, statusCode = " + res.statusCode)); | |
} | |
var len = parseInt(res.headers['content-length'], 10); | |
var bar = new ProgressBar(message, { | |
complete: chalk.green('='), | |
incomplete: ' ', | |
width: 20, | |
total: len | |
}); | |
res.on('data', function(chunk) { | |
bar.tick(chunk.length); | |
}); | |
res.on('end', function() { | |
resolve(file_stream); | |
}); | |
res.pipe(file_stream); | |
}); | |
req.end(); | |
}); | |
} | |
function removeTempFiles() { | |
for (i in temp_files) { | |
var tmp_file = temp_files[i]; | |
if (fs.existsSync(tmp_file)) { | |
fs.unlinkSync(tmp_file); | |
} | |
} | |
} | |
// remove temp files jika terjadi interupsi (misal: ctrl+C) | |
process.on('SIGINT', function() { | |
removeTempFiles(); | |
console.log("Caught interrupt signal"); | |
}); | |
// grab url | |
grab(url, chalk.cyan(">") + " Mengambil informasi halaman :bar") | |
// scrap url playlist | |
.then(function(content) { | |
return new Promise(function(resolve, reject) { | |
var url_data_clip = content.match(/https:\/\/www\.vidio\.com\/videos\/\d+\/playlist\.m3u8/); | |
if (!url_data_clip.length) { | |
reject(new Error("Cannot find data clip url at that page")); | |
} else { | |
resolve(url_data_clip[0]); | |
} | |
}) | |
}) | |
// grab url playlist dan scrap metadata (resolusi video) | |
.then(function(url_data_clip) { | |
return new Promise(function(resolve, reject) { | |
grab(url_data_clip).then(function(content) { | |
var list_metadata = content.match(/(\#[^\n]+[\n\r\t]*)(https[^\n]+)/g).map(function(match) { | |
var split = match.split("\n"); | |
var data = { | |
url: split[1] | |
}; | |
split[0].replace(/^\#/, '').split(',').map(function(metadata) { | |
var s = metadata.split('='); | |
data[s[0].toLowerCase()] = (s[1] || '').trim().replace(/(^\"|\"$)/g, ''); | |
}); | |
return data; | |
}); | |
var resolutions = {}; | |
list_metadata.forEach(function(metadata) { | |
resolutions[metadata.name + " (" + metadata.resolution + ")"] = metadata.url; | |
}); | |
resolve(resolutions); | |
}) | |
}); | |
}) | |
// Propmpt/tanya mau resolusi yang mana? | |
.then(function(resolutions) { | |
return inquirer.prompt({ | |
type: 'list', | |
name: 'resolution', | |
message: 'Pilih resolusi video', | |
choices: Object.keys(resolutions) | |
}).then(function(answer) { | |
return Promise.resolve(resolutions[answer.resolution]); | |
}); | |
}) | |
// grab dan scrap list url transport stream (.ts) | |
.then(function(url_video_resolution) { | |
return new Promise(function(resolve, reject) { | |
grab(url_video_resolution, chalk.cyan(">") + " Mengambil daftar url stream").then(function(result) { | |
var urls = result.match(/https:[^\n]+/g); | |
// jika urls yang match dengan https tidak ada, mungkin hanya berisi url videonya saja | |
if (!urls) { | |
var split = url_video_resolution.split('/'); | |
var file_pattern = new RegExp(split.pop().substr(0, 10) + '[^\n]+', 'g'); | |
var url_video_directory = split.join('/'); | |
urls = (result.match(file_pattern) || []).map(function(url) { | |
return url_video_directory + '/' + url; | |
}); | |
} | |
resolve(urls); | |
}); | |
}); | |
}) | |
// Download semua file .ts ke folder ./temp | |
.then(function(stream_urls) { | |
var count = stream_urls.length; | |
var x = 0; | |
result_filename = stream_urls[0].split('/').pop().replace(/-\d+\.ts$/, ''); | |
// var dest = __dirname+'/temp/'+result_filename; | |
return Promise.each(stream_urls, function(stream_url) { | |
var flags = !fs.existsSync(dest) ? 'w' : 'r+'; | |
var chunk_filename = stream_url.split('/').pop(); | |
var message = chalk.cyan("[") + (++x) + chalk.cyan("/") + count + chalk.cyan("] ") + chunk_filename + " [:bar] :percent"; | |
var sort = '0'.repeat(5 - ('' + x).length) + x; | |
var dest = __dirname + '/temp/' + sort + '_' + chunk_filename; | |
var file_stream = fs.createWriteStream(dest); | |
temp_files.push(dest); | |
return download(stream_url, file_stream, message); | |
}); | |
}) | |
// concat semua file .ts jadi 1 file | |
.then(function(videos) { | |
console.log(chalk.cyan(">") + " Menyatukan potongan-potongan video ..."); | |
concat(temp_files, __dirname + '/' + result_filename, function() { | |
console.log(chalk.green("SELESAI!") + " " + result_filename); | |
removeTempFiles(); // kalo udah remove temp files | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
penggunaan:
node vidio-dl <url-vidio-nya>