This commit is contained in:
SlyAimer 2025-01-05 00:17:12 +08:00
parent 4e9db16b2e
commit 95618ddcba
413 changed files with 1392 additions and 15 deletions

4
.gitignore vendored
View file

@ -1 +1,5 @@
.env.prod
.venv
.xml
.idea
.db

14
bot.py
View file

@ -1,14 +1,22 @@
import nonebot
from nonebot.adapters.qq import Adapter as QQAdapter
from nonebot.adapters.onebot.v11 import Adapter as OneBotV11Adapter
from src.qq_plugins.data_init import data_init # 导入QQ插件
nonebot.init()
driver = nonebot.get_driver()
driver.register_adapter(QQAdapter)
driver.register_adapter(QQAdapter) # 注册QQ适配器
# driver.register_adapter(OneBotV11Adapter) # 注册OneBot V11适配器
nonebot.load_builtin_plugins('echo', 'single_session')
# nonebot.load_builtin_plugins('echo', 'single_session')
nonebot.load_from_toml("pyproject.toml")
def init_all():
# 初始化数据库
data_init.QrFortune_init()
data_init.touch_init()
if __name__ == "__main__":
init_all()
nonebot.run()

View file

@ -0,0 +1,53 @@
# -*- coding: UTF-8 -*-
import random
import execjs
agent = [
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2227.1 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/57.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3",
]
# 获取浏览器认证头
def get_user_agents():
return random.choice(agent)
# 读取js
def djs(js):
f = open(js, 'r', encoding='utf-8')
jst = ''
while True:
readline = f.readline()
if readline:
jst += readline
else:
break
return jst
def getjs():
return djs('src/common_plugins/cloud_music/jsdm.js')
# 获取ptqrtoken
def ptqrtoken(qrsign):
# 加载js
execjs_execjs = execjs.compile(getjs())
return execjs_execjs.call('hash33', qrsign)
# 获取UI
def guid():
# 加载js
execjs_execjs = execjs.compile(getjs())
return execjs_execjs.call('guid')
# 获取g_tk
def get_g_tk(p_skey):
# 加载js
execjs_execjs = execjs.compile(getjs())
return execjs_execjs.call('getToken', p_skey)
# 获取i
def S():
# 加载js
execjs_execjs = execjs.compile(getjs())
return execjs_execjs.call('S')
# 获取key
def a():
# 加载js
execjs_execjs = execjs.compile(getjs())
return execjs_execjs.call('a', 16)

View file

@ -0,0 +1,252 @@
# -*- coding: utf-8 -*-
import base64
import codecs
import json
import pickle
from random import Random
from Crypto.Cipher import AES
import qrcode
import src.common_plugins.cloud_music.agent as agent
from threading import Thread
import time
import requests
from io import BytesIO
from PIL import Image
import os
from graiax import silkcoder
requests.packages.urllib3.disable_warnings()
headers = {'User-Agent': agent.get_user_agents(), 'Referer': 'https://music.163.com/'}
class showpng(Thread):
def __init__(self, data):
Thread.__init__(self)
self.data = data
def run(self):
img = Image.open(BytesIO(self.data))
img.show()
# 解密params和encSecKey值
def keys(key):
while len(key) % 16 != 0:
key += '\0'
return str.encode(key)
def AES_aes(t, key, iv):
def p(s): return s + (AES.block_size - len(s) %AES.block_size) * chr(AES.block_size - len(s) % AES.block_size)
encrypt = str(base64.encodebytes(AES.new( keys(key), AES.MODE_CBC,keys(iv)).encrypt(str.encode(p(t)))),encoding='utf-8')
return encrypt
def RSA_rsa(i, e, f):
return format(int(codecs.encode(
i[::-1].encode('utf-8'), 'hex_codec'), 16) ** int(e, 16) % int(f, 16), 'x').zfill(256)
# 获取的参数
key = agent.S() # i6c的值
d = str({'key': key, 'type': "1", 'csrf_token': ""})
e = "010001" # (["流泪", "强"])的值
f = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
g = "0CoJUm6Qyw8W8jud" # (["爱心", "女孩", "惊恐", "大笑"])的值
iv = "0102030405060708" # 偏移量
i = agent.a() # 随机生成长度为16的字符串
def params(u):
if u is None:
return AES_aes(AES_aes(d, g, iv), i, iv) # g 和 i 都是key代替
else:
return AES_aes(AES_aes(u,g,iv),i,iv) # g 和 i 都是key代替
def encSecKey():
return RSA_rsa(i, e, f)
"""
使用二维码登录网易云音乐需要先获取二维码的key然后使用该key生成二维码扫描二维码登录最后通过登录接口 返回cookie 保存起来
"""
save_path = os.getcwd()+'/src/music/netease_music'
# 判断cookie是否有效
def netease_cloud_music_is_login(session):
try:
session.cookies.load(ignore_discard=True)
except Exception:
pass
csrf_token = session.cookies.get('__csrf')
c = str({'csrf_token': csrf_token})
try:
loginurl = session.post('https://music.163.com/weapi/w/nuser/account/get?csrf_token={}'.format(csrf_token),data={'params': params(None), 'encSecKey': encSecKey()}, headers=headers).json()
if '200' in str(loginurl['code']):
return session, True
else:
return session, False
except BaseException:
return session, False
# 获取二维码的key
def get_qr_key(session):
url = f"https://music.163.com/weapi/login/qrcode/unikey"
data = {"params": params(None),"encSecKey": encSecKey()}
response = session.post(url, headers=headers,params=data)
result = json.loads(response.text)
if result.get("code") == 200:
unikey = result.get("unikey")
print(unikey)
return unikey
else:
return None
# 创建 QRCode 对象
qr = qrcode.QRCode( version=1, error_correction=qrcode.constants.ERROR_CORRECT_L, box_size=10, border=4, )
# 生成二维码
def create_qr_code(unikey):
# 添加数据
pngurl = f"http://music.163.com/login?codekey={unikey}"
qr.add_data(pngurl)
img = qr.make_image()
a = BytesIO()
img.save(a, 'png')
png = a.getvalue()
# 将字节数据转换为图像
img = Image.open(BytesIO(png))
# 保存图像到本地文件
img.save(save_path,'qrcode.png')
a.close()
return os.getcwd()+'/'+save_path+'/qrcode.png'
# # 打开二维码进行扫码操作
# t = showpng(png)
# t.start()
# 检查二维码状态是否被扫描
def check_qr_code(unikey,session):
tokenurl = f"https://music.163.com/weapi/login/qrcode/client/login?csrf_token="
u = str({'key': unikey, 'type': "1", 'csrf_token': ""})
qrcodedata = session.post(
tokenurl,
data={
'params': params(u),
'encSecKey': encSecKey()
},
headers=headers).json()
return qrcodedata.get('code')
def netease_music_search(keyword,session):
url = "http://music.163.com/api/search/get"
params = {
"s": keyword,
"type": 1, # 1 表示搜索歌曲2 表示搜索专辑3 表示搜索歌手等
"limit": 50, # 限制搜索结果的数量
"offset": 0, # 搜索结果的偏移量,可用于分页
"sub": "false",
}
response = session.get(url, headers=headers, params=params)
data = response.json()
if "result" in data and "songs" in data["result"]:
songs = data["result"]["songs"]
if songs:
filtered_data = [item for item in songs if item.get('fee') == 8]# 过滤掉付费歌曲
num = 0
num = Random().randint(0, len(filtered_data) - 1)
first_song = filtered_data[num] # 获取第一首歌曲
song_name = first_song["name"]
singer = first_song["artists"][0]["name"]
song_id = first_song["id"]
song_url = f"https://music.163.com/song?id={song_id}"
print(f"搜索结果:{song_name} - {singer}")
print(f"歌曲链接:{song_url}")
return song_id,song_name,singer,song_url
return None, None, None, None
def netease_music_download(song_id,song_name,singer,session):
if not os.path.exists(save_path):
os.makedirs(save_path)
download_url = f"http://music.163.com/song/media/outer/url?br=999000&id={song_id}.mp3"
response = session.get(download_url, headers=headers)
if response.status_code == 200:
print(f"正在下载 {song_name} - {singer} 歌曲...")
file_path = os.path.join(save_path, f"{song_name}-{singer}.mp3")
file_name = os.path.basename(f"{song_name}-{singer}.mp3")
with open(file_path, "wb") as f:
f.write(response.content)
output_silk_path = os.path.join(save_path, os.path.splitext(file_name)[0] + ".silk")
# 使用 graiax-silkcoder 进行转换
silkcoder.encode(file_path, output_silk_path)
return output_silk_path
else:
return None
def netease_music_delete():
for root, dirs, files in os.walk(save_path):
for file in files:
file_path = os.path.join(root, file)
os.remove(file_path)
# def main():
# keyword = input("请输入你想要搜索的歌曲名称:")
# save_path = '../src/music/netease_music'
# if not os.path.exists(save_path):
# os.makedirs(save_path)
# song_id,song_name,singer,song_url = netease_music_search(keyword)
# if song_id:
# download_result = netease_music_download(song_id,song_name,singer)
# # download_result = netease_music_play(song_id,song_name,singer)
# if download_result:
# print(f"歌曲已成功下载到 {download_result}")
# else:
# print("歌曲下载失败,请检查网络或 API 状态。")
#
# if __name__ == "__main__":
# main()
# def main():
# cloud_music_login()
# if __name__ == "__main__":
# main()

View file

@ -0,0 +1,42 @@
function hash33(t) {
for (var e = 0, i = 0, n = t.length; i < n; ++i)
e += (e << 5) + t.charCodeAt(i);
return 2147483647 & e
}
function getToken(p_skey) {
var str = p_skey || '',
hash = 5381;
for (var i = 0, len = str.length; i < len; ++i) {
hash += (hash << 5) + str.charCodeAt(i);
}
return hash & 0x7fffffff;
}
function guid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
}).toUpperCase();
};
function S() {
var e = (new Date).getTime();
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(t) {
var n = (e + 16 * Math.random()) % 16 | 0;
return e = Math.floor(e / 16),
("x" === t ? n : 7 & n | 8).toString(16)
})
}
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
}

View file

@ -0,0 +1,15 @@
image:
image_local_path: "src/img_resource/MaoYuNa"
#SMMS图床相关配置
smms_token: "<KEY>" # sm.ms图床的token
smms_image_upload_history: "https://sm.ms/api/v2/upload_history" # sm.ms图床获取上传图片历史API地址
#聚合图床相关配置
ju_he_token: "<KEY>" # 聚合图床的token
ju_he_image_list: "https://api.superbed.cn/timeline" # 聚合图床获取上传图片历史API地址

View file

@ -0,0 +1,46 @@
import os
import yaml
import random
import requests
with open(os.getcwd() +'/src/common_plugins/config/common.yaml', 'r', encoding='utf-8') as f:
image = yaml.load(f.read(), Loader=yaml.FullLoader).get('image')
image_local_path = image.get('image_local_path')
smms_token = image.get('smms_token')
smms_image_upload_history = image.get('smms_image_upload_history')
ju_he_token = image.get('ju_he_token')
ju_he_image_list = image.get('ju_he_image_list')
"""本地图片"""
def get_image_names():
image_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp'] # 定义常见的图片文件扩展名
image_names = []
for root, dirs, files in os.walk(os.getcwd()+'/'+image_local_path):
for file in files:
if any(file.endswith(ext) for ext in image_extensions): # 检查文件是否是图片文件
image_names.append(file)
random.choice(image_names) # 随机选取一张图片
local_image_path = os.getcwd() + '/' + image_local_path + '/' + random.choice(image_names) # 随机选取一张图片的路径
return local_image_path
""" sm.ms 图床"""
def get_smms_image_url():
# 定义请求的参数
data = requests.get(smms_image_upload_history, headers={'Authorization': smms_token}, params={"page": "1"}).json().get('data')
urls = [item['url'] for item in data]
random_url = random.choice(urls)
return random_url
"""聚合图床"""
def get_juhe_image_url():
# 定义请求的参数
params = {"token": ju_he_token,"f": "json","categories": "猫羽雫","page": 1, "size": 400}
random_url = random.choice(requests.get(ju_he_image_list, params=params).json().get('docs', [])).get('url')
return random_url
if __name__ == '__main__':
print(get_smms_image_url())
print(get_juhe_image_url())
print(get_image_names())

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 799 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 686 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 913 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 765 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 806 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 891 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 756 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 997 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 775 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 760 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 874 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 617 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 571 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,005 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 738 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 720 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 869 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 755 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 959 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 642 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 797 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 590 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 970 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 641 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 942 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 804 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 764 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 773 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 814 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 924 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 687 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 466 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Some files were not shown because too many files have changed in this diff Show more