天天看點

網易雲音樂下載下傳器

網易雲音樂下載下傳器

全部代碼

import os
import json
import requests
from tkinter import *
 
 
class couldmusic(object):
 
    def __init__(self, tk_root):
        """初始化"""
 
        self.root = tk_root
 
        self.playlist_id = StringVar()                                          # 歌單ID,可以通過網易雲歌單詳情頁面獲位址欄取
        self.song_id = StringVar()                                              # 歌曲ID,可以通過歌曲播放頁面位址欄擷取
        self.song_name = StringVar()                                            # 歌曲名字,用于顯示下載下傳資訊
        self.song_name.set("")
        self.var = StringVar()                                                  # 下載下傳進度值
        self.var.set("開始")
 
        self.index = 0
 
        self.song_list = {}
        self.save_path = os.path.abspath(".")                                   # 擷取工作目錄
        self.save_path = os.path.join(self.save_path, "網易雲音樂")             # 生成網易雲音樂檔案夾路徑
 
        # 浏覽器Headers資訊
        self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36",
            }
 
        # 繪制UI
        self.layout()
 
    def process(self):
        """下載下傳進度條"""
 
        total_length = 260                                                      # 進度條總長度
        if len(self.song_list) > 0:                                             # 判斷歌曲清單非空
            length = total_length * self.index / len(self.song_list)            # 計算下載下傳進度長度
            self.canvas.coords(self.processbar, (0, 0, length,26))              # 建立進度條(起始X坐标,起始Y坐标, 長度,高度)
            self.var.set(f"{self.index}/{len(self.song_list)}")                 # 設定進度值
            if length == total_length:                                          # 判斷是否下載下傳完成
                self.song_name.set("下載下傳完成")
        self.root.update()
 
    def reset(self):
        """重置"""
 
        self.song_id.set("")
        self.playlist_id.set("")
        self.song_list.clear()
        self.var.set("開始")
        self.index = 0
        self.save_path = os.path.abspath(".")
        self.save_path = os.path.join(self.save_path, "網易雲音樂")
 
    def get_playlist(self, playlist_id):
 
        playlist_api = "http://music.163.com/api/playlist/detail?id="           # 歌單詳情API
        playlist_url = playlist_api + playlist_id                               # 擷取歌單詳情位址
 
        r = requests.get(playlist_url, headers = self.headers)                  # 擷取源碼
        json_data = json.loads(r.text)                                          # 源碼轉換Json格式
         
        # 嘗試提取指定資訊
        try:
            song_list_name = json_data['result']['creator']['nickname']         # 提取歌單名字
            self.song_name.set(f"{song_list_name} 的歌單")
            self.save_path = os.path.join(self.save_path, song_list_name)       # 生成歌單檔案路徑
            if not os.path.isdir(self.save_path):                               # 判斷路徑是否存在
                os.mkdir(self.save_path)                                        # 建立歌單檔案夾
        except:
            self.song_name.set("請輸入有效的歌單ID或歌曲ID")
            return
 
        # 提取歌曲資訊
        for i in json_data['result']['tracks']:
            song_name = i["name"].split("/")[0]                                 # 擷取歌曲名字,并移除 "/"
            song_id = i['id']                                                   # 擷取歌曲ID資訊
            self.song_list[song_name] = song_id                                 # 将歌曲資訊加入到字典備用
 
        return song_list_name
 
    def get_song_info(self, song_id):     
        """擷取單首歌曲資訊"""   
 
        song_detail_api = "http://music.163.com/api/song/detail/?id=song_id&ids=%5Bsong_id%5D"      # 歌曲資訊API
        song_url = song_detail_api.replace("song_id", self.song_id.get())                           # 生成歌曲資訊Url
 
        r = requests.get(song_url, headers = self.headers)                      # 擷取源碼
        json_data = json.loads(r.text)                                          # 源碼轉換Json格式
 
        # 嘗試提取指定資訊
        try:             
            for i in json_data['songs']:                                        # 擷取Json_data中 ‘songs’内容
                self.song_list[i['name']] = self.song_id.get()                  # 将歌曲資訊加入到字典備用
        except:
            self.song_name.set("請輸入有效的歌單ID或歌曲ID_2")                                                   
 
    def download(self):
        """下載下傳 "self.song_list" 中歌曲"""
 
        api = "http://music.163.com/song/media/outer/url?id=song_id.mp3"
        # api = "https://www.apicp.cn/API/wyy/api.php?id="                        # 網易雲解析API, 第三方提供
        self.index = 0
         
        for item in self.song_list:                                             # 周遊歌曲清單
            self.index += 1                                                     # 歌曲次序
            song_url = api.replace("song_id", str(self.song_list[item]))             # 解析位址
            name = item + ".mp3"                                                # 歌曲名字
            split_list = ["<", ">", "/", "\\"]                                  # Windows名字機制,移除特殊字元
            for x in split_list:
                name = name.split(x)[0]                                           
            path = os.path.join(self.save_path, name)                           # 歌曲儲存路徑
            self.song_name.set(name)                                            # 更新UI資訊
            content = requests.get(song_url, headers = self.headers).content    # 擷取源碼
            if content[0] != 0x49:                                              # 判斷傳回值是否屬于音頻檔案
                self.song_name.set("灰色歌曲無法下載下傳")                           # 灰色歌曲無法下載下傳
                continue                                                        # 跳出本次循環
            if not os.path.isfile(path):                                        # 判斷檔案是否存在
                with open(path, "wb") as f:                                     # 儲存檔案
                    f.write(content)
            self.process()                                      
 
    def run(self):
        """擷取輸入資訊, 并執行程式"""
 
        playlist_id = self.playlist_id.get()                                    # 擷取頁面輸入歌單ID資訊
        song_id = self.song_id.get()                                            # 擷取頁面輸入歌曲ID資訊
 
        if not os.path.isdir(self.save_path):                                   # 判斷路徑是否存在  
            os.mkdir(self.save_path)                                            # 建立檔案夾
 
        # 判斷輸入歌單ID和歌曲ID有效
        if playlist_id == "" and song_id == "":                                 # 判斷歌單/歌曲非空
            self.song_name.set("請輸入有效的歌單ID或歌曲ID_1")                     
            return       
        elif playlist_id:                                                       # 歌單ID非空,執行歌單處理函數
            self.get_playlist(playlist_id)
        elif song_id:                                                           # 歌曲ID非空,執行歌曲處理函數
            self.get_song_info(song_id)
 
        self.download()                                                         # 執行歌曲下載下傳函數
        self.reset()                                                            # 重置
 
    def layout(self):
        """繪制界面"""
 
        self.root.title("網易雲下載下傳器")                                          # 标題
        self.root.geometry("260x100+600+300")                                   # 位置
        self.root.bind("<Return>", lambda x:self.run())                         # 綁定Enter鍵
 
        # 歌單ID
        Label(self.root, text = "歌單ID:").grid(row = 0, column = 0)
        Entry(self.root, textvariable = self.playlist_id).grid(row = 0, column =1, sticky=N+E+S+W)
         
        # 歌曲ID
        Label(self.root, text = "歌曲ID:").grid(row = 1, column =0)
        Entry(self.root, textvariable = self.song_id).grid(row = 1,column = 1, sticky=N+E+S+W)
 
        # 正在下載下傳的歌曲資訊
        Label(self.root, text = "正在下載下傳:").grid(row = 2, column =0)
        Entry(self.root, textvariable = self.song_name).grid(row = 2,column = 1, sticky=N+E+S+W)
 
        # 進度條
        self.canvas = Canvas(self.root,height=26, bg="white")
        self.canvas.grid(row = 3,  column = 1)
        self.processbar = self.canvas.create_rectangle(0,0,0,0,width = 0,fill = "green")
 
        # 開始
        Button(self.root, textvariable = self.var, command = self.run).grid(row = 3, column = 0, sticky=N+E+S+W)
 
 
if __name__ == "__main__":
    root = Tk()
    couldmusic(root)
    root.mainloop()