You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

390 lines
14 KiB

#-*- coding=utf-8 -*-
import requests
import json
import subprocess
import os
import time
import base64
import sys
if sys.version_info[0]==2:
import xmlrpclib
else:
import xmlrpc.client as xmlrpclib
from self_config import *
class PyAria2(object):
def __init__(self,host,port,secret,scheme,session=None):
'''
PyAria2 constructor.
host: string, aria2 rpc host, default is 'localhost'
port: integer, aria2 rpc port, default is 6800
session: string, aria2 rpc session saving.
'''
if not isAria2Installed():
raise Exception('aria2 is not installed, please install it before.')
if not isAria2rpcRunning():
cmd = 'aria2c' \
' --enable-rpc' \
' --rpc-listen-port {}' \
' --continue' \
' --max-concurrent-downloads=20' \
' --max-connection-per-server=10' \
' --rpc-max-request-size=1024M'.format(port)
if not session is None:
cmd += ' --input-file=%s' \
' --save-session-interval=60' \
' --save-session=%s' % (session, session)
subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
count = 0
while True:
if isAria2rpcRunning():
break
else:
count += 1
time.sleep(3)
if count == 5:
raise Exception('aria2 RPC server started failure.')
print('aria2 RPC server is started.')
else:
print('aria2 RPC server is already running.')
self.server_uri = scheme+'://{}:{}/jsonrpc'.format(host, port)
self.secret = secret
self.server = xmlrpclib.ServerProxy(self.server_uri, allow_none=True)
def sendJsonRPC(self, data):
r = requests.post(self.server_uri, data=data)
return r.text
def getRPCBody(self, method, params=None):
'''Create RPC body'''
uid = '1'
params = params if params else []
if self.secret is not None and self.secret!='':
params.insert(0, 'token:{}'.format(self.secret))
j = json.dumps([{
'jsonrpc': '2.0',
'id': uid,
'method': method,
'params': params,
}])
return j
def addUri(self, uris, options=None, position=None):
'''
This method adds new HTTP(S)/FTP/BitTorrent Magnet URI.
uris: list, list of URIs
options: dict, additional options
position: integer, position in download queue
return: This method returns GID of registered download.
'''
params = [[uris]]
if options:
params.append(options)
#params.append(position)
return self.sendJsonRPC(data=self.getRPCBody('aria2.addUri', params))
def addTorrent(self, torrent, uris=None, options=None, position=None):
'''
This method adds BitTorrent download by uploading ".torrent" file.
torrent: string, torrent file path
uris: list, list of webseed URIs
options: dict, additional options
position: integer, position in download queue
return: This method returns GID of registered download.
'''
return self.server.aria2.addTorrent(xmlrpclib.Binary(open(torrent, 'rb').read()), uris, options, position)
def addMetalink(self, metalink, options=None, position=None):
'''
This method adds Metalink download by uploading ".metalink" file.
metalink: string, metalink file path
options: dict, additional options
position: integer, position in download queue
return: This method returns list of GID of registered download.
'''
return self.server.aria2.addMetalink(xmlrpclib.Binary(open(metalink, 'rb').read()), options, position)
def remove(self, gid):
'''
This method removes the download denoted by gid.
gid: string, GID.
return: This method returns GID of removed download.
'''
params = [gid]
return self.sendJsonRPC(data=self.getRPCBody('aria2.remove', params))
def forceRemove(self, gid):
'''
This method removes the download denoted by gid.
gid: string, GID.
return: This method returns GID of removed download.
'''
params = [gid]
return self.sendJsonRPC(data=self.getRPCBody('aria2.forceRemove', params))
def pause(self, gid):
'''
This method pauses the download denoted by gid.
gid: string, GID.
return: This method returns GID of paused download.
'''
params = [gid]
return self.sendJsonRPC(data=self.getRPCBody('aria2.pause', params))
def pauseAll(self):
'''
This method is equal to calling aria2.pause() for every active/waiting download.
return: This method returns OK for success.
'''
return self.sendJsonRPC(data=self.getRPCBody('aria2.pauseAll'))
def forcePause(self, gid):
'''
This method pauses the download denoted by gid.
gid: string, GID.
return: This method returns GID of paused download.
'''
params = [gid]
return self.sendJsonRPC(data=self.getRPCBody('aria2.forcePause', params))
def forcePauseAll(self):
'''
This method is equal to calling aria2.forcePause() for every active/waiting download.
return: This method returns OK for success.
'''
return self.sendJsonRPC(data=self.getRPCBody('aria2.forcePauseAll'))
def unpause(self, gid):
'''
This method changes the status of the download denoted by gid from paused to waiting.
gid: string, GID.
return: This method returns GID of unpaused download.
'''
params = [gid]
return self.sendJsonRPC(data=self.getRPCBody('aria2.unpause', params))
def unpauseAll(self):
'''
This method is equal to calling aria2.unpause() for every active/waiting download.
return: This method returns OK for success.
'''
return self.sendJsonRPC(data=self.getRPCBody('aria2.unpauseAll'))
def tellStatus(self, gid, keys=None):
'''
This method returns download progress of the download denoted by gid.
gid: string, GID.
keys: list, keys for method response.
return: The method response is of type dict and it contains following keys.
'''
params = [gid]
if keys:
params.append(keys)
return self.sendJsonRPC(data=self.getRPCBody('aria2.tellStatus', params))
def getUris(self, gid):
'''
This method returns URIs used in the download denoted by gid.
gid: string, GID.
return: The method response is of type list and its element is of type dict and it contains following keys.
'''
params = [gid]
return self.sendJsonRPC(data=self.getRPCBody('aria2.getUris', params))
def getFiles(self, gid):
'''
This method returns file list of the download denoted by gid.
gid: string, GID.
return: The method response is of type list and its element is of type dict and it contains following keys.
'''
params = [gid]
return self.sendJsonRPC(data=self.getRPCBody('aria2.getFiles', params))
def getPeers(self, gid):
'''
This method returns peer list of the download denoted by gid.
gid: string, GID.
return: The method response is of type list and its element is of type dict and it contains following keys.
'''
return self.server.aria2.getPeers(gid)
def getServers(self, gid):
'''
This method returns currently connected HTTP(S)/FTP servers of the download denoted by gid.
gid: string, GID.
return: The method response is of type list and its element is of type dict and it contains following keys.
'''
return self.server.aria2.getServers(gid)
def tellActive(self, keys=None):
'''
This method returns the list of active downloads.
keys: keys for method response.
return: The method response is of type list and its element is of type dict and it contains following keys.
'''
return self.server.aria2.tellActive(keys)
def tellWaiting(self, offset, num, keys=None):
'''
This method returns the list of waiting download, including paused downloads.
offset: integer, the offset from the download waiting at the front.
num: integer, the number of downloads to be returned.
keys: keys for method response.
return: The method response is of type list and its element is of type dict and it contains following keys.
'''
return self.server.aria2.tellWaiting(offset, num, keys)
def tellStopped(self, offset, num, keys=None):
'''
This method returns the list of stopped download.
offset: integer, the offset from the download waiting at the front.
num: integer, the number of downloads to be returned.
keys: keys for method response.
return: The method response is of type list and its element is of type dict and it contains following keys.
'''
return self.server.aria2.tellStopped(offset, num, keys)
def changePosition(self, gid, pos, how):
'''
This method changes the position of the download denoted by gid.
gid: string, GID.
pos: integer, the position relative which to be changed.
how: string.
POS_SET, it moves the download to a position relative to the beginning of the queue.
POS_CUR, it moves the download to a position relative to the current position.
POS_END, it moves the download to a position relative to the end of the queue.
return: The response is of type integer and it is the destination position.
'''
return self.server.aria2.changePosition(gid, pos, how)
def changeUri(self, gid, fileIndex, delUris, addUris, position=None):
'''
This method removes URIs in delUris from and appends URIs in addUris to download denoted by gid.
gid: string, GID.
fileIndex: integer, file to affect (1-based)
delUris: list, URIs to be removed
addUris: list, URIs to be added
position: integer, where URIs are inserted, after URIs have been removed
return: This method returns a list which contains 2 integers. The first integer is the number of URIs deleted. The second integer is the number of URIs added.
'''
return self.server.aria2.changeUri(gid, fileIndex, delUris, addUris, position)
def getOption(self, gid):
'''
This method returns options of the download denoted by gid.
gid: string, GID.
return: The response is of type dict.
'''
params = [gid]
return self.sendJsonRPC(data=self.getRPCBody('aria2.getOption', params))
def changeOption(self, gid, options):
'''
This method changes options of the download denoted by gid dynamically.
gid: string, GID.
options: dict, the options.
return: This method returns OK for success.
'''
params = [gid,options]
return self.sendJsonRPC(data=self.getRPCBody('aria2.changeOption', params))
# return self.server.aria2.changeOption(gid, options)
def getGlobalOption(self):
'''
This method returns global options.
return: The method response is of type dict.
'''
return self.server.aria2.getGlobalOption()
def changeGlobalOption(self, options):
'''
This method changes global options dynamically.
options: dict, the options.
return: This method returns OK for success.
'''
return self.sendJsonRPC(data=self.getRPCBody('aria2.changeGlobalOption', options))
def getGlobalStat(self):
'''
This method returns global statistics such as overall download and upload speed.
return: The method response is of type struct and contains following keys.
'''
return self.sendJsonRPC(data=self.getRPCBody('aria2.getGlobalStat'))
def purgeDownloadResult(self):
'''
This method purges completed/error/removed downloads to free memory.
return: This method returns OK for success.
'''
return self.sendJsonRPC(data=self.getRPCBody('aria2.purgeDownloadResult'))
def removeDownloadResult(self, gid):
'''
This method removes completed/error/removed download denoted by gid from memory.
return: This method returns OK for success.
'''
return self.server.aria2.removeDownloadResult(gid)
def getVersion(self):
'''
This method returns version of the program and the list of enabled features.
return: The method response is of type dict and contains following keys.
'''
return self.sendJsonRPC(data=self.getRPCBody('aria2.getSessionInfo'))
def getSessionInfo(self):
'''
This method returns session information.
return: The response is of type dict.
'''
return self.sendJsonRPC(data=self.getRPCBody('aria2.getSessionInfo'))
def shutdown(self):
'''
This method shutdowns aria2.
return: This method returns OK for success.
'''
return self.sendJsonRPC(self.server_uri, data=self.getRPCBody('aria2.shutdown'))
def forceShutdown(self):
'''
This method shutdowns aria2.
return: This method returns OK for success.
'''
return self.sendJsonRPC(self.server_uri, data=self.getRPCBody('aria2.forceShutdown'))
def isAria2Installed():
for cmdpath in os.environ['PATH'].split(':'):
if os.path.isdir(cmdpath) and 'aria2c' in os.listdir(cmdpath):
return True
return False
def isAria2rpcRunning():
pgrep_process = subprocess.Popen(
'pgrep -l aria2', shell=True, stdout=subprocess.PIPE)
if pgrep_process.stdout.readline() == b'':
return False
else:
return True
if __name__=='__main__':
p = PyAria2()