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 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(".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 # cover picture.mime = "image/jpeg" picture.data = requests.get(cover).content audio.add_picture(picture) 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.tags.add(USLT(encoding=3, desc="Lyrics", text=lyric)) audio.tags.add( APIC( encoding=3, # UTF-8 encoding mime="image/jpeg", # Picture MIME type type=3, # cover desc="Cover", data=requests.get(cover).content, ) ) audio.save() print(f"Metadata was successfully inserted into {file_path}") def download_file( id, quality, url, title, artist, album, lyric, cover, cache="./__pycache__", ): if os.path.exists(cache): shutil.rmtree(cache) os.makedirs(cache) fmt = "mp3" if " MP3" in quality else "flac" local_filename = f"{cache}/{id}.{fmt}" 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 url.isdigit(): return int(url) url = extract_fst_url(url) if not url: return None if url.startswith("http://163cn.tv/"): url = get_real_url(url) match = re.search(r"id=(\d+)", url) if match: return int(match.group(1)) else: return None def infer(url: str, level: str): song = title = cover = artist = album = quality = size = lyric = None try: song_id = parse_id(url) if not song_id or not level: title = "Please input valid url or id and select a sound quality level!" return song, title, artist, album, lyric, cover, song_id, quality, size response = requests.get( os.getenv("api_music163"), params={"id": song_id, "type": "json", "level": level}, ) if response.status_code == 200: data = response.json()["data"] title = data["name"] cover = data["pic"] artist = data["artist"] album = data["album"] quality = data["format"] size = data["size"] lyric = data["lyric"] song = download_file( data["id"], quality, data["url"], title, artist, album, lyric, cover, ) 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 input music163 song ID or URL", placeholder="https://music.163.com/#/song?id=", ), gr.Dropdown( choices=[ "standard", "exhigh", "lossless", "hires", "sky", "jyeffect", "jymaster", ], value="lossless", label="Sound Quality", ), ], 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="Parse Music163 Songs without Loss", description="This site does not provide any audio and video storage services, but only to provide the most basic resolution services", flagging_mode="never", examples=[ ["36990266", "standard"], ["https://music.163.com/#/song?id=36990266", "exhigh"], ["http://163cn.tv/CmHfO44", "lossless"], ], cache_examples=False, ).launch()