import time, os, requests, threading, re, multiprocessing
from multiprocessing import Pool


class KuwoMusic:

    def __init__(self,cookie):
        self.cookie = cookie


    def get_music_url(self, rid):
        # http://www.kuwo.cn/url?format=mp3&rid=440613&response=url&type=convert_url3&br=320kmp3&from=web&t=1620179066636&httpsStatus=1
        base_url = 'http://www.kuwo.cn/url'
        params = {
            'format': 'mp3',
            'rid': rid,
            'response': 'url',
            'type': 'convert_url3',
            'br': '320kmp3',  # 320K 代表是无陨音质。
            'from': 'web',
            't': str(int(time.time() * 1000)),
            'httpsStatus': '1'
        }
        headers = {
            'Connection': 'keep-alive',
            'Host': 'www.kuwo.cn',
            'Referer': 'http://www.kuwo.cn/search/list',
            'Cookie': self.cookie,
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'
        }
        resp = requests.get(url=base_url, params=params, headers=headers)
        music_url = resp.json().get("url")
        return music_url

    def music_download(self, url, name):
        host = re.findall('https://(.*?)/', url)[0]
        headers = {
            'Accept': '*/*',
            'sec-ch-ua': '" Not A;Brand";v = "99", "Chromium";v = "90", "Google Chrome";v = "90"',
            'Connection': 'keep-alive',
            'Host': host,
            'Referer': url,
            'Cookie': self.cookie,
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'
        }
        print(name + ".mp3\t开始下载...")
        data = requests.get(url=url, headers=headers).content
        try:
            if not os.path.exists("音乐下载"):
                os.mkdir("音乐下载")
        except:
            pass
        filepath = "音乐下载/" + name + '.mp3'
        with open(filepath, 'wb') as f:
            f.write(data)
            print(name + ".mp3\t下载完成.")

    def get_music_list(self, key, pn):
        # http://www.kuwo.cn/api/www/search/searchMusicBykeyWord?key=%E5%91%A8%E6%9D%B0%E4%BC%A6&pn=1&rn=30&httpsStatus=1&reqId=1aee48d0-ad43-11eb-b9fa-5f2f406dcb43
        base_url = 'http://www.kuwo.cn/api/www/search/searchMusicBykeyWord'
        params = {
            'key': key,
            'pn': pn,
            'rn': 30,
            'httpsStatus': '1'
        }
        csrf = re.findall("kw_token=(.{11})", self.cookie)[0]
        headers = {
            'Connection': 'keep-alive',
            'Cookie': self.cookie,
            'csrf': csrf,  # 这个值是cookie 里面的 kw_token值
            'Host': 'www.kuwo.cn',
            'Referer': 'http://www.kuwo.cn/search/list',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36'
        }
        resp = requests.get(url=base_url, params=params, headers=headers)
        music_data = []
        if len(resp.text) > 88:     # 出错返回长度是84
            music_list = resp.json()
            music_list = music_list['data']['list']
            for music in music_list:
                artist = music['artist']  # 歌曲演唱者
                artist = self.rename_use(artist)
                name = music['name']
                name = self.rename_use(name)
                rid = music['rid']  # 歌曲 rid
                duration = music['duration']  # 这个值是歌曲时长，单位是 秒
                duration = self.s_to_m(duration)
                music_data.append({'name': name, 'artist': artist, 'rid': rid, 'duration': duration})
        else:
            print("数据获取失败，请重试。")
        return music_data


    def reset_list(self, a):        # 列表去重复数据， a 代表一下列表
        c = []
        for i in range(len(a)):
            b = a.pop()
            if b not in a:
                c.append(b)
        return c


    def rename_use(self, file_name):
        file_name = file_name.replace("\\", '').replace("/", '').replace(":", '').replace("*", '').replace("?",
                                                                                                           '').replace(
            '"', '').replace("<", '').replace(">", '').replace("|", '').replace("&nbsp;", "")
        return file_name


    def s_to_m(self, s):
        m = int(s) / 60
        a = m - int(m)
        b = a * 60
        b = int(b)
        if int(b) < 10:
            b = "0" + str(int(b))
        ms = str(int(m)) + "：" + str(b)
        return ms


    def show_short(self, name):
        if len(name) > 18:
            name = name[:18] + ".."
        return name


    def main(self):
        inp = input("请输入歌曲名或歌手：\n")
        pn = 1
        musics_all = []
        while True:
            music_data = self.get_music_list(inp, pn=pn)
            if music_data:
                musics_all.append(music_data)                           # 在这里判断去重，也行。只是把去重方法写出来才想到， 唉！！
                for i, music in enumerate(music_data):
                    artist = music['artist']  # 歌曲演唱者
                    artist = self.show_short(artist)
                    name = music['name']
                    name = self.show_short(name)
                    rid = music['rid']  # 歌曲 rid
                    duration = music['duration']  # 歌曲时长 单位 秒  songTimeMinutes
                    print(f"{i + 1}. {name} \t演唱:{artist} \t时长:{duration}")
                print("*" * 40 + "  华丽的分割线  " + "*" * 40)
                if pn == 1:
                    print("请选择下载方式： \n1.按歌曲编号下载 \t3.下一页\t4.全部下载\t 按0退出\n")
                elif pn > 1:
                    print("请选择下载方式： \n1.按歌曲编号下载 \t2.上一页 \t3.下一页\t4.全部下载\t 按0退出\n")
                inp_b = input()
                if inp_b == '1':
                    while True:
                        print("选择歌曲编号，加入下载..输入'0', 退出")
                        inp_c = input("")
                        if int(inp_c) in [i for i in range(1, 31)]:
                            rid = music_data[int(inp_c) - 1]['rid']
                            artist = music_data[int(inp_c) - 1]['artist']
                            name = music_data[int(inp_c) - 1]['name']
                            music_url = self.get_music_url(rid)
                            music_name = name + "-" + artist
                            th = threading.Thread(target=self.music_download, args=(music_url, music_name))
                            th.start()
                            # th.join()
                            print("添加成功，请继续")

                        elif inp_c == '0':
                            print("成功退出")
                            break
                        else:
                            print("输入有误,是对应歌曲的编号（1,4 或是 12）")
                            time.sleep(3)
                elif inp_b == '2':
                    pn -= 1
                    if pn <1:
                        print("操作不当，请重试")
                        pn = 1
                elif inp_b == '3':
                    pn += 1
                elif inp_b == '4':
                    musics_all = self.reset_list(musics_all)    # 去除重复歌单
                    for musics in musics_all:
                        for music in  musics:
                            rid = music['rid']
                            artist = music['artist']
                            name = music['name']
                            music_url = self.get_music_url(rid)
                            music_name = name + "-" + artist
                            # print(music_name,music_url)
                            # th = threading.Thread(target=self.music_download, args=(music_url, music_name))
                            # th.start()
                            # th.join()
                            pool.apply_async(self.music_download, args=(music_url, music_name))
                    pool.close()
                    pool.join()

                    print("下载完毕，程序即将退出")
                    time.sleep(2)
                    break

                elif inp_b == '0':
                    print('成功退出，程序即将关闭')
                    time.sleep(2)
                    break
                else:
                    print("可能输入有误，可以重试")
                    time.sleep(2)
            else:
                print("数据获取失败，或没有更多歌曲了")
                time.sleep(2)


def get_cookie():
    url = 'http://www.kuwo.cn/'
    headers = {
        'Connection': 'keep-alive',
        'Host': 'www.kuwo.cn',
        'Referer': 'http://www.kuwo.cn/',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'
    }

    res = requests.get(url=url, headers=headers)
    cookies = res.cookies.items()
    cookie = ''
    for name, value in cookies:
        cookie += '{0}={1};'.format(name, value)
    return cookie

if __name__ == '__main__':
    multiprocessing.freeze_support()
    pool = Pool(3)
    cookie = get_cookie()
    kuwo = KuwoMusic(cookie)
    kuwo.main()
