├── .gitignore ├── README.md └── Super_bili ├── bili ├── __init__.py ├── bili_api.py ├── model │ ├── __init__.py │ └── pc_pgc_pcurl.py └── rsa_bili.py ├── main.py ├── requirements.txt └── 油猴脚本.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Super-Bili 2 | 网页共享账号解锁哔哩哔哩大会员 3 | -------------------------------------------------------------------------------- /Super_bili/bili/__init__.py: -------------------------------------------------------------------------------- 1 | ### -------------------------------------------------------------------------------- /Super_bili/bili/bili_api.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | from time import time 4 | from bili.rsa_bili import Rsa_a, Getkey 5 | 6 | key = Getkey() 7 | access_key = key.login() 8 | 9 | 10 | async def pc_pgc_pcurl(params): 11 | from bili.model.pc_pgc_pcurl import url, headers, data 12 | 13 | appkey = params.get("appkey", "84956560bc028eb7") 14 | cid = params.get("cid", "") 15 | fnval = params.get("fnval", "") 16 | fourk = params.get("fourk", "") 17 | qn = params.get("qn", "64") 18 | data["access_key"] = access_key 19 | data["appkey"] = appkey 20 | data["cid"] = cid 21 | data["fnval"] = fnval 22 | data["fourk"] = fourk 23 | data["qn"] = qn 24 | data["ts"] = int(time()) 25 | md5 = Rsa_a() 26 | sign_params = md5.sign(data) 27 | req = requests.get(url + sign_params, headers=headers, timeout=5) 28 | return req.text 29 | -------------------------------------------------------------------------------- /Super_bili/bili/model/__init__.py: -------------------------------------------------------------------------------- 1 | ### -------------------------------------------------------------------------------- /Super_bili/bili/model/pc_pgc_pcurl.py: -------------------------------------------------------------------------------- 1 | headers = { 2 | "Host": "api.bilibili.com", 3 | "User-Agent": "Bilibili Freedoooooom/MarkII", 4 | } 5 | data = { 6 | "access_key": "", 7 | "appkey": "84956560bc028eb7", 8 | "build": "12450", 9 | "cid": "", 10 | "fnval": "", 11 | "fnver": "0", 12 | "fourk": "", 13 | "otype": "json", 14 | "platform": "pc", 15 | "qn": "", 16 | "ts": "", 17 | } 18 | url = "https://api.bilibili.com/pgc/player/web/playurl?" 19 | -------------------------------------------------------------------------------- /Super_bili/bili/rsa_bili.py: -------------------------------------------------------------------------------- 1 | import base64 2 | import rsa 3 | import requests 4 | import hashlib 5 | import ujson 6 | from time import time 7 | from urllib import parse 8 | 9 | # pipreqs . --encoding=utf8 --force 10 | 11 | 12 | class Rsa_a(object): 13 | def __init__(self): 14 | self.username = "" # 大会员账号 15 | self.password = "" # 大会员密码 16 | ### 17 | self.pc_APPKEY = "84956560bc028eb7" 18 | self.pc_SECRET = "94aba54af9065f71de72f5508f1cd42e" 19 | ### 20 | self.android_APPKEY = "1d8b6e7d45233436" 21 | self.android_SECRET = "560c52ccd288fed045859ed18bffd973" 22 | 23 | def sign(self, params): 24 | data = "" 25 | secret = "" 26 | appkey = params.setdefault(("appkey"), "84956560bc028eb7") 27 | if params.setdefault(("sign"), None) != None: 28 | del params["sign"] 29 | else: 30 | del params["sign"] 31 | if appkey == "1d8b6e7d45233436": 32 | secret = self.android_SECRET 33 | else: 34 | secret == self.pc_SECRET 35 | paras = sorted(params) 36 | paras.sort() 37 | for para in paras: 38 | if data != "": 39 | data += "&" 40 | data += para + "=" + str(params[para]) 41 | m = hashlib.md5() 42 | m.update((data + secret).encode("utf-8")) 43 | return data + "&sign=" + m.hexdigest() 44 | 45 | def rsa_pass(self, password, pub_key, hash): 46 | pub_key = rsa.PublicKey.load_pkcs1_openssl_pem(pub_key.encode("utf-8")) 47 | pass_rsa = parse.quote_plus( 48 | base64.b64encode(rsa.encrypt(f"{hash}{password}".encode(), pub_key)) 49 | ) 50 | return pass_rsa 51 | 52 | 53 | class Getkey(Rsa_a): 54 | def __init__(self): 55 | super().__init__() 56 | self.getrsa_url = "https://passport.bilibili.com/api/oauth2/getKey" 57 | self.login_url = "https://passport.bilibili.com/api/v3/oauth2/login" 58 | self.headers = { 59 | "Host": "passport.bilibili.com", 60 | "APP-KEY": "android", 61 | "Content-Type": "application/x-www-form-urlencoded", 62 | "User-Agent": "BiliDroid/6.8.0 os/android", 63 | } 64 | self.time = int(time()) 65 | 66 | def get(self): 67 | params = { 68 | "actionKey": "appkey", 69 | "appkey": self.android_APPKEY, 70 | "build": "6080500", 71 | "device": "android", 72 | "mobi_app": "android", 73 | "platform": "android", 74 | "ts": self.time, 75 | } 76 | sign_params = self.sign(params) 77 | a = requests.post( 78 | self.getrsa_url, data=sign_params, headers=self.headers, timeout=5 79 | ) 80 | return a.text 81 | 82 | def login(self): 83 | try: 84 | login_rsa = ujson.loads(self.get()) 85 | login_hash = login_rsa["data"]["hash"] 86 | login_rsa_key = login_rsa["data"]["key"] 87 | self.password_rsa = self.rsa_pass(self.password, login_rsa_key, login_hash) 88 | params = { 89 | "actionKey": "appkey", 90 | "appkey": self.android_APPKEY, 91 | "appver": "6080500", 92 | "build": "6080500", 93 | "captcha": "", 94 | "challenge": "", 95 | "device": "android", 96 | "mobi_app": "android", 97 | "password": self.password_rsa, 98 | "permission": "ALL", 99 | "platform": "android", 100 | "seccode": "", 101 | "subid": 1, 102 | "ts": self.time, 103 | "username": self.username, 104 | "validate": "", 105 | } 106 | sign_params = self.sign(params) 107 | res = requests.post( 108 | self.login_url, data=sign_params, headers=self.headers, timeout=5 109 | ) 110 | access_key = ujson.loads(res.text) 111 | return access_key["data"]["token_info"]["access_token"] 112 | 113 | except BaseException as err: 114 | print(err) 115 | return "登录错误,错误为:" + str(err) -------------------------------------------------------------------------------- /Super_bili/main.py: -------------------------------------------------------------------------------- 1 | from starlette.applications import Starlette 2 | from starlette.responses import JSONResponse, Response 3 | from starlette.routing import Route, Mount 4 | from starlette.staticfiles import StaticFiles 5 | import uvicorn 6 | import asyncio 7 | import ujson 8 | from bili.bili_api import * # API模块 9 | 10 | headers = { 11 | "Content-Type": "application/json", 12 | "Access-Control-Allow-Origin": "https://www.bilibili.com", 13 | "Access-Control-Allow-Credentials": "true", 14 | } 15 | 16 | 17 | async def not_found(request, exc): 18 | return JSONResponse( 19 | {"code": -404, "message": "服务器错误,请稍后再试"}, status_code=exc.status_code 20 | ) 21 | 22 | 23 | async def server_error(request, exc): 24 | return JSONResponse( 25 | {"code": -500, "message": "服务器未响应,请稍后再试"}, status_code=exc.status_code 26 | ) 27 | 28 | 29 | exception_handlers = {404: not_found, 500: server_error} 30 | app = Starlette(debug=True, exception_handlers=exception_handlers) 31 | 32 | 33 | @app.route("/pgc/player/web/playurl", methods=["GET"]) 34 | async def uid(request): 35 | try: 36 | data = await pc_pgc_pcurl(request.query_params) 37 | return JSONResponse(ujson.loads(data), status_code=200, headers=headers) 38 | except Exception as err: 39 | print(err) 40 | return JSONResponse({"code": -400, "message": "服务器错误,请稍后再试"}, status_code=400) 41 | 42 | 43 | @app.route(path="/", methods=["POST", "GET"]) 44 | async def index(request): 45 | return Response("By:mk39", status_code=200) 46 | 47 | 48 | if __name__ == "__main__": 49 | uvicorn.run(app, host="0.0.0.0", port=39831) 50 | -------------------------------------------------------------------------------- /Super_bili/requirements.txt: -------------------------------------------------------------------------------- 1 | requests==2.24.0 2 | rsa==4.6 3 | ujson==4.0.1 4 | aiofiles==0.6.0 5 | starlette==0.14.1 6 | uvicorn==0.13.1 -------------------------------------------------------------------------------- /Super_bili/油猴脚本.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name super bili 3 | // @namespace http://tampermonkey.net/ 4 | // @version 0.1 5 | // @description try to take over the world! 6 | // @author mk39 7 | // @require https://unpkg.com/ajax-hook@2.0.2/dist/ajaxhook.min.js 8 | // @include *//www.bilibili.com/bangumi/play/* 9 | // @grant none 10 | // ==/UserScript== 11 | 12 | (function () { 13 | 'use strict'; 14 | //输入你的域名 15 | var url = '' 16 | ah.proxy({ 17 | onRequest: (config, handler) => { 18 | if (/^[\s\S]*\/\/api.bilibili.com\/pgc\/player\/web\/playurl[\s\S]*/.test(config.url)) { 19 | config.url = `https://${url}/pgc/player/web/playurl?` + config.url.split("?")[1] 20 | } 21 | handler.next(config); 22 | }, 23 | onError: (err, handler) => { 24 | console.log(err.type) 25 | handler.next(err) 26 | }, 27 | onResponse: (response, handler) => { 28 | if (`https://${url}/pgc/player/web/playurl` == response.config.url) { 29 | if (response.response.code == -10043) { 30 | alert(response.response.message) 31 | } 32 | } else if (/^[\s\S]*\/\/api.bilibili.com\/pgc\/review\/user[\s\S]*/.test(response.config.url)) { 33 | var view = JSON.parse(response.response) 34 | if (view.result.media.type_name == '电影') { 35 | alert('电影如果只有6分钟请尝试切换1080p+,如果只有480p就切换自动画质然后会出现1080p+,再切换1080p+') 36 | } 37 | } 38 | handler.next(response) 39 | } 40 | }) 41 | function getCookie(cookie_name) { 42 | var allcookies = document.cookie; 43 | var cookie_pos = allcookies.indexOf(cookie_name); 44 | if (cookie_pos != -1) { 45 | cookie_pos = cookie_pos + cookie_name.length + 1; 46 | var cookie_end = allcookies.indexOf(";", cookie_pos); 47 | if (cookie_end == -1) { 48 | cookie_end = allcookies.length; 49 | } 50 | var value = unescape(allcookies.substring(cookie_pos, cookie_end)); 51 | } 52 | return value; 53 | } 54 | 55 | //感谢解除区域限制脚本 56 | function modiy(name, modifyFn) { 57 | const name_origin = `${name}_origin` 58 | window[name_origin] = window[name] 59 | let value = undefined 60 | Object.defineProperty(window, name, { 61 | configurable: true, 62 | enumerable: true, 63 | get: () => { 64 | return value 65 | }, 66 | set: (val) => { 67 | value = modifyFn(val) 68 | } 69 | }) 70 | if (window[name_origin]) { 71 | window[name] = window[name_origin] 72 | } 73 | } 74 | function vip2() { 75 | modiy('__INITIAL_STATE__', (value) => { 76 | for (let ep of [value.epInfo, ...value.epList]) { 77 | if (ep.epStatus === 13) { 78 | ep.epStatus = 2 79 | } 80 | } 81 | return value 82 | }) 83 | } 84 | function vip() { 85 | modiy('__PGC_USERSTATE__', (value) => { 86 | if (value) { 87 | value.pay = 1 88 | value.area_limit = 0 89 | value.vip_info.status = 1 90 | value.vip_info.due_date = 1888953600000 91 | value.vip_info.type = 2 92 | } 93 | console.log(value) 94 | return value 95 | }) 96 | } 97 | vip() 98 | vip2() 99 | })(); --------------------------------------------------------------------------------