import requests import json import os import re from pydub import AudioSegment from pydub.playback import play import pygame import io import urllib.request # Headers for the request headers = { "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36", "Referer": "https://y.qq.com/portal/player.html", } def fetch_latest_music(): """Fetch the latest music data and return structured information.""" music_info_list = [] # url = "https://c.y.qq.com/v8/fcg-bin/fcg_v8_toplist_cp.fcg?g_tk=5381&uin=0&format=json&inCharset=utf-8&outCharset=utf-8¬ice=0&platform=h5&needNewCode=1&tpl=3&page=detail&type=top&topid=27&_=1519963122923" url = "https://robotstorm.tech/cyqq/v8/fcg-bin/fcg_v8_toplist_cp.fcg?g_tk=5381&uin=0&format=json&inCharset=utf-8&outCharset=utf-8¬ice=0&platform=h5&needNewCode=1&tpl=3&page=detail&type=top&topid=27&_=1519963122923" try: response = requests.get(url, headers=headers) response.encoding = "utf-8" # Handle Chinese characters if response.status_code == 200: data = response.json() # print(data) music_list = data["songlist"] for music in music_list: payplay = music["data"]["pay"]["payplay"] if payplay == 0: music_name = music["data"]["songname"] singer_name = music["data"]["singer"][0]["name"] songmid = music["data"]["songmid"] albummid = music["data"]["albummid"] music_info_list.append((music_name, singer_name, songmid, albummid)) print(music_info_list) return music_info_list else: print("Failed to fetch music data, status code:", response.status_code) return [] except Exception as e: print("Error occurred:", e) return [] def get_music_info(name, page=1, num=10): """Search for music information.""" music_info_list = [] # url = f'https://c.y.qq.com/soso/fcgi-bin/client_search_cp?p={page}&n={num}&w={name}' # url = f"https://c.y.qq.com/soso/fcgi-bin/client_search_cp?w={name}" url = f"https://robotstorm.tech/cyqq/soso/fcgi-bin/client_search_cp?w={name}" response = requests.get(url, headers=headers).text # Get response as text music_json = response[9:-1] # Strip extra characters music_data = json.loads(music_json) # Convert to dictionary music_list = music_data["data"]["song"]["list"] for music in music_list: payplay = music["pay"]["payplay"] if payplay == 0: music_name = music["songname"] singer_name = music["singer"][0]["name"] songmid = music["songmid"] albummid = music["albummid"] music_info_list.append((music_name, singer_name, songmid, albummid)) return music_info_list def get_purl(music_info_list): """Get song URLs.""" music_data = [] for music in music_info_list: music_name = music[0] singer_name = music[1] songmid = music[2] albummid = music[3] # url = ( # 'https://u.y.qq.com/cgi-bin/musicu.fcg?data={"req":{"module":"CDN.SrfCdnDispatchServer","method":"GetCdnDispatch","param":{"guid":"8846039534","calltype":0,"userip":""}},"req_0":{"module":"vkey.GetVkeyServer","method":"CgiGetVkey","param":{"guid":"8846039534","songmid":["%s"],"songtype":[0],"uin":"1152921504784213523","loginflag":1,"platform":"20"}},"comm":{"uin":"1152921504784213523","format":"json","ct":24,"cv":0}}' # % songmid # ) url = ( 'https://robotstorm.tech/uyqq/cgi-bin/musicu.fcg?data={"req":{"module":"CDN.SrfCdnDispatchServer","method":"GetCdnDispatch","param":{"guid":"8846039534","calltype":0,"userip":""}},"req_0":{"module":"vkey.GetVkeyServer","method":"CgiGetVkey","param":{"guid":"8846039534","songmid":["%s"],"songtype":[0],"uin":"1152921504784213523","loginflag":1,"platform":"20"}},"comm":{"uin":"1152921504784213523","format":"json","ct":24,"cv":0}}' % songmid ) response = requests.get(url, headers=headers).json() purl = response["req_0"]["data"]["midurlinfo"][0]["purl"] full_media_url = "http://dl.stream.qqmusic.qq.com/" + purl # album_img_url = ( # "http://y.gtimg.cn/music/photo_new/T002R180x180M000" + albummid + ".jpg" # ) album_img_url = ( "https://robotstorm.tech/ygtimg/music/photo_new/T002R180x180M000" + albummid + ".jpg" ) # lyrics_url = f"https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg?songmid={songmid}&format=json&nobase64=1" lyrics_url = f"https://robotstorm.tech/cyqq/lyric/fcgi-bin/fcg_query_lyric_new.fcg?songmid={songmid}&format=json&nobase64=1" music_data.append( { "music_name": music_name, "singer_name": singer_name, "full_media_url": full_media_url, "album_img_url": album_img_url, "lyrics_url": lyrics_url, "songmid": songmid, } ) print(music_data) return music_data def get_lyrics(music_data): """Get lyrics for songs.""" for music in music_data: lyrics_url = music["lyrics_url"] lyrics_response = requests.get(lyrics_url, headers=headers).text print(lyrics_response) def save_music_mp3(music_data): """Download songs.""" if not os.path.exists("歌曲下载"): os.mkdir("歌曲下载") for music in music_data: music_name = music["music_name"] singer_name = music["singer_name"] full_url = music["full_media_url"] music_response = requests.get(full_url, headers=headers).content with open(f"歌曲下载/{music_name}-{singer_name}.mp3", "wb") as fp: fp.write(music_response) print(f"[{music_name}]保存成功!") def get_song_info(songmid, music_info_list): """Get song details by songmid.""" # Find the music information matching the songmid music = next((item for item in music_info_list if item[2] == songmid), None) if not music: return {"error": "Song not found"} music_name = music[0] singer_name = music[1] albummid = music[3] # url = ( # 'https://u.y.qq.com/cgi-bin/musicu.fcg?data={"req":{"module":"CDN.SrfCdnDispatchServer","method":"GetCdnDispatch","param":{"guid":"8846039534","calltype":0,"userip":""}},"req_0":{"module":"vkey.GetVkeyServer","method":"CgiGetVkey","param":{"guid":"8846039534","songmid":["%s"],"songtype":[0],"uin":"1152921504784213523","loginflag":1,"platform":"20"}},"comm":{"uin":"1152921504784213523","format":"json","ct":24,"cv":0}}' # % songmid # ) url = ( 'https://robotstorm.tech/uyqq/cgi-bin/musicu.fcg?data={"req":{"module":"CDN.SrfCdnDispatchServer","method":"GetCdnDispatch","param":{"guid":"8846039534","calltype":0,"userip":""}},"req_0":{"module":"vkey.GetVkeyServer","method":"CgiGetVkey","param":{"guid":"8846039534","songmid":["%s"],"songtype":[0],"uin":"1152921504784213523","loginflag":1,"platform":"20"}},"comm":{"uin":"1152921504784213523","format":"json","ct":24,"cv":0}}' % songmid ) response = requests.get(url, headers=headers).json() purl = response["req_0"]["data"]["midurlinfo"][0]["purl"] full_media_url = "http://dl.stream.qqmusic.qq.com/" + purl # album_img_url = ( # "http://y.gtimg.cn/music/photo_new/T002R180x180M000" + albummid + ".jpg" # ) album_img_url = ( "https://robotstorm.tech/ygtimg/music/photo_new/T002R180x180M000" + albummid + ".jpg" ) # lyrics_url = f"https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg?songmid={songmid}&format=json&nobase64=1" lyrics_url = f"https://robotstorm.tech/cyqq/lyric/fcgi-bin/fcg_query_lyric_new.fcg?songmid={songmid}&format=json&nobase64=1" song_info = { "music_name": music_name, "singer_name": singer_name, "full_media_url": full_media_url, "album_img_url": album_img_url, "lyrics_url": lyrics_url, "songmid": songmid, } return song_info # def get_song_list(categoryID): # url = f"https://i.y.qq.com/qzone-music/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg?type=1&json=1&utf8=1&onlysong=0&nosign=1&disstid={categoryID}&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=GB2312&outCharset=utf-8¬ice=0&platform=yqq&needNewCode=0" # # url = f"https://c.y.qq.com/qzone/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg?type=1&json=1&utf8=1&onlysong=0&disstid={categoryID}&format=jsonp&g_tk=5381&jsonpCallback=playlistinfoCallback&loginUin=0&hostUin=0&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq&needNewCode=0" # try: # response = requests.get(url, headers=headers) # # response.raise_for_status() # print(response.text) # data = response.json() # # print(data) # diss_info = { # 'dissname': data['cdlist'][0]['dissname'], # 'logo': data['cdlist'][0]['logo'] # } # song_list = data['cdlist'][0]['songlist'] # music_info_list = [] # for music in song_list: # payplay = music['pay']['payplay'] # if payplay == 0: # music_name = music['songname'] # singer_name = music['singer'][0]['name'] # songmid = music['songmid'] # albummid = music['albummid'] # music_info_list.append((music_name, singer_name, songmid, albummid)) # print(music_name) # return diss_info, music_info_list # except requests.RequestException as e: # print(e) # return {}, [] def get_song_list(categoryID): # url = f"https://c.y.qq.com/qzone/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg?type=1&json=1&utf8=1&onlysong=0&disstid={categoryID}&format=jsonp&g_tk=5381&jsonpCallback=playlistinfoCallback&loginUin=0&hostUin=0&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq&needNewCode=0" url = f"https://robotstorm.tech/cyqq/qzone/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg?type=1&json=1&utf8=1&onlysong=0&disstid={categoryID}&format=jsonp&g_tk=5381&jsonpCallback=playlistinfoCallback&loginUin=0&hostUin=0&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq&needNewCode=0" try: response = requests.get(url, headers=headers) if response.status_code == 200: # 去掉jsonp包装部分 json_str = response.text.lstrip("playlistinfoCallback(").rstrip(")") data = json.loads(json_str) logo_url = data["cdlist"][0]["logo"] if logo_url.startswith("https://music-file.y.qq.com"): logo_url = logo_url.replace("https://music-file.y.qq.com", "https://robotstorm.tech/musicfileyqq") elif logo_url.startswith("https://qpic.y.qq.com"): logo_url = logo_url.replace("https://qpic.y.qq.com", "https://robotstorm.tech/qpicyqq") elif logo_url.startswith("http://qpic.y.qq.com"): logo_url = logo_url.replace("http://qpic.y.qq.com", "https://robotstorm.tech/qpicyqq") diss_info = { "dissname": data["cdlist"][0]["dissname"], "logo": logo_url, } song_list = data["cdlist"][0]["songlist"] music_info_list = [] for music in song_list: payplay = music["pay"]["payplay"] if payplay == 0: music_name = music["songname"] singer_name = music["singer"][0]["name"] songmid = music["songmid"] albummid = music["albummid"] music_info_list.append((music_name, singer_name, songmid, albummid)) # print(music_name) return diss_info, music_info_list else: print(f"Request failed with status code {response.status_code}") return {}, [] except requests.RequestException as e: print(e) return {}, [] def parse_data(data): diss_info = { "dissname": data["cdlist"][0]["dissname"], "logo": data["cdlist"][0]["logo"], } song_list = data["cdlist"][0]["songlist"] music_info_list = [] for music in song_list: payplay = music["pay"]["payplay"] if payplay == 0: music_name = music["songname"] singer_name = music["singer"][0]["name"] songmid = music["songmid"] albummid = music["albummid"] music_info_list.append((music_name, singer_name, songmid, albummid)) return diss_info, music_info_list # def get_song_list(categoryID): # url2 = f"https://i.y.qq.com/qzone-music/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg?type=1&json=1&utf8=1&onlysong=0&nosign=1&disstid={categoryID}&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=GB2312&outCharset=utf-8¬ice=0&platform=yqq&needNewCode=0" # url1 = f"https://c.y.qq.com/qzone/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg?type=1&json=1&utf8=1&onlysong=0&disstid={categoryID}&format=jsonp&g_tk=5381&jsonpCallback=playlistinfoCallback&loginUin=0&hostUin=0&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq&needNewCode=0" # try: # # 优先尝试第一个URL # response = requests.get(url1, headers=headers, timeout=0.5) # response.raise_for_status() # data = response.json() # return parse_data(data) # except (requests.RequestException, ValueError) as e: # print(f"URL1请求失败,尝试URL2:{e}") # try: # response = requests.get(url2, headers=headers, timeout=0.5) # response.raise_for_status() # # 去掉jsonp包装部分 # json_str = response.text.lstrip("playlistinfoCallback(").rstrip(")") # data = json.loads(json_str) # return parse_data(data) # except requests.RequestException as e: # print(f"URL2请求失败:{e}") # return {}, [] # def get_song_list(categoryID): # url = f"https://i.y.qq.com/qzone-music/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg?type=1&json=1&utf8=1&onlysong=0&nosign=1&disstid={categoryID}&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=GB2312&outCharset=utf-8¬ice=0&platform=yqq&needNewCode=0" # try: # # 创建请求对象 # req = urllib.request.Request(url, headers=headers) # # 发起请求并读取响应 # with urllib.request.urlopen(req) as response: # data = response.read().decode('utf-8') # data = json.loads(data) # diss_info = { # 'dissname': data['cdlist'][0]['dissname'], # 'logo': data['cdlist'][0]['logo'] # } # song_list = data['cdlist'][0]['songlist'] # music_info_list = [] # for music in song_list: # payplay = music['pay']['payplay'] # if payplay == 0: # music_name = music['songname'] # singer_name = music['singer'][0]['name'] # songmid = music['songmid'] # albummid = music['albummid'] # music_info_list.append((music_name, singer_name, songmid, albummid)) # print(music_name) # return diss_info, music_info_list # except urllib.error.URLError as e: # print(e) # return {}, [] def fetch_album_image(singer_name): # Constructing the search query URL # url = f"http://music.163.com/api/search/get/web?s={singer_name}&type=100" url = f"https://robotstorm.tech/api/search/get/web?s={singer_name}&type=100" # Sending request with User-Agent header headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36" } try: response = requests.get(url, headers=headers) data = response.json() # Extracting album image URL from the response if data["result"]["artists"]: artist_info = data["result"]["artists"][0] # pic_url = artist_info.get('picUrl') pic_url = artist_info.get("img1v1Url") if pic_url: return pic_url, None # Return the album image URL else: return None, "No album image found" else: return None, "Artist not found" except Exception as e: return None, str(e) class MusicPlayer: def __init__(self): pygame.init() pygame.mixer.init() pygame.mixer.music.set_volume(1) self.is_playing = False self.is_paused = False self.music_length = 0 self.start_position = 0 def play_music(self, url): try: response = requests.get(url) if response.status_code != 200: print(f"Failed to fetch music: HTTP {response.status_code}") return audio_stream = io.BytesIO(response.content) audio = AudioSegment.from_file(audio_stream, format="m4a") audio.export("../tmp/temp_audio.wav", format="wav") if self.is_playing: pygame.mixer.music.stop() self.start_position = 0 pygame.mixer.music.load("../tmp/temp_audio.wav") self.music_length = len(audio) / 1000 # 获取音频长度(秒) pygame.mixer.music.set_volume(1) print(f"Current volume: {pygame.mixer.music.get_volume()}") pygame.mixer.music.play() self.is_playing = True self.is_paused = False except Exception as e: print(f"An error occurred while playing music: {e}") def pause_music(self): if self.is_playing and not self.is_paused: pygame.mixer.music.pause() self.is_paused = True def resume_music(self): if self.is_playing and self.is_paused: pygame.mixer.music.unpause() self.is_paused = False def stop_music(self): if self.is_playing: pygame.mixer.music.stop() self.is_playing = False self.is_paused = False def seek_music(self, position): if self.is_playing: self.start_position = position pygame.mixer.music.load("../tmp/temp_audio.wav") pygame.mixer.music.play(start=position) self.is_paused = False def get_music_length(self): if self.is_playing: return self.music_length return 0 def get_current_position(self): if self.is_playing: # print(pygame.mixer.music.get_pos()) current_position = pygame.mixer.music.get_pos() if current_position < 0: self.start_position = 0 return ( current_position / 1000 + self.start_position ) # 返回当前播放位置(秒) return 0 def fetch_music_url(self, music_page): url = "https://music.liuzhijin.cn/" headers = { "Accept": "application/json, text/javascript, */*; q=0.01", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "X-Requested-With": "XMLHttpRequest", } data = {"input": music_page, "filter": "url", "type": "_", "page": 1} response = requests.post(url, headers=headers, data=data) response_data = response.json() print(f"music_page: {music_page}, response_data: {response_data}") # 检查是否有有效数据或错误 if response_data["code"] == 200 and response_data["data"]: print(f"Fetched URL: {response_data['data'][0]['url']}") return response_data["data"][0]["url"] else: print(f"Error fetching URL: {response_data.get('error', 'Unknown error')}") return None def fetch_music_url_by_mid(self, song_mid): # 生成请求URL # url = f"https://i.y.qq.com/v8/playsong.html?ADTAG=ryqq.songDetail&songmid={song_mid}&songid=0&songtype=0" # url = f"http://8.138.8.114/qqmusic/v8/playsong.html?ADTAG=ryqq.songDetail&songmid={song_mid}&songid=0&songtype=0" url = f"https://robotstorm.tech/iyqq/v8/playsong.html?ADTAG=ryqq.songDetail&songmid={song_mid}&songid=0&songtype=0" print(url) # 发送请求 response = requests.get(url) # 检查请求是否成功 if response.status_code == 200: html_str = response.text # 正则表达式匹配获取JSON数据 match = re.search(r">window.__ssrFirstPageData__ =(.*?)<\/script", html_str) if match: json_str = match.group(1) json_data = json.loads(json_str) # 确保'songList'存在并包含至少一首歌 if "songList" in json_data and len(json_data["songList"]) > 0: # 获取第一首歌的URL song_data = json_data["songList"][0] if "url" in song_data: original_url = song_data["url"] modified_url = original_url.replace("http://aqqmusic.tc.qq.com/", "https://robotstorm.tech/aqqmusictcqq/") print(f"original_url:{original_url}\nmodified_url:{modified_url}") return modified_url else: return "URL not found in the response data." else: return "Song list is empty or not found." else: return "No match found in HTML response." else: return f"Request failed with status code: {response.status_code}" # 使用示例 player = MusicPlayer() # songmid = "002B2EAA3brD5b" # music_page = f"https://y.qq.com/n/yqq/song/{songmid}.html" # music_url = player.fetch_music_url(music_page) # player.play_music(music_url) if __name__ == "__main__": # latest_music = fetch_latest_music() # if latest_music: # print(latest_music) # music_info_list = get_music_info("zjl") # print(music_info_list) # music_data = get_purl(music_info_list) # music_data = get_purl(latest_music) # get_lyrics(music_data) # save_music_mp3(music_data) # songmid = input("输入songmid:") # song_info = get_song_info(songmid, latest_music) # print(song_info) # latest_music = fetch_latest_music() # print(latest_music) # play_song("0039MnYb0qxYhV",music_info_list) # print(get_mp3_data("0039MnYb0qxYhV")) # music_data = get_purl(latest_music) # print(music_data) # get_song_list("7299191148") # categoryID = "9126599100" # 请替换为实际的歌单 ID # diss_info, music_info = get_song_list(categoryID) # print("歌单信息:", diss_info) # print("歌曲列表:", music_info) # print(get_song_list("7299191148")) # while True: # pass # def get_mp3_data(song_mid): # url = f"https://i.y.qq.com/v8/playsong.html?ADTAG=ryqq.songDetail&songmid={song_mid}&songid=0&songtype=0" # print(url) # response = requests.get(url) # if response.status_code == 200: # html_str = response.text # match = re.search(r">window.__ssrFirstPageData__ =(.*?)<\/script", html_str) # if match: # json_str = match.group(1) # json_data = json.loads(json_str) # return json_data # else: # print("No match found in HTML response.") # return None # else: # print(f"Request failed with status code: {response.status_code}") # return None print(player.fetch_music_url_by_mid("004g2ZZ64a5kAN")) print(player.fetch_music_url("https://y.qq.com/n/yqq/song/004g2ZZ64a5kAN.html"))