溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

python如何實(shí)現(xiàn)可下載音樂的音樂播放器

發(fā)布時間:2021-03-23 12:49:02 來源:億速云 閱讀:261 作者:小新 欄目:開發(fā)技術(shù)

小編給大家分享一下python如何實(shí)現(xiàn)可下載音樂的音樂播放器,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

1.確定頁面

SongSheet ------ 顯示歌單
MusicCtrl ------顯示音樂一些控件(播放,跳轉(zhuǎn),音量調(diào)節(jié))
SearchWindows ------搜索欄(搜索歌曲默認(rèn)顯示20條,可下載)

songSheet.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Author: Minions
# @Date: 2019-11-24 19:51:16
# @Last Modified by: Minions
# @Last Modified time: 2019-12-17 10:01:53

import tkinter
import os
from tkinter import ttk
import time

class SongSheet(tkinter.Frame):
 def __init__(self, master):
 self.frame = tkinter.Frame(master, height=230, width=300, bd=1,
     bg="SkyBlue")
 self.frame.place(x=0, y=0)
 self.filePath = "C:\Musics"
 self.music = "" # 點(diǎn)擊歌曲獲得更新的路徑
 self.count = 0 # 計數(shù),共多少歌曲

 def run(self):
 # 搜索按鈕
 searchBtn = tkinter.Button(self.frame, text="更新", bg="SkyBlue",
     command=self.showSheet, width=10,
     height=1)

 searchBtn.place(x=0, y=200)

 # 顯示歌單
 def showSheet(self):
 self.count = 0
 musics = os.listdir(self.filePath)
 tree = ttk.Treeview(self.frame)
 # 定義列
 tree["columns"] = ("song")
 # 設(shè)置列,列還不顯示
 tree.column("song", width=95)

 # 設(shè)置表頭 和上面一一對應(yīng)
 tree.heading("song", text="song")

 # 添加數(shù)據(jù) 往第0行添加
 for music in musics:
  # 去除空格
  music = "".join(music.split(" "))
  tree.insert("", 0, text=self.count, values=(music))
  self.count += 1

 # 鼠標(biāo)選中一行回調(diào)
 def selectTree(event):
  for item in tree.selection():
  item_text = tree.item(item, "values")
  self.music = "".join(item_text)
  # print(self.music)

 # 選中行
 tree.bind('<<TreeviewSelect>>', selectTree)
 tree.place(width=300, height=200, x=0, y=0)

 # 添加滾動條
 sy = tkinter.Scrollbar(tree)
 sy.pack(side=tkinter.RIGHT, fill=tkinter.Y)
 sy.config(command=tree.yview)
 tree.config(yscrollcommand=sy.set)

python如何實(shí)現(xiàn)可下載音樂的音樂播放器

2.寫出音樂控件

musicCtrl.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Author: Minions
# @Date: 2019-11-24 16:28:18
# @Last Modified by: Minions
# @Last Modified time: 2019-12-17 10:25:31

import tkinter
from tkinter import ttk
import os
import time
import pygame
from mutagen.mp3 import MP3
import random
from songSheet import SongSheet

class MusicCtrl(object):
 def __init__(self, master):
 self.frame = tkinter.Frame(master,height=150, width=700, bd=1,
     bg="MediumSeaGreen")
 self.frame.place(height=150, width=700, x=0, y=250)
 self.nowPaly = True # 是否正在播放音樂
 self.filePath = r"C:\Musics" # 從該文件夾讀取
 self.musicPath = "" # 用于拼接音樂的路徑
 self.songSheet = SongSheet(master)
 self.songSheet.run()
 self.music = os.path.join(self.filePath,self.musicPath) # 音樂的路徑


 # 整合功能
 def run(self):
 self.playMusic()
 self.refreshName()
 self.pauseMusic()
 self.volume()
 try:
  self.songPos()
 except:
  print("暫無歌曲載入!")

 # 播放音樂按鈕
 def playMusic(self):
 playBtn = tkinter.Button(self.frame, text="播放", command=self.playFunc,
     width=10,height=2)
 playBtn.place(x=300,y=10)

 # 實(shí)現(xiàn)播放功能
 def playFunc(self):
 pygame.mixer.init()
 track = pygame.mixer.music.load(self.music) # 載入一個音樂文件用于播放
 pygame.mixer.music.play() # 開始播放音樂流

 # 暫停播放按鈕
 def pauseMusic(self):
 pauseBtn = tkinter.Button(self.frame, text="暫停/繼續(xù)",
     command=self.pauseFunc,
     width=10, height=2)

 pauseBtn.place(x=400, y=10)

 # 暫停播放功能
 def pauseFunc(self):
 # pygame.mixer.music.get_busy() # 檢測是否正在播放音樂
 if self.nowPaly:
  pygame.mixer.music.pause()
  self.nowPaly = False
 else:
  pygame.mixer.music.unpause() # 恢復(fù)音樂播放
  self.nowPaly = True

 # 顯示歌曲名稱以及歌手
 def showName(self):
 songName = tkinter.Label(self.frame,
   fg="white",font=("華文行楷", 10),bg="MediumSeaGreen",
     width=25, height=1)
 songName['text'] = self.songSheet.music.split('.')[0]
 songName.place(x=35,y=15)
 self.music = os.path.join(self.filePath,self.songSheet.music)

 # 更換音樂后應(yīng)該繼續(xù)播放,并且更換音樂時長
 self.playFunc()
 self.songPos()

 # 音量調(diào)節(jié)
 def volume(self):
 volumeNum = tkinter.Label(self.frame, text="volume", fg="Aquamarine",
     font=("華文行楷", 10), bg="MediumSeaGreen",
     width=5, height=1)

 volumeNum.place(x=500, y=70)

 volume = tkinter.Scale(self.frame, from_=0, to=100,
    orient=tkinter.HORIZONTAL)
 volume.place(x=550,y=50)

 def showNum():
  pygame.mixer.music.set_volume(volume.get()*0.01) # 參數(shù)值范圍為 0.0~1.0

 tkinter.Button(self.frame, text="設(shè)置", command=showNum, bg="Aqua").place(
  x=550, y=100)

 # 音樂絕對定位
 def songPos(self):
 # print(self.music.info.length)
 pos = tkinter.Scale(self.frame, from_=0, to=round(
  MP3(self.music).info.length),
   orient=tkinter.HORIZONTAL, tickinterval=50, length=300)

 pos.place(x=180, y=60)
 def showNum():
  # 為了對一個 MP3 文件的進(jìn)行絕對定位,建議首先調(diào)用 rewind()函數(shù),不然會一直往后走
  pygame.mixer.music.rewind()
  if pygame.mixer.music.get_busy():
  self.curDuration = pos.get()
  pygame.mixer.music.set_pos(self.curDuration)
  else:
  print("請先播放音樂!")

 tkinter.Button(self.frame, text="設(shè)置", command=showNum, bg="Aqua").place(
  x=490, y=90)

 # 點(diǎn)擊歌單的歌更新名稱
 def refreshName(self):
 refreshNameBtn = tkinter.Button(self.frame, text="update",command=self.showName,
     width=10, height=2)

 refreshNameBtn.place(x=45, y=50)

python如何實(shí)現(xiàn)可下載音樂的音樂播放器

3.核心爬取音樂

music.py

# -*- coding:utf-8 -*-
import requests, hashlib, sys, click, re, base64, binascii, json, os
from Cryptodome.Cipher import AES
from http import cookiejar

class Encrypyed():
 """
 解密算法
 """

 def __init__(self):
 self.modulus = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'
 self.nonce = '0CoJUm6Qyw8W8jud'
 self.pub_key = '010001'

 # 登錄加密算法, 基于https://github.com/stkevintan/nw_musicbox腳本實(shí)現(xiàn)
 def encrypted_request(self, text):
 text = json.dumps(text)
 sec_key = self.create_secret_key(16)
 enc_text = self.aes_encrypt(self.aes_encrypt(text, self.nonce), sec_key.decode('utf-8'))
 enc_sec_key = self.rsa_encrpt(sec_key, self.pub_key, self.modulus)
 data = {'params': enc_text, 'encSecKey': enc_sec_key}
 return data

 def aes_encrypt(self, text, secKey):
 pad = 16 - len(text) % 16
 text = text + chr(pad) * pad
 encryptor = AES.new(secKey.encode('utf-8'), AES.MODE_CBC, b'0102030405060708')
 ciphertext = encryptor.encrypt(text.encode('utf-8'))
 ciphertext = base64.b64encode(ciphertext).decode('utf-8')
 return ciphertext

 def rsa_encrpt(self, text, pubKey, modulus):
 text = text[::-1]
 rs = pow(int(binascii.hexlify(text), 16), int(pubKey, 16), int(modulus, 16))
 return format(rs, 'x').zfill(256)

 def create_secret_key(self, size):
 return binascii.hexlify(os.urandom(size))[:16]


class Song():
 """
 歌曲對象,用于存儲歌曲的信息
 """

 def __init__(self, song_id, song_name, song_num, picUrl, singer_name,
   song_url=None):
 self.song_id = song_id
 self.song_name = song_name
 self.song_num = song_num
 self.singer_name = singer_name
 self.picUrl = picUrl
 self.song_url = '' if song_url is None else song_url


class Crawler():
 """
 網(wǎng)易云爬取API
 """

 def __init__(self, timeout=60, cookie_path='.'):
 self.headers = {
  'Accept': '*/*',
  'Accept-Encoding': 'gzip,deflate,sdch',
  'Accept-Language': 'zh-CN,zh;q=0.8,gl;q=0.6,zh-TW;q=0.4',
  'Connection': 'keep-alive',
  'Content-Type': 'application/x-www-form-urlencoded',
  'Host': 'music.163.com',
  'Referer': 'http://music.163.com/search/',
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'
 }
 self.session = requests.Session()
 self.session.headers.update(self.headers)
 self.session.cookies = cookiejar.LWPCookieJar(cookie_path)
 self.download_session = requests.Session()
 self.timeout = timeout
 self.ep = Encrypyed()
 self.result =[]

 def post_request(self, url, params):
 """
 Post請求
 :return: 字典
 """

 data = self.ep.encrypted_request(params)
 resp = self.session.post(url, data=data, timeout=self.timeout)
 result = resp.json()
 if result['code'] != 200:
  click.echo('post_request error')
 else:
  return result

 def search(self, search_content, search_type, limit=9):
 """
 搜索API
 :params search_content: 搜索內(nèi)容
 :params search_type: 搜索類型
 :params limit: 返回結(jié)果數(shù)量
 :return: 字典.
 """

 url = 'http://music.163.com/weapi/cloudsearch/get/web?csrf_token='
 params = {'s': search_content, 'type': search_type, 'offset': 0, 'sub': 'false', 'limit': limit}
 result = self.post_request(url, params)
 # print(result['result']['songs'][3]['ar'][0]['name'])

 return result

 def search_song(self, song_name, song_num, quiet=True, limit=20):
 """
 根據(jù)音樂名搜索
 :params song_name: 音樂名
 :params song_num: 下載的歌曲數(shù)
 :params quiet: 自動選擇匹配最優(yōu)結(jié)果
 :params limit: 返回結(jié)果數(shù)量
 :return: Song獨(dú)享
 """

 result = self.search(song_name, search_type=1, limit=limit)

 if result['result']['songCount'] <= 0:
  click.echo('Song {} not existed.'.format(song_name))
 else:
  songs = result['result']['songs']
  if quiet:
  self.result = [] # 更新result
  for song in songs:
   singers = []
   # """
   picUrl = song['al']['picUrl']
   # """
   for name in song['ar']:
   singers.append(name['name'])
   song_id, song_name = song['id'], song['name']
   singer_name = "_".join(singers)
   song = Song(song_id=song_id, song_name=song_name,
    song_num=song_num, singer_name=singer_name,picUrl=picUrl)
   self.result.append(song)
  picUrl = songs[0]['al']['picUrl']
  # """
  song_id, song_name = songs[0]['id'], songs[0]['name']
  song = Song(song_id=song_id, song_name=song_name,
   song_num=song_num, singer_name=self.result[0].singer_name,
    picUrl=picUrl)
  return song

 def get_song_url(self, song_id, bit_rate=320000):
 """
 獲得歌曲的下載地址
 :params song_id: 音樂ID<int>.
 :params bit_rate: {'MD 128k': 128000, 'HD 320k': 320000}
 :return: 歌曲下載地址
 """

 url = 'http://music.163.com/weapi/song/enhance/player/url?csrf_token='
 csrf = ''
 params = {'ids': [song_id], 'br': bit_rate, 'csrf_token': csrf}
 result = self.post_request(url, params)
 # 歌曲下載地址
 song_url = result['data'][0]['url']

 # 歌曲不存在
 if song_url is None:
  click.echo('Song {} is not available due to copyright issue.'.format(song_id))
 else:
  return song_url

 def get_song_by_url(self, song_url, song_name, song_num, singer_name,
   folder):
 """
 下載歌曲到本地
 :params song_url: 歌曲下載地址
 :params song_name: 歌曲名字
 :params song_num: 下載的歌曲數(shù)
 :params folder: 保存路徑
 """
 # for res in self.result:
 # print(res.song_name, res.song_id, res.singer_name)
 # print("--------")
 # print(song_url, song_name, singer_name)


class Netease():
 """
 網(wǎng)易云音樂下載
 """

 def __init__(self, timeout, folder, quiet, cookie_path):
 self.crawler = Crawler(timeout, cookie_path)
 self.folder = '.' if folder is None else folder
 self.quiet = quiet
 self.url = ''
 self.pic = ''

 def download_song_by_search(self, song_name):
 """
 根據(jù)歌曲名進(jìn)行搜索
 :params song_name: 歌曲名字
 :params song_num: 下載的歌曲數(shù)
 """

 try:
  song = self.crawler.search_song(song_name, self.quiet)
 except:
  click.echo('download_song_by_serach error')
 # 如果找到了音樂, 則下載
 if song != None:
  self.download_song_by_id(song.song_id, song.song_name,
    song.song_num, song.singer_name, self.folder)
  self.pic = song.picUrl

 def download_song_by_id(self, song_id, song_name, song_num, singer_name,
    folder='.'):
 """
 通過歌曲的ID下載
 :params song_id: 歌曲ID
 :params song_name: 歌曲名
 :params song_num: 下載的歌曲數(shù)
 :params folder: 保存地址
 """
 try:
  url = self.crawler.get_song_url(song_id)
  # 去掉非法字符
  song_name = song_name.replace('/', '')
  song_name = song_name.replace('.', '')
  self.crawler.get_song_by_url(url, song_name, song_num,
      singer_name, folder)

 except:
  click.echo('download_song_by_id error')

4.將爬取音樂搜索欄整合

searchWindows.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Author: Minions
# @Date: 2019-11-25 10:31:56
# @Last Modified by: Minions
# @Last Modified time: 2019-12-17 12:40:31

import tkinter
from tkinter import ttk
import os
from urllib import request
from music import Netease,Crawler
import requests

class SearchWindows(tkinter.Frame):
 def __init__(self, master):
 self.frame = tkinter.Frame(master, height=240, width=500, bd=1,
     bg="Purple")

 self.songs = None # 搜索到的所有歌曲(20)的信息
 self.frame.place(x=300,y=0)
 self.info = None # 當(dāng)前歌曲的信息
 self.fileName = "C:\Musics\\"

 timeout = 60
 output = 'Musics'
 quiet = True
 cookie_path = 'Cookie'
 self.netease = Netease(timeout, output, quiet, cookie_path)

 def run(self):
 self.searchBar()
 self.download()

 # 搜索框
 def searchBar(self):
 entry = tkinter.Entry(self.frame)
 entry.place(width=200, height=30, x=50, y=10)

 def getValue():
  self.netease.download_song_by_search(entry.get())
  self.songs = self.netease.crawler.result
  self.showSong()

 searchBtn = tkinter.Button(self.frame, text="搜索", bg="DarkOrchid",
     command=getValue, width=10, height=1)

 searchBtn.place(x=270, y=10)

 # 顯示搜索到的歌曲
 def showSong(self):
 tree = ttk.Treeview(self.frame)
 # 定義列
 tree["columns"] = ("song", "singer", "url")

 # 設(shè)置列,列還不顯示
 tree.column("song", width=50)
 tree.column("singer", width=50)
 tree.column("url", width=50)

 # 設(shè)置表頭 和上面一一對應(yīng)
 tree.heading("song", text="song")
 tree.heading("singer", text="singer")
 tree.heading("url", text="url")

 count = len(self.songs)
 for song in reversed(self.songs):
  url = self.netease.crawler.get_song_url(song.song_id)
  tree.insert("", 0, text=count, values=(song.song_name,
       song.singer_name, url))
  count -= 1

 # 鼠標(biāo)選中一行回調(diào)
 def selectTree(event):
  for item in tree.selection():
  item_text = tree.item(item, "values")
  self.info = item_text

 # 滾動條
 sy = tkinter.Scrollbar(tree)
 sy.pack(side=tkinter.RIGHT, fill=tkinter.Y)
 sy.config(command=tree.yview)
 tree.config(yscrollcommand=sy.set)

 # 選中行
 tree.bind('<<TreeviewSelect>>', selectTree)
 tree.place(width=300, height=200, x=50, y=50)

 # 下載選中的歌曲
 def download(self):

 def downloadSong():
  if self.info is None:
  print("該歌曲下載失敗")
  else:
  request.urlretrieve(self.info[2],
    self.fileName+self.info[1]+'-'+self.info[0]+'.mp3')
  print("%s-%s下載成功" %(self.info[1], self.info[0]))
 
 # 下載按鈕
 downloadBtn = tkinter.Button(self.frame, text="下載", bg="DarkOrchid",
     command=downloadSong, width=6, height=1)

 downloadBtn.place(x=345, y=200)

python如何實(shí)現(xiàn)可下載音樂的音樂播放器

5.整合所有部分

main.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Author: Minions
# @Date: 2019-11-24 20:10:15
# @Last Modified by: Minions
# @Last Modified time: 2019-12-17 9:55:31

import tkinter
from searchWindows import SearchWindows
from musicCtrl import MusicCtrl
from songSheet import SongSheet
import os

win = tkinter.Tk()
win.title("Minions音樂播放器")
win.geometry("700x400")
if os.path.exists("C:/Musics"):
 print("xxx")
else:
 os.mkdir("C:/Musics")

searchWin = SearchWindows(win)
searchWin.run()

songSheetWin = SongSheet(win)
songSheetWin.run()

musicWin = MusicCtrl(win)
musicWin.run()

win.mainloop()

python如何實(shí)現(xiàn)可下載音樂的音樂播放器

以上是“python如何實(shí)現(xiàn)可下載音樂的音樂播放器”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI