使用Python Django框架做一个音乐网站,
本篇主要为排行榜功能及音乐播放器部分功能实现。
目录
排行榜列表
设置路由
视图处理
模板渲染
设置跳转入口
播放器功能开发
设置路由
模板页面
脚本渲染
列表渲染和播放器实现
音乐播放器列表展示关闭
总结
排行榜列表
设置路由
在子应用文件夹中urls.py中新增一条记录。
# 排行榜
path('rank', views.rank, name='rank'),
视图处理
榜单列表需要展示各个排行榜所有一定时间段中上榜单曲列表;
因为前期单曲没有与类型表关联,目前就只能做一个类似的功能。
下方代码中处理了分页查询;通过id来区别类型进行排序;
设置了榜单的名称,更新时间是取单曲列表中时间最晚的一个时间。
def rank(request):
""" 排行榜 """
id = int(request.GET.get('id', 1))
page = int(request.GET.get('page', 1))
singe_db = Singe.objects
if id == 1:
song_list = singe_db.order_by('-id').all()
rank_name = '新歌榜'
elif id == 2:
song_list = singe_db.order_by('-playnum').all()
rank_name = '热歌榜'
elif id == 3:
song_list = singe_db.order_by('playnum').all()
rank_name = '飙升榜'
elif id == 4:
song_list = singe_db.order_by('-id').all()
rank_name = '抖音歌曲榜'
elif id == 5:
song_list = singe_db.order_by('id').all()
rank_name = '万物DJ榜'
else:
song_list = singe_db.order_by('-playnum').all()
rank_name = '会员畅听榜'
# 实例化Paginator
page_num = 20
paginator = Paginator(song_list, page_num)
try:
res = paginator.page(page)
except PageNotAnInteger:
res = paginator.page(1)
except EmptyPage:
res = paginator.page(paginator.num_pages)
list_num = len(res)
# 榜单更新时间
updatetime = date.today()
for item in song_list:
if updatetime.ctime() < item.updatetime.ctime():
updatetime = item.updatetime
return render(request, 'rank/index.html', locals())
模板渲染
在templates文件夹下创建rank文件夹,并在其中创建index.html文件。
其他渲染都大同小异,主要有一点新的东西,因为榜单数据比较多,在第一页时候有个前三名标识,需要区别处理第二页之后的序列号和相应标识处理,这里使用了模板中的过滤器。
内容如下:
{% extends 'common/base.html' %}
{% load static %}
{% block title %}我的音乐{% endblock title %}
{% block content %}
<link rel="stylesheet" href="{% static 'css/rank.css' %}">
<!--导航条开始-->
<div class="header">
<img src="{% static 'images/logo.png' %}" class="logo" alt="">
<ul>
<li><a href="{% url 'player:index' %}">推荐</a></li>
<li><a href="javascript:void(0)" class="selected">排行榜</a></li>
<li><a href="{% url 'player:singer' 1 '#' %}">歌手</a></li>
<li><a href="{% url 'player:songsheet' %}">歌单</a></li>
</ul>
</div>
<!--导航条结束-->
<div class="main_con">
<div class="con_l">
<div class="con">
<div class="tabs flex_c">
<span class="active">官方</span>
<span class="">特色</span>
<span class="">场景</span>
</div>
<ul class="tab_con">
<li class="flex_c active">
<img alt="" class="cover" data-src="{% static 'images/rank_list_1.png' %}" src="{% static 'images/rank_list_1.png' %}" lazy="loaded">
<div class="item_info">
<p class="name"><a href="{% url 'player:rank' %}?id=1">新歌榜</a></p>
<p class="time">今日更新</p>
</div>
</li>
<li class="flex_c active">
<img alt="" class="cover" data-src="{% static 'images/rank_list_2.png' %}" src="{% static 'images/rank_list_2.png' %}" lazy="loaded">
<div class="item_info">
<p class="name"><a href="{% url 'player:rank' %}?id=2">热歌榜</a></p>
<p class="time">今日更新</p>
</div>
</li>
<li class="flex_c active">
<img alt="" class="cover" data-src="{% static 'images/rank_list_3.png' %}" src="{% static 'images/rank_list_3.png' %}" lazy="loaded">
<div class="item_info"><p class="name"><a href="{% url 'player:rank' %}?id=3">飙升榜</a></p>
<p class="time">今日更新</p>
</div>
</li>
<li class="flex_c active">
<img alt="" class="cover" data-src="{% static 'images/rank_list_4.png' %}" src="{% static 'images/rank_list_4.png' %}" lazy="loaded">
<div class="item_info"><p class="name"><a href="{% url 'player:rank' %}?id=4">抖音歌曲榜</a></p>
<p class="time">今日更新</p>
</div>
</li>
<li class="flex_c active">
<img alt="" class="cover" data-src="{% static 'images/rank_list_5.png' %}" src="{% static 'images/rank_list_5.png' %}" lazy="loaded">
<div class="item_info"><p class="name"><a href="{% url 'player:rank' %}?id=5">万物DJ榜</a></p>
<p class="time">今日更新</p>
</div>
</li>
<li class="flex_c active">
<img alt="" class="cover" data-src="{% static 'images/rank_list_6.png' %}" src="{% static 'images/rank_list_6.png' %}" lazy="loaded">
<div class="item_info"><p class="name"><a href="{% url 'player:rank' %}?id=6">会员畅听榜</a></p>
<p class="time">今日更新</p>
</div>
</li>
</ul>
</div>
</div>
<div class="con_r">
<div>
<div><span class="title">{{rank_name}}</span> <span class="update_time">更新时间:{{updatetime}}</span></div>
<div class="btns">
<button class="play bg_primary">
<i class="glyphicon glyphicon-play"></i> <span>立即播放</span>
</button>
<button><i class="glyphicon glyphicon-plus"></i> <span>添加</span>
</button>
<button>
<i class="glyphicon glyphicon-heart"></i> <span>收藏</span>
</button>
</div>
<div class="list_out">
<div class="list_head head_name_rank" style="">
<ul class="flex_c">
<li class="head_num">序号</li>
<li class="head_name">歌曲</li>
<li class="head_artist">歌手</li>
<li class="head_album">发布时间</li>
<li class="head_time">时长</li>
</ul>
</div>
<ul class="rank_list">
{% for item in res %}
<li class="song_item flex_c">
<div class="song_rank flex_c">
{% if page == 1 %}
{% if forloop.counter == 1 %}
<div class="rank_num top1"></div>
{% elif forloop.counter == 2 %}
<div class="rank_num top2"></div>
{% elif forloop.counter == 3 %}
<div class="rank_num top3"></div>
{% else %}
<div class="rank_num"><span>{{forloop.counter}}</span></div>
{% endif %}
{% else %}
<div class="rank_num"><span>{{forloop.counter|add:page_num}}</span></div>
{% endif %}
<div class="status"></div>
</div>
<div class="song_name flex_c">
<a title="{{item.name}}" href="{% url 'player:album_song' %}?sid={{item.id}}" class="name">{{item.name}}</a>
</div>
<div class="song_artist">
<span title="{{item.singler.name}}">{{item.singler.name}}</span>
</div>
<div class="song_album">
<span>{{item.addtime}}</span>
</div>
<div class="song_time"><span>{{item.get_song_duration}}</span></div>
<div class="song_opts flex_c">
<i class="glyphicon glyphicon-plus"></i>
<i class="glyphicon glyphicon-play"></i>
<i class="glyphicon glyphicon-heart"></i>
</div>
</li>
{% endfor %}
</ul>
{% if list_num < 1 %}
<!--设置无数据内容-->
<div class="nodata flex_c">
<div class="inner">
<img src="{% static 'images/nodata.png' %}"
alt="" class="nodata_img">
<div class="tip"><p>暂无相关数据</p></div>
</div>
</div>
{% endif %}
<div class="loading-mask" style="display: none;">
<div class="loading-wrap">
<div class="load"><span class="side1"></span> <span
class="side2"></span> <span class="mid"></span>
<span class="side2"></span> <span
class="side1"></span></div>
</div>
</div>
</div>
{% if list_num > 0 %}
<!--设置分页页码-->
<div class="page">
<i class="li-page glyphicon glyphicon-menu-left notPointer"></i>
<ul>
{% for index in res.paginator.page_range %}
{% if res.number == index %}
<li><a href="#" class="notCursor currentPage">{{index}}</a></li>
{% else %}
<li><a href="{% url 'player:rank' %}?page={{index}}">{{index}}</a></li>
{% endif %}
{% endfor %}
</ul>
<i class="glyphicon glyphicon-menu-right li-page"></i>
</div>
{% endif %}
</div>
</div>
</div>
{% endblock content %}
设置跳转入口
点击推荐排行榜中更多按钮,进入排行榜列表。
内容如下:
<div class="title">
<div class="name">推荐排行榜</div>
<ul>
<li><a href="{% url 'player:rank' %}">更多></a></li>
</ul>
</div>
播放器功能开发
其他功能大致算完成了,开始做播放音乐的功能开发。
播放器设置在网站的底部,采用固定悬浮;
可以左右切换音乐,设置音量,查看播放音乐列表。
设置路由
主要用来获取播放器音乐列表信息。
# 播放器列表
path('play_list', views.play_list, name='play_list'),
模板页面
播放器的主要功能采用之前使用html做的播放器,
直接嵌入到django音乐网站基类模板(templates/common/base.html)的底部。
内容如下:
<div id="music_all">
<div class="music_main" style="opacity:1;background:#fff">
<div class="music_left">
<img class="music_img" id="music_img" src="{% static 'images/s1.jpg' %}" alt="">
</div>
<audio id="player">
<source src="/media/uploads/1691649371/七里香_-_周杰伦.mp3" type="audio/mpeg">
您的浏览器不支持 audio 元素。
</audio>
<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>
</div>
<div class="music_rate">
<div class="music-progress"></div>
</div>
</div>
<div class="play_right">
<i class="glyphicon glyphicon-step-backward" id="music_prev"></i>
<i class="glyphicon glyphicon-play" id="music_dian"></i>
<i class="glyphicon glyphicon-step-forward" id="music_next"></i>
</div>
<div class="music_right">
<ul>
<li><i class="glyphicon glyphicon-th-list" id="setList"></i></li>
<li><i class="glyphicon glyphicon-volume-up" id="setVolume"></i></li>
<li>
<div class="slider">
<input type="range" id="volume" min="0" max="100" value="0">
</div>
</li>
</ul>
</div>
</div>
<div class="songList" style="display:none">
<div class="list_top flex_c">
<div id="play_title"></div>
<div class="flex_c">
<div class="clear_all"><i class="glyphicon glyphicon-trash"></i> <span
class="clear_btn">清空列表</span>
</div>
<i class="close glyphicon glyphicon-remove"></i></div>
</div>
<div class="list_con">
<div id="play_list" style="transition-timing-function: cubic-bezier(0.23, 1, 0.32, 1);
transition-duration: 0ms; transform: translate(0px) scale(1) translateZ(0px);overflow-y: scroll;height:400px;"></div>
<div style="position: absolute; z-index: 9999; width: 7px; bottom: 2px; top: 2px; right: 1px; overflow: hidden;"
class="bscroll-vertical-scrollbar">
<div style="box-sizing: border-box; position: absolute; background: rgba(0, 0, 0, 0.5); border: 1px solid rgba(255, 255, 255, 0.9); border-radius: 3px; width: 100%; transition-duration: 0ms; height: 190px; transform: translateY(0px) translateZ(0px); transition-timing-function: cubic-bezier(0.23, 1, 0.32, 1);"
class="bscroll-indicator"></div>
</div>
</div>
</div>
</div>
效果:
脚本渲染
使用JavaScript来实例化audio的提供的接口方法,并结合后台数据进行渲染和调用audio来实现播放器功能。
列表渲染和播放器实现
内容如下:
window.onload = function () {
// 绑定音频元素
var $player = document.getElementById('player');
// 绑定播放按钮
var $dian = document.getElementById('music_dian');
// 设置音频初始属性
var volume_num = 0.5;
// 当前歌曲索引
var currentIndex = 0;
// 设置播放列表
var music_list = [{
'id': 1,
'cover': '/static/images/s1.jpg',
'singer': '周杰伦',
'song_name': '七里香',
'song_path': '/media/uploads/1691649371/七里香_-_周杰伦.mp3'
},];
// 设置播放器音乐列表
var play_list = document.getElementById('play_list');
var play_title = document.getElementById('play_title');
// 初始化设置
setInit();
// 绑定音频控制开关
$dian.onclick = function () {
if (this.classList == 'glyphicon glyphicon-play') {
this.className = 'glyphicon glyphicon-pause';
$player.play();
} else {
// layui-icon-pause
this.className = 'glyphicon glyphicon-play';
$player.pause();
}
};
// 设置播放器初始属性
function setInit() {
// 设定音量
$player.volume = volume_num;
$('#volume').val(volume_num * 100);
// 通过同步方式获取播放列表信息
$.ajaxSettings.async = false;
$.getJSON('/play_list', {}, function (res) {
// 赋值播放列表
music_list = res.list;
});
// 设定歌曲封面
$('#music_img').attr('src', '/media/' + music_list[0].cover);
// 设定歌曲名称和歌手
$('.music_name').text(music_list[0].song_name + ' - ' + music_list[0].singer);
// 设定歌曲路径
$player.src = '/media/' + music_list[0].song_path;
// 设置播放器音乐列表
set_media_list(music_list)
}
// 监听播放器播放时间改变事件
$player.addEventListener('timeupdate', function () {
// 当前播放时间
var currentTime = $player.currentTime;
// 总时间
var totalTime = $player.duration;
// 当是数字的时候
if (!isNaN(totalTime)) {
// 得到播放时间与总时长的比值
var rate = currentTime / totalTime;
// 设置时间显示
// 播放时间
$('.playTimeSpan').text(musicTime(currentTime));
// 总时长
$('.totalTimeSpan').text('/' + musicTime(totalTime));
// 设置进度条
$('.music-progress').css('width', rate * 441 + 'px');
}
});
// 设置音量
$('#volume').change(function () {
volume_num = $(this).val();
$player.volume = volume_num * 0.01
});
// 上一首
$('#music_prev').click(function () {
if (currentIndex > 0) {
currentIndex -= 1;
} else {
// 切换到最后一首
currentIndex = music_list.length - 1;
}
// 设置播放标识为暂停
$dian.className = 'glyphicon glyphicon-play';
// 播放时间
$('.playTimeSpan').text('00:00');
// 设置歌曲进度归零
$('.music-progress').css('width', '1px');
// 设置歌曲
setMusic();
});
// 下一首
$('#music_next').click(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();
});
// 设置播放器歌曲信息
function setMusic() {
// 设定歌曲封面
$('#music_img').attr('src', '/media/' + music_list[currentIndex].cover);
// 设定歌曲名称和歌手
$('.music_name').text(music_list[currentIndex].song_name +
' - ' + music_list[currentIndex].singer);
// 设定歌曲路径
$player.src = '/media/' + music_list[currentIndex].song_path;
}
// 歌曲时长(00:00)
function musicTime(sens) {
// 分
var m = parseInt(sens / 60);
// 秒
var s = parseInt(sens % 60);
// 补零
m = m > 9 ? m : "0" + m;
s = s > 9 ? s : "0" + s;
return m + ":" + s;
}
// 设置音乐播放器列表
function set_media_list(music_list) {
var play_html = '';
for (var i = 0; i < music_list.length; i++) {
if (i) {
play_html += '<div class="flex_c list_item" style="pointer-events: auto;">' +
'<div class="list_idx">' + (i + 1) + '' +
'<span class="playing" style="display: none">';
} else {
play_html += '<div class="flex_c list_item active_cur" style="pointer-events: auto;">' +
'<div class="list_idx">' + (i + 1) + '' +
'<span class="playing">';
}
play_html += '<span class="side1 pause"></span>' +
'<span class="side2 pause"></span>' +
'<span class="side3 pause"></span>' +
'</span>' +
'</div>' +
'<div class="song_name">' +
'<a href="/album/song?sid='+ music_list[i].id +'" title="' + music_list[i].song_name + '" ' +
'target="_blank">' + music_list[i].song_name + '</a>' +
'</div>' +
'<div class="artist">' +
'<a href="/singer/detail/'+music_list[i].singer_id +'" ' +
'class="" title="' + music_list[i].singer + '" target="_blank">' + music_list[i].singer + '</a>' +
'</div>' +
'<div class="time">' + music_list[i].duration + '</div>' +
'<div class="song_opts flex_c">' +
'<i title="添加歌曲" class="glyphicon glyphicon-plus"></i> ' +
'<i title="收藏歌曲" class="glyphicon glyphicon-heart"></i> ' +
'<i title="下载歌曲" class="glyphicon glyphicon-save"></i> ' +
'<i title="删除歌曲" class="glyphicon glyphicon-trash"></i> ' +
'</div>' +
'</div>';
}
play_title.innerHTML='<span class="text">播放列表</span> <span class="num">(共'+ music_list.length +'首)</span>';
play_list.innerHTML=play_html;
console.log(play_title);
}
};
音乐播放器列表展示关闭
可通过底部播放器列表icon来打开和关闭播放列表;
也可以通过播放列表中关闭icon来隐藏播放列表。
内容如下:
$('#setList').click(function(){
// 展示关闭音乐播放器列表
var songList = $('.songList');
if (songList.css('display') == 'none') {
songList.show();
}else{
songList.hide();
}
})
$('.close').click(function(){
// 关闭播放列表
$('.songList').hide();
});
总结
本篇主要是推荐页-排行榜功能改为动态数据及播放器功能部分实现,可以播放音乐和左右切换以及查看播放音乐列表。