From cb58a808a167fbb8860e7d6be6d57e4aae23488b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8B=8F=E6=99=93=E6=99=B4?= <37541680+Suxiaoqinx@users.noreply.github.com> Date: Tue, 27 Aug 2024 16:36:28 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dtype=3Ddown=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E8=B7=B3=E8=BD=AC=E9=97=AE=E9=A2=98=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.py | 202 +++++++++++++++++++++++++++----------------------------- 1 file changed, 97 insertions(+), 105 deletions(-) diff --git a/main.py b/main.py index 8e55488..16bf641 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,4 @@ -from flask import Flask, request, redirect ,jsonify ,Response +from flask import Flask, request, jsonify ,redirect ,Response import json import os import urllib.parse @@ -7,17 +7,15 @@ from random import randrange import requests from cryptography.hazmat.primitives import padding from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes + def HexDigest(data): - # Digests a `bytearray` to a hex string return "".join([hex(d)[2:].zfill(2) for d in data]) def HashDigest(text): - # Digests 128 bit md5 hash HASH = md5(text.encode("utf-8")) return HASH.digest() def HashHexDigest(text): - """Digests 128 bit md5 hash,then digest it as a hexstring""" return HexDigest(HashDigest(text)) def parse_cookie(text: str): @@ -25,6 +23,37 @@ def parse_cookie(text: str): cookie_ = {k.strip(): v.strip() for k, v in cookie_} return cookie_ +def ids(ids): + if '163cn.tv' in ids: + response = requests.get(ids, allow_redirects=False) + ids = response.headers.get('Location') + if 'music.163.com' in ids: + index = ids.find('id=') + 3 + ids = ids[index:].split('&')[0] + return ids + +def read_cookie(): + script_dir = os.path.dirname(os.path.abspath(__file__)) + cookie_file = os.path.join(script_dir, 'cookie.txt') + with open(cookie_file, 'r') as f: + cookie_contents = f.read() + return cookie_contents + +def post(url, params, cookie): + headers = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36 Chrome/91.0.4472.164 NeteaseMusicDesktop/2.10.2.200154', + 'Referer': '', + } + cookies = { + "os": "pc", + "appver": "", + "osver": "", + "deviceId": "pyncm!" + } + cookies.update(cookie) + response = requests.post(url, headers=headers, cookies=cookies, data={"params": params}) + return response.text + # 输入id选项 def ids(ids): if '163cn.tv' in ids: @@ -64,72 +93,7 @@ def music_level1(value): else: return "未知音质" -def post(url, params, cookie): - headers = { - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36 Chrome/91.0.4472.164 NeteaseMusicDesktop/2.10.2.200154', - 'Referer': '', - } - cookies = { - "os": "pc", - "appver": "", - "osver": "", - "deviceId": "pyncm!" - } - cookies.update(cookie) - response = requests.post(url, headers=headers, cookies=cookies, data={"params": params}) - return response.text - -def read_cookie(): - script_dir = os.path.dirname(os.path.abspath(__file__)) - cookie_file = os.path.join(script_dir, 'cookie.txt') - with open(cookie_file, 'r') as f: - cookie_contents = f.read() - return cookie_contents - -app = Flask(__name__) - -@app.route('/') - -def hello_world(): - return '你好,世界!' - -@app.route('/Song_V1',methods=['GET','POST']) - -def Song_v1(): - if request.method == 'GET': - # 从查询字符串中获取所有参数的值 - song_ids = request.args.get('ids') - url = request.args.get('url') - level = request.args.get('level') - type = request.args.get('type') - else: - song_ids = request.form.get('ids') - url = request.form.get('url') - level = request.form.get('level') - type = request.form.get('type') - - # 检查至少提供一个 'ids' 或 'url' 参数 - if not song_ids and url is None: - return jsonify({'error': '必须提供 ids 或 url 参数'}), 400 - if level is None: - return jsonify({'error': 'level参数为空'}), 400 - if type is None: - return jsonify({'error': 'type参数为空'}), 400 - - # Check if either song_ids or url is provided - if song_ids: - # Process song_ids - jsondata = song_ids - elif url: - # Process url - jsondata = url - else: - # Neither song_ids nor url provided - return jsonify({'error': '错误!'}), 400 - - # 网易云cookie - cookies = parse_cookie(read_cookie()) - +def url_v1(id, level, cookies): url = "https://interface3.music.163.com/eapi/song/enhance/player/url/v1" AES_KEY = b"e82ckenh8dichen8" config = { @@ -141,7 +105,7 @@ def Song_v1(): } payload = { - 'ids': [ids(jsondata)], + 'ids': [id], 'level': level, 'encodeType': 'flac', 'header': json.dumps(config), @@ -153,61 +117,91 @@ def Song_v1(): url2 = urllib.parse.urlparse(url).path.replace("/eapi/", "/api/") digest = HashHexDigest(f"nobody{url2}use{json.dumps(payload)}md5forencrypt") params = f"{url2}-36cd479b6b5-{json.dumps(payload)}-36cd479b6b5-{digest}" - # AES-256-ECB PKCS7padding padder = padding.PKCS7(algorithms.AES(AES_KEY).block_size).padder() padded_data = padder.update(params.encode()) + padder.finalize() cipher = Cipher(algorithms.AES(AES_KEY), modes.ECB()) encryptor = cipher.encryptor() enc = encryptor.update(padded_data) + encryptor.finalize() params = HexDigest(enc) - # 发送POST请求 response = post(url, params, cookies) - #print(response) - if "参数错误" in response: - return jsonify({"status": 400,'msg': '参数错误!'}), 400 - - jseg = json.loads(response) - #歌曲信息接口 - song_names = "https://interface3.music.163.com/api/v3/song/detail" - song_data = {'c': json.dumps([{"id":jseg['data'][0]['id'],"v":0}])} - resp = requests.post(url=song_names, data=song_data) - jse = json.loads(resp.text) - #歌词接口 - lyric_names = "https://interface3.music.163.com/api/song/lyric" - lyric_data = {'id' : jseg['data'][0]['id'],'cp' : 'false','tv' : '0','lv' : '0','rv' : '0','kv' : '0','yv' : '0','ytv' : '0','yrv' : '0'} - lyricresp = requests.post(url=lyric_names, data=lyric_data, cookies=cookies) - lyricjse = json.loads(lyricresp.text) + return json.loads(response) - if jseg['data'][0]['url'] is not None: - if jse['songs']: - song_url = jseg['data'][0]['url'] - song_name = jse['songs'][0]['name'] - song_picUrl = jse['songs'][0]['al']['picUrl'] - song_alname = jse['songs'][0]['al']['name'] +def name_v1(id): + #歌曲信息接口 + urls = "https://interface3.music.163.com/api/v3/song/detail" + data = {'c': json.dumps([{"id":id,"v":0}])} + response = requests.post(url=urls, data=data) + return response.json() + +def lyric_v1(id,cookies): + #歌词接口 + url = "https://interface3.music.163.com/api/song/lyric" + data = {'id' : id,'cp' : 'false','tv' : '0','lv' : '0','rv' : '0','kv' : '0','yv' : '0','ytv' : '0','yrv' : '0'} + response = requests.post(url=url, data=data, cookies=cookies) + return response.json() + +app = Flask(__name__) + +@app.route('/') +def hello_world(): + return '你好,世界!' + +@app.route('/Song_V1', methods=['GET', 'POST']) +def Song_v1(): + if request.method == 'GET': + song_ids = request.args.get('ids') + url = request.args.get('url') + level = request.args.get('level') + type_ = request.args.get('type') + else: + song_ids = request.form.get('ids') + url = request.form.get('url') + level = request.form.get('level') + type_ = request.form.get('type') + + if not song_ids and not url: + return jsonify({'error': '必须提供 ids 或 url 参数'}), 400 + if level is None: + return jsonify({'error': 'level参数为空'}), 400 + if type_ is None: + return jsonify({'error': 'type参数为空'}), 400 + + jsondata = song_ids if song_ids else url + cookies = parse_cookie(read_cookie()) + urlv1 = url_v1(ids(jsondata),level,cookies) + namev1 = name_v1(urlv1['data'][0]['id']) + lyricv1 = lyric_v1(urlv1['data'][0]['id'],cookies) + + if urlv1['data'][0]['url'] is not None: + if namev1['songs']: + song_url = urlv1['data'][0]['url'] + song_name = namev1['songs'][0]['name'] + song_picUrl = namev1['songs'][0]['al']['picUrl'] + song_alname = namev1['songs'][0]['al']['name'] artist_names = [] - for song in jse['songs']: + for song in namev1['songs']: ar_list = song['ar'] if len(ar_list) > 0: artist_names.append('/'.join(ar['name'] for ar in ar_list)) song_arname = ', '.join(artist_names) else: data = jsonify({"status": 400,'msg': '信息获取不完整!'}), 400 - if type == 'text': - data = '歌曲名称:' + song_name + '
歌曲图片:' + song_picUrl + '
歌手:' + song_arname + '
歌曲专辑:' + song_alname + '
歌曲音质:' + music_level1(jseg['data'][0]['level']) + '
歌曲大小:' + size(jseg['data'][0]['size']) + '
音乐地址:' + song_url - elif type == 'down': + if type_ == 'text': + data = '歌曲名称:' + song_name + '
歌曲图片:' + song_picUrl + '
歌手:' + song_arname + '
歌曲专辑:' + song_alname + '
歌曲音质:' + music_level1(urlv1['data'][0]['level']) + '
歌曲大小:' + size(urlv1['data'][0]['size']) + '
音乐地址:' + song_url + elif type_ == 'down': data = redirect(song_url) - elif type == 'json': + elif type_ == 'json': data = { "status": 200, "name": song_name, "pic": song_picUrl, "ar_name": song_arname, "al_name": song_alname, - "level":music_level1(jseg['data'][0]['level']), - "size": size(jseg['data'][0]['size']), + "level":music_level1(urlv1['data'][0]['level']), + "size": size(urlv1['data'][0]['size']), "url": song_url, - "lyric": lyricjse['lrc']['lyric'], - "tlyric": lyricjse['tlyric']['lyric'] + "lyric": lyricv1['lrc']['lyric'], + "tlyric": lyricv1['tlyric']['lyric'] } json_data = json.dumps(data) data = Response(json_data, content_type='application/json') @@ -216,6 +210,4 @@ def Song_v1(): return data if __name__ == '__main__': - app.config['JSON_SORT_KEYS'] = False - app.config['JSON_AS_ASCII'] = False app.run(host='0.0.0.0', port=5000, debug=False)