Spaces:
Running
Running
import os | |
import re | |
import requests | |
import gradio as gr | |
from utils import ( | |
extract_fst_url, | |
get_real_url, | |
download_file, | |
API_QQ_2, | |
API_QQ_1, | |
KEY_QQ_1, | |
TIMEOUT, | |
TMP_DIR, | |
EN_US, | |
) | |
ZH2EN = { | |
"请输入QQ音乐 mid 或 URL 链接": "Please enter the mid or URL of QQ music song", | |
"含元信息音频下载": "Audio with metadata", | |
"歌名": "Title", | |
"作者": "Artist", | |
"专辑": "Album", | |
"歌词": "Lyrics", | |
"歌曲图片": "Cover", | |
"歌曲 ID": "Song ID", | |
"音质": "Quality", | |
"大小": "Size", | |
"QQ音乐直链解析": "QQ Music Parser", | |
"状态栏": "Status", | |
} | |
def _L(zh_txt: str): | |
return ZH2EN[zh_txt] if EN_US else zh_txt | |
def parse_id(url: str): | |
if not url: | |
return None | |
if re.fullmatch(r"^[A-Za-z0-9]{14}$", url): | |
return str(url) | |
url = extract_fst_url(url) | |
if not url: | |
return None | |
if url.startswith("https://c6.y.qq.com/base/fcgi-bin/"): | |
return get_real_url(url).split("songmid=")[1].split("&")[0] | |
match = re.search(r"songDetail/([^?]+)", url) | |
if match: | |
return str(match.group(1)) | |
else: | |
return None | |
def get_file_size(file_path): | |
size_in_bytes = os.path.getsize(file_path) | |
units = ["B", "KB", "MB", "GB"] # 初始单位为字节 | |
unit_index = 0 # 根据文件大小选择合适的单位 | |
if size_in_bytes >= 1024**3: # 大于等于 1 GB | |
unit_index = 3 | |
size = size_in_bytes / (1024**3) | |
# 大于等于 1 MB | |
elif size_in_bytes >= 1024**2: | |
unit_index = 2 | |
size = size_in_bytes / (1024**2) | |
# 大于等于 1 KB | |
elif size_in_bytes >= 1024: | |
unit_index = 1 | |
size = size_in_bytes / 1024 | |
else: | |
size = size_in_bytes | |
# 格式化输出,保留两位小数 | |
if unit_index == 0: | |
return f"{size}{units[unit_index]}" | |
else: | |
return f"{size:.2f}{units[unit_index]}" | |
# outer func requires try except | |
def infer(url: str): | |
status = "Success" | |
song = title = artist = album = lyric = cover = song_id = quality = size = None | |
try: | |
song_mid = parse_id(url) | |
if not song_mid: | |
raise ValueError("请输入有效的网址或mid!") | |
# title, artist, album, cover | |
response = requests.get( | |
API_QQ_1, | |
params={"key": KEY_QQ_1, "type": "song", "mid": song_mid}, | |
timeout=TIMEOUT, | |
) | |
if response.status_code == 200 and response.json()["code"] == 200: | |
data = response.json()["data"] | |
title = data["title"] | |
artist = data["author"] | |
album = data["album_title"] | |
cover = str(data["pic"]).replace("300x300", "800x800").split("?max_age=")[0] | |
# lyrics | |
response = requests.get( | |
API_QQ_1, | |
params={"key": KEY_QQ_1, "type": "lrc", "mid": song_mid, "format": "json"}, | |
timeout=TIMEOUT, | |
) | |
if response.status_code == 200 and response.json()["code"] == 200: | |
lyric = response.json()["data"] | |
# url | |
response = requests.get( | |
API_QQ_2, | |
params={"id": song_mid}, | |
timeout=TIMEOUT, | |
verify=False, | |
) | |
if response.status_code == 200: | |
url = response.json()["data"] | |
song_id = song_mid | |
quality = "128kb" | |
song = download_file( | |
song_mid, | |
url, | |
title, | |
artist, | |
album, | |
lyric, | |
cover, | |
f"{TMP_DIR}/qq", | |
) | |
size = get_file_size(song) | |
else: | |
raise ConnectionError(response.json()["msg"] + ", 可能是歌曲mid或URL有误") | |
except Exception as e: | |
status = f"{e}" | |
return status, song, title, artist, album, lyric, cover, song_id, quality, size | |
def qmusic_parser(): | |
return gr.Interface( | |
fn=infer, | |
inputs=[ | |
gr.Textbox( | |
label=_L("请输入QQ音乐 mid 或 URL 链接"), | |
placeholder="https://y.qq.com/n/ryqq/songDetail/*", | |
) | |
], | |
outputs=[ | |
gr.Textbox(label=_L("状态栏"), show_copy_button=True), | |
gr.Audio( | |
label=_L("含元信息音频下载"), | |
show_download_button=True, | |
show_share_button=False, | |
), | |
gr.Textbox(label=_L("歌名"), show_copy_button=True), | |
gr.Textbox(label=_L("作者"), show_copy_button=True), | |
gr.Textbox(label=_L("专辑"), show_copy_button=True), | |
gr.TextArea(label=_L("歌词"), show_copy_button=True), | |
gr.Image(label=_L("歌曲图片"), show_share_button=False), | |
gr.Textbox(label=_L("歌曲 ID"), show_copy_button=True), | |
gr.Textbox(label=_L("音质"), show_copy_button=True), | |
gr.Textbox(label=_L("大小"), show_copy_button=True), | |
], | |
title=_L("QQ音乐直链解析"), | |
flagging_mode="never", | |
examples=[ | |
"000ZjUoy0DeHRO", | |
"https://y.qq.com/n/ryqq/songDetail/000ZjUoy0DeHRO", | |
"DJMOUN《一氧化碳 (监狱兔概念神) (DJ版)》 https://c6.y.qq.com/base/fcgi-bin/u?__=fY3GHnkxtiHJ @QQ音乐", | |
], | |
cache_examples=False, | |
) | |