w3812247 发表于 2023-2-23 09:03

歌词下载器~~~

本帖最后由 w3812247 于 2023-4-3 16:12 编辑

目前源网站不能用了,所以这个软件现在也不好用了,等我有时间更新一下。
隔壁老王,前一阵下载了不少歌放到了U盘里,用于在车上听歌,但是老王说好多歌都没有歌词,他想把歌词补全,但是歌太多了,于是老王找到了我,写了个小程序,帮他下载歌词。
目前程序只支持mp3格式的,有些歌曲网站没有收录的话可能会找不到,但是大部分还是能找到的。
如果谁有比较全的歌词网站可以给我留言,到时候更新一下获取歌词的源。

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) == '.mp3':
                  print(file)# 当前路径下所有非目录子文件
                  havelrc = False
                  lrcname = os.path.splitext(file) + ".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")
      global musicname
      musicname = strmusicname
      strmusicname = str(strmusicname).split("(")
      strmusicname = str(strmusicname).split("(")
      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/ul')
      self.tk_list_box_lrc.delete(0, END)# 清空历史内容
      for re in result:
            url = re.xpath('./li/a/@href') #歌词地址
            name = re.xpath('./li/a/text()') #歌名
            sanger = re.xpath('./li/a/text()') #歌手
            album = re.xpath('./li/a/text()') #专辑
            if len(url) > 0:
                url = str(url)
            else:
                url = "无"
            if len(name)>0:
                name = str(name)
            else:
                name = "无"
            if len(sanger)>0:
                sanger = str(sanger)
            else:
                sanger = "无"
            if len(album)>0:
                album = str(album)
            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("##$##")
      #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("//*[@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) == '.mp3':
                  print(file)# 当前路径下所有非目录子文件
                  havelrc = False
                  lrcname =os.path.splitext(file)+".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()



附一个成品链接:https://www.aliyundrive.com/s/EvBmEBmL2ru
再补一个蓝凑的连接:https://wwox.lanzout.com/iCkE10off08d密码:bz65

w3812247 发表于 2023-2-23 11:29

吾爱破解田甜 发表于 2023-2-23 11:27
所有的歌曲都是红色的,下载不了

对啊,不是全自动的,因为同名的歌太多了,需要点击一下红色的歌名,然后右侧会出现搜索到的歌词名,在点一下歌词名,会出现歌词,回车键可以直接下载。如果没有搜索到歌词,那个就说明网站还没有收录。

h512h 发表于 2023-2-23 09:12

大佬挺好 用用看

hot58172485 发表于 2023-2-23 09:12

谢谢楼主的分享~~~

ouzhzh 发表于 2023-2-23 09:19

是的,我保存了一些歌曲,却没有歌词,这个就派上用场了。

wuy009 发表于 2023-2-23 09:21

坐等难揍或者123的下载通道,谢谢大佬。

q5501948 发表于 2023-2-23 09:21

哎哟 不错哦

debug_cat 发表于 2023-2-23 09:21

收藏了 =,感谢分享

ouzhzh 发表于 2023-2-23 09:31

试用了一下,自己录制的MP3歌曲是不能下载歌词的。

JuDC8 发表于 2023-2-23 09:38

ouzhzh 发表于 2023-2-23 09:31
试用了一下,自己录制的MP3歌曲是不能下载歌词的。

哈哈 兄弟你真秀{:1_921:}

qinni8513 发表于 2023-2-23 09:55

下载的歌词是空白的.........

页: [1] 2 3 4 5
查看完整版本: 歌词下载器~~~