Aria2 RPC

Aria2 RPC Library

This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.greatest.deepsurf.us/scripts/5672/933444/Aria2%20RPC.js

  1. // ==UserScript==
  2. // @name Aria2 RPC
  3. // @namespace moe.jixun
  4. // @version 0.1
  5. // @license MIT
  6. // ==/UserScript==
  7.  
  8. // Public Class Aria2 ( options )
  9.  
  10. var Aria2 = (function (_isGM, _arrFn, _merge, _format, _isFunction) {
  11. var jsonrpc_ver = '2.0';
  12.  
  13. if (_isGM) {
  14. var doRequest = function ( opts ) {
  15. console.warn ([
  16. 'Warning: You are now using an simple implementation of GM_xmlhttpRequest',
  17. 'Cross-domain request are not avilible unless configured correctly @ target server.',
  18. '',
  19. 'Some of its features are not avilible, such as `username` and `password` field.'
  20. ].join('\n'));
  21.  
  22. var oReq = new XMLHttpRequest ();
  23. var cbCommon = function (cb) {
  24. return (function () {
  25. cb ({
  26. readyState: oReq.readyState,
  27. responseHeaders: opts.getHeader ? oReq.getAllResponseHeaders() : null,
  28. getHeader: oReq.getResponseHeader.bind (oReq),
  29. responseText: oReq.responseText,
  30. status: oReq.status,
  31. statusText: oReq.statusText
  32. });
  33. }).bind (opts);
  34. };
  35.  
  36. if (opts.onload) oReq.onload = cbCommon (opts.onload);
  37. if (opts.onerror) oReq.onerror = cbCommon (opts.onerror);
  38.  
  39. oReq.open(opts.method || 'GET', opts.url, !opts.synchronous);
  40.  
  41. if (opts.headers) {
  42. Object.keys(opts.headers).forEach (function (key) {
  43. oReq.setRequestHeader (key, opts.headers[key]);
  44. });
  45. }
  46. return oReq.send(opts.data || null);
  47. };
  48. } else {
  49. var doRequest = GM_xmlhttpRequest;
  50. }
  51.  
  52. var AriaBase = function ( options ) {
  53. this.options = _merge ({
  54. auth: {
  55. type: AriaBase.AUTH.noAuth,
  56. user: '',
  57. pass: ''
  58. },
  59. host: '127.0.0.1',
  60. port: 6800
  61. }, options || {});
  62.  
  63. this.id = parseInt (options, 10) || (+ new Date());
  64. };
  65. // 静态常量
  66. AriaBase.AUTH = {
  67. noAuth: 0,
  68. basic: 1,
  69. secret: 2
  70. };
  71.  
  72. // public 函数
  73. AriaBase.prototype = {
  74. getBasicAuth: function () {
  75. return btoa (_format('%s:%s', this.options.auth.user, this.options.auth.pass));
  76. },
  77.  
  78. send: function ( bIsDataBatch, data, cbSuccess, cbError ) {
  79. var srcTaskObj = { jsonrpc: jsonrpc_ver, id: this.id };
  80.  
  81. var payload = {
  82.  
  83. method: 'POST',
  84. url: _format('http://%s:%s/jsonrpc', this.options.host, this.options.port),
  85. headers: {
  86. 'Content-Type': 'application/json; charset=UTF-8'
  87. },
  88. data: bIsDataBatch
  89. ? data.map (function (e) { return _merge ({}, srcTaskObj, e); })
  90. : _merge ({}, srcTaskObj, data),
  91. onload: function (r) {
  92. var repData = JSON.parse (r.responseText);
  93. if (repData.error) {
  94. cbError && cbError (false, repData);
  95. } else {
  96. cbSuccess && cbSuccess (repData);
  97. }
  98. },
  99. onerror: cbError ? cbError.bind(null, false) : null
  100. };
  101.  
  102. switch ( parseInt (this.options.auth.type, 10) ) {
  103. case AriaBase.AUTH.noAuth:
  104. // DO NOTHING
  105. break;
  106.  
  107. case AriaBase.AUTH.basic:
  108. payload.headers.Authorization = 'Basic ' + this.getBasicAuth();
  109. break;
  110.  
  111. case AriaBase.AUTH.secret:
  112. (function (sToken) {
  113. if (bIsDataBatch) {
  114. for (var i = 0; i < payload.data.length; i++) {
  115. payload.data[i].params.splice(0, 0, sToken);
  116. }
  117. } else {
  118. if (!payload.data.params)
  119. payload.data.params = [];
  120. payload.data.params.splice(0, 0, sToken);
  121. }
  122. })(_format('token:%s', this.options.auth.pass));
  123. break;
  124.  
  125. default:
  126. throw new Error('Undefined auth type: ' + this.options.auth.type);
  127. }
  128.  
  129. payload.data = JSON.stringify ( payload.data );
  130.  
  131. return doRequest (payload);
  132. },
  133.  
  134. // batchAddUri ( foo, { uri: 'http://example.com/xxx', options: { ... } } )
  135. batchAddUri: function (fCallback) {
  136. console.warn (
  137. 'This function [%s] has deprecated! Consider use %s instead.',
  138. 'batchAddUri', 'AriaBase.BATCH'
  139. );
  140.  
  141. // { url, name }
  142. var payload = [].slice.call (arguments, 1).map (function (arg) {
  143. return {
  144. method: 'aria2.addUri',
  145. params: [ arg.uri.map ? arg.uri : [ arg.uri ] ].concat (arg.options || [])
  146. };
  147. });
  148. return this.send (true, payload, fCallback, fCallback);
  149. }
  150. };
  151.  
  152.  
  153. // 添加各类函数
  154. AriaBase.fn = {};
  155. _arrFn.forEach (function (sMethod) {
  156. // 函数链表
  157. AriaBase.fn[sMethod] = sMethod;
  158.  
  159. // arg1, arg2, ... , [cbSuccess, [cbError]]
  160. AriaBase.prototype[sMethod] = function ( ) {
  161. var args = [].slice.call (arguments);
  162.  
  163. var cbSuccess, cbError;
  164. if (args.length && _isFunction(args[args.length - 1])) {
  165. cbSuccess = args[args.length - 1];
  166. args.splice (-1, 1);
  167.  
  168. if (args.length && _isFunction(args[args.length - 1])) {
  169. cbError = cbSuccess;
  170. cbSuccess = args[args.length - 1];
  171. args.splice (-1, 1);
  172. }
  173. }
  174.  
  175. return this.send (false, {
  176. method: 'aria2.' + sMethod,
  177. params: args
  178. }, cbSuccess, cbError);
  179. };
  180. });
  181.  
  182. AriaBase.BATCH = function ( parent, cbSuccess, cbFail ) {
  183. if (!(parent instanceof AriaBase))
  184. throw new Error ('Parent is not AriaBase!');
  185.  
  186. this.parent = parent;
  187. this.data = [];
  188.  
  189. this.onSuccess = cbSuccess;
  190. this.onFail = cbFail;
  191. };
  192.  
  193. AriaBase.BATCH.prototype = {
  194. addRaw: function (fn, args) {
  195. this.data.push ({
  196. method: 'aria2.' + fn,
  197. params: args
  198. });
  199. return this;
  200. },
  201.  
  202. add: function (fn) {
  203. // People can add more without edit source.
  204. if (!AriaBase.fn[fn])
  205. throw new Error ('Unknown function: ' + fn + ', please check if you had a typo.');
  206.  
  207. return this.addRaw (fn, [].slice.call(arguments, 1));
  208. },
  209.  
  210. send: function () {
  211. // bIsDataBatch, data, cbSuccess, cbError
  212. var ret = this.parent.send ( true, this.data, this.onSuccess, this.onFail );
  213. this.reset ();
  214. return ret;
  215. },
  216.  
  217. getActions: function () {
  218. return this.data.slice();
  219. },
  220.  
  221. setActions: function (actions) {
  222. if (!actions || !actions.map) return ;
  223.  
  224. this.data = actions;
  225. },
  226.  
  227. reset: function () {
  228. this.onSuccess = this.onFail = null;
  229. this.setActions ( [] );
  230. }
  231. };
  232. return AriaBase;
  233. })
  234. // const 变量
  235. ('undefined' == typeof GM_xmlhttpRequest, [
  236. "addUri", "addTorrent", "addMetalink", "remove", "forceRemove",
  237. "pause", "pauseAll", "forcePause", "forcePauseAll", "unpause",
  238. "unpauseAll", "tellStatus", "getUris", "getFiles", "getPeers",
  239. "getServers", "tellActive", "tellWaiting", "tellStopped",
  240. "changePosition", "changeUri", "getOption", "changeOption",
  241. "getGlobalOption", "changeGlobalOption", "getGlobalStat",
  242. "purgeDownloadResult", "removeDownloadResult", "getVersion",
  243. "getSessionInfo", "shutdown", "forceShutdown", "saveSession"
  244. ],
  245. // private 函数
  246. (function (base) {
  247. var _isObject = function (obj) {
  248. return obj instanceof Object;
  249. };
  250. var _merge = function (base) {
  251. var args = arguments,
  252. argL = args.length;
  253. for ( var i = 1; i < argL; i++ ) {
  254. Object.keys (args[i]).forEach (function (key) {
  255. if (_isObject(args[i][key]) && _isObject(base[key])) {
  256. base[key] = _merge (base[key], args[i][key]);
  257. } else {
  258. base[key] = args[i][key];
  259. }
  260. });
  261. }
  262. return base;
  263. };
  264. return _merge;
  265. })(), function (src) {
  266. var args = arguments,
  267. argL = args.length;
  268.  
  269. var ret = src.slice ();
  270. for ( var i = 1; i < argL; i++ )
  271. ret = ret.replace ('%s', args[i]);
  272. return ret;
  273. }, function (foo) {
  274. return typeof foo === 'function'
  275. });