qmusic_parser / app.py
admin
upd sdk
8df591e
raw
history blame
7.06 kB
import os
import re
import shutil
import requests
import gradio as gr
from mutagen.mp3 import MP3
from mutagen.flac import FLAC, Picture
from mutagen.id3 import TIT2, TPE1, TALB, USLT, APIC
API2 = os.getenv("api_qmusic_2")
API1 = os.getenv("api_qmusic_1")
KEY = os.getenv("apikey_qmusic_1")
def insert_metadata(file_path: str, title, artist, album, lyric, cover):
print(f"The file was successfully downloaded and saved to {file_path}")
if file_path.endswith(".mp3"):
audio = MP3(file_path)
try:
audio.add_tags()
except Exception as e:
print(e)
audio.tags.add(TIT2(encoding=3, text=title))
audio.tags.add(TPE1(encoding=3, text=artist))
audio.tags.add(TALB(encoding=3, text=album))
audio.tags.add(USLT(encoding=3, desc="Lyrics", text=lyric))
audio.tags.add(
APIC(
encoding=3, # UTF-8 编码
mime="image/jpeg", # 图片的 MIME 类型
type=3, # 封面图片
desc="Cover",
data=requests.get(cover).content,
)
)
audio.save()
elif file_path.endswith(".flac"):
audio = FLAC(file_path)
audio.tags["TITLE"] = title
audio.tags["ARTIST"] = artist
audio.tags["ALBUM"] = album
audio.tags["LYRICS"] = lyric
picture = Picture()
picture.type = 3 # 封面图片
picture.mime = "image/jpeg"
picture.data = requests.get(cover).content
audio.add_picture(picture)
audio.save()
def download_file(
mid: str,
url: str,
title,
artist,
album,
lyric,
cover,
cache="./__pycache__",
):
if os.path.exists(cache):
shutil.rmtree(cache)
os.makedirs(cache)
local_filename = f"{cache}/{mid}.mp3"
response = requests.get(url, stream=True)
if response.status_code == 200:
with open(local_filename, "wb") as file:
for chunk in response.iter_content(chunk_size=8192):
file.write(chunk)
insert_metadata(local_filename, title, artist, album, lyric, cover)
return local_filename
else:
print(f"Download Failure, status code: {response.status_code}")
return url
def extract_fst_url(text):
url_pattern = r'(https?://[^\s"]+)'
match = re.search(url_pattern, text)
if match:
return match.group(1)
else:
return None
def get_real_url(short_url):
return requests.get(
short_url,
headers={
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36"
},
allow_redirects=True,
timeout=10,
).url
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 parse_size(size_in_bytes):
units = ["B", "KB", "MB", "GB"]
unit_index = 0
if size_in_bytes >= 1024**3:
unit_index = 3
size = size_in_bytes / (1024**3)
elif size_in_bytes >= 1024**2:
unit_index = 2
size = size_in_bytes / (1024**2)
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]}"
def infer(url: str):
song = title = artist = album = lyric = cover = song_id = quality = size = None
try:
song_mid = parse_id(url)
if not song_mid:
title = "Please enter a valid URL or mid!"
return song, title, artist, album, lyric, cover, song_id, quality, size
# title, artist, album, cover
response = requests.get(
API1,
params={
"key": KEY,
"type": "song",
"mid": song_mid,
},
)
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(
API1,
params={
"key": KEY,
"type": "lrc",
"mid": song_mid,
"format": "json",
},
)
if response.status_code == 200 and response.json()["code"] == 200:
lyric = response.json()["data"]
# url
response = requests.get(API2, params={"mid": song_mid})
if response.status_code == 200 and response.json()["code"] == 200:
data = response.json()["data"]
song = download_file(
song_mid,
data["urls"][0]["url"],
title,
artist,
album,
lyric,
cover,
)
song_id = data["id"]
quality = data["urls"][0]["type"]
size = parse_size(int(data["urls"][0]["size"]))
else:
raise Exception(response.json()["msg"])
except Exception as e:
size = f"{e}"
return song, title, artist, album, lyric, cover, song_id, quality, size
if __name__ == "__main__":
gr.Interface(
fn=infer,
inputs=[
gr.Textbox(
label="Please enter the mid or URL of QQ music song",
placeholder="https://y.qq.com/n/ryqq/songDetail/*",
),
],
outputs=[
gr.Audio(label="Audio", show_download_button=True, show_share_button=False),
gr.Textbox(label="Title", show_copy_button=True),
gr.Textbox(label="Artist", show_copy_button=True),
gr.Textbox(label="Album", show_copy_button=True),
gr.TextArea(label="Lyrics", show_copy_button=True),
gr.Image(label="Cover", show_share_button=False),
gr.Textbox(label="Song ID", show_copy_button=True),
gr.Textbox(label="Quality", show_copy_button=True),
gr.Textbox(label="Size", show_copy_button=True),
],
title="QQ Music Parser",
description="This site does not provide any audio storage services, only provide the most basic parsing services",
flagging_mode="never",
examples=[
"000ZjUoy0DeHRO",
"https://y.qq.com/n/ryqq/songDetail/000ZjUoy0DeHRO",
"https://c6.y.qq.com/base/fcgi-bin/u?__=fY3GHnkxtiHJ",
],
cache_examples=False,
).launch()