Django实现音乐网站 (22)
使用Python Django框架做一个音乐网站,
本篇音乐播放器功能完善:顺序播放、设置播放数、歌词滚动等功能。
目录
顺序播放
设置顺序播放
单曲播放数
添加路由
视图处理
模板处理
歌词滚动
视图内容返回修改
样式设置
模板内容
歌词滚动脚本
歌词滚动判断
模板设置
播放器脚本修改
设置音乐
播放器初始化修改
歌曲详情修改
借鉴博客
项目源码
项目目录结构
说明
下载地址
总结
顺序播放
当播放完一首歌曲后,继续播放下一首,循环播放列表中的单曲。
实践发现使用audio媒体的loop属性只是对当前的单曲的循环播放。
需自定义实现循环播放功能。
设置顺序播放
通过监听播放器结束事件,设置触发播放下一曲。
脚本内容如下:
$player.addEventListener('ended', function () {if (currentIndex < (music_list.length - 1)) {currentIndex += 1;} else {// 切换为第一首currentIndex = 0;}// 设置播放标识为暂停$dian.className = 'glyphicon glyphicon-play';// 播放时间$('.playTimeSpan').text('00:00');// 设置歌曲进度归零$('.music-progress').css('width', '1px');// 设置歌曲setMusic();// 同步播放列表状态var nowDiv = $("#play_list").children('.active_cur');nowDiv.find('.playing').hide();nowDiv.removeClass('active_cur');var newDiv = $("#music_num"+(currentIndex+1));newDiv.addClass('active_cur');newDiv.find('.playing').show();// 设置播放器 播放状态var music_dian = $('#music_dian');if (music_dian.attr('class') == 'glyphicon glyphicon-play') {music_dian.attr('class', 'glyphicon glyphicon-pause');}$player.play();
});
单曲播放数
在歌曲播放时,增加歌曲播放数功能;在排行榜中需要播放数进行排序。
添加路由
# 增加播放数
path('add_play_num', views.add_play_num, name='add_play_num'),
视图处理
通过模板传递的单曲id,查询单曲记录;
如果存在:即在原来基础上增加1;
最后返回状态并做json处理。
内容如下:
def add_play_num(request):""" 增加单曲播放量 """id = request.GET.get('id')info = Singe.objects.filter(pk=id).first()if info:info.playnum += 1info.save()return JsonResponse({'status': 1, 'msg': '操作成功!'})
模板处理
对audio媒体监听播放事件时,获取当前播放歌曲的单曲id,传递给视图进行处理。
内容如下:
// 监听播放器 播放时触发
$player.addEventListener('play', function () {// 处理同步播放列表 播放状态$("#music_num"+currentIndex).removeClass('active_cur');$("#music_num"+currentIndex).find('.playing').hide();$("#music_num"+(currentIndex+1)).addClass('active_cur');$("#music_num"+(currentIndex+1)).find('.playing').show();// 增加单曲播放数$. get('/add_play_num', {'id':music_list[currentIndex].song_id}, function (msg) {if(msg.status == 1) {layer.msg(msg.msg, {icon: 6});} else {layer.msg(msg.msg, {icon: 5});}});
});
效果:

歌词滚动
在歌曲详情中播放音乐时,歌词与播放进度同步滚动显示。
视图内容返回修改
原来的视图中歌词处理为列表了,现在只需要通过join函数连接为文本即可。
内容如下:
def album_song(request):""" 专辑中单曲详情 """sid = request.GET.get('sid')song_info = Singe.objects.filter(id=sid).first()# 反向查询专辑info = song_info.album_set.first()# 歌词处理lyrics = []if song_info:lyrics = read_lyric(song_info.lyric)lyric_text = "".join(lyrics)return render(request, 'album/song.html', locals())def read_lyric(path):""" 读取歌词文件 """f = open(os.path.join(settings.MEDIA_ROOT, str(path)), 'r', encoding='utf-8')lines = []for line in f:lines.append(line)f.close()return lines
样式设置
设置歌词滚动功能所需的样式。
内容如下:
.bg {/* 歌词调整区 */width: 100%;/* 歌词显示盒子宽 */height: 200px;/* 歌词显示盒子高度,需要多显示几行歌词相应调大即可 *//* background-color:#333; *//* 歌词背景颜色 */margin: 15px auto;color: darkgrey;/* 歌词默认颜色,灰色 */font-size: 15px; /* 歌词字体默认大小 */overflow: hidden;position: relative;font-family: "宋体"; /*字体可以随便换*/
}.bg ul {width: 100%;position: absolute;top: 0;left: 0;list-style: none;
}.bg ul li {width: 100%;height: 30px;line-height: 30px;text-align: left;
}.bg ul li.active { /* 歌词高亮滚动区 */color: #ffe12c;font-size: 18px;
}
模板内容
把歌词文本放入一个隐藏输入框中及设定歌词渲染的元素。
内容如下:
<input type="hidden" id="text" value="{{lyric_text}}">
<div class="lyric lyricAll bg"></div>
歌词滚动脚本
歌词滚动效果,用的网上的文章内容做的,能够实现滚动;
就是有两个问题:
1.播放进度与显示进度不符。
2.滚动的速度太快了,歌词显示选中的都已经卷过了。
之后有时间就调试一下,这两个问题归根其实是一个问题,播放进度与显示进度不符。
分割歌词、歌曲进度计算、设置卷动速度都调了一遍,发现没问题。
最后发现设置元素这里有问题,给ul、li分别设置了id、class完美实现歌词滚动。
脚本内容如下:
$(function() {function parseLyric(text) {//按行分割歌词let lyricArr = text.split('\n');let result = []; //新建一个数组存放最后结果// 遍历分割后的歌词数组,将格式化后的时间节点,歌词填充到result数组for (i = 0; i < lyricArr.length; i++) {let playTimeArr = lyricArr[i].match(/\[\d{2}:\d{2}((\.|\:)\d{2})\]/g); //正则匹配播放时间let lineLyric = "";if (lyricArr[i].split(playTimeArr).length > 0) {lineLyric = lyricArr[i].split(playTimeArr);}if (playTimeArr != null) {for (let j = 0; j < playTimeArr.length; j++) {let time = playTimeArr[j].substring(1, playTimeArr[j].indexOf("]")).split(":");// 数组填充result.push({time: (parseInt(time[0]) * 60 + parseFloat(time[1])).toFixed(4),content: String(lineLyric).substr(1)});}}}return result;}// 这里请按照格式放入相应歌词--开始let text = $('#text').val();// 这里请按照格式放入相应歌词--结束let audio = document.querySelector('audio');// 执行lyc解析let result = parseLyric(text);// 把生成的数据显示到界面上去let $ul = $("<ul id='ly'></ul>");for (let i = 0; i < result.length; i++) {let $li = $("<li class='ld'></li>").text(result[i].content);$ul.append($li);}$(".bg").append($ul);// 当前行歌词let lineNo = 0;// 当播放6行后开始滚动歌词let preLine = 1;// 每次滚动的距离let lineHeight = -30;// 滚动播放 歌词高亮 增加类名activefunction highLight() {let $li = $(".ld");$li.eq(lineNo).addClass("active").siblings().removeClass("active");if (lineNo > preLine) {$ul.stop(true, true).animate({ top: (lineNo - preLine) * lineHeight });}}highLight();// 播放的时候不断渲染audio.addEventListener("timeupdate", function() {if (lineNo == result.length) return;if ($(".ld").eq(0).hasClass("active")) {$("#ly").css("top", "0");}lineNo = getLineNo(audio.currentTime);highLight();lineNo++;});// 当快进或者倒退的时候,找到最近的后面那个result[i].timefunction getLineNo(currentTime) {if (currentTime >= parseFloat(result[lineNo].time)) {// 快进for (let i = result.length - 1; i >= lineNo; i--) {if (currentTime >= parseFloat(result[i].time)) {return i;}}} else {// 后退for (let i = 0; i <= lineNo; i++) {if (currentTime <= parseFloat(result[i].time)) {return i - 1;}}}}// 播放结束自动回到开头audio.addEventListener("ended", function() {lineNo = 0;highLight();audio.play();$("#ly").css("top", "0");});
});
效果:

歌词滚动判断
增加歌词滚动判断是否为播放当前音乐;因为歌词滚动功能在歌曲详情实现的,如果不加判断,在播放歌曲时,查看另外一首歌曲的详情也会滚动。
模板设置
在设置音乐播放的盒子中,增加一个隐藏输入框,
用来设置当前播放音乐的id,用以歌词滚动判断。
内容如下:
<div class="play_left"><div class="music_title"><span class="music_name">七里香 – 周杰伦</span><span class="totalTimeSpan">/04:59</span><span class="playTimeSpan">00:00</span><input type="hidden" id="now_music" value="0"></div><div class="music_rate"><div class="music-progress"></div></div>
</div>
播放器脚本修改
设置音乐
在音乐播放器play.js中设置音乐的方法中,增加设置隐藏输入框当前音乐id.
内容如下:
// 设置播放器歌曲信息
function setMusic() {// 设定歌曲封面$('#music_img').attr('src', music_list[currentIndex].cover);// 设定歌曲名称和歌手$('.music_name').text(music_list[currentIndex].song_name +' - ' + music_list[currentIndex].singer);// 设定歌曲路径$player.src = music_list[currentIndex].song_path;// 设置当前播放音乐id$('.now_music').val(music_list[currentIndex].song_id);
}
播放器初始化修改
需要在播放器初始化方法中也增加设置。
内容如下:
$('#now_music').val(music_list[currentIndex].song_id);
歌曲详情修改
在歌曲详情歌词滚动脚本中增加判断是否为当前播放音乐。
原来脚本内容的基础上,在歌词渲染完毕之后,
增加三行内容判断是否为播放当前音乐,
如果不是,则终止向下执行。
内容如下:
// 把生成的数据显示到界面上去
let $ul = $("<ul id='ly'></ul>");
for (let i = 0; i < result.length; i++) {let $li = $("<li class='ld'></li>").text(result[i].content);$ul.append($li);
}
$(".bg").append($ul);// 判断播放音乐是否为当前页音乐
let now_music = $('#now_music').val();
let page_music = "{{song_info.id}}";
if(now_music != page_music) return;
借鉴博客
html页面制作滚动歌词_网页版动态歌词-CSDN博客
项目源码
如果觉得通过文章讲解不直观或者还是有些不懂的,
可以下载源码再针对某方面内容仔细查看。
项目目录结构

说明
Media:前端和后台上传文件媒体目录
myMusic:项目工程目录
Player:项目子应用目录
Static:项目静态文件存储目录
Templates:应用模板路径
Mymusic.sql 音乐网站数据库表文件
下载地址
链接:百度网盘 请输入提取码
提取码:13lq
总结
本篇还是播放器功能完善,主要实现功能为:
播放列表顺序播放;添加单曲播放数;播放时歌词滚动等功能实现。
相关文章:
Django实现音乐网站 (22)
使用Python Django框架做一个音乐网站, 本篇音乐播放器功能完善:顺序播放、设置播放数、歌词滚动等功能。 目录 顺序播放 设置顺序播放 单曲播放数 添加路由 视图处理 模板处理 歌词滚动 视图内容返回修改 样式设置 模板内容 歌词滚动脚本 歌…...
pnpm ERR_PNPM_ADDING_TO_ROOT
ERR_PNPM_ADDING_TO_ROOT Running this command will add the dependency to the workspace root, which might not be what you want - if you really meant it, make it explicit by running this command again with the -w flag (or --workspace-root). If you don’t wa…...
统计学习方法 拉格朗日对偶性
文章目录 统计学习方法 拉格朗日对偶性原始问题对偶问题原始问题和对偶问题的关系 统计学习方法 拉格朗日对偶性 读李航的《统计学习方法》时,关于拉格朗日对偶性的笔记。 在许多统计学习的约束最优化问题中,例如最大熵模型和支持向量机,常…...
.rancher-pipeline.yml
一、注意点 其实下文二的image是基于这个镜像作为基础镜像在这个镜像中执行打包,shellScript 当前路径是你代码块与上图settings.xml,图中的settings.xml可以替换下你当前镜像的settings.xml 示例 二、.rancher-pipeline.yml ${CICD_GIT_BRANCH}这些从官…...
RK3588平台开发系列讲解(显示篇)MIPI DSI协议介绍之分层
🚀返回专栏总目录 文章目录 一、MIPI DSI 分层1.1、应用层1.2、协议层1.3、链路层1.4、物理层沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 DSI 全称是 Display Serial Interface,是主控和显示模组之间的串行连接接口。 MIPI DSI 接口分为数据线和时钟线,均为…...
前端学成在线项目详细解析三
19-推荐课程-内容样式 HTML结构 <ul><li><a href"#"><div class"pic"><img src"./uploads/course01.png" alt""></div><div class"text"><h4>JavaScript数据看板项目实战…...
使用Kali进行实验---主机发现
主机发现 【实训目的】 掌握主机扫描的工作原理,学会使用ping等扫描工具,发现网络当中活跃的主机。 【场景描述】 在虚拟机环境下配置4个虚拟系统“Win XP1” “Win XP2” “Kali Linux”和“Metasploitable2”,使得4个系统之间能够相互通…...
美团笔试真题2023第一场(4题)
点评: 题目总体来说偏向于中下难度 1.字符串前缀 题目描述: 现在有两个字符串S和T,你需要对S进行若干次操作,使得S是T的一个前缀(空串也是一个前缀)。每次操作可以修改S的一个字符,或者删除一个…...
PHP explode (多)分隔符(delimiters) 使用
PHP explode (多)分隔符(delimiters) 使用 问题:[https://blog.csdn.net/YBaog?typeblog] 把链接中所有的字符串取出。 ㊙️ 神秘算法 ㊙️ function multi_explode($delimiters, $string) {$data [];if ($string) {$str str_replace($delimiters, $delimiter…...
AI的Prompt是什么
一.AI的Prompt的作用 在人工智能(AI)中,"Prompt"通常指的是向AI系统提供的输入或指令,用于引导AI进行特定的操作或生成特定的输出。例如,在一个对话型AI系统中,用户输入的问题就是一个prompt&…...
Qt之自定义model读写CSV文件
一.效果 本文基于QAbstractTableModel实现了一个支持读写CSV文件的TableModel。CSV数据格式虽然很简单,但是网上大多数读写方式其实都是有bug的,没考虑到字段里包含逗号或换行符这种复杂数据的情况。 二.原理 CSV(Comma-Separated Values)文件是一种简单类型的纯文本文件…...
golang 工程组件:grpc-gateway 环境安装+默认网关测试
grpc-gateway grpc-gateway 顾名思义是专门是grpc的网关。也是一个protobuf的编译器,是一个proto的插件。 grpc-gateway就是将http请求处理后转发到对应grpc服务上。很多浏览器,或者客户端开箱不支持grpc,只支持传统的restful API。 grpc网关…...
IP地址SSL证书 IP证书
在许多企业用例中,公司需要SSL证书作为IP地址。公司使用IP地址通过Internet访问各种类型的应用程序。 公网IP地址的SSL证书: 内部IP(也称为私有IP)是IANA设置为保存的IPv4或IPv6地址,例如: RFC 1918范围内…...
MVCC 过程中会加锁吗?
MVCC 机制,全称(Multi-Version Concurrency Control)多版本并发控制,是确保 在高并发下, 多个事务读取数据时不加锁也可以多次读取相同的值。 MVCC 在读已提交(READ COMMITTED)、可重复读&…...
NLP入门——语言结构/语言建模
一、Linguistics 语言学 wordsmorphology 形态学:词的构成和内部结构研究。如英语的dog、dogs和dog-catcher有相当的关系morpheme 语素:最小的语法单位,是最小的音义结合体lexeme 词位:词的意义的基本抽象单位,是一组…...
2023java攻克了抖音视频去水印视频下载
2023java攻克了抖音视频去水印视频下载 1、过滤链接 /*** 过滤链接,获取http连接地址* param url* return*/public static String decodeHttpUrl(String url) {int start url.indexOf("http");int end url.lastIndexOf("/");String decodeu…...
云计算要学习哪些技术?
学习云计算需要涉及多个技术领域和相关的工具、平台和框架。以下是一个详细的介绍,帮助您了解学习云计算所需的技术。 1. 虚拟化技术 虚拟化是云计算的基础,因此了解虚拟化技术至关重要。学习虚拟化技术时,需要掌握以下知识点: …...
Spring bean 和 Java Bean的区别
Spring bean 和 Java Bean的区别 一,JavaBean JavaBean 是一种特殊的 Java 类,遵循一定的命名规范和属性访问规范。它是一种用于表示简单数据类型、封装业务逻辑或与其他对象交互的可重用组件。 JavaBean 必须满足以下规范: 公共无参构造方…...
性能测试 —— Jmeter 命令行详细
我们在启动Jmeter时 会看见:Don’t use GUI mode for load testing !, only for Test creation and Test debugging.For load testing, use CLI Mode (was NON GUI) 这句话的意思就是说,不要使用gui模式进行负载测试,gui模式仅仅是创建脚本…...
ChatGPT AIGC 办公自动化拆分Excel工作表
在职场办公中对数据的操作,经常需要将一份表格数据拆分成多个表。 但是在Excel中进行表格拆分的步骤比较多。 在Excel中拆分工作表的步骤: 1.打开您的Excel工作簿,选择您要拆分的工作表。 2.右键单击工作表标签(通常在底部),选择“移动或复制”。 3.在“移动或复制”…...
Clawdbot企业集成:飞书机器人深度定制开发
Clawdbot企业集成:飞书机器人深度定制开发 企业级AI助手如何无缝融入日常工作流?飞书机器人正成为智能办公的新入口 在现代企业环境中,AI助手与办公平台的深度集成已经成为提升效率的关键。Clawdbot作为企业级AI助手平台,与飞书的…...
Go Context 生命周期控制逻辑解析
Go语言中的Context是控制并发任务生命周期的核心机制,它像一根隐形的线,贯穿于Goroutine的创建、执行和终止全过程。本文将深入解析Context如何通过精巧的设计实现超时控制、级联取消和数据传递,帮助开发者构建更健壮的分布式系统。理解其生命…...
为什么外贸企业需要私域CRM系统?公域CRM差在哪?
摘要:在当今全球化竞争日益激烈、B2B平台流量红利见顶的背景下,传统外贸企业的获客成本正在呈指数级上升。越来越多的外贸人发现,花大价钱在公域平台买来的线索,往往面临着“询盘多、成交少、流失快”的尴尬局面。现在做外贸&…...
Arduino RTCtime库:标准time.h兼容的DS1307/DS3231驱动
1. 项目概述RTCtime 是一款专为 Arduino 平台设计的实时时钟(RTC)驱动库,核心目标是在硬件 RTC 模块与标准 C 运行时时间系统之间建立语义一致、类型兼容的桥梁。它并非一个独立的时间计算引擎,而是对底层硬件寄存器操作的封装层&…...
Windows下OpenClaw全攻略:千问3.5-35B-A3B-FP8接入与飞书联动
Windows下OpenClaw全攻略:千问3.5-35B-A3B-FP8接入与飞书联动 1. 为什么选择OpenClaw作为Windows自动化助手 去年我接手了一个跨部门协作项目,每天需要在飞书、Excel和多个网页工具间反复切换操作。当我在凌晨三点第七次手动整理数据时,突然…...
软件系统规划步骤和可行性研究步骤
前者是系统开发初始阶段的宏观活动序列,后者则是规划阶段中的一项核心子任务。 一、软件系统规划步骤(典型过程) 系统规划通常属于软件生命周期的“项目立项与计划”阶段,常见步骤如下: 初步调查 识别项目机会、用户需求、业务痛点,明确系统建设的初步目标与范围。 问题…...
2026年程序员必备:高质量源码分享平台大盘点
在程序员的日常开发工作中,源码是极为重要的学习与开发资源。优质的源码不仅能助力我们快速掌握新技术,还能为项目开发提供宝贵的参考。2026年,众多源码分享平台不断涌现与更新,下面就为大家详细盘点一些高质量的源码分享平台&…...
MCP3221 12位I²C ADC驱动设计与精度优化实战
1. MCP3221 12位IC模数转换器底层驱动技术解析MCP3221是Microchip公司推出的超低功耗、单通道、12位分辨率的串行模数转换器(ADC),采用标准IC总线接口,工作电压范围宽达2.7V至5.0V,静态电流典型值仅仅为1.5μA…...
cka-2026-etcd
kubeadm 配置的集群已迁移到新机器。它需要更改配置才能成功运行。Task修复在机器迁移过程中损坏的单节点集群。首先,确定损坏的集群组件,并调查导致其损坏的原因。注意:已停用的集群使用外部 etcd 服务器。接下来,修复所有损坏的…...
WeChatMsg:如何从微信聊天记录中提取个人数据宝藏并生成年度报告?
WeChatMsg:如何从微信聊天记录中提取个人数据宝藏并生成年度报告? 【免费下载链接】WeChatMsg 提取微信聊天记录,将其导出成HTML、Word、CSV文档永久保存,对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/Gi…...
