├── .gitignore ├── README.md ├── http_request.py ├── task.txt ├── taskprocess.txt ├── tasksuccess.txt ├── u115_api.py └── u115_bot.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | .idea/ 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # PyInstaller 26 | # Usually these files are written by a python script from a template 27 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 28 | *.manifest 29 | *.spec 30 | 31 | # Installer logs 32 | pip-log.txt 33 | pip-delete-this-directory.txt 34 | 35 | # Unit test / coverage reports 36 | htmlcov/ 37 | .tox/ 38 | .coverage 39 | .cache 40 | nosetests.xml 41 | coverage.xml 42 | 43 | # Translations 44 | *.mo 45 | *.pot 46 | 47 | # Django stuff: 48 | *.log 49 | 50 | # Sphinx documentation 51 | docs/_build/ 52 | 53 | # PyBuilder 54 | target/ 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
3 | 115 离线 API 4 |
5 |
6 | ============= 7 |
8 |
9 | 115网盘离线下载API 10 |
11 |
12 | 注意:目前只有会员才能使用离线功能
13 |
14 |
15 |
16 |
17 | 包含以下接口 18 |
19 |
20 | ----------- 21 |
22 |
23 | web登陆网盘 24 |
25 |
26 | 通过种子添加任务 27 |
28 |
29 | 离线任务管理 30 |
31 |
32 | -队列管理 33 |
34 |
35 | --自动清理已完成任务 36 |
37 |
38 | --自动清理失败任务 39 |
40 |
41 | --自动制作分享礼包 42 |
43 |
44 |
45 |
46 |
47 | 不包含以下接口(因为我暂时用不着) 48 |
49 |
50 | ----------- 51 |
52 |
53 | -文件管理 54 |
55 |
56 | -文件下载 57 |
58 |
59 |
60 |
61 |
62 | 作用 63 |
64 |
65 | ----------- 66 |
67 |
68 | 爬一些资源站比如nyaa.se 69 |
70 |
71 |
72 |
73 |
74 | 副作用 75 |
76 |
77 | ----------- 78 |
79 |
80 | 够115喝上一壶23333 81 |
82 |
83 |
84 |
85 |
86 | 为什么PT站点没有速度 87 |
88 |
89 | ----------- 90 |
91 |
92 | 115更换了客户端,目前不推荐这么做,现在客户端会一直报告一个即将完成的进度,不报告上传下载,需要进行trakcer转发可以参考https://github.com/mengskysama/BaiduDL-X-NexusPHP 93 | 96 |
97 |
-------------------------------------------------------------------------------- /http_request.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import requests 5 | 6 | class http_request: 7 | 8 | def __init__(self, cookie=None): 9 | self.set_cookie = None 10 | self.cookies = requests.cookies.RequestsCookieJar() 11 | 12 | def post(self, url, body=None): 13 | try: 14 | r = requests.post(url=url, data=body, cookies=self.cookies, timeout=10.0) 15 | resp = {'status': r.status_code} 16 | content = r.text 17 | for c in r.cookies: 18 | self.cookies.set_cookie(c) 19 | except Exception, e: 20 | resp = {'status': 600} 21 | content = 'HttpHelper: %s' % e 22 | return resp, content 23 | 24 | def upload(self, url, files): 25 | try: 26 | headers = {'User-Agent': 'Shockwave Flash'} 27 | r = requests.post(url=url, files=files, cookies=self.cookies, headers=headers, timeout=60.0) 28 | resp = {'status': r.status_code} 29 | content = r.text 30 | for c in r.cookies: 31 | self.cookies.set_cookie(c) 32 | except Exception, e: 33 | resp = {'status': 600} 34 | content = 'HttpHelper: %s' % e 35 | return resp, content 36 | 37 | def get(self, url, _headers=None): 38 | try: 39 | r = requests.get(url=url, cookies=self.cookies, timeout=10.0) 40 | resp = {'status': r.status_code} 41 | content = r.text 42 | for c in r.cookies: 43 | self.cookies.set_cookie(c) 44 | except Exception, e: 45 | resp = {'status': 600} 46 | content = 'HttpHelper: %s' % e 47 | return resp, content 48 | 49 | if __name__ == "__main__": 50 | http = http_request() 51 | resp, ret = http.get("http://www.baidu.com") 52 | print ret 53 | -------------------------------------------------------------------------------- /task.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mengskysama/115-Lixian-API/0c1f8b27dcf0d3fbb1126ec6b78f1fa4320490dd/task.txt -------------------------------------------------------------------------------- /taskprocess.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mengskysama/115-Lixian-API/0c1f8b27dcf0d3fbb1126ec6b78f1fa4320490dd/taskprocess.txt -------------------------------------------------------------------------------- /tasksuccess.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mengskysama/115-Lixian-API/0c1f8b27dcf0d3fbb1126ec6b78f1fa4320490dd/tasksuccess.txt -------------------------------------------------------------------------------- /u115_api.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import re 5 | import json 6 | import time 7 | import random 8 | import string 9 | import os 10 | import logging 11 | 12 | from hashlib import sha1 13 | from http_request import http_request 14 | 15 | logging.getLogger("requests").setLevel(logging.WARNING) 16 | logging.basicConfig(level=logging.INFO) 17 | 18 | BT_API_URL = 'http://btapi.115.com' 19 | UPLOAD_URL = 'http://upload.115.com' 20 | BASE_URL = 'http://115.com' 21 | PASSPORT_URL = 'http://passport.115.com' 22 | WEB_API_URL = 'http://web.api.115.com' 23 | LOGIN_URL = PASSPORT_URL + '/?ct=login&ac=ajax&is_ssl=1' 24 | 25 | 26 | class u115_api: 27 | 28 | def __init__(self): 29 | self.http = http_request() 30 | self.torrents = None 31 | self.sign = None 32 | self.time = None 33 | self.uid = 0 34 | 35 | def setcookie(self, cookie): 36 | self.http.cookie = cookie 37 | 38 | def login(self, username, password): 39 | #这混蛋115也是存密码明文 40 | #好吧,我们也来生成一个key 41 | key = string.join(random.sample(['a', 'b', 'c', 'd', 'e', 'f', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] 42 | , 13)).replace(' ', '') 43 | vcode = key.upper() 44 | password = sha1(sha1(sha1(password).hexdigest() + sha1(username).hexdigest()).hexdigest() + vcode).hexdigest() 45 | data = {'login[ssoent]': 'B1', 46 | 'login[version]': '2.0', 47 | 'login[ssoext]': key, 48 | 'login[ssoln]': username, 49 | 'login[ssopw]': password, 50 | 'login[ssovcode]': key, 51 | 'login[safe]': '1', 52 | 'login[time]': '1', 53 | 'login[safe_login]': '0', 54 | 'login[goto]': 'http://www.115.com/'} 55 | resp, ret = self.http.post(LOGIN_URL, data) 56 | if not resp['status'] == 200: 57 | logging.error('115登陆失败:请求失败'.decode('utf-8')) 58 | return False 59 | ret = json.loads(ret) 60 | if 'err_msg' in ret: 61 | logging.error(('115登陆失败:%s' % ret['err_msg'].encode('utf-8')).decode('utf-8')) 62 | return False 63 | else: 64 | logging.info('115登陆成功'.decode('utf-8')) 65 | self.get_uid() 66 | return True 67 | 68 | def siginup(self, email, email_pwd, passwd): 69 | """已经变更为手机注册""" 70 | 71 | def get_uid(self): 72 | resp, ret = self.http.get(BASE_URL) 73 | if not resp['status'] == 200: 74 | logging.error('获取用户id失败:请求失败'.decode('utf-8')) 75 | return 76 | reg = re.compile('USER_ID = \'(\d+)') 77 | ids = re.findall(reg, ret) 78 | if len(ids) == 0: 79 | logging.error('获取用户id失败:似乎没有找到id'.decode('utf-8')) 80 | return 81 | self.uid = str(ids[0]) 82 | logging.info(('用户id:%s' % self.uid).decode('utf-8')) 83 | 84 | def get_sign(self): 85 | get_url = BASE_URL + '/?ct=offline&ac=space&_=' + str(time.time()) 86 | #print get_url 87 | resp, ret = self.http.get(get_url) 88 | if not resp['status'] == 200: 89 | logging.error('get_sign失败:请求失败'.decode('utf-8')) 90 | return 91 | ret = json.loads(ret) 92 | if ret.has_key('error_msg'): 93 | logging.error(('get_sign失败:%s' % ret['error_msg'].encode('utf-8')).decode('utf-8')) 94 | return 95 | else: 96 | self.sign = str(ret['sign']) 97 | self.time = str(ret['time']) 98 | 99 | def get_bt_task_list(self): 100 | ''' 101 | "status": 2完成 102 | "status": 4,正在找资源,-1失败 103 | "percentDone": 7.57,完成率 104 | ''' 105 | self.get_sign() 106 | 107 | post_url = BASE_URL + '/lixian/?ct=lixian&ac=task_lists' 108 | torrents = [] 109 | current_page = 1 110 | page_count = 1 111 | while current_page <= page_count: 112 | data = {'page': current_page, 'uid': self.uid, 'sign': self.sign, 'time' : self.time} 113 | resp, ret = self.http.post(post_url, data) 114 | if not resp['status'] == 200: 115 | self.torrents = None 116 | logging.error('获取列表失败:请求失败'.decode('utf-8')) 117 | return 118 | #print ret 119 | ret = json.loads(ret) 120 | if 'page_count' in ret: 121 | page_count = ret['page_count'] 122 | if 'tasks' in ret and ret['tasks'] is not None: 123 | torrents.extend(ret['tasks']) 124 | current_page += 1 125 | self.torrents = torrents 126 | 127 | def ret_current_bt_task_count(self, refresh = True): 128 | #非完成状态都算在活动内 129 | count = 0 130 | if refresh: 131 | self.get_bt_task_list() 132 | if self.torrents is None: 133 | return 999 134 | for i in range(0, len(self.torrents)): 135 | if self.torrents[i]['status'] == 2: 136 | continue 137 | #if self.torrents[i]['file_id'] == None: 138 | count += 1 139 | return count 140 | 141 | 142 | def add_torrent_task(self, torrent_file_path): 143 | ''' 144 | 这个接口简直屌炸天了有没有................ 145 | ''' 146 | #step.0 147 | #更新sign 148 | self.get_sign() 149 | #step.1 150 | #得到CID 151 | resp, ret = self.http.get(BASE_URL + '/?ct=lixian&ac=get_id&torrent=1&_=' + self.time) 152 | ret = json.loads(ret) 153 | cid = ret['cid'] 154 | #print cid 155 | #step.2 156 | #得到上传地址 157 | resp, ret = self.http.get(BASE_URL + '/?tab=offline&mode=wangpan') 158 | reg = re.compile('upload\?(\S+?)"') 159 | ids = re.findall(reg, ret) 160 | if ids == 0: 161 | logging.error('没有找到上传入口'.decode('utf-8')) 162 | return False 163 | url = 'http://upload.115.com/upload?' + ids[0] 164 | #step.3 165 | #模拟flash提交插件把种子传上去 166 | torrent_file_name = os.path.basename(torrent_file_path) 167 | post_url = url 168 | params = {'Filename': (None, torrent_file_name), 'target': (None, 'U_1_' + cid), 169 | 'Filedata': (torrent_file_name, open(torrent_file_path, 'rb'), 'application/octet-stream'), 170 | 'Upload': (None, 'Submit Query')} 171 | resp, ret = self.http.upload(post_url, files=params) 172 | #{"state":true,"data":{"cid":138235783244134093,"aid":1,"file_name":"ea97783ca86b4ec4b409e8c766e3feff8848c7d7.torrent","file_ptime":1411607247,"file_status":1,"file_id":"348892672322418456","file_size":21309,"pick_code":"ewu87sytxapt7zwyi","sp":1}} 173 | ret = json.loads(ret) 174 | if 'state' is False: 175 | logging.error(('上传种子step.3出错 %s!' % str(ret)).decode('utf-8')) 176 | return False 177 | #step.4 178 | #还要传一个地方.. 179 | url = WEB_API_URL + '/files/file' 180 | data = {'file_id': ret['data']['file_id']} 181 | resp, ret = self.http.post(url, data) 182 | ret = json.loads(ret) 183 | print ret 184 | #返回{"data":[{"file_id":"348892672322418456","file_name":"ea97783ca86b4ec4b409e8c766e3feff8848c7d7.torrent","pick_code":"ewu87sytxapt7zwyi","sha1":"C72830D1D4C559E553A1A1074A8FC33D3D1F1336"}],"state":true,"error":"","errNo":0} 185 | if ret['state'] is False: 186 | logging.error(('上传种子step.4出错 %s!' % str(ret)).decode('utf-8')) 187 | return False 188 | #step.5 189 | #获取服务器解析结果 190 | post_url = BASE_URL + '/lixian/?ct=lixian&ac=torrent' 191 | data = {'pickcode': ret['data'][0]['pick_code'], 192 | 'sha1': ret['data'][0]['sha1'], 193 | 'uid': self.uid, 194 | 'sign': self.sign, 195 | 'time': self.time} 196 | resp, ret = self.http.post(post_url, data) 197 | ret = json.loads(ret) 198 | #fail 199 | #{"file_size":0,"torrent_name":"","file_count":0,"info_hash":"","torrent_filelist_web":null,"state":false,"error_msg":""} 200 | #success 201 | #{"file_size":2201795620,"torrent_name":"[KTXP][RE Hamatora][01-12][BIG5][720p][MP4]","file_count":23,"info_hash":"d62d53175e0367a4e99fa464665d11ea1a666de0","torrent_filelist_web":[{"size":192359446,"path":"[KTXP][RE Hamatora][01][BIG5][720p][MP4].mp4","wanted":1},{"size":54250,"path":"_____padding_file_0_if you see this file, please update to BitComet 0.85 or above____","wanted":-1},{"size":207823616,"path":"[KTXP][RE Hamatora][02][BIG5][720p][MP4].mp4","wanted":1},{"size":318720,"path":"_____padding_file_1_if you see this file, please update to BitComet 0.85 or above____","wanted":-1},{"size":211146572,"path":"[KTXP][RE Hamatora][03][BIG5][720p][MP4].mp4","wanted":1},{"size":141492,"path":"_____padding_file_2_if you see this file, please update to BitComet 0.85 or above____","wanted":-1},{"size":188201661,"path":"[KTXP][RE Hamatora][04][BIG5][720p][MP4].mp4","wanted":1},{"size":17731,"path":"_____padding_file_3_if you see this file, please update to BitComet 0.85 or above____","wanted":-1},{"size":179834914,"path":"[KTXP][RE Hamatora][05][BIG5][720p][MP4].mp4","wanted":1},{"size":520158,"path":"_____padding_file_4_if you see this file, please update to BitComet 0.85 or above____","wanted":-1},{"size":181628715,"path":"[KTXP][RE Hamatora][06][BIG5][720p][MP4].mp4","wanted":1},{"size":299221,"path":"_____padding_file_5_if you see this file, please update to BitComet 0.85 or above____","wanted":-1},{"size":174835936,"path":"[KTXP][RE Hamatora][07][BIG5][720p][MP4].mp4","wanted":1},{"size":276256,"path":"_____padding_file_6_if you see this file, please update to BitComet 0.85 or above____","wanted":-1},{"size":173709712,"path":"[KTXP][RE Hamatora][08][BIG5][720p][MP4].mp4","wanted":1},{"size":353904,"path":"_____padding_file_7_if you see this file, please update to BitComet 0.85 or above____","wanted":-1},{"size":186998397,"path":"[KTXP][RE Hamatora][09][BIG5][720p][MP4].mp4","wanted":1},{"size":172419,"path":"_____padding_file_8_if you see this file, please update to BitComet 0.85 or above____","wanted":-1},{"size":190285300,"path":"[KTXP][RE Hamatora][10][BIG5][720p][MP4].mp4","wanted":1},{"size":31244,"path":"_____padding_file_9_if you see this file, please update to BitComet 0.85 or above____","wanted":-1},{"size":155175370,"path":"[KTXP][RE Hamatora][11][BIG5][720p][MP4].mp4","wanted":1},{"size":13878,"path":"_____padding_file_10_if you see this file, please update to BitComet 0.85 or above____","wanted":-1},{"size":157596708,"path":"[KTXP][RE Hamatora][12][BIG5][720p][MP4].mp4","wanted":1}],"state":true} 202 | if ret['state'] is False: 203 | logging.error(('上传种子step.5出错 %s!' % str(ret)).decode('utf-8')) 204 | return False 205 | #step.6 206 | #选择需要下载的文件(能下的都下) 207 | wanted = None 208 | idx = 0 209 | for item in ret['torrent_filelist_web']: 210 | if item['wanted'] != -1: 211 | if wanted is None: 212 | wanted = str(idx) 213 | else: 214 | wanted = wanted + ',' + str(idx) 215 | idx += 1 216 | 217 | post_url = BASE_URL + '/lixian/?ct=lixian&ac=add_task_bt' 218 | data = {'info_hash': ret['info_hash'], 219 | 'wanted': wanted, 220 | #115有个小bug,文件名包含'会出问题 221 | 'savepath': ret['torrent_name'].replace('\'', ''), 222 | 'uid': self.uid, 223 | 'sign': self.sign, 224 | 'time': self.time} 225 | resp, ret = self.http.post(post_url, data) 226 | ret = json.loads(ret) 227 | if 'error_msg' in ret: 228 | logging.error(ret['error_msg']) 229 | return False 230 | 231 | logging.info(('任务 torrent=%s 提交成功' % torrent_file_name).decode('utf-8')) 232 | return True 233 | #完成添加操作,将ret['info_hash'] ret['name']更新入数据库 234 | #m = {'torrent_info_hash' : ret['info_hash'], 'torrent_name' : ret['name']} 235 | #s = urlencode(m) 236 | #get_url = config.MY_DATAQUERY_URL + '&type=update_info_hash&' + s + '&ori_torrent_id=' + torrent_oid + "&" 237 | #h.request(get_url) 238 | 239 | def print_bt_task_info(self): 240 | self.get_bt_task_list() 241 | total_ratedownload = 0 242 | for i in range(0, len(self.torrents)): 243 | if self.torrents[i]['status'] == -1: 244 | status = '已失败' 245 | elif self.torrents[i]['status'] == 2: 246 | status = '已完成' 247 | if self.torrents[i]['move'] == 0: 248 | status = '转储中' 249 | else: 250 | status = '下载中' 251 | if self.torrents[i]['file_id'] is not None: 252 | print ('任务[%s]:%100s 进度:%8s 速度:%10dKB/s 种子:%5s 体积: %5.2fGB 散列值:%40s' \ 253 | % (status, 254 | self.torrents[i]['name'].encode('utf-8'), 255 | str(self.torrents[i]['percentDone']), 256 | self.torrents[i]['rateDownload']/1024.0, 257 | str(self.torrents[i]['peers']), 258 | self.torrents[i]['size']/1024.0/1024.0/1024.0, 259 | self.torrents[i]['info_hash'].encode('utf-8'))).decode('utf-8') 260 | total_ratedownload += self.torrents[i]['rateDownload']/1024.0 261 | print ('---------------------------------总速度:%5.2f MB/s' % (total_ratedownload/1024.0)).decode('utf-8') 262 | 263 | def add_http_task(self, url): 264 | self.get_sign() 265 | post_url = BASE_URL + '/lixian/?ct=lixian&ac=add_task_url' 266 | post_data = {'url': url.encode('utf-8'), 267 | 'uid': self.uid, 268 | 'sign': self.sign, 269 | 'time': self.time} 270 | resp, ret = self.http.post(post_url, post_data) 271 | if not resp['status'] == 200: 272 | logging.error('任务添加失败:请求失败'.decode('utf-8')) 273 | return False 274 | ret = json.loads(ret) 275 | if ret['state'] is False: 276 | if 'error_msg' in ret: 277 | print ret['error_msg'] 278 | return False 279 | logging.error('任务添加失败'.decode('utf-8')) 280 | return False 281 | logging.info(('任务 url=%s 提交成功' % url).decode('utf-8')) 282 | return True 283 | 284 | def auto_make_share_link(self, refresh=True, delfromlist=True): 285 | #自动将完成任务生成网盘礼包 286 | result = [] 287 | if refresh: 288 | self.get_bt_task_list() 289 | else: 290 | self.get_sign() 291 | if self.torrents is None: 292 | print 'torrents is None' 293 | return False, result 294 | for i in range(0, len(self.torrents)): 295 | torrent_name = '%s' % self.torrents[i]['name'].encode('utf-8') 296 | if self.torrents[i]['status'] == -1: 297 | post_url = BASE_URL + '/lixian/?ct=lixian&ac=task_del' 298 | post_data = {'hash[0]': self.torrents[i]['info_hash'].encode('utf-8'), 299 | 'uid': self.uid, 300 | 'sign': self.sign, 301 | 'time': self.time} 302 | self.http.post(post_url, post_data) 303 | logging.info(('删除失败的任务:%s' % torrent_name).decode('utf-8')) 304 | continue 305 | if self.torrents[i]['status'] == 2 \ 306 | and self.torrents[i]['percentDone'] == 100 \ 307 | and self.torrents[i]['move'] == 1: 308 | 309 | cid = str(self.torrents[i]['file_id']) 310 | if cid != '132111574000449453': 311 | get_url = 'http://web.api.115.com/category/get?aid=1&cid=%s' % cid 312 | resp, ret = self.http.get(get_url)#sometime has bom 313 | if not resp['status'] == 200: 314 | logging.error('%s 分享失败:请求失败' % torrent_name) 315 | continue 316 | if ret.find('pick_code') < 0: 317 | #此时无bom 318 | logging.error('%s 分享失败:未找到pick_code' % torrent_name) 319 | continue 320 | #此时有bom..................... 321 | #ret = ret[3:] 322 | #妈蛋你们搞来搞去是闹哪样 323 | ret = json.loads(ret) 324 | pick_code = ret['pick_code'].encode('utf-8') 325 | else: 326 | #115一定是默默地star了我... 327 | get_url = 'http://web.api.115.com/files/search?offset=0&limit=30&search_value=%s' \ 328 | '&date=&aid=-1&pick_code=&type=&source=&format=json' % (torrent_name) 329 | resp, ret = self.http.get(get_url) 330 | if not resp['status'] == 200: 331 | logging.error(('%s 创建礼包失败:请求失败' % torrent_name).decode('utf-8')) 332 | continue 333 | ret = json.loads(ret) 334 | if ret['count'] == 0: 335 | logging.info(('%s 创建礼包失败,未找到下载的文件,请稍后再试' % torrent_name).decode('utf-8')) 336 | continue 337 | pick_code = ret['data'][0]['pc'] 338 | #创建礼包 339 | post_url = BASE_URL + '/?ct=filegift&ac=create' 340 | post_data = {'pickcodes[]': pick_code} 341 | resp, ret = self.http.post(post_url, post_data) 342 | if not resp['status'] == 200: 343 | logging.error(('%s 创建礼包失败:请求失败' % torrent_name).decode('utf-8')) 344 | continue 345 | ret = json.loads(ret) 346 | if ret['state'] is False: 347 | logging.error(('%s 创建礼包失败:%s' % (torrent_name, ret['message'].encode('utf-8'))).decode('utf-8')) 348 | continue 349 | gift_code = ret['gift_code'].encode('utf-8') 350 | #保存礼包名字 351 | post_url = BASE_URL + '/?ct=filegift&ac=update_remark' 352 | post_data = {'gift_code': gift_code, 353 | 'remark': torrent_name} 354 | resp, ret = self.http.post(post_url, post_data) 355 | if not resp['status'] == 200: 356 | logging.error(('%s 创建礼包失败:请求失败' % torrent_name).decode('utf-8')) 357 | continue 358 | ret = json.loads(ret) 359 | result.append({'Code': gift_code, 'Name': torrent_name}) 360 | logging.info(('生成礼包成功:Code=%s Hash=%s Name=%s' % 361 | (gift_code, self.torrents[i]['info_hash'].encode('utf-8'), torrent_name)).decode('utf-8')) 362 | #115从完成列表中删除 363 | if delfromlist is True: 364 | post_url = BASE_URL + '/lixian/?ct=lixian&ac=task_del' 365 | post_data = {'hash[0]': self.torrents[i]['info_hash'].encode('utf-8'), 366 | 'uid': self.uid, 367 | 'sign': self.sign, 368 | 'time': self.time} 369 | self.http.post(post_url, post_data) 370 | #logging.info('删除完成任务:Code=%s Hash=%s Name=%s' % 371 | # (gift_code.encode('utf-8'), 372 | # self.torrents[i]['info_hash'].encode('utf-8'), torrent_name)) 373 | return True, result 374 | 375 | if __name__ == "__main__": 376 | u115 = u115_api() 377 | u115.login('13125180000', '000000') 378 | #print u115.ret_current_bt_task_count() 379 | #u115.print_bt_task_info() 380 | #u115.add_http_task('http://down.360safe.com/360/inst.exe') 381 | #u115.add_torrent_task('2.torrent') 382 | #ret, result = u115.auto_make_share_link() 383 | #print result -------------------------------------------------------------------------------- /u115_bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import time 5 | import logging 6 | import getopt 7 | 8 | import sys 9 | reload(sys) 10 | sys.setdefaultencoding('utf-8') 11 | 12 | from u115_api import u115_api 13 | 14 | arg_user = None 15 | arg_pass = None 16 | arg_sleeptime = 120 17 | arg_taskfile = None 18 | 19 | def readtask(): 20 | global arg_taskfile 21 | return open(arg_taskfile).readlines() 22 | 23 | def update_task(context): 24 | #lock 25 | return open('task.txt', 'w').writelines(context) 26 | 27 | def update_task_process(context): 28 | return open('taskprocess.txt', 'a').write(context + '\n') 29 | 30 | def update_task_success(context): 31 | return open('tasksuccess.txt', 'a').write(context + '\n') 32 | 33 | def monitor(): 34 | global arg_pass 35 | global arg_user 36 | global arg_sleeptime 37 | global arg_taskfile 38 | 39 | u115 = u115_api() 40 | u115.login(arg_user, arg_pass) 41 | while True: 42 | try: 43 | ret, result = u115.auto_make_share_link() 44 | for res in result: 45 | update_task_success('http://115.com/lb/%s ---- %s' % (res['Code'], res['Name'])) 46 | if 15 > u115.ret_current_bt_task_count(): 47 | task_list = readtask() 48 | if len(task_list) == 0: 49 | logging.info('没有任务文件...zZZ'.decode('utf-8')) 50 | else: 51 | i = task_list[0] 52 | task_list.pop(0) 53 | update_task(task_list) 54 | if not i.startswith("http"): 55 | continue 56 | update_task_process(i) 57 | u115.add_http_task(i) 58 | continue 59 | time.sleep(arg_sleeptime) 60 | except KeyboardInterrupt: 61 | break 62 | except: 63 | import traceback 64 | print traceback.print_exc() 65 | time.sleep(arg_sleeptime * 10) 66 | u115 = u115_api() 67 | u115.login(arg_user, arg_pass) 68 | 69 | def Usage(): 70 | print '115Bot usage:' 71 | print '-u, --user: 115 account login user' 72 | print '-p, --pass: 115 account login pass' 73 | print '-f, --file: task list file\n' 74 | print '-h, --help: print help message.' 75 | print '-v, --version: print script version' 76 | 77 | def Version(): 78 | print '115Bot ver 0.1' 79 | 80 | def main(argv): 81 | global arg_pass 82 | global arg_user 83 | global arg_sleeptime 84 | global arg_taskfile 85 | 86 | try: 87 | opts, args = getopt.getopt(argv[1:], 'u:p:f:v:h', ['user=', 'pass=', 'file=', 'help', 'version']) 88 | except getopt.GetoptError, err: 89 | print str(err) 90 | Usage() 91 | sys.exit(2) 92 | 93 | for o, a in opts: 94 | if o in ('-h', '--help'): 95 | Usage() 96 | sys.exit(1) 97 | elif o in ('-v', '--version'): 98 | Version() 99 | sys.exit(0) 100 | elif o in ('-f', '--file'): 101 | arg_taskfile = a 102 | elif o in ('-u', '--user'): 103 | arg_user = a 104 | elif o in ('-p', '--pass'): 105 | arg_pass = a 106 | else: 107 | print 'unhandled option' 108 | sys.exit(1) 109 | 110 | if arg_taskfile is None: 111 | print 'missing arg -f' 112 | sys.exit(2) 113 | if arg_user is None: 114 | print 'missing arg -u' 115 | sys.exit(2) 116 | if arg_pass is None: 117 | print 'missing arg -p' 118 | sys.exit(2) 119 | monitor() 120 | 121 | if __name__ == '__main__': 122 | main(sys.argv) 123 | --------------------------------------------------------------------------------