// Last Change: 12-Jun-2009. Jan 2008
var PLUGIN_INFO = xml`
{NAME}
Flv Downloader for Nicovideo
Trapezoid
0.5
MIT License
2.0pre
2.0pre
https://github.com/vimpr/vimperator-plugins/raw/master/ldrizecooperation_fetch_flv.js
||
Direct download flv from Nicovideo.
||<
=== :nicomylist ===
>||
Select Nicovideo Mylist of registration destination.
||<
== Parts ==
- http://d.hatena.ne.jp/fls/20080309/p1
- Pagerization (c) id:ofk
- AutoPagerize (c) id:swdyjh
- JSDeferred id:cho45
== Variables ==
=== g:nicovideo_mylist ==
>||
Nicovideo Mylist of registration destination.
||<
]]>
`;
(function () {
function Deferred () this instanceof Deferred ? this.init(this) : new Deferred();
Deferred.prototype = {
init : function () {
this._next = null;
this.callback = {
ok: function (x) x,
ng: function (x) { throw x }
};
return this;
},
next : function (fun) this._post("ok", fun),
error : function (fun) this._post("ng", fun),
call : function (val) this._fire("ok", val),
fail : function (err) this._fire("ng", err),
cancel : function () {
(this.canceller || function () {})();
return this.init();
},
_post : function (okng, fun) {
this._next = new Deferred();
this._next.callback[okng] = fun;
return this._next;
},
_fire : function (okng, value) {
var self = this, next = "ok";
try {
value = self.callback[okng].call(self, value);
} catch (e) {
next = "ng";
value = e;
}
if (value instanceof Deferred) {
value._next = self._next;
} else if (self._next) {
self._next._fire(next, value);
}
return this;
}
};
Deferred.next = function (fun) {
var d = new Deferred();
var id = setTimeout(function () { clearTimeout(id); d.call() }, 0);
if (fun) d.callback.ok = fun;
d.canceller = function () { try { clearTimeout(id) } catch (e) {} };
return d;
};
Deferred.wait = function (n) {
var d = new Deferred(), t = new Date();
var id = setTimeout(function () {
d.call((new Date).getTime() - t.getTime());
}, n * 1000);
d.canceller = function () { clearTimeout(id) };
return d;
};
function http (opts) {
var d = Deferred();
var req = new XMLHttpRequest();
req.open(opts.method, opts.url, true, opts.user || null, opts.password || null);
if (opts.headers) {
for (var k in opts.headers) if (opts.headers.hasOwnProperty(k)) {
req.setRequestHeader(k, opts.headers[k]);
}
}
req.onreadystatechange = function () {
if (req.readyState == 4) d.call(req);
};
req.send(opts.data || null);
d.xhr = req;
return d;
}
http.get = function (url) http({method:"get", url:url});
http.post = function (url, data) http({method:"post", url:url, data:data, headers:{"Content-Type":"application/x-www-form-urlencoded"}});
Deferred.Deferred = Deferred;
Deferred.http = http;
// copied from AutoPagerize (c) id:swdyh
function getElementsByXPath(xpath, node){
node = node || document;
var nodesSnapshot = (node.ownerDocument || node).evaluate(xpath, node, null,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
var data = [];
for(var i = 0, l = nodesSnapshot.snapshotLength; i < l;
data.push(nodesSnapshot.snapshotItem(i++)));
return (data.length > 0) ? data : null;
}
function getFirstElementByXPath(xpath, node){
node = node || document;
var result = (node.ownerDocument || node).evaluate(xpath, node, null,
XPathResult.FIRST_ORDERED_NODE_TYPE, null);
return result.singleNodeValue ? result.singleNodeValue : null;
}
// copied from Pagerization (c) id:ofk
function parseHTML(str, ignoreTags) {
var exp = "^[\\s\\S]*?]*)?>|[\\S\\s]*$";
if (ignoreTags) {
if (typeof ignoreTags == "string") ignoreTags = [ignoreTags];
var stripTags = [];
ignoreTags = ignoreTags.filter(function(tag) tag[tag.length - 1] == "/" || !stripTags.push(tag))
.map(function(tag) tag.replace(/\/$/, ""));
if (stripTags.length > 0) {
stripTags = stripTags.length > 1
? "(?:" + stripTags.join("|") + ")"
: String(stripTags);
exp += "|<" + stripTags + "(?:\\s[^>]*|/)?>|" + stripTags + "\\s*>";
}
}
str = str.replace(new RegExp(exp, "ig"), "");
var res = document.implementation.createDocument(null, "html", null);
var range = document.createRange();
range.setStartAfter(window.content.document.body);
res.documentElement.appendChild(res.importNode(range.createContextualFragment(str), true));
if (ignoreTags) ignoreTags.forEach(function(tag) {
var elements = res.getElementsByTagName(tag);
for (var i = elements.length, el; el = elements.item(--i); el.parentNode.removeChild(el));
});
return res;
}
var DownloadManager = Cc['@mozilla.org/download-manager;1']
.getService(Ci.nsIDownloadManager);
const nicoApiEndPoint = 'http://www.nicovideo.jp/api/getflv?v=';
const nicoWatchEndPoint = 'http://www.nicovideo.jp/watch/';
var groupId = liberator.globalVariables.nicovideo_mylist || '';
function NiconicoFlvHandler(url, title) {
let videoId = url.match(/\w{2}\d+/)[0];
let fileName = title.replace(/[?\\*\/:`|"]/g, '_') + '.flv';
Deferred.http.get(nicoApiEndPoint + videoId).next(function(apiResult){
let flvUrl = decodeURIComponent(apiResult.responseText.match(/url=(.*?)&/)[1]);
return Deferred.http.get(nicoWatchEndPoint + videoId).next(function(watchPage){
let WebBrowserPersist = Cc['@mozilla.org/embedding/browser/nsWebBrowserPersist;1']
.createInstance(Ci.nsIWebBrowserPersist);
let sourceUri = makeURI(flvUrl, null, null);
let file = DownloadManager.userDownloadsDirectory;
file.appendRelativePath(fileName);
let fileUri = makeFileURI(file);
let download = DownloadManager.addDownload(
0, sourceUri, fileUri, fileName,
null, null, null, null, WebBrowserPersist
);
WebBrowserPersist.progressListener = download;
WebBrowserPersist.saveURI(sourceUri, null, null, null, null, file);
});
}).error(function(e){
log(e);
liberator.echoerr(e);
});
}
var count = 0;
function NiconicoMylistHandler(url, title){
let videoId = url.match(/\w{2}\d+/)[0];
Deferred.wait(count++ * 5).next(function(est){
return Deferred.http.get(nicoWatchEndPoint + videoId).next(function(watchResult){
var html = parseHTML(watchResult.responseText, ['img', 'script']);
var csrfToken = getElementsByXPath('//input[@name="csrf_token"]', html)[0].value;
var mylists = getElementsByXPath('id("mylist_add_group_id")/option', html).map(function(element) [element.innerHTML, element.value]);
var params = [['ajax', '1'], ['mylist', 'add'], ['mylist_add', '登録'], ['csrf_token', csrfToken], ['group_id', groupId]].map(function(p) p[0] + "=" + encodeURIComponent(p[1])).join("&");
return Deferred.wait(count++ * 5).next(function(est){
return Deferred.http.post(nicoWatchEndPoint + videoId, params).next(function(mylistResult){
liberator.log(mylistResult.responseText);
});
});
});
}).error(function(e){
log(e);
liberator.echoerr(e);
});
}
function setupLDRizeCooperationNiconicoFlvFetcher() {
let NiconicoFlvFetcher = {
pattern: 'http://www.nicovideo.jp/watch/*',
handler: {
download: NiconicoFlvHandler,
mylist: NiconicoMylistHandler
},
wait: 5000,
};
this.convertHandlerInfo([NiconicoFlvFetcher]);
this.handlerInfo.unshift(NiconicoFlvFetcher);
}
if (liberator.plugins.LDRizeCooperation === undefined) {
liberator.plugins.LDRizeCooperationPlugins = liberator.plugins.LDRizeCooperationPlugins || [];
liberator.plugins.LDRizeCooperationPlugins.push(setupLDRizeCooperationNiconicoFlvFetcher);
}
else {
setupLDRizeCooperationNiconicoFlvFetcher.apply(liberator.plugins.LDRizeCooperation);
}
function httpGET(uri, callback) {
let xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) callback.call(this,xhr.responseText);
else throw new Error(xhr.statusText)
}
};
xhr.open('GET', uri, true);
xhr.send(null);
}
liberator.modules.commands.addUserCommand(
['fetchflv'],
'Download flv file from Nicovideo',
function (arg) {
httpGET(
arg.string || liberator.modules.buffer.URL,
function (responseText) {
let [, title] = responseText.match(/
]*)?>([^<]*)<\/title[ \t\n\r]*>/i);
liberator.log(title);
NiconicoFlvHandler(arg.string || liberator.modules.buffer.URL, title);
}
);
},
{}
);
liberator.modules.commands.addUserCommand(
['nicomylist'],
'Select Nicovideo mylist',
function (arg) {
groupId = arg.string;
},
{
completer: function(context,arg){
Deferred.http.get(nicoWatchEndPoint + "sm2757983").next(function(watchResult){
var html = parseHTML(watchResult.responseText, ['img', 'script']);
var mylists = getElementsByXPath('id("mylist_add_group_id")/option', html).map(function(element) [element.value, element.innerHTML]);
context.title = ['ID', 'Name'];
context.advance = mylists.length;
context.completions = mylists;
}).error(function(e){
log(e);
liberator.echoerr(e);
});
}
});
})();