Created
October 28, 2012 05:49
-
-
Save private-face/3967789 to your computer and use it in GitHub Desktop.
Postnauka video 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
const INCOMPLETE_DOWNLOADS_FOLDER_PATH = '/Users/vz/Downloads/'; | |
const COMPLETE_DOWNLOADS_FOLDER_PATH = '/Users/vz/Music/iTunes/iTunes Media/Automatically Add to iTunes/'; | |
const USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.52 Safari/537.11'; | |
const VIDEO_INFO_URL = 'http://player.vimeo.com/config/'; | |
const VIDEO_DOWNLOAD_URL = 'http://player.vimeo.com/play_redirect?clip_id={{id}}&sig={{signature}}&time={{timestamp}}&quality={{quality}}&codecs=H264&type=moogaloop&embed_location={{location}}'; | |
const RECHECK_PERIOD = 2 * 60 * 60 * 1000; | |
var fs = require("fs"), | |
xml2js = require('xml2js'), | |
request = require('request'), | |
db = new require('dirty')('data.db.json'), | |
ProgressBar = require('progress'), | |
growl = require('growl'), | |
videos = {}; | |
function stripHTML(s) { | |
return s.replace(/<[^>]+>/gm, ' '); | |
} | |
function createVideo(rawVideoData) { | |
return { | |
title: rawVideoData.title[0], | |
description: stripHTML(rawVideoData.description[0]), | |
pageUrl: rawVideoData.link[0], | |
date: +new Date(rawVideoData.pubDate[0]), | |
category: rawVideoData.category | |
}; | |
} | |
function getVimeoId(url, callback) { | |
request(url, function(error, response, body) { | |
if (!error && response.statusCode == 200) { | |
var match = body.match(/https?:\/\/player\.vimeo\.com\/video\/(\d+)/i); | |
callback(match && match[1] || null); | |
} else { | |
callback(null); | |
} | |
}); | |
} | |
function getDownloadUrl(id, location, callback) { | |
request({ | |
url: VIDEO_INFO_URL + id, | |
headers: { | |
'User-Agent': USER_AGENT, | |
'Referer': location | |
} | |
}, function(error, response, body) { | |
if (!error && response.statusCode == 200) { | |
try { | |
var data = JSON.parse(body); | |
var url = VIDEO_DOWNLOAD_URL | |
.replace('{{id}}', data.video.id) | |
.replace('{{signature}}', data.request.signature) | |
.replace('{{timestamp}}', data.request.timestamp) | |
.replace('{{quality}}', data.video.files.h264[0]) // best format always goes first | |
.replace('{{location}}', location); | |
callback(url); | |
} catch(e) { | |
callback(null); | |
} | |
} else { | |
callback(null) | |
} | |
}); | |
} | |
function downloadVideo(videoUrl, name, callback) { | |
var req = request({ | |
url: videoUrl, | |
headers: { | |
'User-Agent': USER_AGENT | |
} | |
}); | |
req.on('response', function(res) { | |
var file = fs.createWriteStream(INCOMPLETE_DOWNLOADS_FOLDER_PATH + name), | |
len = parseInt(res.headers['content-length'], 10), | |
bar = new ProgressBar('[:bar] :percent :etas', { | |
complete: '=', | |
incomplete: ' ', | |
width: 40, | |
total: len | |
}); | |
res.on('data', function(chunk){ | |
bar.tick(chunk.length); | |
file.write(chunk, encoding='binary'); | |
}); | |
res.on('end', function(){ | |
console.log('\n'); | |
file.end(); | |
fs.rename(INCOMPLETE_DOWNLOADS_FOLDER_PATH + name, COMPLETE_DOWNLOADS_FOLDER_PATH + name); | |
growl(name + ' has been successfully downloaded.', {title: 'Postnauka'}); | |
callback(true); | |
}); | |
res.on('error', function() { | |
console.log('\n'); | |
file.end(); | |
growl(name + ' has failed to download.', {title: 'Postnauka'}); | |
callback(null); | |
}); | |
}); | |
req.end(); | |
} | |
function downloadVideos(items, callback) { | |
var queue = []; | |
for(var url in items) { | |
if (!items[url].done) { | |
queue.push(items[url]); | |
} | |
} | |
queue.sort(function(a, b) { | |
return a.date - b.date; | |
}); | |
processQueue(queue, callback); | |
} | |
function processQueue(items, callback) { | |
var item = items.shift(); | |
if (!item) { | |
return callback(); | |
} | |
console.log(item.title); | |
console.log('* geting vimeo id...'); | |
getVimeoId(item.pageUrl, function(id) { | |
if (id === null) { | |
console.log('! could not get vimeo id, file skipped.'); | |
return processQueue(items, callback); | |
} | |
console.log('* geting download url...'); | |
getDownloadUrl(id, item.pageUrl, function(url) { | |
if (url === null) { | |
console.log('! could not get download url, file skipped.'); | |
return processQueue(items, callback); | |
} | |
downloadVideo(url, item.title + '.mp4', function(result) { | |
if (result) { | |
item.done = true; | |
db.set('rss_items', videos); | |
processQueue(items, callback); | |
} else { | |
console.log('! download failed.'); | |
} | |
}) | |
}); | |
}); | |
} | |
function checkForNewVideos() { | |
request('http://postnauka.ru/video/feed', function (error, response, body) { | |
if (!error && response.statusCode == 200) { | |
var parser = new xml2js.Parser; | |
parser.parseString(body, function (err, result) { | |
var c = 0; | |
result.rss.channel[0].item.forEach(function(item) { | |
var pageUrl = item.link[0]; | |
if (!videos[pageUrl]) { | |
c++; | |
videos[pageUrl] = createVideo(item); | |
} | |
}); | |
if (c) { | |
var msg = c + ' new video' + (c * 1 ? 's' : '') + ' found.'; | |
growl(msg, {title: 'Postnauka'}); | |
console.log(msg + ' found.'); | |
} | |
downloadVideos(videos, function() { | |
setTimeout(checkForNewVideos, RECHECK_PERIOD); | |
}); | |
}); | |
} | |
}); | |
} | |
db.on('load', function() { | |
videos = db.get('rss_items') || {}; | |
checkForNewVideos(); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment