网易云音乐UI界面

网易云音乐UI界面

接着上期的网易云音乐搜索和下载,现在再添加一个功能。用pyqt5制作一个UI界面
效果展示:
在这里插入图片描述
主窗口中有个控件:行编辑输入框、搜索按钮、表格

代码

class MyQLabel(QLabel):
    """自定义标签"""

    # 自定义信号
    clicked_signal = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)

    def mouseReleaseEvent(self, QMouseEvent):
        self.clicked_signal.emit()

    # 可在外部与槽函数连接
    def connect(self, callback):
        self.clicked_signal.connect(callback)


class NeteaseUI(QWidget):
    """UI界面"""

    def __init__(self):
        super().__init__()

        self.songs = []

        self.line = QLineEdit(self)
        self.button = QPushButton("搜索", self)
        self.table = QTableWidget(self)

        self.initUI()

    def initUI(self):

        self.lineEditstyle()
        self.buttonstyle()
        self.tablestyle()

        self.setGeometry(600, 350, 600, 480)
        self.setWindowTitle("网易云音乐 V 1.0 zly")
        self.setWindowIcon(QIcon('images/icon.png'))
        self.show()

    def search(self):
        """搜索按钮事件"""

        song_name = self.line.text()

        if not song_name:
            return

        text = str({
            "hlpretag": '<span class="s-fc7">',
            "hlposttag": "</span>",
            "s": song_name,
            "type": "1",
            "offset": "0",
            "total": "true",
            "limit": "30",
            "csrf_token": ""
        })
        self.songs = SearchMusic(text).search()

        for i, song in enumerate(self.songs):
            for j, s in enumerate(song):
                self.table.setItem(i, j, QTableWidgetItem(str(song[s])))

        # 给每行点击后绑定下载事件
        self.table.clicked.connect(self.download)

    def download(self, QIndex):
        """下载事件"""

        NeteaseCloudMusic(self.songs[QIndex.row()]).music()

    def tablestyle(self):
        """表格样式"""

        self.table.setGeometry(35, 90, 528, 360)
        self.table.setStyleSheet("""
            border-width: 1px;
            border-style: solid;
            border-color: rgb(255, 0, 0);
            border:0
        """)

        # 20行3列
        self.table.setRowCount(20)
        self.table.setColumnCount(3)

        # 设置表头内容
        self.table.setHorizontalHeaderLabels(['id', '歌曲', '歌手'])
        # 设置水平方向自伸展模式
        self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        # 设置表格整行选中
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        # 表格禁止编辑
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        # 表头样式
        self.table.horizontalHeader().setStyleSheet("""
            border-width:1px;
            border-style:solid;
            border-color:grey;
        """)
        self.table.verticalHeader().setStyleSheet("""
            border-width:1px;
            border-style:solid;
            border-color:grey;
        """)
        self.table.setStyleSheet("""QTableWidget::item{
            padding-left: 15px;
            font-size: 30px;
            font-family: "微软雅黑 黑体 楷体 宋体";
            font-weight: 500;
            color: black;
            border-width: 1px;
            border-color: burlywood;
            border-style: solid;
            border-radius: 5px;
            outline: none;}
        """)

    def lineEditstyle(self):
        """行编辑样式"""

        self.line.setPlaceholderText("\t请输入歌名")
        self.line.setGeometry(35, 30, 400, 50)
        self.line.setStyleSheet('''
            padding-left:20px;
            font-size: 20px;
            font-family: "微软雅黑 黑体 楷体 宋体";
            font-weight: 500;
            color: black;
            border-width: 1px;
            border-color: burlywood;
            border-style: solid;
            border-radius: 5px;
            outline: none;
            background-color: rgb(211, 202, 202);
        ''')

    def buttonstyle(self):
        """按钮样式"""

        self.button.setCursor(Qt.PointingHandCursor)
        self.button.setIcon(QIcon('images/search.png'))
        self.button.clicked.connect(self.search)
        self.button.setGeometry(445, 30, 120, 50)
        self.button.setStyleSheet("""
            font-size: 20px;
            font-family: "微软雅黑 黑体 楷体 宋体";
            font-weight: 500;
            color: white;
            border-width: 1px;
            border-color: burlywood;
            border-style: solid;
            border-radius: 5px;
            outline: none;
            background-color: rgb(38, 16, 231);
        """)

代码解释

自定义标签

class MyQLabel(QLabel):...

重写鼠标事件

    def mouseReleaseEvent(self, QMouseEvent):
        self.clicked_signal.emit()
        

发送信号,当标签被点击了调用相应的事件

    def connect(self, callback):
        self.clicked_signal.connect(callback)

主窗口类

class NeteaseUI(QWidget)...

控件样式

     def tablestyle(self):
        """表格样式"""

        self.table.setGeometry(35, 90, 528, 360)
        self.table.setStyleSheet("""
            border-width: 1px;
            border-style: solid;
            border-color: rgb(255, 0, 0);
            border:0
        """)

        # 20行3列
        self.table.setRowCount(20)
        self.table.setColumnCount(3)

        # 设置表头内容
        self.table.setHorizontalHeaderLabels(['id', '歌曲', '歌手'])
        # 设置水平方向自伸展模式
        self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        # 设置表格整行选中
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        # 表格禁止编辑
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        # 表头样式
        self.table.horizontalHeader().setStyleSheet("""
            border-width:1px;
            border-style:solid;
            border-color:grey;
        """)
        self.table.verticalHeader().setStyleSheet("""
            border-width:1px;
            border-style:solid;
            border-color:grey;
        """)
        self.table.setStyleSheet("""QTableWidget::item{
            padding-left: 15px;
            font-size: 30px;
            font-family: "微软雅黑 黑体 楷体 宋体";
            font-weight: 500;
            color: black;
            border-width: 1px;
            border-color: burlywood;
            border-style: solid;
            border-radius: 5px;
            outline: none;}
        """)

    def lineEditstyle(self):
        """行编辑样式"""

        self.line.setPlaceholderText("\t请输入歌名")
        self.line.setGeometry(35, 30, 400, 50)
        self.line.setStyleSheet('''
            padding-left:20px;
            font-size: 20px;
            font-family: "微软雅黑 黑体 楷体 宋体";
            font-weight: 500;
            color: black;
            border-width: 1px;
            border-color: burlywood;
            border-style: solid;
            border-radius: 5px;
            outline: none;
            background-color: rgb(211, 202, 202);
        ''')

    def buttonstyle(self):
        """按钮样式"""

        self.button.setCursor(Qt.PointingHandCursor)
        self.button.setIcon(QIcon('images/search.png'))
        self.button.clicked.connect(self.search)
        self.button.setGeometry(445, 30, 120, 50)
        self.button.setStyleSheet("""
            font-size: 20px;
            font-family: "微软雅黑 黑体 楷体 宋体";
            font-weight: 500;
            color: white;
            border-width: 1px;
            border-color: burlywood;
            border-style: solid;
            border-radius: 5px;
            outline: none;
            background-color: rgb(38, 16, 231);
        """)

搜索功能

       def search(self):
        """搜索按钮事件"""

        song_name = self.line.text()

        if not song_name:
            return

        text = str({
            "hlpretag": '<span class="s-fc7">',
            "hlposttag": "</span>",
            "s": song_name,
            "type": "1",
            "offset": "0",
            "total": "true",
            "limit": "30",
            "csrf_token": ""
        })
        self.songs = SearchMusic(text).search()

        for i, song in enumerate(self.songs):
            for j, s in enumerate(song):
                self.table.setItem(i, j, QTableWidgetItem(str(song[s])))

        # 给每行点击后绑定下载事件
        self.table.clicked.connect(self.download)

接着上篇的全部代码

import os
import sys
from base64 import b64encode

import requests
from Crypto.Cipher import AES
from PyQt5.QtCore import pyqtSignal, Qt
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import (QApplication, QTableWidget, QWidget,
                             QPushButton, QLineEdit, QLabel,
                             QHeaderView, QAbstractItemView, QTableWidgetItem)

from pretty.pretty import HeaderPrettyDict


class MyQLabel(QLabel):
    """自定义标签"""

    # 自定义信号
    clicked_signal = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)

    def mouseReleaseEvent(self, QMouseEvent):
        self.clicked_signal.emit()

    # 可在外部与槽函数连接
    def connect(self, callback):
        self.clicked_signal.connect(callback)


class NeteaseUI(QWidget):
    """UI界面"""

    def __init__(self):
        super().__init__()

        self.songs = []

        self.line = QLineEdit(self)
        self.button = QPushButton("搜索", self)
        self.table = QTableWidget(self)

        self.initUI()

    def initUI(self):

        self.lineEditstyle()
        self.buttonstyle()
        self.tablestyle()

        self.setGeometry(600, 350, 600, 480)
        self.setWindowTitle("网易云音乐 V 1.0 zly")
        self.setWindowIcon(QIcon('images/icon.png'))
        self.show()

    def search(self):
        """搜索按钮事件"""

        song_name = self.line.text()

        if not song_name:
            return

        text = str({
            "hlpretag": '<span class="s-fc7">',
            "hlposttag": "</span>",
            "s": song_name,
            "type": "1",
            "offset": "0",
            "total": "true",
            "limit": "30",
            "csrf_token": ""
        })
        self.songs = SearchMusic(text).search()

        for i, song in enumerate(self.songs):
            for j, s in enumerate(song):
                self.table.setItem(i, j, QTableWidgetItem(str(song[s])))

        # 给每行点击后绑定下载事件
        self.table.clicked.connect(self.download)

    def download(self, QIndex):
        """下载事件"""

        NeteaseCloudMusic(self.songs[QIndex.row()]).music()

    def tablestyle(self):
        """表格样式"""

        self.table.setGeometry(35, 90, 528, 360)
        self.table.setStyleSheet("""
            border-width: 1px;
            border-style: solid;
            border-color: rgb(255, 0, 0);
            border:0
        """)

        # 20行3列
        self.table.setRowCount(20)
        self.table.setColumnCount(3)

        # 设置表头内容
        self.table.setHorizontalHeaderLabels(['id', '歌曲', '歌手'])
        # 设置水平方向自伸展模式
        self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        # 设置表格整行选中
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        # 表格禁止编辑
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        # 表头样式
        self.table.horizontalHeader().setStyleSheet("""
            border-width:1px;
            border-style:solid;
            border-color:grey;
        """)
        self.table.verticalHeader().setStyleSheet("""
            border-width:1px;
            border-style:solid;
            border-color:grey;
        """)
        self.table.setStyleSheet("""QTableWidget::item{
            padding-left: 15px;
            font-size: 30px;
            font-family: "微软雅黑 黑体 楷体 宋体";
            font-weight: 500;
            color: black;
            border-width: 1px;
            border-color: burlywood;
            border-style: solid;
            border-radius: 5px;
            outline: none;}
        """)

    def lineEditstyle(self):
        """行编辑样式"""

        self.line.setPlaceholderText("\t请输入歌名")
        self.line.setGeometry(35, 30, 400, 50)
        self.line.setStyleSheet('''
            padding-left:20px;
            font-size: 20px;
            font-family: "微软雅黑 黑体 楷体 宋体";
            font-weight: 500;
            color: black;
            border-width: 1px;
            border-color: burlywood;
            border-style: solid;
            border-radius: 5px;
            outline: none;
            background-color: rgb(211, 202, 202);
        ''')

    def buttonstyle(self):
        """按钮样式"""

        self.button.setCursor(Qt.PointingHandCursor)
        self.button.setIcon(QIcon('images/search.png'))
        self.button.clicked.connect(self.search)
        self.button.setGeometry(445, 30, 120, 50)
        self.button.setStyleSheet("""
            font-size: 20px;
            font-family: "微软雅黑 黑体 楷体 宋体";
            font-weight: 500;
            color: white;
            border-width: 1px;
            border-color: burlywood;
            border-style: solid;
            border-radius: 5px;
            outline: none;
            background-color: rgb(38, 16, 231);
        """)


class Encrypt:

    def __init__(self, text):
        self.data = {
            'encSecKey': '01ec48cb405730aa77f993a988cc1f5bc1938511d75f49eddc581f2fe2aaf18988853200564b2d4b1312cf6e0bb344425addce5a4c81b38b89a5973900946bd100b0f1865d22d2a8e5dd8be208eb5d6eb2f71309a165daeffe95355e1e44edd65bdf28088fe4f5e835a7d9f7569fc2530f9d17c00b51cfafbe421eb462247ea3'
        }

        self.text = text
        self.key = '0CoJUm6Qyw8W8jud'

    def get_form_data(self):
        """生成表单参数"""

        # 随机秘钥参数,可以用固定值
        i = "4JknCzx6uEXUwxpU"

        # 两次加密
        first_encrypt = self.AES_encpyt(self.text, self.key)
        self.data['params'] = self.AES_encpyt(first_encrypt, i)

        return self.data

    def AES_encpyt(self, text, key):
        """AES加密"""

        # AES加密明文必须为16的整数倍
        padding = 16 - len(text.encode()) % 16
        text += padding * chr(padding)

        aes = AES.new(key.encode(), AES.MODE_CBC, b'0102030405060708')
        enctext = aes.encrypt(text.encode())

        return b64encode(enctext).decode('utf-8')


class SearchMusic:

    def __init__(self, text):

        self.url = 'https://music.163.com/weapi/cloudsearch/get/web?csrf_token='

        reqstr = '''
                authority: music.163.com
                method: POST
                path: /weapi/song/enhance/player/url/v1?csrf_token=
                scheme: https
                accept: */*
                accept-encoding: gzip, deflate, br
                accept-language: zh-CN,zh;q=0.9
                cache-control: no-cache
                content-length: 434
                content-type: application/x-www-form-urlencoded
                cookie: __root_domain_v=.163.com; _qddaz=QD.28yaab.3jymc6.kf0ihnaf; _ntes_nnid=e7c5f90265b4d5a5bcb511efebf7a890,1600596980395; _ntes_nuid=e7c5f90265b4d5a5bcb511efebf7a890; _iuqxldmzr_=32; WM_TID=OlHvFOuIVclAQFQUAEJvJZyLuh3MwtGb; NMTID=00ODCot1Uq8CvcXIUIMmKBlPfRiyfoAAAF3NHwibw; WM_NI=%2BWiHzgkFWg%2BON3YYI0rQzlpsOW8x4BPGt%2FWRNpkD3r2Utv8U1gx6RZgvmmJQ0IpSBgdk1GvY9uIQW6BfIN7lVoHo8z1BIoa%2FdLUgKwpx6twUKJtgDlexKOu7LqWGuYApZzg%3D; WM_NIKE=9ca17ae2e6ffcda170e2e6eeb9c844a3b1aba3b24489eb8eb6d15b929a9baaaa5cace70087b64e8ab18299d02af0fea7c3b92ae989a7a9f96da99a9988aa458eed97bacc3cb28fb68df3798d89f899b74a9499bcd0d65a8eb0a5a5b27af28bbc97bb5ff3b9b8d7d152a5aaa38ec95bf497c0b4c16da8b5ffa8f553fbab87b2d63e82ba87afb66896b18890bb72f39e8790e425a8949b88ca7db4a8fa95f65f8996bc88c768a7a885b0f83d90af99a8f85383b0969be637e2a3; hb_MA-9F44-2FC2BD04228F_source=www.baidu.com; JSESSIONID-WYYY=bERBG86BVbD29X%5C35acjg8ndIoGYPEZvQ8fc0t7WUnMu3KTujvG1zqfSMIG%2By4%2FZRz9hC%2FwBN0Mf%2B%2B1RJBK2TeR96X7l%2BmS%2FHhuuqBwl7yxwe4jQ%5ChzFoFgKylb3ZdOnw6%2FqsqaUYUrJ12EVVy0m66JVlQez0T5ijmgZuOsk0KcMnUe4%3A1611553513123; WEVNSM=1.0.0; WNMCID=kctjbv.1611551714155.01.0
                origin: https://music.163.com
                pragma: no-cache
                referer: https://music.163.com/
                sec-fetch-dest: empty
                sec-fetch-mode: cors
                sec-fetch-site: same-origin
                user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36
            '''
        self.headers = HeaderPrettyDict().pretty(reqstr)

        self.text = text

    def search(self):
        """搜索音乐,返回音乐列表"""

        data = Encrypt(self.text).get_form_data()
        res = requests.post(self.url, headers=self.headers, data=data)

        songlist = []
        songs = res.json()['result']['songs']

        for song in songs:
            item = {}

            # id、歌名、歌手、封面
            item['song_id'] = song['id']
            item['song_name'] = song['name']
            item['singer'] = song['ar'][0]['name']
            # item['song_pic_url'] = song['al']['picUrl']

            songlist.append(item)

        return songlist


class NeteaseCloudMusic:

    def __init__(self, song):

        self.url = 'https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token='

        reqstr = '''
                        authority: music.163.com
                        method: POST
                        path: /weapi/song/enhance/player/url/v1?csrf_token=
                        scheme: https
                        accept: */*
                        accept-encoding: gzip, deflate, br
                        accept-language: zh-CN,zh;q=0.9
                        cache-control: no-cache
                        content-length: 434
                        content-type: application/x-www-form-urlencoded
                        cookie: __root_domain_v=.163.com; _qddaz=QD.28yaab.3jymc6.kf0ihnaf; _ntes_nnid=e7c5f90265b4d5a5bcb511efebf7a890,1600596980395; _ntes_nuid=e7c5f90265b4d5a5bcb511efebf7a890; _iuqxldmzr_=32; WM_TID=OlHvFOuIVclAQFQUAEJvJZyLuh3MwtGb; NMTID=00ODCot1Uq8CvcXIUIMmKBlPfRiyfoAAAF3NHwibw; WM_NI=%2BWiHzgkFWg%2BON3YYI0rQzlpsOW8x4BPGt%2FWRNpkD3r2Utv8U1gx6RZgvmmJQ0IpSBgdk1GvY9uIQW6BfIN7lVoHo8z1BIoa%2FdLUgKwpx6twUKJtgDlexKOu7LqWGuYApZzg%3D; WM_NIKE=9ca17ae2e6ffcda170e2e6eeb9c844a3b1aba3b24489eb8eb6d15b929a9baaaa5cace70087b64e8ab18299d02af0fea7c3b92ae989a7a9f96da99a9988aa458eed97bacc3cb28fb68df3798d89f899b74a9499bcd0d65a8eb0a5a5b27af28bbc97bb5ff3b9b8d7d152a5aaa38ec95bf497c0b4c16da8b5ffa8f553fbab87b2d63e82ba87afb66896b18890bb72f39e8790e425a8949b88ca7db4a8fa95f65f8996bc88c768a7a885b0f83d90af99a8f85383b0969be637e2a3; hb_MA-9F44-2FC2BD04228F_source=www.baidu.com; JSESSIONID-WYYY=bERBG86BVbD29X%5C35acjg8ndIoGYPEZvQ8fc0t7WUnMu3KTujvG1zqfSMIG%2By4%2FZRz9hC%2FwBN0Mf%2B%2B1RJBK2TeR96X7l%2BmS%2FHhuuqBwl7yxwe4jQ%5ChzFoFgKylb3ZdOnw6%2FqsqaUYUrJ12EVVy0m66JVlQez0T5ijmgZuOsk0KcMnUe4%3A1611553513123; WEVNSM=1.0.0; WNMCID=kctjbv.1611551714155.01.0
                        origin: https://music.163.com
                        pragma: no-cache
                        referer: https://music.163.com/
                        sec-fetch-dest: empty
                        sec-fetch-mode: cors
                        sec-fetch-site: same-origin
                        user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36
                    '''
        self.headers = HeaderPrettyDict().pretty(reqstr)

        self.text = '{"ids":"[' + str(song['song_id']) + ']","level":"standard","encodeType":"aac","csrf_token":""}'
        self.name = song['song_name']
        self.singer = song['singer']

    def music(self):
        """获取音乐的url"""

        data = Encrypt(self.text).get_form_data()
        res = requests.post(self.url, headers=self.headers, data=data)

        song_url = res.json()['data'][0]['url']
        self.save(self.download(song_url))

    def download(self, url):
        """下载音乐"""

        headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'}
        res = requests.get(url, headers=headers)
        return res.content

    def save(self, content):
        """保存音乐"""

        # 当前文件目录
        path = os.path.dirname(__file__)
        # 检查'data'目录是否存在,不存在则创建目录
        if not os.path.exists(path+'\\data'):
            os.mkdir(path+'\\data')
        # 音乐保存路径
        music_path = path+'\\data'+f'\\{self.name} {self.singer}.m4a'
        # 保存
        if not os.path.exists(music_path):

            with open(music_path, 'wb') as f:
                f.write(content)


if __name__ == '__main__':

    def run():
        app = QApplication(sys.argv)
        g = NeteaseUI()
        sys.exit(app.exec_())

    run()


  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值