183 lines
8.2 KiB
Python
183 lines
8.2 KiB
Python
import requests
|
|
from bs4 import BeautifulSoup
|
|
import tkinter as tk
|
|
from tkinter import filedialog
|
|
import re
|
|
import os
|
|
|
|
class MusicDownloader:
|
|
def __init__(self, master):
|
|
self.master = master
|
|
master.title("Music Downloader")
|
|
|
|
# Search song section
|
|
tk.Label(master, text="Song keyword:").grid(row=0, column=0, padx=10, pady=10)
|
|
self.keyword_entry = tk.Entry(master, width=30)
|
|
self.keyword_entry.grid(row=0, column=1, padx=10, pady=10)
|
|
self.search_button = tk.Button(master, text="Search", command=self.search_song)
|
|
self.search_button.grid(row=0, column=2, padx=10, pady=10)
|
|
|
|
# Text box to show search results
|
|
self.result_text = tk.Text(master, height=10, width=50)
|
|
self.result_text.grid(row=1, column=0, columnspan=3, padx=10, pady=10)
|
|
# Hyperlink hint
|
|
self.hint_label = tk.Label(master, text="Not the result you want?", fg="blue", cursor="hand2")
|
|
self.hint_label.grid(row=2, column=0, columnspan=10, pady=10)
|
|
self.hint_label.bind("<Button-1>", self.show_search_hint)
|
|
# Download song section
|
|
tk.Label(master, text="Song ID:").grid(row=3, column=0, padx=10, pady=10)
|
|
self.song_id_entry = tk.Entry(master, width=30)
|
|
self.song_id_entry.grid(row=3, column=1, padx=10, pady=10)
|
|
self.download_button = tk.Button(master, text="Download", command=self.download_song)
|
|
self.download_button.grid(row=3, column=2, padx=10, pady=10)
|
|
|
|
# Save path section
|
|
tk.Label(master, text="Save path:").grid(row=4, column=0, padx=10, pady=10)
|
|
self.save_path_entry = tk.Entry(master, width=30)
|
|
self.save_path_entry.grid(row=4, column=1, padx=10, pady=10)
|
|
self.browse_button = tk.Button(master, text="Browse", command=self.browse_save_path)
|
|
self.browse_button.grid(row=4, column=2, padx=10, pady=10)
|
|
# Hot music recommendation section
|
|
self.hot_music_button = tk.Button(master, text="Hot Songs", command=self.get_hot_music)
|
|
self.hot_music_button.grid(row=5, column=0, padx=10, pady=10)
|
|
|
|
def search_song(self):
|
|
keyword = self.keyword_entry.get()
|
|
details = self.get_music_details(keyword)
|
|
self.result_text.delete(1.0, tk.END) # clear the text box
|
|
for detail in details:
|
|
self.result_text.insert(tk.END, detail + "\n")
|
|
|
|
def get_music_details(self, keyword):
|
|
base_url = "https://www.gequbao.com/s/"
|
|
search_url = f"{base_url}{keyword}"
|
|
headers = {
|
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0'
|
|
}
|
|
|
|
try:
|
|
response = requests.get(search_url, headers=headers)
|
|
response.raise_for_status() # check if the request succeeded
|
|
soup = BeautifulSoup(response.text, 'html.parser')
|
|
|
|
# Find all matching <a> tags
|
|
music_links = soup.select('div.card.mb-1 a.music-link.d-block')
|
|
|
|
# Find all matching <span> tags
|
|
music_titles = soup.select('span.text-primary.font-weight-bolder.music-title.d-md-inline-block.align-middle span')
|
|
|
|
# Extract all href attributes, removing the '/music/' prefix
|
|
hrefs = [link['href'].replace('/music/', '') for link in music_links]
|
|
|
|
# Extract all song titles
|
|
titles = [title.get_text(strip=True) for title in music_titles]
|
|
|
|
# Combine titles and links
|
|
results = [f"Title: {title}, ID: {href}" for title, href in zip(titles, hrefs)]
|
|
|
|
return results
|
|
except requests.RequestException as e:
|
|
print(f"Request failed, please try again later: {e}")
|
|
return []
|
|
|
|
def download_song(self):
|
|
in_id = self.song_id_entry.get()
|
|
save_path = self.save_path_entry.get()
|
|
|
|
# Check whether the save path exists
|
|
if not save_path or not os.path.exists(save_path):
|
|
tk.messagebox.showwarning("Warning", "Save path does not exist. Please choose a valid path.")
|
|
return
|
|
|
|
headers = {
|
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0'
|
|
}
|
|
url = f"https://www.gequbao.com/music/{in_id}"
|
|
|
|
try:
|
|
resp = requests.get(url, headers=headers, timeout=5) # set timeout to 5 seconds
|
|
except requests.exceptions.Timeout:
|
|
tk.messagebox.showwarning("Warning", "Request timed out. Please check your network.")
|
|
return
|
|
except requests.exceptions.RequestException as e:
|
|
tk.messagebox.showwarning("Warning", f"Request failed, please try again later: {e}")
|
|
return
|
|
|
|
|
|
link = "https://www.gequbao.com/api/play-url"
|
|
data = {'id':'RFALUCRUAVZeSVsNV3NRXF5fF1pdAnhXU10DE1gPU3IaUVtRQlFNVndQUFpWRF9YUQ=='}
|
|
|
|
try:
|
|
response = requests.post(url=link, data=data, headers=headers, timeout=5) # set timeout to 5 seconds
|
|
json_data = response.json()
|
|
play_url = json_data['data']['url']
|
|
except requests.exceptions.Timeout:
|
|
tk.messagebox.showwarning("Warning", "Request timed out. Please check your network.")
|
|
return
|
|
except requests.exceptions.RequestException as e:
|
|
tk.messagebox.showwarning("Warning", f"Request failed, please try again later: {e}")
|
|
return
|
|
|
|
try:
|
|
content = requests.get(play_url, headers=headers, timeout=5).content # set timeout to 5 seconds
|
|
except requests.exceptions.Timeout:
|
|
tk.messagebox.showwarning("Warning", "Request timed out. Please check your network.")
|
|
return
|
|
except requests.exceptions.RequestException as e:
|
|
tk.messagebox.showwarning("Warning", f"Request failed, please try again later: {e}")
|
|
return
|
|
|
|
# Save the song
|
|
file_path = os.path.join(save_path, f"ruyuan.mp3")
|
|
with open(file_path, 'wb') as f:
|
|
f.write(content)
|
|
|
|
self.result_text.insert(tk.END, f'Song downloaded successfully\n')
|
|
|
|
def browse_save_path(self):
|
|
path = filedialog.askdirectory()
|
|
self.save_path_entry.delete(0, tk.END)
|
|
self.save_path_entry.insert(0, path)
|
|
|
|
def get_hot_music(self):
|
|
# clear the text box
|
|
self.result_text.delete(1.0, tk.END)
|
|
|
|
base_url = "https://www.gequbao.com/hot-music/"
|
|
headers = {
|
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0'
|
|
}
|
|
|
|
results = []
|
|
for page in range(1, 7):
|
|
url = f"{base_url}{page}"
|
|
try:
|
|
response = requests.get(url, headers=headers)
|
|
response.raise_for_status() # check if the request succeeded
|
|
soup = BeautifulSoup(response.text, 'html.parser')
|
|
|
|
# Find all matching <td> tags (singers)
|
|
singers = [td.get_text(strip=True) for td in soup.select('td.text-success')]
|
|
|
|
# Find all matching <a> tags
|
|
music_links = soup.select('a.text-info.font-weight-bold')
|
|
titles = [a.get_text(strip=True) for a in music_links]
|
|
hrefs = [a['href'].replace('/music/', '') for a in music_links]
|
|
|
|
# Combine title, singer and ID
|
|
page_results = [f"Title: {title}, Singer: {singer}, ID: {href}" for title, singer, href in zip(titles, singers, hrefs)]
|
|
results.extend(page_results)
|
|
except requests.RequestException as e:
|
|
tk.messagebox.showwarning("Warning", f"Request failed, please try again later: {e}")
|
|
return
|
|
for result in results:
|
|
self.result_text.insert(tk.END, result + "\n")
|
|
|
|
def show_search_hint(self, event):
|
|
tk.messagebox.showinfo("Search Hint", "Avoid special characters when searching. Enter the name and author together for better matching (e.g. ru yuan Wang Fei)")
|
|
|
|
if __name__ == "__main__":
|
|
root = tk.Tk()
|
|
app = MusicDownloader(root)
|
|
root.mainloop()
|