185 lines
7.2 KiB
Python
185 lines
7.2 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
cron: 0 8 * * *
|
||
new Env('网易音乐合伙人');
|
||
"""
|
||
import requests
|
||
import base64
|
||
import codecs
|
||
import execjs
|
||
import json
|
||
|
||
from Crypto.Cipher import AES
|
||
from notify import send
|
||
|
||
|
||
def to_16(key):
|
||
while len(key) % 16 != 0:
|
||
key += '\0'
|
||
return str.encode(key)
|
||
|
||
|
||
def aes_encrypt(text, key, iv):
|
||
bs = AES.block_size
|
||
pad2 = lambda s: s + (bs - len(s) % bs) * chr(bs - len(s) % bs)
|
||
encryptor = AES.new(to_16(key), AES.MODE_CBC, to_16(iv))
|
||
encrypt_aes = encryptor.encrypt(str.encode(pad2(text)))
|
||
encrypt_text = str(base64.encodebytes(encrypt_aes), encoding='utf-8')
|
||
return encrypt_text
|
||
|
||
|
||
def rsa_encrypt(text, pubKey, modulus):
|
||
text = text[::-1]
|
||
rs = int(codecs.encode(text.encode('utf-8'), 'hex_codec'), 16) ** int(pubKey, 16) % int(modulus, 16)
|
||
return format(rs, 'x').zfill(256)
|
||
|
||
|
||
# 获取i值的函数,即随机生成长度为16的字符串
|
||
get_i = execjs.compile(r"""
|
||
function a(a) {
|
||
var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";
|
||
for (d = 0; a > d; d += 1)
|
||
e = Math.random() * b.length,
|
||
e = Math.floor(e),
|
||
c += b.charAt(e);
|
||
return c
|
||
}
|
||
""")
|
||
|
||
|
||
class Copartner():
|
||
name = "音乐合伙人"
|
||
|
||
def __init__(self, check_item):
|
||
self.csrf = None
|
||
self.musicDataUrl = "http://interface.music.163.com/api/music/partner/daily/task/get"
|
||
self.userInfoUrl = "https://music.163.com/api/nuser/account/get"
|
||
self.signUrl = "https://interface.music.163.com/weapi/music/partner/work/evaluate?csrf_token="
|
||
self.g = '0CoJUm6Qyw8W8jud' # buU9L(["爱心", "女孩", "惊恐", "大笑"])的值
|
||
self.b = "010001" # buU9L(["流泪", "强"])的值
|
||
# buU9L(Rg4k.md)的值
|
||
self.c = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'
|
||
self.i = get_i.call('a', 16) # 随机生成长度为16的字符串
|
||
self.iv = "0102030405060708" # 偏移量
|
||
self.headers = {
|
||
"Accept": "application/json, text/javascript",
|
||
"Accept-Encoding": "gzip, deflate",
|
||
"Accept-Language": "zh-CN,zh-Hans;q=0.9",
|
||
"Content-Type": "application/x-www-form-urlencoded",
|
||
"Origin": "http://mp.music.163.com",
|
||
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 15_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 CloudMusic/0.1.1 NeteaseMusic/8.8.01"
|
||
}
|
||
self.musicTags = "3-A-1"
|
||
self.musicScore = "3"
|
||
self.check_item = check_item
|
||
|
||
def get_enc_sec_key(self):
|
||
return rsa_encrypt(self.i, self.b, self.c)
|
||
|
||
def get_params(self, data):
|
||
enc_text = str(data)
|
||
return aes_encrypt(aes_encrypt(enc_text, self.g, self.iv), self.i, self.iv)
|
||
|
||
def sign(self, session, music_data, msg):
|
||
works = music_data['works']
|
||
task_id = music_data['id']
|
||
begin = False
|
||
for work in works:
|
||
_work = work['work']
|
||
if work['completed']:
|
||
msg.append({
|
||
"name": f"{_work['name']}({_work['authorName']})",
|
||
"value": f"评分完成:{work['score']}分"
|
||
})
|
||
else:
|
||
if not begin:
|
||
msg.append({"name": "本次进度", "value": ""})
|
||
begin = True
|
||
data = {
|
||
"params": self.get_params({
|
||
"taskId": task_id,
|
||
"workId": _work['id'],
|
||
"score": self.musicScore,
|
||
"tags": self.musicTags,
|
||
"customTags": "%5B%5D",
|
||
"comment": "",
|
||
"syncYunCircle": "true",
|
||
"csrf_token": self.csrf
|
||
}).replace("\n", ""),
|
||
"encSecKey": self.get_enc_sec_key()
|
||
}
|
||
try:
|
||
response = session.post(
|
||
url=f"{self.signUrl}={self.csrf}",
|
||
data=data, headers=self.headers).json()
|
||
if response["code"] == 200:
|
||
msg.append({
|
||
"name": f"{_work['name']}({_work['authorName']})",
|
||
"value": f"评分完成:{self.musicScore}分"
|
||
})
|
||
except Exception as e:
|
||
print(f"歌曲 {_work['name']} 评分异常,原因{str(e)}")
|
||
|
||
def valid(self, session):
|
||
try:
|
||
content = session.get(url=self.musicDataUrl,
|
||
headers={**self.headers, "Referer": "https://mp.music.163.com/"})
|
||
except Exception as e:
|
||
return False, f"登录验证异常,错误信息: {e}"
|
||
data = content.json()
|
||
if data["code"] == 301:
|
||
return False, data["message"]
|
||
if data["code"] == 200:
|
||
music_data = data["data"]
|
||
user_name = self.login_info(session=session)["profile"]["nickname"]
|
||
return music_data, user_name
|
||
return False, "登录信息异常"
|
||
|
||
def login_info(self, session):
|
||
try:
|
||
return session.get(url=self.userInfoUrl, headers=self.headers).json()
|
||
except Exception as e:
|
||
print(e)
|
||
return {
|
||
"profile": {
|
||
"nickname": "获取用户信息异常"
|
||
}
|
||
}
|
||
|
||
def main(self):
|
||
session = requests.session()
|
||
cookie = self.check_item.get("cookie")
|
||
music_cookie = {item.split("=")[0]: item.split("=")[1] for item in cookie.split("; ")}
|
||
self.csrf = music_cookie['__csrf']
|
||
requests.utils.add_dict_to_cookiejar(session.cookies, music_cookie)
|
||
music_data, user_name = self.valid(session)
|
||
if music_data:
|
||
completed = music_data['completed']
|
||
msg = [
|
||
{"name": "帐号信息", "value": f"{user_name}"},
|
||
{"name": "当前进度", "value": ""},
|
||
{"name": "今日完成状态", "value": f"{'已完成' if completed else '未完成'}"},
|
||
{"name": "当前获得积分", "value": music_data['integral']},
|
||
{"name": "已完成评定数", "value": music_data["completedCount"]},
|
||
]
|
||
if not completed:
|
||
self.sign(session, music_data, msg)
|
||
else:
|
||
msg = [
|
||
{"name": "帐号信息", "value": user_name},
|
||
{"name": "cookie信息", "value": "Cookie 可能过期"},
|
||
]
|
||
msg = "\n".join([f"{one.get('name')}: {one.get('value')}" for one in msg])
|
||
return msg
|
||
|
||
|
||
if __name__ == "__main__":
|
||
with open("/ql/config/netease_music_cookie.json", "r", encoding="utf-8") as f:
|
||
all_data = json.loads(f.read())
|
||
_check_item = all_data.get("MUSIC_COPARTNER", [])
|
||
res = ""
|
||
for index, item in enumerate(_check_item):
|
||
res = f'{res}账号{index + 1}:\n{Copartner(item).main()}\n'
|
||
print(res)
|
||
send('网易音乐合伙人', res)
|