bili-nft-avatar / nft.py
rdp-studio's picture
Create nft.py
f5e6625
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