七夕送女朋友什么礼物好?我反手写了个音乐播放器,女友眼冒金光

Posted yeanky

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了七夕送女朋友什么礼物好?我反手写了个音乐播放器,女友眼冒金光相关的知识,希望对你有一定的参考价值。

七夕送女朋友什么礼物好?我反手写了个音乐播放器,女友眼冒金光!

这是一个用 Python 的 tkinter 库做的一个网络音乐播放器。我不说它的 UI 设计的有多好看,但是它的功能绝对是全站首个!坚持看到底,你不点赞算我输!

成果展示


程序截图

前期准备

程序结构:

文件或文件夹描述
_pycache_导入模块形成的文件夹
musics存储下载的音乐
get.py爬取音乐
gui.pyGUI界面
lrc.py歌词操作
main.pyw入口文件,双击运行
player.py播放器文件
requirements.txt所需库

所需第三方库(requirement.txt):

mutagen==1.45.1
pygame==2.0.1
requests==2.26.0
Pillow==8.3.1

安装:

pip install mutagen		# 查看歌曲长度
pip install pygame		# 播放音乐
pip install requests	# 爬取音乐
pip install pillow		# 显示图片

或者:

pip install -r requirements.txt

一、爬取音乐

下面的代码为 get.py 里的内容。
具体教程见 酷我音乐搜索、下载详解

import requests

search_url = 'http://www.kuwo.cn/api/www/search/searchMusicBykeyWord'

search_headers = {
    'Referer': 'http://www.kuwo.cn/search/list?key=',
    'Cookie': '_ga=GA1.2.12......',
    'csrf': 'YO4OH2VYH1A'}

search_params = {
'key': 'str',   # 查找关键字
'pn': '1',  # 页数
'rn': '20', # 项数
'httpsStatus': '1',
'reqId': '6e028fc0-db8f-11eb-b6f5-ff7d54a57f2b'
}

from_url = 'http://www.kuwo.cn/url'
  
from_params = {
    'rid': '148526468', # 歌曲 rid
    'type': 'convert_url3',
    'br': '128kmp3',
}

lrc_url = 'http://m.kuwo.cn/newh5/singles/songinfoandlrc?musicId={rid}'

headers = {'user-agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/91.0.4472.114 Safari/537.36 Edg/91.0.864.59'}

class Kuwo:
    def search_kuwo(self, kw):#
        search_params.update({'key': kw})

        response = requests.get(search_url,
                                params=search_params,
                                headers={**headers, **search_headers},
                                timeout=2,
                               ).json()

        datas = response.get('data', {}).get('list', {})

        result = [[r.get('name', ''),
                   r.get('artist', ''),
                   r.get('album', ''),
                   r.get('songTimeMinutes', ''),
                   r.get('pic', ''),
                   r.get('pic120', ''),
                   r.get('rid', '')]
                  for r in datas]

        return result

    def get_music_url(self, rid):#
        from_params['rid'] = rid
        url = requests.get(from_url, params=from_params, headers=headers, timeout=2).json()['url']

        return url

    def get_music_content(self, rid):
        url = self.get_music_url(rid)
        content = requests.get(url, headers=headers, timeout=2).content

        return content

    def get_music_lrc(self, rid):
        lrc_data = requests.get(lrc_url.format(rid=rid), headers=headers, timeout=2).json()

        lrc_list = lrc_data.get('data', {}).get('lrclist', [{1: '无歌词', 2: '0'}])

        lrc = [list(l.values()) for l in lrc_list]

        return lrc

    def get_pic(self, url):
        pic = requests.get(url, headers=headers).content
        
        return pic

二、歌词操作

下面代码为 lrc.py 里的代码。

import re

class Lrc:
	def __init__(self):
		self.LRC = [[0.0, '无歌词']]
		self.Times = [0.0]
		self.Words = ['无歌词']

	def decode_from_str(self, lrc: str):
		lrc = lrc.strip('\\n')
		res1 = self.SP_DTWDSTR.findall(lrc)
		res2 = list()
		res3 = dict()
		result = dict()
		for r in res1:
			res2.append([self.SP_DTSTR.findall(r[0]), r[1]])
		for r in res2:
			for t in r[0]:
				res3[self.tosec(t)] = r[1]

		result = sorted(list(res3.items()), key=lambda x: x[0])

		self.decode(result)

		return self.LRC

	def decode(self, lrcs):
		self.LRC = lrcs
		r = list(zip(*lrcs))
		self.Words = list(r[0])
		self.Times = list(map(self.tosec, list(r[1])))

	# 将字符串时间变为秒
	def tosec(self, t:str):
		res1 = t.split(':')[::-1]
		res2 = [float(r) * (60 ** i) for i, r in enumerate(res1)]
		result = sum(res2)

		return result

	# 根据浮点数播放进度获取对应歌词索引
	def get_index(self, t:float):
		times = [*self.Times, t]
		times.sort()
		
		return times.index(t) - 1

三、播放器

下面代码为 player.py 里的内容。

播放器的方法其实和 pygame.mixer.music 的方法差别不大。但要注意的是第 1~2 行代码是用于去除导入 pygame 模块时自动打印的信息。

from os import environ
environ['PYGAME_HIDE_SUPPORT_PROMPT'] = '1'

import pygame
from io import BytesIO

class Player:
    def __init__(self):
        pygame.mixer.init()
        self.music = pygame.mixer.music

    def reset(self):
        self.music.stop()
        pygame.mixer.pre_init()

    def load(self, filename):
        self.music.load(filename)

    def play(self):
        self.music.play()

    def pause(self):
        self.music.pause()

    def unpause(self):
        self.music.unpause()

    def stop(self):
        self.music.stop()

    def get_length(self):
        return self.music.get_length()

    def get_pos(self):
        return self.music.get_pos()

    def set_pos(self, value=0):
        self.music.rewind()
        self.music.set_pos(value)

    def get_volume(self):
        return self.music.get_volume()

    def set_volume(self, value=0.5):
        return self.music.get_volume(value)

    def addsong(self, filename):
        self.music.quene(filename)

四、GUI 界面

下面代码为 gui.py 中的代码。

有关教程见

from tkinter import *
from tkinter import ttk
from io import BytesIO
from mutagen.mp3 import MP3
from PIL import Image, ImageTk
import get
import player
import lrc

class Window(Tk):
    ischanging = False
    last_pos = 0

    words = ['']
    times = [0]
    
    def __init__(self):

        Tk.__init__(self)
        self.title('JIE 音乐')
        self.geometry('650x400')
        self.resizable(0, 0)

        self.set_notebook()
        self.set_control()

        self.set_weight()

        self.update()

        self.after(100, self.timer)

        self.mainloop()

    def set_notebook(self):
        self.nb = ttk.Notebook(self)
        self.nb.grid(row=0, column=0, sticky='nswe', padx=2, pady=1)

        self.set_search_frame()
        self.set_lrc_frame()

        self.nb.add(self.search_frame, text=' 搜索 ')
        self.nb.add(self.lrc_frame, text=' 歌词 ')

    # 控制框
    def set_control(self):
        self.control_frame = Frame(self)
        self.control_frame.grid(row=1, column=0, sticky='nswe', padx=2, pady=1)

        self.ctrl_pic = Canvas(self.control_frame, height=40, width=40)
        self.ctrl_pic.grid(row=0, column=0)

        self.play_btn = Label(self.control_frame, text='▶', font=('宋体', 24, 'bold'), 
                              width=2, height=1, relief='flat')
        self.play_btn.bind('<Enter>', lambda event: self.play_btn.configure(fg='orange'))
        self.play_btn.bind('<Leave>', lambda event: self.play_btn.configure(fg='black'))
        self.play_btn.bind('<Button-1>', self.play_or_pause)
        self.play_btn.grid(row=0, column=1, sticky='nswe')

        self.var = IntVar()
        self.var.set(0)

        self.bar = Scale(self.control_frame, label='无歌曲', orient='horizontal', 
                         variable=self.var, showvalue=False, from_=0, to=0, 
                         command=self.change, width=10, length=500)
        self.bar.grid(row=0, column=2, sticky='nwe')

        self.download_btn = Label(self.control_frame, text='↓', font=('微软雅黑', 15), width=2)
        self.download_btn.bind('<Enter>', lambda event: self.download_btn.configure(fg='orange'))
        self.download_btn.bind('<Leave>', lambda event: self.download_btn.configure(fg='black'))
        self.download_btn.bind('<Button-1>', self.download)
        self.download_btn.grid(row=0, column=3, sticky='nswe')

    # 搜索界面
    def set_search_frame(self):
        self.search_frame = Frame(self.nb)

        self.inputbox = ttk.Entry(self.search_frame, width=14)
        self.inputbox.bind('<Return>',lambda event: self.get_datas(self.inputbox.get()))
        self.inputbox.grid(row=0, column=0, sticky='nswe', padx=(2, 0), pady=2)

        self.surebtn = ttk.Button(self.search_frame, text='搜索', width=6, 
                                  command=lambda: self.get_datas(self.inputbox.get()))
        self.surebtn.grid(row=0, column=1, columnspan=2, sticky='nswe', padx=(0, 2), pady=2)
        
        columns = [0, 1, 2, 3, 4]
        self.songstable = ttk.Treeview(self.search_frame, columns=columns, show='headings')
        
        self.songstable.column(0, width=25, anchor='w', stretch='no')
        self.songstable.heading(0, text='')
        self.songstable.column(1, width=200, anchor='w')
        self.songstable.heading(1, text='歌曲')
        self.songstable.column(2, width=70, anchor='w')
        self.songstable.heading(2, text='歌手')
        self.songstable.column(3, width=100, anchor='w')
        self.songstable.heading(3, text='专辑')
        self.songstable.column(4, width=45, anchor='w', stretch='no')
        self.songstable.heading(4, text='时长')

        self.songstable.grid(row=1, column=0, columnspan=2, sticky='nswe')
        self.songstable.bind('<Double-Button-1>', 
                             lambda event: self.selected(self.songstable.item(self.songstable.selection()[0], 'value')))

        self.songscroll = ttk.Scrollbar(self.search_frame, orient='vertical', 
                                        command=self.songstable.yview)
        self.songscroll.grid(row=1, column=2, sticky='nswe')

        self.songstable.configure(yscrollcommand=self.songscroll.set)

    # 歌词界面
    def set_lrc_frame(self):
        self.lrc_frame = Frame(self.nb)

        self感动哭了!七夕用python送男朋友99999朵玫瑰!!!

感动哭了!七夕用python送男朋友99999朵玫瑰!!!

感动哭了!七夕用python送男朋友99999朵玫瑰!!!

女朋友想要听歌,我反手用Flutter做了2个音乐播放器,给她拿捏了

女朋友想要听歌,我反手用Flutter做了2个音乐播放器,给她拿捏了

明天就母亲节,你们打算送什么呢?分享用Python准备好的礼物