diff --git a/default.py b/default.py index 8afe792..de31c34 100644 --- a/default.py +++ b/default.py @@ -58,7 +58,7 @@ def main_menu(): break else: cookie,tokens = get_auth.run(user_info['username'], user_info['password']) - if tokens['bdstoken']: + if tokens and tokens['bdstoken']: save_user_info(user_info['username'], user_info['password'], cookie, tokens) else: items.extend([{'label': u'重新登录', 'path': plugin.url_for('relogin')}]) @@ -331,6 +331,8 @@ def save_user_info(username, password, cookie, tokens): def MakeList(pcs_files): item_list = [] + item_list_dir = [] + item_list_file = [] ContextMenu = [ ('搜索', actions.background(plugin.url_for('search'))), ('刷新', actions.background(plugin.url_for('refresh'))), @@ -344,7 +346,7 @@ def MakeList(pcs_files): 'is_playable': False, 'context_menu': ContextMenu, } - item_list.append(item) + item_list_dir.append(item) elif result['category'] == 1: if 'thumbs' in result and 'url2' in result['thumbs']: ThumbPath = result['thumbs']['url2'] @@ -362,7 +364,7 @@ def MakeList(pcs_files): 'is_playable': False, 'context_menu': ContextMenu, } - item_list.append(item) + item_list_file.append(item) elif result['category'] == 2: item = { 'label': result['server_filename'], @@ -370,7 +372,9 @@ def MakeList(pcs_files): 'is_playable': False, 'context_menu': ContextMenu, } - item_list.append(item) + item_list_file.append(item) + item_list_file=sorted(item_list_file,key=lambda item:item['label']) + item_list=item_list_dir+item_list_file return item_list diff --git a/resources/modules/auth.py b/resources/modules/auth.py index a10bdcd..f26c898 100644 --- a/resources/modules/auth.py +++ b/resources/modules/auth.py @@ -5,14 +5,15 @@ # in http://www.gnu.org/licenses/gpl-3.0.html -import time, json, base64, re, random, urlparse, os +import time, json, base64, re, random, urlparse, os, sys import requests import rsa + from resources.modules import utils -#some base url and information needed by service -timestamp = str(int(time.time()*1000)) +# some base url and information needed by service +timestamp = str(int(time.time())) ppui_logintime = str(random.randint(52000, 58535)) PASSPORT_BASE = 'https://passport.baidu.com/' PASSPORT_URL = PASSPORT_BASE + 'v2/api/' @@ -23,7 +24,6 @@ PAN_REFERER = 'http://pan.baidu.com/disk/home' ACCEPT_JSON = 'application/json, text/javascript, */*; q=0.8' - default_headers = { 'User-agent': USER_AGENT, 'Referer': PAN_REFERER, @@ -36,7 +36,7 @@ def json_loads_single(s): - return json.loads(s.replace("'",'"').replace('\t','')) + return json.loads(s.replace("'", '"').replace('\t', '')) def RSA_encrypt(public_key, message): @@ -45,11 +45,11 @@ def RSA_encrypt(public_key, message): return base64.encodestring(encrypted).decode('utf-8').replace('\n', '') -def add_cookie(cookie,string,keys): +def add_cookie(cookie, string, keys): str_list = re.split('[,;]\s*', string) for key in keys: for item in str_list: - if re.match(key,item): + if re.match(key, item): s = re.search('=(.+)', item) cookie[key] = s.group(1) return cookie @@ -57,11 +57,11 @@ def add_cookie(cookie,string,keys): def get_BAIDUID(): url = ''.join([ - PASSPORT_URL, - '?getapi&tpl=mn&apiver=v3', - '&tt=', timestamp, - '&class=login&logintype=basicLogin', - ]) + PASSPORT_URL, + '?getapi&tpl=mn&apiver=v3', + '&tt=', timestamp, + '&class=login&logintype=basicLogin', + ]) req = requests.get(url, headers={'Referer': ''}, timeout=50, verify=False) if req: cookie = req.cookies.get_dict() @@ -74,19 +74,19 @@ def get_BAIDUID(): def get_token(cookie): url = ''.join([ - PASSPORT_URL, - '?getapi&tpl=mn&apiver=v3', - '&tt=', timestamp, - '&class=login&logintype=basicLogin', - ]) + PASSPORT_URL, + '?getapi&tpl=mn&apiver=v3', + '&tt=', timestamp, + '&class=login&logintype=basicLogin', + ]) - headers={ - 'Accept': ACCEPT_HTML, - 'Cache-control': 'max-age=0', - } + headers = { + 'Accept': ACCEPT_HTML, + 'Cache-control': 'max-age=0', + } headers_merged = default_headers.copy() - #merge the headers + # merge the headers for key in headers.keys(): headers_merged[key] = headers[key] @@ -103,39 +103,39 @@ def get_token(cookie): def get_UBI(cookie, tokens): url = ''.join([ - PASSPORT_URL, - '?loginhistory', - '&token=', tokens['token'], - '&tpl=pp&apiver=v3', - '&tt=', timestamp, - ]) - headers={'Referer': REFERER,} + PASSPORT_URL, + '?loginhistory', + '&token=', tokens['token'], + '&tpl=pp&apiver=v3', + '&tt=', timestamp, + ]) + headers = {'Referer': REFERER, } headers_merged = default_headers.copy() - #merge the headers + # merge the headers for key in headers.keys(): headers_merged[key] = headers[key] - req=requests.get(url, headers=headers_merged, cookies=cookie, timeout=50, verify=False) + req = requests.get(url, headers=headers_merged, cookies=cookie, timeout=50, verify=False) if req: - ubi=req.headers['Set-Cookie'] + ubi = req.headers['Set-Cookie'] return ubi return None def get_public_key(cookie, tokens): url = ''.join([ - PASSPORT_BASE, - 'v2/getpublickey', - '?token=', tokens['token'], - '&tpl=pp&apiver=v3&tt=', timestamp, + PASSPORT_BASE, + 'v2/getpublickey', + '?token=', tokens['token'], + '&tpl=pp&apiver=v3&tt=', timestamp, - ]) + ]) - headers={'Referer': REFERER,} + headers = {'Referer': REFERER, } headers_merged = default_headers.copy() - #merge the headers + # merge the headers for key in headers.keys(): headers_merged[key] = headers[key] @@ -147,90 +147,92 @@ def get_public_key(cookie, tokens): def post_login(cookie, tokens, username, password_enc, rsakey='', verifycode='', codeString=''): - url=PASSPORT_LOGIN - headers={ - 'Accept': ACCEPT_HTML, - 'Referer': REFERER, - 'Connection': 'Keep-Alive', + url = PASSPORT_LOGIN + headers = { + 'Accept': ACCEPT_HTML, + 'Referer': REFERER, + 'Connection': 'Keep-Alive', } headers_merged = default_headers.copy() - #merge the headers + # merge the headers for key in headers.keys(): headers_merged[key] = headers[key] + data = {'staticpage': 'http://www.baidu.com/cache/user/html/v3Jump.html', + 'charset': 'UTF-8', + 'token': tokens['token'], + 'tpl': 'pp', + 'subpro': '', + 'apiver': 'v3', + 'tt': str(int(time.time())), + 'codestring': codeString, + 'isPhone': 'false', + 'safeflg': '0', + 'u': 'https://passport.baidu.com/', + 'quick_user': '0', + 'logLoginType': 'pc_loginBasic', + 'loginmerge': 'true', + 'logintype': 'basicLogin', + 'username': username, + 'password': password_enc, + 'verifycode': verifycode, + 'mem_pass': 'on', + 'rsakey': rsakey, + 'crypttype': 12, + 'ppui_logintime': ppui_logintime, + 'dv': 'MDEwAAoA2wAKAk4AGwAAAF00AA0CAB3Ly25ZQRVUGl0PTgNcA1MAUA87ZDtLKlkqXTJAJAcCAATLy8vLDAIAI9OKjo6OFeWx8L75q-qn-Kf3pPSrn8Cf7479jvmW5IDwg_SQBwIABMvLy8sHAgAEy8vLywcCAATLy8vLBgIAKMvLy9DQ0NDQ0NDVkpKSkEBAQEUTExMQEBAQFUNDQ0GkpKSh9_f39RAXAgAIy8qBgYKljqkFAgAEy8vLwQECAAbLw8PNWugVAgAIy8vKkCqBv5wEAgAGycnLyfzKFgIAIuqe9cXr2eDT4tXi1uTQ59Hl0-DX4tPn3-bX7t7q3OXU4NMQAgAByxMCABnL3t7etsK2xvzT_IXwnrDSs9q-y-WG6YSrCAIACcvI9fWHh4cPCwgCAAnLz6Cg09PTWMYJAgAMy8--vs3Nzc3NQDIyCQIAJNPQCwoKCgoKCpnKyp7fkdaExYjXiNiL24Sw77DAodKh1rnLrw0CAB3Ly1gBGU0MQgVXFlsEWwtYCFdjPGMTcgFyBWoYfAwCACPTw8PDw1SO2pvVksCBzJPMnM-fwPSr9ITlluWS_Y_rm-if-wcCAATLy8vLDAIAI9Ofm5ubAsSQ0Z_YisuG2YbWhdWKvuG-zq_cr9i3xaHRotWxBwIABMvLy8sMAgAj05mdnZ0CpvKz_broqeS75LTnt-jcg9yszb7NutWnw7PAt9MMAgAj05-fn58-IXU0ej1vLmM8YzNgMG9bBFsrSjlKPVIgRDRHMFQNAgAby8tuLjhsLWMkdjd6JXoqeSl2Qh1CMUQmSyJW', + 'callback': 'parent.bd__pcbs__oa36qm'} - data={ - 'staticpage':'http://yun.baidu.com/res/static/thirdparty/pass_v3_jump.html', - 'charset':'UTF-8', - 'token':tokens['token'], - 'tpl':'netdisk', - 'subpro':'netdisk_web', - 'apiver':'v3', - 'tt': timestamp, - 'codestring':codeString, - 'safeflg':'0', - 'u':'http://yun.baidu.com/disk/home', - 'isPhone':'', - 'quick_user':'0', - 'logintype':'basicLogin', - 'logLoginType':'pc_loginBasic&idc=', - 'loginmerge':'true', - 'username':username, - 'password':password_enc, - 'verifycode':verifycode, - 'mem_pass':'on', - 'rsakey':rsakey, - 'crypttype':'12', - 'ppui_logintime':ppui_logintime, - 'callback':'parent.bd__pcbs__28g1kg', - 'dv': 'MDEwAAoA2wAKAk4AGwAAAF00AA0CAB3Ly25ZQRVUGl0PTgNcA1MAUA87ZDtLKlkqXTJAJAcCAATLy8vLDAIAI9OKjo6OFeWx8L75q-qn-Kf3pPSrn8Cf7479jvmW5IDwg_SQBwIABMvLy8sHAgAEy8vLywcCAATLy8vLBgIAKMvLy9DQ0NDQ0NDVkpKSkEBAQEUTExMQEBAQFUNDQ0GkpKSh9_f39RAXAgAIy8qBgYKljqkFAgAEy8vLwQECAAbLw8PNWugVAgAIy8vKkCqBv5wEAgAGycnLyfzKFgIAIuqe9cXr2eDT4tXi1uTQ59Hl0-DX4tPn3-bX7t7q3OXU4NMQAgAByxMCABnL3t7etsK2xvzT_IXwnrDSs9q-y-WG6YSrCAIACcvI9fWHh4cPCwgCAAnLz6Cg09PTWMYJAgAMy8--vs3Nzc3NQDIyCQIAJNPQCwoKCgoKCpnKyp7fkdaExYjXiNiL24Sw77DAodKh1rnLrw0CAB3Ly1gBGU0MQgVXFlsEWwtYCFdjPGMTcgFyBWoYfAwCACPTw8PDw1SO2pvVksCBzJPMnM-fwPSr9ITlluWS_Y_rm-if-wcCAATLy8vLDAIAI9Ofm5ubAsSQ0Z_YisuG2YbWhdWKvuG-zq_cr9i3xaHRotWxBwIABMvLy8sMAgAj05mdnZ0CpvKz_broqeS75LTnt-jcg9yszb7NutWnw7PAt9MMAgAj05-fn58-IXU0ej1vLmM8YzNgMG9bBFsrSjlKPVIgRDRHMFQNAgAby8tuLjhsLWMkdjd6JXoqeSl2Qh1CMUQmSyJW', - - } req = requests.post(url, headers=headers_merged, cookies=cookie, data=data, timeout=50, verify=False) content = req.text if content: match = re.search('"(err_no[^"]+)"', content) if not match: - return (-1, None) + return (-1, None, None) query = dict(urlparse.parse_qsl(match.group(1))) query['err_no'] = int(query['err_no']) err_no = query['err_no'] if err_no == 0 or err_no == 18: auth_cookie = req.headers['Set-Cookie'] - keys = ['STOKEN','HOSUPPORT','BDUSS','BAIDUID','USERNAMETYPE','PTOKEN','PASSID','UBI','PANWEB','HISTORY','cflag','SAVEUSERID'] - auth_cookie = add_cookie(cookie,auth_cookie,keys) - return (0, auth_cookie) + keys = ['STOKEN', 'HOSUPPORT', 'BDUSS', 'BAIDUID', 'USERNAMETYPE', 'PTOKEN', 'PASSID', 'UBI', 'PANWEB', + 'HISTORY', 'cflag', 'SAVEUSERID'] + auth_cookie = add_cookie(cookie, auth_cookie, keys) + return (0, query, auth_cookie) elif err_no == 257: - return (err_no, query) + auth_cookie = req.headers['Set-Cookie'] + keys = ['STOKEN', 'HOSUPPORT', 'BDUSS', 'BAIDUID', 'USERNAMETYPE', 'PTOKEN', 'PASSID', 'UBI', 'PANWEB', + 'HISTORY', 'cflag', 'SAVEUSERID'] + auth_cookie = add_cookie(cookie, auth_cookie, keys) + return (err_no, query, auth_cookie) elif err_no == 400031: - return (err_no, query) + return (err_no, query, None) else: - return (err_no, query) + return (err_no, query, None) else: - return (-1, None) + return (-1, None, None) def get_signin_vcode(cookie, codeString): - url=''.join([ - PASSPORT_BASE, - 'cgi-bin/genimage?', - codeString, - ]) - headers={'Referer':REFERER,} - - headers_merged = default_headers.copy() - #merge the headers - for key in headers.keys(): - headers_merged[key] = headers[key] - req=requests.get(url, headers=headers_merged, cookies=cookie, timeout=50, verify=False) - #vcode_data is bytes - vcode_data=req.content - if vcode_data: - vcode_path = os.path.join(utils.data_dir(), 'vcode.png') - with open(vcode_path, 'wb') as fh: - fh.write(vcode_data) - - return vcode_path + url = ''.join([ + PASSPORT_BASE, + 'cgi-bin/genimage?', + codeString, + ]) + headers = {'Referer': REFERER, } + + headers_merged = default_headers.copy() + # merge the headers + for key in headers.keys(): + headers_merged[key] = headers[key] + req = requests.get(url, headers=headers_merged, cookies=cookie, timeout=50, verify=False) + # vcode_data is bytes + vcode_data = req.content + if vcode_data: + vcode_path = os.path.join(utils.data_dir(), 'vcode.png') + with open(vcode_path, 'wb') as fh: + fh.write(vcode_data) + + return vcode_path def get_refresh_codeString(cookie, tokens, vcodetype): @@ -242,7 +244,7 @@ def get_refresh_codeString(cookie, tokens, vcodetype): '&tt=', timestamp, '&fr=ligin', '&vcodetype=', vcodetype, - ]) + ]) headers_merged = default_headers.copy() headers_merged.update({'Referer': REFERER}) @@ -273,7 +275,7 @@ def parse_bdstoken(content): return None -#get baidu accout token +# get baidu accout token def get_bdstoken(temp_cookie): url = PAN_REFERER headers_merged = default_headers.copy() @@ -282,8 +284,62 @@ def get_bdstoken(temp_cookie): req.encoding = 'utf-8' if req: _cookie = req.headers['Set-Cookie'] - key = ['STOKEN','SCRC','PANPSC'] + key = ['STOKEN', 'SCRC', 'PANPSC'] auth_cookie = add_cookie(temp_cookie, _cookie, key) return (auth_cookie, parse_bdstoken(req.text)) else: return None + + +def send_email_verfication(authtoken): + url = ''.join([ + PASSPORT_BASE, + 'v2/sapi/authwidgetverify' + ]) + params = {'authtoken': urlparse.unquote(authtoken), + 'type': 'email', + 'apiver': 'v3', + 'action': 'send', + 'vcode': '', + 'questionAndAnswer': '', + 'needsid': '', + 'rsakey': '', + 'countrycode': '', + 'subpro': '', + 'callback': '', + 'tpl': 'mn', + 'u': 'https://www.baidu.com/' + } + ev_resp = requests.get(url, params=params) + return ev_resp + + +def send_email_verification_code(authtoken, emailVCode, loginproxy,cookie): + url = ''.join([ + PASSPORT_BASE, + 'v2/sapi/authwidgetverify' + ]) + params = {'authtoken': urlparse.unquote(authtoken), + 'type': 'email', + 'apiver': 'v3', + 'action': 'check', + 'vcode': emailVCode, + 'questionAndAnswer': '', + 'needsid': '', + 'rsakey': '', + 'countrycode': '', + 'subpro': '', + 'callback': '' + } + vresp = requests.get(url, params=params) + cookies = None + #errno 110000 is successful + vresp_data = json.loads(vresp.content.decode()) + if vresp_data['errno'] == 110000: + proxyResq = requests.get(loginproxy, cookies=cookie) + cookies = proxyResq.headers['Set-Cookie'] + keys = ['STOKEN', 'HOSUPPORT', 'BDUSS', 'BAIDUID', 'USERNAMETYPE', 'PTOKEN', 'PASSID', 'UBI', + 'PANWEB', + 'HISTORY', 'cflag', 'SAVEUSERID'] + cookies = add_cookie(cookie, cookies, keys) + return cookies diff --git a/resources/modules/get_auth.py b/resources/modules/get_auth.py index bcd8713..e654511 100644 --- a/resources/modules/get_auth.py +++ b/resources/modules/get_auth.py @@ -54,7 +54,7 @@ def run(username,password): pubkey = key_data['pubkey'] rsakey = key_data['key'] password_enc = auth.RSA_encrypt(pubkey, password) - err_no,query = auth.post_login(cookie,tokens,username,password_enc,rsakey) + err_no,query,authCookie = auth.post_login(cookie,tokens,username,password_enc,rsakey) if err_no == 257: vcodetype = query['vcodetype'] codeString = query['codeString'] @@ -66,9 +66,10 @@ def run(username,password): verifycode = dialog.input(heading=u'验证码') if verifycode: - err_no,query = auth.post_login(cookie,tokens,username,password_enc,rsakey,verifycode,codeString) + err_no,query,authCookie = auth.post_login(cookie,tokens,username,password_enc,rsakey,verifycode,codeString) + if err_no == 0: - temp_cookie = query + temp_cookie = authCookie auth_cookie, bdstoken = auth.get_bdstoken(temp_cookie) if bdstoken: tokens['bdstoken'] = bdstoken @@ -80,8 +81,28 @@ def run(username,password): elif err_no == 6: dialog.ok('Error',u'验证码错误') + elif err_no == 120021: + dialog.ok('Info',u'发送电邮验证') + #send email verification + authToken = query['authtoken'] + loginProxyUrl = query['loginproxy'] + + sndResp = auth.send_email_verfication(authToken) + if sndResp.ok: + emailVerifyCode = dialog.input(heading=u'电邮验证码') + temp_cookie = auth.send_email_verification_code(authToken, emailVerifyCode,loginProxyUrl,cookie) + if temp_cookie: + + auth_cookie, bdstoken = auth.get_bdstoken(temp_cookie) + if bdstoken: + tokens['bdstoken'] = bdstoken + return auth_cookie,tokens + + # failure status + dialog.ok('Error', u'未知错误,请重试') else: dialog.ok('Error',u'未知错误,请重试') + else: dialog.ok('Error',u'请输入验证码') @@ -89,7 +110,7 @@ def run(username,password): dialog.ok('Error',u'密码错误') elif err_no == 0: - auth_cookie = query + auth_cookie = authCookie bdstoken = auth.get_bdstoken(auth_cookie) if bdstoken: tokens['bdstoken'] = bdstoken diff --git a/resources/modules/pcs.py b/resources/modules/pcs.py index 1188580..9a95b9e 100644 --- a/resources/modules/pcs.py +++ b/resources/modules/pcs.py @@ -39,9 +39,15 @@ def get_quota(cookie, tokens): '百度云用户容量接口' - url = 'http://yun.baidu.com/api/quota?bdstoken=' + tokens['bdstoken'] + url = 'http://pan.baidu.com/api/quota' + params={'method': None, + 'BDUSS': cookie['BDUSS'], + 't': str(int(time.time()*1000)), + 'bdstoken': tokens['bdstoken'] + } headers_merged = default_headers.copy() - req = requests.get(url, cookies=cookie, headers=headers_merged, timeout=50, verify=False) + headers_merged.update({'User-agent': 'netdisk;4.6.2.0;PC;PC-Windows;10.0.10240;WindowsBaiduYunGuanJia'}) + req = requests.get(url, params=params, cookies=cookie, headers=headers_merged, timeout=50, verify=False) if req: return req.json() else: @@ -91,6 +97,7 @@ def list_dir(cookie, tokens, path, page=1, num=100): 'dir': path, 't': str(random.random()), 'bdstoken': tokens['bdstoken'], + 'BDUSS': cookie['BDUSS'], 'channel': 'chunlei', 'app_id': '250528', 'clienttype': '0', @@ -98,6 +105,7 @@ def list_dir(cookie, tokens, path, page=1, num=100): headers_merged = default_headers.copy() headers_merged.update({'Content-type': CONTENT_FORM_UTF8}) + headers_merged.update({'User-agent': 'netdisk;4.6.2.0;PC;PC-Windows;10.0.10240;WindowsBaiduYunGuanJia'}) req = requests.get(url, headers=headers_merged, cookies=cookie, params=url_params, timeout=50, verify=False) if req: @@ -163,12 +171,24 @@ def get_download_link(cookie, tokens, path): else: return req.headers['location'] +def get_fastest_pcs_server(): + """通过百度返回设置最快的pcs服务器 + """ + url = 'http://pcs.baidu.com/rest/2.0/pcs/file?app_id=250528&method=locateupload' + ret = requests.get(url).content + foo = json.loads(ret.decode('utf-8')) + return foo['host'] def stream_download(cookie, tokens, path): '''下载流媒体文件. path - 流文件的绝对路径. ''' + fastServer = get_fastest_pcs_server() + if fastServer: + global PCS_URL_D + PCS_URL_D = 'https://{0}/rest/2.0/pcs/'.format(fastServer) + url = ''.join([ PCS_URL_D, 'file?method=download',