Aria2 RPC

Aria2 RPC Library

Este script não deve ser instalado diretamente. Este script é uma biblioteca de outros scripts para incluir com o diretório meta // @require https://update.greatest.deepsurf.us/scripts/5672/933444/Aria2%20RPC.js

Você precisará instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Você precisará instalar uma extensão como o Tampermonkey para instalar este script.

Você precisará instalar um gerenciador de scripts de usuário para instalar este script.

(Eu já tenho um gerenciador de scripts de usuário, me deixe instalá-lo!)

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

(Eu já possuo um gerenciador de estilos de usuário, me deixar fazer a instalação!)

// ==UserScript==
// @name         Aria2 RPC
// @namespace    moe.jixun
// @version      0.1
// @license      MIT
// ==/UserScript==

// Public Class Aria2 ( options )

var Aria2 = (function (_isGM, _arrFn, _merge, _format, _isFunction) {
	var jsonrpc_ver = '2.0';

	if (_isGM) {
		var doRequest = function ( opts ) {
			console.warn ([
				'Warning: You are now using an simple implementation of GM_xmlhttpRequest',
				'Cross-domain request are not avilible unless configured correctly @ target server.',
				'',
				'Some of its features are not avilible, such as `username` and `password` field.'
			].join('\n'));

			var oReq = new XMLHttpRequest ();
			var cbCommon = function (cb) {
				return (function () {
					cb ({
						readyState: oReq.readyState,
						responseHeaders: opts.getHeader ? oReq.getAllResponseHeaders() : null,
						getHeader: oReq.getResponseHeader.bind (oReq),
						responseText: oReq.responseText,
						status: oReq.status,
						statusText: oReq.statusText
					});
				}).bind (opts);
			};

			if (opts.onload)  oReq.onload   = cbCommon (opts.onload);
			if (opts.onerror) oReq.onerror  = cbCommon (opts.onerror);

			oReq.open(opts.method || 'GET', opts.url, !opts.synchronous);

			if (opts.headers) {
				Object.keys(opts.headers).forEach (function (key) {
					oReq.setRequestHeader (key, opts.headers[key]);
				});
			}
			return oReq.send(opts.data || null);
		};
	} else {
		var doRequest = GM_xmlhttpRequest;
	}

	var AriaBase = function ( options ) {
		this.options = _merge ({
			auth: {
				type: AriaBase.AUTH.noAuth,
				user: '',
				pass: ''
			},
			host: '127.0.0.1',
			port: 6800
		}, options || {});

		this.id = parseInt (options, 10) || (+ new Date());
	};
	
	// 静态常量
	AriaBase.AUTH = {
		noAuth: 0,
		basic:  1,
		secret: 2
	};

	// public 函数
	AriaBase.prototype = {
		getBasicAuth: function () {
			return btoa (_format('%s:%s', this.options.auth.user, this.options.auth.pass));
		},

		send: function ( bIsDataBatch, data, cbSuccess, cbError ) {
			var srcTaskObj = { jsonrpc: jsonrpc_ver, id: this.id };

			var payload = {

				method: 'POST',
				url: _format('http://%s:%s/jsonrpc', this.options.host, this.options.port),
				headers: {
					'Content-Type': 'application/json; charset=UTF-8'
				},
				data: bIsDataBatch
					? data.map (function (e) { return _merge ({}, srcTaskObj, e); })
					: _merge ({}, srcTaskObj, data),
				onload: function (r) {
					var repData = JSON.parse (r.responseText);
					if (repData.error) {
						cbError && cbError (false, repData);
					} else {
						cbSuccess && cbSuccess (repData);
					}
				},
				onerror: cbError ? cbError.bind(null, false) : null
			};

			switch ( parseInt (this.options.auth.type, 10) ) {
				case AriaBase.AUTH.noAuth:
					// DO NOTHING
					break;

				case AriaBase.AUTH.basic:
					payload.headers.Authorization = 'Basic ' + this.getBasicAuth();
					break;

				case AriaBase.AUTH.secret:
					(function (sToken) {
						if (bIsDataBatch) {
							for (var i = 0; i < payload.data.length; i++) {
								payload.data[i].params.splice(0, 0, sToken);
							}
						} else {
							if (!payload.data.params)
								payload.data.params = [];
							payload.data.params.splice(0, 0, sToken);
						}
					})(_format('token:%s', this.options.auth.pass));
					break;

				default:
					throw new Error('Undefined auth type: ' + this.options.auth.type);
			}

			payload.data = JSON.stringify ( payload.data );

			return doRequest (payload);
		},

		// batchAddUri ( foo, { uri: 'http://example.com/xxx', options: { ... } } )
		batchAddUri: function (fCallback) {
			console.warn (
				'This function [%s] has deprecated! Consider use %s instead.',
				'batchAddUri', 'AriaBase.BATCH'
			);

			// { url, name }
			var payload = [].slice.call (arguments, 1).map (function (arg) {
				return {
					method: 'aria2.addUri',
					params: [ arg.uri.map ? arg.uri : [ arg.uri ] ].concat (arg.options || [])
				};
			});
			
			return this.send (true, payload, fCallback, fCallback);
		}
	};


	// 添加各类函数
	AriaBase.fn = {};
	_arrFn.forEach (function (sMethod) {
		// 函数链表
		AriaBase.fn[sMethod] = sMethod;

		// arg1, arg2, ... , [cbSuccess, [cbError]]
		AriaBase.prototype[sMethod] = function ( ) {
			var args = [].slice.call (arguments);

			var cbSuccess, cbError;
			if (args.length && _isFunction(args[args.length - 1])) {
				cbSuccess = args[args.length - 1];
				args.splice (-1, 1);

				if (args.length && _isFunction(args[args.length - 1])) {
					cbError = cbSuccess;
					cbSuccess = args[args.length - 1];
					args.splice (-1, 1);
				}
			}

			return this.send (false, {
				method: 'aria2.' + sMethod,
				params: args
			}, cbSuccess, cbError);
		};
	});

	AriaBase.BATCH = function ( parent, cbSuccess, cbFail ) {
		if (!(parent instanceof AriaBase))
			throw new Error ('Parent is not AriaBase!');

		this.parent = parent;
		this.data = [];

		this.onSuccess = cbSuccess;
		this.onFail = cbFail;
	};

	AriaBase.BATCH.prototype = {
		addRaw: function (fn, args) {
			this.data.push ({
				method: 'aria2.' + fn,
				params: args
			});
			return this;
		},

		add: function (fn) {
			// People can add more without edit source.
			if (!AriaBase.fn[fn])
				throw new Error ('Unknown function: ' + fn + ', please check if you had a typo.');

			return this.addRaw (fn, [].slice.call(arguments, 1));
		},

		send: function () {
			// bIsDataBatch, data, cbSuccess, cbError
			var ret = this.parent.send ( true, this.data, this.onSuccess, this.onFail );
			this.reset ();
			return ret;
		},

		getActions: function () {
			return this.data.slice();
		},

		setActions: function (actions) {
			if (!actions || !actions.map) return ;

			this.data = actions;
		},

		reset: function () {
			this.onSuccess = this.onFail = null;
			this.setActions ( [] );
		}
	};
	
	return AriaBase;
})
// const 变量
('undefined' == typeof GM_xmlhttpRequest, [
	"addUri", "addTorrent", "addMetalink", "remove", "forceRemove",
	"pause", "pauseAll", "forcePause", "forcePauseAll", "unpause",
	"unpauseAll", "tellStatus", "getUris", "getFiles", "getPeers",
	"getServers", "tellActive", "tellWaiting", "tellStopped",
	"changePosition", "changeUri", "getOption", "changeOption",
	"getGlobalOption", "changeGlobalOption", "getGlobalStat",
	"purgeDownloadResult", "removeDownloadResult", "getVersion",
	"getSessionInfo", "shutdown", "forceShutdown", "saveSession"
], 
// private 函数
(function (base) {
	var _isObject = function (obj) {
		return obj instanceof Object;
	};
	var _merge = function (base) {
		var args = arguments,
			argL = args.length;
		for ( var i = 1; i < argL; i++ ) {
			Object.keys (args[i]).forEach (function (key) {
				if (_isObject(args[i][key]) && _isObject(base[key])) {
					base[key] = _merge (base[key], args[i][key]);
				} else {
					base[key] = args[i][key];
				}
			});
		}
		return base;
	};
	return _merge;
})(), function (src) {
	var args = arguments,
		argL = args.length;

	var ret = src.slice ();
	for ( var i = 1; i < argL; i++ )
		ret = ret.replace ('%s', args[i]);
	return ret;
}, function (foo) {
	return typeof foo === 'function'
});