Spaces:
Running
Running
import os | |
import re | |
import shutil | |
import requests | |
import gradio as gr | |
from mutagen.mp3 import MP3 | |
from mutagen.flac import FLAC | |
from mutagen.id3 import TIT2, TPE1, TALB | |
def insert_metadata(file_path: str, title, artist, album): | |
print(f"The file was successfully downloaded and saved to {file_path}") | |
if file_path.endswith(".flac"): | |
audio = FLAC(file_path) | |
audio["TITLE"] = title | |
audio["ARTIST"] = artist | |
audio["ALBUM"] = album | |
else: | |
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.save() | |
print(f"Metadata was successfully inserted into {file_path}") | |
def download_file(mid: str, url: str, title, artist, album, 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) | |
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 infer(url: str): | |
song = title = song_id = artist = album = quality = size = None | |
try: | |
song_mid = parse_id(url) | |
if not song_mid: | |
title = "Please enter a valid URL or mid!" | |
return song, title, song_id, artist, album, quality, size | |
response = requests.get( | |
os.getenv("api"), | |
params={"mid": song_mid}, | |
) | |
if response.status_code == 200 and response.json()["code"] == 200: | |
data = response.json()["data"] | |
song = download_file( | |
data["mid"], | |
data["urls"][0]["url"], | |
data["title"], | |
data["author"], | |
data["album"], | |
) | |
title = data["title"] | |
song_id = data["id"] | |
artist = data["author"] | |
album = data["album"] | |
quality = data["urls"][0]["type"] | |
size = data["urls"][0]["size"] | |
else: | |
raise Exception(response.json()["msg"]) | |
except Exception as e: | |
title = f"{e}" | |
return song, title, song_id, artist, album, 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="Song download", show_download_button=True), | |
gr.Textbox(label="Title", show_copy_button=True), | |
gr.Textbox(label="Song ID", show_copy_button=True), | |
gr.Textbox(label="Artist", show_copy_button=True), | |
gr.Textbox(label="Album", show_copy_button=True), | |
gr.Textbox(label="Quality", show_copy_button=True), | |
gr.Textbox(label="Size(B)", 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=[ | |
"003N68WJ0mh5jN", | |
"https://y.qq.com/n/ryqq/songDetail/003N68WJ0mh5jN", | |
"https://c6.y.qq.com/base/fcgi-bin/u?__=VfAFlMiujMhz", | |
], | |
cache_examples=False, | |
).launch() | |