网易云音乐UI界面

今天药忘吃喽~ 2022-10-26 14:08 445阅读 0赞

网易云音乐UI界面

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

代码

  1. class MyQLabel(QLabel):
  2. """自定义标签"""
  3. # 自定义信号
  4. clicked_signal = pyqtSignal()
  5. def __init__(self, parent=None):
  6. super().__init__(parent)
  7. def mouseReleaseEvent(self, QMouseEvent):
  8. self.clicked_signal.emit()
  9. # 可在外部与槽函数连接
  10. def connect(self, callback):
  11. self.clicked_signal.connect(callback)
  12. class NeteaseUI(QWidget):
  13. """UI界面"""
  14. def __init__(self):
  15. super().__init__()
  16. self.songs = []
  17. self.line = QLineEdit(self)
  18. self.button = QPushButton("搜索", self)
  19. self.table = QTableWidget(self)
  20. self.initUI()
  21. def initUI(self):
  22. self.lineEditstyle()
  23. self.buttonstyle()
  24. self.tablestyle()
  25. self.setGeometry(600, 350, 600, 480)
  26. self.setWindowTitle("网易云音乐 V 1.0 zly")
  27. self.setWindowIcon(QIcon('images/icon.png'))
  28. self.show()
  29. def search(self):
  30. """搜索按钮事件"""
  31. song_name = self.line.text()
  32. if not song_name:
  33. return
  34. text = str({
  35. "hlpretag": '<span class="s-fc7">',
  36. "hlposttag": "</span>",
  37. "s": song_name,
  38. "type": "1",
  39. "offset": "0",
  40. "total": "true",
  41. "limit": "30",
  42. "csrf_token": ""
  43. })
  44. self.songs = SearchMusic(text).search()
  45. for i, song in enumerate(self.songs):
  46. for j, s in enumerate(song):
  47. self.table.setItem(i, j, QTableWidgetItem(str(song[s])))
  48. # 给每行点击后绑定下载事件
  49. self.table.clicked.connect(self.download)
  50. def download(self, QIndex):
  51. """下载事件"""
  52. NeteaseCloudMusic(self.songs[QIndex.row()]).music()
  53. def tablestyle(self):
  54. """表格样式"""
  55. self.table.setGeometry(35, 90, 528, 360)
  56. self.table.setStyleSheet(""" border-width: 1px; border-style: solid; border-color: rgb(255, 0, 0); border:0 """)
  57. # 20行3列
  58. self.table.setRowCount(20)
  59. self.table.setColumnCount(3)
  60. # 设置表头内容
  61. self.table.setHorizontalHeaderLabels(['id', '歌曲', '歌手'])
  62. # 设置水平方向自伸展模式
  63. self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
  64. # 设置表格整行选中
  65. self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
  66. # 表格禁止编辑
  67. self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
  68. # 表头样式
  69. self.table.horizontalHeader().setStyleSheet(""" border-width:1px; border-style:solid; border-color:grey; """)
  70. self.table.verticalHeader().setStyleSheet(""" border-width:1px; border-style:solid; border-color:grey; """)
  71. 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;} """)
  72. def lineEditstyle(self):
  73. """行编辑样式"""
  74. self.line.setPlaceholderText("\t请输入歌名")
  75. self.line.setGeometry(35, 30, 400, 50)
  76. 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); ''')
  77. def buttonstyle(self):
  78. """按钮样式"""
  79. self.button.setCursor(Qt.PointingHandCursor)
  80. self.button.setIcon(QIcon('images/search.png'))
  81. self.button.clicked.connect(self.search)
  82. self.button.setGeometry(445, 30, 120, 50)
  83. 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); """)

代码解释

自定义标签

  1. class MyQLabel(QLabel):...

重写鼠标事件

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

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

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

主窗口类

  1. class NeteaseUI(QWidget):...

控件样式

  1. def tablestyle(self):
  2. """表格样式"""
  3. self.table.setGeometry(35, 90, 528, 360)
  4. self.table.setStyleSheet(""" border-width: 1px; border-style: solid; border-color: rgb(255, 0, 0); border:0 """)
  5. # 20行3列
  6. self.table.setRowCount(20)
  7. self.table.setColumnCount(3)
  8. # 设置表头内容
  9. self.table.setHorizontalHeaderLabels(['id', '歌曲', '歌手'])
  10. # 设置水平方向自伸展模式
  11. self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
  12. # 设置表格整行选中
  13. self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
  14. # 表格禁止编辑
  15. self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
  16. # 表头样式
  17. self.table.horizontalHeader().setStyleSheet(""" border-width:1px; border-style:solid; border-color:grey; """)
  18. self.table.verticalHeader().setStyleSheet(""" border-width:1px; border-style:solid; border-color:grey; """)
  19. 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;} """)
  20. def lineEditstyle(self):
  21. """行编辑样式"""
  22. self.line.setPlaceholderText("\t请输入歌名")
  23. self.line.setGeometry(35, 30, 400, 50)
  24. 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); ''')
  25. def buttonstyle(self):
  26. """按钮样式"""
  27. self.button.setCursor(Qt.PointingHandCursor)
  28. self.button.setIcon(QIcon('images/search.png'))
  29. self.button.clicked.connect(self.search)
  30. self.button.setGeometry(445, 30, 120, 50)
  31. 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); """)

搜索功能

  1. def search(self):
  2. """搜索按钮事件"""
  3. song_name = self.line.text()
  4. if not song_name:
  5. return
  6. text = str({
  7. "hlpretag": '<span class="s-fc7">',
  8. "hlposttag": "</span>",
  9. "s": song_name,
  10. "type": "1",
  11. "offset": "0",
  12. "total": "true",
  13. "limit": "30",
  14. "csrf_token": ""
  15. })
  16. self.songs = SearchMusic(text).search()
  17. for i, song in enumerate(self.songs):
  18. for j, s in enumerate(song):
  19. self.table.setItem(i, j, QTableWidgetItem(str(song[s])))
  20. # 给每行点击后绑定下载事件
  21. self.table.clicked.connect(self.download)

接着上篇的全部代码

  1. import os
  2. import sys
  3. from base64 import b64encode
  4. import requests
  5. from Crypto.Cipher import AES
  6. from PyQt5.QtCore import pyqtSignal, Qt
  7. from PyQt5.QtGui import QIcon
  8. from PyQt5.QtWidgets import (QApplication, QTableWidget, QWidget,
  9. QPushButton, QLineEdit, QLabel,
  10. QHeaderView, QAbstractItemView, QTableWidgetItem)
  11. from pretty.pretty import HeaderPrettyDict
  12. class MyQLabel(QLabel):
  13. """自定义标签"""
  14. # 自定义信号
  15. clicked_signal = pyqtSignal()
  16. def __init__(self, parent=None):
  17. super().__init__(parent)
  18. def mouseReleaseEvent(self, QMouseEvent):
  19. self.clicked_signal.emit()
  20. # 可在外部与槽函数连接
  21. def connect(self, callback):
  22. self.clicked_signal.connect(callback)
  23. class NeteaseUI(QWidget):
  24. """UI界面"""
  25. def __init__(self):
  26. super().__init__()
  27. self.songs = []
  28. self.line = QLineEdit(self)
  29. self.button = QPushButton("搜索", self)
  30. self.table = QTableWidget(self)
  31. self.initUI()
  32. def initUI(self):
  33. self.lineEditstyle()
  34. self.buttonstyle()
  35. self.tablestyle()
  36. self.setGeometry(600, 350, 600, 480)
  37. self.setWindowTitle("网易云音乐 V 1.0 zly")
  38. self.setWindowIcon(QIcon('images/icon.png'))
  39. self.show()
  40. def search(self):
  41. """搜索按钮事件"""
  42. song_name = self.line.text()
  43. if not song_name:
  44. return
  45. text = str({
  46. "hlpretag": '<span class="s-fc7">',
  47. "hlposttag": "</span>",
  48. "s": song_name,
  49. "type": "1",
  50. "offset": "0",
  51. "total": "true",
  52. "limit": "30",
  53. "csrf_token": ""
  54. })
  55. self.songs = SearchMusic(text).search()
  56. for i, song in enumerate(self.songs):
  57. for j, s in enumerate(song):
  58. self.table.setItem(i, j, QTableWidgetItem(str(song[s])))
  59. # 给每行点击后绑定下载事件
  60. self.table.clicked.connect(self.download)
  61. def download(self, QIndex):
  62. """下载事件"""
  63. NeteaseCloudMusic(self.songs[QIndex.row()]).music()
  64. def tablestyle(self):
  65. """表格样式"""
  66. self.table.setGeometry(35, 90, 528, 360)
  67. self.table.setStyleSheet(""" border-width: 1px; border-style: solid; border-color: rgb(255, 0, 0); border:0 """)
  68. # 20行3列
  69. self.table.setRowCount(20)
  70. self.table.setColumnCount(3)
  71. # 设置表头内容
  72. self.table.setHorizontalHeaderLabels(['id', '歌曲', '歌手'])
  73. # 设置水平方向自伸展模式
  74. self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
  75. # 设置表格整行选中
  76. self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
  77. # 表格禁止编辑
  78. self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
  79. # 表头样式
  80. self.table.horizontalHeader().setStyleSheet(""" border-width:1px; border-style:solid; border-color:grey; """)
  81. self.table.verticalHeader().setStyleSheet(""" border-width:1px; border-style:solid; border-color:grey; """)
  82. 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;} """)
  83. def lineEditstyle(self):
  84. """行编辑样式"""
  85. self.line.setPlaceholderText("\t请输入歌名")
  86. self.line.setGeometry(35, 30, 400, 50)
  87. 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); ''')
  88. def buttonstyle(self):
  89. """按钮样式"""
  90. self.button.setCursor(Qt.PointingHandCursor)
  91. self.button.setIcon(QIcon('images/search.png'))
  92. self.button.clicked.connect(self.search)
  93. self.button.setGeometry(445, 30, 120, 50)
  94. 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); """)
  95. class Encrypt:
  96. def __init__(self, text):
  97. self.data = {
  98. 'encSecKey': '01ec48cb405730aa77f993a988cc1f5bc1938511d75f49eddc581f2fe2aaf18988853200564b2d4b1312cf6e0bb344425addce5a4c81b38b89a5973900946bd100b0f1865d22d2a8e5dd8be208eb5d6eb2f71309a165daeffe95355e1e44edd65bdf28088fe4f5e835a7d9f7569fc2530f9d17c00b51cfafbe421eb462247ea3'
  99. }
  100. self.text = text
  101. self.key = '0CoJUm6Qyw8W8jud'
  102. def get_form_data(self):
  103. """生成表单参数"""
  104. # 随机秘钥参数,可以用固定值
  105. i = "4JknCzx6uEXUwxpU"
  106. # 两次加密
  107. first_encrypt = self.AES_encpyt(self.text, self.key)
  108. self.data['params'] = self.AES_encpyt(first_encrypt, i)
  109. return self.data
  110. def AES_encpyt(self, text, key):
  111. """AES加密"""
  112. # AES加密明文必须为16的整数倍
  113. padding = 16 - len(text.encode()) % 16
  114. text += padding * chr(padding)
  115. aes = AES.new(key.encode(), AES.MODE_CBC, b'0102030405060708')
  116. enctext = aes.encrypt(text.encode())
  117. return b64encode(enctext).decode('utf-8')
  118. class SearchMusic:
  119. def __init__(self, text):
  120. self.url = 'https://music.163.com/weapi/cloudsearch/get/web?csrf_token='
  121. 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 '''
  122. self.headers = HeaderPrettyDict().pretty(reqstr)
  123. self.text = text
  124. def search(self):
  125. """搜索音乐,返回音乐列表"""
  126. data = Encrypt(self.text).get_form_data()
  127. res = requests.post(self.url, headers=self.headers, data=data)
  128. songlist = []
  129. songs = res.json()['result']['songs']
  130. for song in songs:
  131. item = { }
  132. # id、歌名、歌手、封面
  133. item['song_id'] = song['id']
  134. item['song_name'] = song['name']
  135. item['singer'] = song['ar'][0]['name']
  136. # item['song_pic_url'] = song['al']['picUrl']
  137. songlist.append(item)
  138. return songlist
  139. class NeteaseCloudMusic:
  140. def __init__(self, song):
  141. self.url = 'https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token='
  142. 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 '''
  143. self.headers = HeaderPrettyDict().pretty(reqstr)
  144. self.text = '{"ids":"[' + str(song['song_id']) + ']","level":"standard","encodeType":"aac","csrf_token":""}'
  145. self.name = song['song_name']
  146. self.singer = song['singer']
  147. def music(self):
  148. """获取音乐的url"""
  149. data = Encrypt(self.text).get_form_data()
  150. res = requests.post(self.url, headers=self.headers, data=data)
  151. song_url = res.json()['data'][0]['url']
  152. self.save(self.download(song_url))
  153. def download(self, url):
  154. """下载音乐"""
  155. 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'}
  156. res = requests.get(url, headers=headers)
  157. return res.content
  158. def save(self, content):
  159. """保存音乐"""
  160. # 当前文件目录
  161. path = os.path.dirname(__file__)
  162. # 检查'data'目录是否存在,不存在则创建目录
  163. if not os.path.exists(path+'\\data'):
  164. os.mkdir(path+'\\data')
  165. # 音乐保存路径
  166. music_path = path+'\\data'+f'\\{ self.name} { self.singer}.m4a'
  167. # 保存
  168. if not os.path.exists(music_path):
  169. with open(music_path, 'wb') as f:
  170. f.write(content)
  171. if __name__ == '__main__':
  172. def run():
  173. app = QApplication(sys.argv)
  174. g = NeteaseUI()
  175. sys.exit(app.exec_())
  176. run()

发表评论

表情:
评论列表 (有 0 条评论,445人围观)

还没有评论,来说两句吧...

相关阅读