/* * readitlater.js * read it later apiをたたく * API Reffernce : http://readitlaterlist.com/api/docs/ * TODO:ADDにbufferからのリストを入れられるように */ let PLUGIN_INFO = readitlater Read it Later を快適に使うためのプラグインです 0.3.1 3.0 ninja.tottori https://github.com/vimpr/vimperator-plugins/raw/master/readitlater.js で補完にreaditlaterのリストが出てくるので、任意のURLを選択()して実行すると新しいタブに開きます。 :ril open! と!をつけると既読のみ補完に表示されます。 また、開くと同時に既読フラグを立てに行く事ができます。 let g:readitlater_open_as_read = 1 としてもらえれば大丈夫です。 :ril read 既読フラグを立てる為のサブコマンドです。 openした時に既読にしたくないっていう人はこれを使って既読フラグを立てて下さい。 :ril stats since, list, unread, read の情報がとれます ]]> ; (function(){ commands.addUserCommand(["ril","readitlater"], "Read It Late plugin", function(args){ addItemByArgs(args); }, { subCommands: [ new Command(["add","a"], "Add a page to a user's list", function (args) { addItemByArgs(args); },{ literal: 0, options : [ [["url","u"],commands.OPTION_STRING,null, (function(){ return [[ buffer.URL ,"target url"]] }) ], [["title","t"],commands.OPTION_STRING,null, (function(){ return [[ buffer.title ,"title"]] }) ], ], completer: function (context, args) completion.url(context, liberator.globalVariables.readitlater_complete) } ), /* new Command(["get","g"], "Retrieve a user's reading list", function (args) { ListCache.unread.update(true, function(data) echo(countObjectValues(data.list) + " found.")); },{ options : [ //[["num"],commands.OPTION_INT], //[["read","-r"],commands.OPTION_NOARG], //[["tags","-t"],commands.OPTION_NOARG], //[["myAppOnly"],commands.OPTION_NOARG], ], } ), */ new Command(["open","o"], "Open url in new tab from RIL list.", function (args) { liberator.open(args, liberator.NEW_BACKGROUND_TAB); if(liberator.globalVariables.readitlater_open_as_read == 1) markAsRead(args); },{ bang: true, completer : listCompleter, } ), new Command(["read","r"], "Mark items as read.", function (args) { markAsRead(args); },{ bang: true, completer : listCompleter, } ), new Command(["stats","s"], "Retrieve information about a user's list", function (args) { ReadItLater.stats(); },{} ), /* new Command(["test"], "Return stats / current rate limit information about your API key", function () { ReadItLater.apiTest(); },{} ), */ ], }, true ); const CacheStore = storage.newMap("readitlater",{store:true}); // Cache {{{ function Cache ({updater, name, limit}) { this.limit = limit || 10 * 1000 * 60; this.name = name; this.updater = updater; } Cache.prototype = { get cache() CacheStore.get(name, void 0), set cache(value) CacheStore.set(name, value), get: function(callback){ // {{{ let self = this; if (this.isExpired || !this.cache) { this.lastUpdated = new Date().getTime(); this.update(true, callback); return; } callback(this.cache); }, // }}} update: function(force, callback){ // {{{ if (!force && !this.isExpired) return; let self = this; liberator.log('[ReadItLater] cache updating'); this.updater(function(data){ self.cache = data; if (callback) callback(data); }); }, //}}} save: function() CacheStore.save(), get isExpired() (!this.lastUpdated || (new Date().getTime() > (this.lastUpdated + this.limit))), remove: function(url){ // {{{ if (!this.cache) return this.udpate(true); let names = [n for ([n, v] in Iterator(this.cache.list)) if (v.url == url)]; for (let [, name] in Iterator(names)) delete this.cache.list[name]; this.save(); this.update(); } // }}} }; // }}} let ReadItLater = { api_key : (liberator.globalVariables.readitlater_api_key) ? liberator.globalVariables.readitlater_api_key : "966T6ahYgb081icU10d44byL31p5bF20" , text : function(){ // {{{ let req = new libly.Request( "https://text.readitlaterlist.com/v2/text" , // url null, // headers { // options asynchronous:true, postBody:getParameterMap( { apikey : this.api_key, url : buffer.URL, mode : "less", images : 0, } ) } ); req.addEventListener("success",function(data){ e(data.responseText) }); req.addEventListener("failure",function(data){ liberator.echoerr(data.statusText); liberator.echoerr(data.responseText); }); req.post(); }, // }}} get : function(state, callback){ // {{{ // document => http://readitlaterlist.com/api/docs#get let manager = Components.classes["@mozilla.org/login-manager;1"].getService(Components.interfaces.nsILoginManager); let logins = manager.findLogins({},"http://readitlaterlist.com","",null); let req = new libly.Request( "https://readitlaterlist.com/v2/get" , // url null, // headers { // options asynchronous:true, postBody:getParameterMap( { apikey : this.api_key, username : logins[0].username, password : logins[0].password, format : "json", count : (liberator.globalVariables.readitlater_get_count? liberator.globalVariables.readitlater_get_count : 50 ), state : state //tags : (args["tags"]) ? 1 : 0, //myAppOnly: (args["myAppOnly"]) ? 1 : 0, } ) } ); req.addEventListener("success",function(data) callback(libly.$U.evalJson(data.responseText))); req.addEventListener("failure",function(data){ liberator.echoerr(data.statusText); liberator.echoerr(data.responseText); }); req.post(); }, // }}} add : function(url,title,callback){ // {{{ let manager = Components.classes["@mozilla.org/login-manager;1"].getService(Components.interfaces.nsILoginManager); let logins = manager.findLogins({},"http://readitlaterlist.com","",null); let req = new libly.Request( "https://readitlaterlist.com/v2/add" , // url null, // headers { // options asynchronous:true, postBody:getParameterMap( { apikey : this.api_key, username : logins[0].username, password : logins[0].password, url : url, title : title, } ) } ); req.addEventListener("success",callback); req.addEventListener("failure",function(data){ liberator.echoerr(data.statusText); liberator.echoerr(data.responseText); }); req.post(); }, // }}} send : function(urls, callback) { //{{{ // http://readitlaterlist.com/api/docs/#send let manager = Components.classes["@mozilla.org/login-manager;1"].getService(Components.interfaces.nsILoginManager); let logins = manager.findLogins({},"http://readitlaterlist.com","",null); function make_read_list(args){ let o = {}; for (let i = 0; i < args.length; i++) { o[i] = {"url":args[i]}; }; return JSON.stringify(o); } let req = new libly.Request( "https://readitlaterlist.com/v2/send" , // url null, // headers { // options asynchronous:true, postBody:getParameterMap( { apikey : this.api_key, username : logins[0].username, password : logins[0].password, read : make_read_list(urls), } ) } ); var ref = this; req.addEventListener("success",callback); req.addEventListener("failure",function(data){ liberator.echoerr(data.statusText); liberator.echoerr(data.responseText); }); req.post(); }, // }}} stats : function(){ // {{{ let manager = Components.classes["@mozilla.org/login-manager;1"].getService(Components.interfaces.nsILoginManager); let logins = manager.findLogins({},"http://readitlaterlist.com","",null); let req = new libly.Request( "https://readitlaterlist.com/v2/stats" , // url null, // headers { // options asynchronous:true, postBody:getParameterMap( { apikey : this.api_key, username : logins[0].username, password : logins[0].password, format : "json", } ) } ); req.addEventListener("success",function(data){ let res = libly.$U.evalJson(data.responseText); liberator.echo( +
#ReadItLater Stats
+
since : {unixtimeToDate(res.user_since)}
list : {res.count_list}
unread : {res.count_unread}
read : {res.count_read}
); }); req.addEventListener("failure",function(data){ liberator.echoerr(data.statusText); liberator.echoerr(data.responseText); }); req.post(); }, // }}} apiTest : function(){ // {{{ let req = new libly.Request( "https://readitlaterlist.com/v2/api" , // url null, // headers { // options asynchronous:true, postBody:getParameterMap( { apikey : this.api_key, } ) } ); req.addEventListener("success",function(data){ liberator.echo(
X-Limit-User-Limit : {data.transport.getResponseHeader("X-Limit-User-Limit")}
X-Limit-User-Remaining : {data.transport.getResponseHeader("X-Limit-User-Remaining")}
X-Limit-User-Reset : {data.transport.getResponseHeader("X-Limit-User-Reset")}
X-Limit-Key-Limit : {data.transport.getResponseHeader("X-Limit-Key-Limit")}
X-Limit-Key-Remaining : {data.transport.getResponseHeader("X-Limit-Key-Remaining")}
X-Limit-Key-Reset : {data.transport.getResponseHeader("X-Limit-Key-Reset")}
); }); req.addEventListener("failure",function(data){ liberator.echoerr(data.statusText); liberator.echoerr(data.responseText); }); req.post(); }, // }}} } let ListCache = { all: new Cache({name: 'list', updater: ReadItLater.get.bind(ReadItLater, '')}), unread: new Cache({name: 'list', updater: ReadItLater.get.bind(ReadItLater, 'unread')}) }; function markAsRead(urls){ // {{{ for (let [, url] in Iterator(urls)) ListCache.unread.remove(url); ReadItLater.send(urls, echo.bind(null, "Mark as read: " + urls.length)); } // }}} function addItemByArgs(args){ // {{{ let url = args["url"] || args.literalArg; let title = args["title"] || (url ? undefined : buffer.title); if (!url) url = buffer.URL; ReadItLater.add(url, title, function(){ echo("Added: " + (title || url)); ListCache.unread.update(true); }); } // }}} function echo(msg){ // {{{ liberator.echo("[ReadItLater] " + msg); } // }}} function listCompleter(context,args){ // {{{ function sortDate(store){ let ary = []; for (let s in store){ ary.push([s[1].time_updated,s[1]]); // 更新日でソート } ary.sort(function(a,b){return -(a[0] - b[0])}); return ary; } context.title = ["url","title"] context.filters = [CompletionContext.Filter.textDescription]; // titleも補完対象にする context.compare = void 0; context.anchored = false; context.incomplete = true; ListCache[args.bang ? 'all' : 'unread'].get(function(data){ context.completions = [ [item.url,item.title] for([, item] in Iterator(data.list)) if( !args.some(function (arg) arg == item.url) ) ]; context.incomplete = false; }); } //}}} function unixtimeToDate(ut) { // {{{ var t = new Date( ut * 1000 ); t.setTime( t.getTime() + (60*60*1000 * 9) ); // +9は日本のタイムゾーン return t; } // }}} function getParameterMap(parameters){ // {{{ return [ key + "=" + encodeURIComponent(value) for ([key, value] in Iterator(parameters)) if (value) ].join("&"); } // }}} function countObjectValues(obj){ // {{{ return [1 for (_ in Iterator(obj))].length; } // }}} // for debug {{{ function e(v,c){ if(c) util.copyToClipboard(v); liberator.log(v,-1) } // }}} // Export {{{ __context__.ListCache = ListCache; __context__.API = ReadItLater; __context__.WrappedAPI = { markAsRead: markAsRead } // }}} })(); // vim: set noet :