admin
sync ms
3e6dcd1
raw
history blame
5.38 kB
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,
)