隔壁老王下載了很多歌放在u盤里,用來在車上聽歌,但是老王說很多歌沒有歌詞,他想把歌詞補全,但是歌太多了,于是老王找到我,寫了一個小程序幫他下載歌詞。
目前該程序只支持mp3格式,有些歌曲如果不收錄在網站中可能找不到,但大部分還是可以找到的。
如果誰有比較完整的歌詞網站,可以給我留言,然后更新歌詞來源。
![圖片[1]-MP3歌詞下載器-資源網站](http://m.oilmaxhydraulic.com.cn/wp-content/uploads/2023/02/036f924401130012-1024x650.gif)
代碼分享
import os
import threading
import time
from tkinter import *
from tkinter import filedialog
from tkinter.ttk import *
import zhconv
import requests
from lxml import etree
"""
全局通用函數
"""
musicname = ""
# 自動隱藏滾動條
def scrollbar_autohide(bar, widget):
def show():
bar.lift(widget)
def hide():
bar.lower(widget)
hide()
widget.bind("<Enter>", lambda e: show())
bar.bind("<Enter>", lambda e: show())
widget.bind("<Leave>", lambda e: hide())
bar.bind("<Leave>", lambda e: hide())
class WinGUI(Tk):
def __init__(self):
super().__init__()
self.__win()
self.tk_list_box_music = self.__tk_list_box_music()
self.tk_list_box_lrc = self.__tk_list_box_lrc()
self.tk_label_downloadinfo = self.__tk_label_downloadinfo()
self.tk_button_refresh = self.__tk_button_refresh()
self.tk_button_next = self.__tk_button_next()
self.tk_label_info = self.__tk_label_info()
self.tk_input_mp3path = self.__tk_input_mp3path()
self.tk_button_openpath = self.__tk_button_openpath()
self.tk_label_info1 = self.__tk_label_info1()
self.tk_text_lrcinfo = self.__tk_text_lrcinfo()
self.tk_button_download = self.__tk_button_download()
def __win(self):
self.title("哇哈哈歌詞下載器")
# 設置窗口大小、居中
width = 600
height = 800
screenwidth = self.winfo_screenwidth()
screenheight = self.winfo_screenheight()
geometry = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
self.geometry(geometry)
self.resizable(width=False, height=False)
def __tk_list_box_music(self):
lb = Listbox(self)
lb.insert(END, "此處顯示文件夾內的所有MP3文件")
#lb.place(x=20, y=40, width=259, height=305)
lb.place(x=20, y=40, width=157, height=305)
return lb
def __tk_list_box_lrc(self):
lb = Listbox(self)
lb.insert(END, "此處顯示獲取到的歌詞文件,雙擊可以下載")
#lb.place(x=320, y=40, width=259, height=302)
lb.place(x=204, y=40, width=375, height=302)
return lb
def __tk_label_downloadinfo(self):
label = Label(self, text="還沒下載呢!")
label.place(x=20, y=760, width=557, height=24)
return label
def __tk_button_refresh(self):
btn = Button(self, text="刷新",command=lambda: self.thread_it(self.refresh()))
btn.place(x=20, y=720, width=563, height=24)
return btn
def __tk_button_next(self):
btn = Button(self, text="不顯示已匹配到歌詞的MP3", command=lambda: self.thread_it(self.next1()))
btn.place(x=20, y=680, width=563, height=24)
return btn
def __tk_label_info(self):
label = Label(self, text="本程序自動獲取文件夾下的所有mp3歌曲,沒有歌詞的標注紅色,有歌詞的標注黑色,\n左側選擇歌曲,右側顯示獲取到的歌詞,單擊歌詞列表后回車即可自動下載歌詞。",
anchor="center")
label.place(x=20, y=0, width=560, height=36)
return label
def __tk_input_mp3path(self):
ipt = Entry(self)
ipt.place(x=110, y=610, width=360, height=24)
return ipt
def __tk_button_openpath(self):
btn = Button(self, text="選擇",command=lambda: self.thread_it(self.openpath('select_path')))
btn.place(x=490, y=610, width=50, height=24)
return btn
def __tk_label_info1(self):
label = Label(self, text="選擇MP3文件夾", anchor="center")
label.place(x=20, y=610, width=77, height=24)
return label
def __tk_text_lrcinfo(self):
text = Text(self)
text.place(x=20, y=350, width=558, height=250)
return text
def __tk_button_download(self):
btn = Button(self, text="回車可下載")
btn.place(x=20, y=644, width=563, height=24)
return btn
class Win(WinGUI):
def __init__(self):
super().__init__()
self.__event_bind()
self.bind('<Return>',self.download1)
def __event_bind(self):
self.tk_list_box_music.bind('<ButtonRelease>', self.downthis)
self.tk_list_box_lrc.bind('<ButtonRelease>', self.getlrcinfo)
pass
def refresh(self):
self.getallmp3(mp3path)
def next1(self):
self.tk_list_box_music.delete(0, END) # 清空歷史內容
for root, dirs, files in os.walk(mp3path):
# print(files) # 當前路徑下所有非目錄子文件
for file in files:
if os.path.splitext(file)[1] == '.mp3':
print(file) # 當前路徑下所有非目錄子文件
havelrc = False
lrcname = os.path.splitext(file)[0] + ".lrc"
print(mp3path + "/" + lrcname)
if os.path.isfile(mp3path + "/" + lrcname):
havelrc = True
print(havelrc)
if havelrc is False:
self.tk_list_box_music.insert(END, file)
# 文本框滑動
self.tk_list_box_music.see(END)
self.tk_list_box_music.itemconfig("end", bg="white" if havelrc else "red")
# 更新
self.tk_list_box_music.update()
def openpath(self, strpath):
# 單個文件選擇
strpath = filedialog.StringVar()
selected_file_path = filedialog.askdirectory() #filedialog.askopenfilename(title='選擇文件', filetypes=[(('JPG', '*.jpg')), ('All Files', '*')]) # 使用askopenfilename函數選擇單個文件
self.tk_input_mp3path.delete(0, "end")
self.tk_input_mp3path.insert(0, selected_file_path)
global mp3path
mp3path = selected_file_path
self.getallmp3(mp3path)
def thread_it(self, func, *args):
""" 將函數打包進線程,防止解析的時候GUI出現卡死的情況 """
print("----------------------啟動多線程--------------")
self.myThread = threading.Thread(target=func, args=args)
self.myThread.setDaemon(True) # 主線程退出就直接讓子線程跟隨退出,不論是否運行完成。
self.myThread.start()
def downthis(self, evt):
#print("<Button>事件未處理", evt)
w = evt.widget
#print(w.index(w.curselection()))
value = w.get(w.curselection())
#print(value)
strmusicname = str(value).split(".mp3")[0]
global musicname
musicname = strmusicname
strmusicname = str(strmusicname).split("(")[0]
strmusicname = str(strmusicname).split("(")[0]
strmusicname = strmusicname.replace(" ", "").replace("*", "").replace("#", "").replace("(", "").replace(")", "").replace("(", "").replace(")", "")
print(strmusicname+".lrc")
self.getlrcs(strmusicname)
def getlrcs(self,strmusicname):
strmusicname = zhconv.convert(strmusicname, 'zh-hans')
print(strmusicname)
headers = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36",
# 判斷請求是異步還是同步
"x-requested-with": "XMLHttpRequest", }
url = "https://www.90lrc.cn/so.php?wd="+strmusicname
#url="https://www.90lrc.cn/so.php?wd=%E5%A4%84%E5%A4%84%E5%90%BB"
# print(url)
data = requests.get(url, headers=headers).content.decode("utf-8")
data = str(data).replace("<em>","").replace("</em>","") #去除xpath不識別的標簽
html = etree.HTML(data)
#print(data)
#print(data)
result = html.xpath('/html/body/div[3]/ul')
self.tk_list_box_lrc.delete(0, END) # 清空歷史內容
for re in result:
url = re.xpath('./li[1]/a/@href') #歌詞地址
name = re.xpath('./li[1]/a/text()') #歌名
sanger = re.xpath('./li[2]/a/text()') #歌手
album = re.xpath('./li[3]/a/text()') #專輯
if len(url) > 0:
url = str(url[0])
else:
url = "無"
if len(name)>0:
name = str(name[0])
else:
name = "無"
if len(sanger)>0:
sanger = str(sanger[0])
else:
sanger = "無"
if len(album)>0:
album = str(album[0])
else:
album = "無"
strinfo = "歌名:"+name+" 歌手:"+sanger+" 專輯:"+album+"##$##"+str(url)
self.tk_list_box_lrc.insert(END, strinfo)
# 文本框滑動
self.tk_list_box_lrc.see(END)
# 更新
self.tk_list_box_lrc.update()
def getlrcinfo(self, evt):
# print("<Button>事件未處理", evt)
w = evt.widget
# print(w.index(w.curselection()))
value = w.get(w.curselection())
value = str(value).split("##$##")[1]
#print(value)
url = "https://www.90lrc.cn" + value
headers = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36",
# 判斷請求是異步還是同步
"x-requested-with": "XMLHttpRequest", }
data = requests.get(url, headers=headers).content.decode("utf-8")
html = etree.HTML(data)
varlrc = html.xpath("http://*[@id=\"lrc\"]/text()")
strlrc = ""
i = 0
for lrc in varlrc:
if i==0:
lrc = str(lrc).replace("\n","")
if len(lrc)>0:
strlrc = strlrc+lrc
i=i+1
#print(strlrc)
self.tk_text_lrcinfo.delete(0.0,END) # 清空歷史內容
self.tk_text_lrcinfo.insert(END,strlrc)
# 文本框滑動
# 更新
self.tk_text_lrcinfo.update()
def getallmp3(self,mp3path):
self.tk_list_box_music.delete(0, END) #清空歷史內容
for root, dirs, files in os.walk(mp3path):
#print(files) # 當前路徑下所有非目錄子文件
for file in files:
if os.path.splitext(file)[1] == '.mp3':
print(file) # 當前路徑下所有非目錄子文件
havelrc = False
lrcname =os.path.splitext(file)[0]+".lrc"
print(mp3path+"/"+lrcname)
if os.path.isfile(mp3path+"/"+lrcname):
havelrc = True
print(havelrc)
self.tk_list_box_music.insert(END, file)
# 文本框滑動
self.tk_list_box_music.see(END)
self.tk_list_box_music.itemconfig("end", bg="white" if havelrc else "red")
# 更新
self.tk_list_box_music.update()
def download1(self, event = None):
strlrc = self.tk_text_lrcinfo.get(1.0,END)
path = self.tk_input_mp3path.get()
name = musicname
print(path)
print(name)
r = path + "/"+name+".lrc"
if os.path.exists(r): # 如果存在a/1.txt文件
file = open(r, 'a', encoding='utf-8') # a表示在原有文檔下繼續編輯
file.write(str(strlrc)) # 在文件中寫入loss: 2
file.flush()
file.close()
else:
# r為路徑,'a\\1.txt','\\'與'/'一致,在os.path.join()函數中,
# 每個逗號之間的元素都會被'\\'分開,無需添加分隔符
file = open(r, 'w', encoding='utf-8') # w表示在重新創建文件
file.write(str(strlrc)) # 在文件中寫入loss: 2
file.flush()
file.close()
self.tk_label_downloadinfo["text"] = name+"已下載完畢~"
if __name__ == "__main__":
win = Win()
win.mainloop()
下載地址
? 版權聲明
THE END













暫無評論內容