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()