import time import requests from hashlib import md5 from typing import Union from urllib.parse import urlencode from requests_toolbelt.multipart.encoder import MultipartEncoder import imghdr class Crypto: APPKEY = '4409e2ce8ffd12b8' APPSECRET = '59b43e04ad6965f34319062b478f83dd' @staticmethod def md5(data: Union[str, bytes]) -> str: '''generates md5 hex dump of `str` or `bytes`''' if type(data) == str: return md5(data.encode()).hexdigest() return md5(data).hexdigest() @staticmethod def sign(data: Union[str, dict]) -> str: '''salted sign funtion for `dict`(converts to qs then parse) & `str`''' if isinstance(data, dict): _str = urlencode(data) elif type(data) != str: raise TypeError return Crypto.md5(_str + Crypto.APPSECRET) class SingableDict(dict): @property def sorted(self): '''returns a alphabetically sorted version of `self`''' return dict(sorted(self.items())) @property def signed(self): '''returns our sorted self with calculated `sign` as a new key-value pair at the end''' _sorted = self.sorted return {**_sorted, 'sign': Crypto.sign(_sorted)} def get_image_type(file_path): with open(file_path, 'rb') as f: data = f.read() return imghdr.what(None, data) def get_have_card_id_list(UID, ACCESS_KEY, sid): url = "https://api.bilibili.com/x/vas/nftcard/cardlist" params = SingableDict( { "access_key": ACCESS_KEY, "act_id": sid, # 这里默认已经是三体数字藏品卡14,github下载的默认是4,也就是胶囊卡 "appkey": "4409e2ce8ffd12b8", "disable_rcmd": "0", "ruid": UID, "statistics": "{\"appId\":1,\"platform\":3,\"version\":\"7.9.0\",\"abtest\":\"\"}", "ts": int(time.time()), } ).signed response = requests.request("GET", url, params=params) data = response.json() if data['code'] != 0: print(f"获取卡片信息出错,下面是 api 返回:\n{data}") return # print(data) # 查询已添加无需再填 have_card_id_list = {} try: for round in data['data']['round_list']: for card in round['card_list']: if card['card_id_list']: print(f"找到付费卡 card_id: {card['card_id_list'][0]['card_id']}\n这个id属于{card['card_name']}") have_card_id_list.update({card['card_name']: card['card_id_list'][0]['card_id']}) if data["data"]["pre_list"]: for i in data["data"]["pre_list"]: if card_id_list := i.get("card_id_list"): for j in card_id_list: if card_id := j.get("card_id"): print(f"找到预约卡card_id: {card_id}\n这个 id 属于{i.get('card_name')}") have_card_id_list.update({i.get('card_name'): card_id}) except Exception as e: print(f"处理卡牌列表出错{e.args[0]},下面是 api 返回:\n{data}") return {} if have_card_id_list: print(f"已经找到卡片") return have_card_id_list else: print("没有找到可用的卡片") return {} def set_face(card_id, ACCESS_KEY, img_data): api = "https://api.bilibili.com/x/member/app/face/digitalKit/update" params = SingableDict( { "access_key": ACCESS_KEY, "appkey": "4409e2ce8ffd12b8", "build": "7090300", "c_locale": "zh_CN", "channel": "xiaomi", "disable_rcmd": "0", "mobi_app": "android", "platform": "android", "s_locale": "zh_CN", "statistics": "{\"appId\":1,\"platform\":3,\"version\":\"7.9.0\",\"abtest\":\"\"}", "ts": int(time.time()), } ).signed m = MultipartEncoder( fields={ 'digital_kit_id': str(card_id), 'face': ('face', img_data, 'application/octet-stream'), } ) headers = { "Content-Type": m.content_type, } response = requests.request("POST", api, data=m, headers=headers, params=params) if response.json()['code'] != 0: return False, response.json() return True, '设置头像成功, 请等待审核' def having_card_id_list(uid, key, sid): uid = int(uid) access_key = str(key) sid = str(sid) had_card_id_list = get_have_card_id_list(uid, access_key, sid) # 根据你所取得的卡card_id进行更改 if had_card_id_list: return True, had_card_id_list, "已找到拥有卡牌" return False, {}, "没找到任何card_id ,请确认当前卡组已拥有卡片" def card_id_set_ava(card_id, key, img_data): access_key = str(key) result, code = set_face(card_id, access_key, img_data) return result, code