Flask与Html5+的项目:音乐播放器
目录
1 需求
- App:
- 支持移动设备:Android / iOS
- Mui + Html5+
- 通讯协议:
- WebSocket
- HTTP FlaskWeb框架逻辑:
- 轻量化
- 快速实现 HTTP rest-API 接口
- Flask
- MongoDB数据存储:
- JSON存储,便于后期数据分析、用户画像
- 数据格式灵活
- 存储读取速度很快
- 业务需求:
- 用户:
- 登录注册
- 绑定APP
- 内容展示
- 文字
- 图片
- 音频
- 仿微信通讯
- 用户控制APP播放内容:基于websocket 实现内容推送
- 用户:
- FlaskWeb框架 后台:
- 用户相关功能
- 登录
- 注册
- 头像
- 控制App通讯录
- 文件功能相关
- 文件内容传输
- 文件上传
- 通讯服务:
- 幼教内容推送至App
- 可以和App进行通讯
- 玩具和App进行通讯
- 用户相关功能
2 实现
2.1 内容采集
import math
import os.path
import time
import requests
from pro01 import setting
from uuid import uuid4
# 1. 根据专辑ID访问专辑页面,https://www.example.com/revision/album/v1/getTracksList?albumId=4436043&pageNum=2&sort=0&pageSize=30
# 2. 得到列表中对应的ID名称:content.get('data').get('tracks')[0].get('trackId')
# 3. 构建访问歌曲url:https://www.example.com/revision/play/v1/audio?id=31719610&ptype=1
wanna_get_dict = {
"儿歌": ["20880781", "4436043"],
"故事": ["6233693", "260744"],
"古诗": ["11106118", "52208331"]
}
def get_content(content_dict: dict):
for tag, album_list in content_dict.items():
for album in album_list:
# 统计当前专集共有多少页
page = 1
content = requests.get(url=setting.CONTENT_LIST_URL % (album, page), headers=setting.HEADERS).json()
total_page = math.ceil(int(content.get('data').get('trackTotalCount')) / 30)
print(total_page)
while page <= total_page:
if page != 1:
content = requests.get(url=setting.CONTENT_LIST_URL % (album, page), headers=setting.HEADERS).json()
content_list = content.get('data').get('tracks')
for sound in content_list:
music_name = sound.get('title')
music_file = uuid4()
music_path = os.path.join(setting.MUSIC_PATH, f'{music_file}.mp3')
cover_path = os.path.join(setting.COVER_PATH, f'{music_file}.jpg')
music_author = sound.get('anchorName')
music_create_time = sound.get('createDateFormat')
music_tag = sound.get('tag')
music_id = sound.get('trackId')
cover_url = setting.IMG_HOST + sound.get('albumCoverPath')
cover = requests.get(url=cover_url, headers=setting.HEADERS).content
with open(cover_path, 'wb') as f:
f.write(cover)
music_content = requests.get(url=setting.SOUND_URL % music_id, headers=setting.HEADERS).json()
music_url = music_content.get('data').get('src')
music = requests.get(url=music_url, headers=setting.HEADERS).content
with open(music_path, 'wb') as f:
f.write(music)
music_info = {
'title': music_name,
'music_file': f'{music_file}.mp3',
'cover': f'{music_file}.jpg',
'author': music_author,
'create_time': music_create_time,
'tag': music_tag,
}
setting.MongoDB.music_info.insert_one(music_info)
print(music_info)
time.sleep(5)
page += 1
get_content(content_dict=wanna_get_dict)
2.2 创建App项目
- MUI、HTML5+
- 使用Get方式获取内容列表
2.2.1 前端
2.2.1.1 index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<link rel="stylesheet" type="text/css" href="css/mui.css"/>
</head>
<body>
<header class="mui-bar mui-bar-nav">
<h1 class="mui-title">首页</h1>
</header>
<div class="mui-content">
it's 首页.
</div>
<nav class="mui-bar mui-bar-tab">
<a class="mui-tab-item mui-active" id="index">
<span class="mui-icon mui-icon-home"></span>
<span class="mui-tab-label">首页</span>
</a>
<a class="mui-tab-item" id='login'>
<span class="mui-icon mui-icon-phone"></span>
<span class="mui-tab-label">登录</span>
</a>
<a class="mui-tab-item" id="player">
<span class="mui-icon mui-icon-email"></span>
<span class="mui-tab-label">播放</span>
</a>
<a class="mui-tab-item">
<span class="mui-icon mui-icon-gear"></span>
<span class="mui-tab-label">设置</span>
</a>
</nav>
<script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
mui.init()
document.getElementById('index').addEventListener('tap',function () {
mui.openWindow('index.html','index.html',{})
});
document.getElementById('login').addEventListener('tap',function () {
mui.openWindow({
url: 'login.html',
id:'login.html',
styles:{
top:'0px',//新页面顶部位置
bottom:'50px',//新页面底部位置
},
createnew:true,
});
});
document.getElementById('player').addEventListener('tap',function () {
mui.openWindow({
url: 'playerlist.html',
id:'playerlist.html',
styles:{
top:'0px',//新页面顶部位置
bottom:'50px',//新页面底部位置
},
});
});
</script>
</body>
</html>
2.2.1.2 playlist.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<link rel="stylesheet" type="text/css" href="css/mui.css"/>
</head>
<body>
<header class="mui-bar mui-bar-nav">
<h1 class="mui-title">儿歌列表</h1>
</header>
<div class="mui-content">
<ul class="mui-table-view mui-grid-view mui-grid-9">
<li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
<a href="#">
<span class="mui-icon mui-icon-home"></span>
<div class="mui-media-body">儿歌</div>
</a>
</li>
<li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
<a href="#">
<span class="mui-icon mui-icon-email"><span class="mui-badge mui-badge-red">5</span></span>
<div class="mui-media-body">故事</div>
</a>
</li>
<li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
<a href="#">
<span class="mui-icon mui-icon-chatbubble"></span>
<div class="mui-media-body">诗词</div>
</a>
</li>
<li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
<a href="#">
<span class="mui-icon mui-icon-location"></span>
<div class="mui-media-body">Location</div>
</a>
</li>
<li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
<a href="#">
<span class="mui-icon mui-icon-search"></span>
<div class="mui-media-body">Search</div>
</a>
</li>
<li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
<a href="#">
<span class="mui-icon mui-icon-phone"></span>
<div class="mui-media-body">Phone</div>
</a>
</li>
</ul>
<ul class="mui-table-view" id='data_list'>
<li class="mui-table-view-cell mui-media">
<a href="javascript:;">
<img class="mui-media-object mui-pull-left" src="">
<div class="mui-media-body">
幸福
<p class="mui-ellipsis">能和心爱的人一起睡觉,是件幸福的事情;可是,打呼噜怎么办?</p>
</div>
</a>
</li>
</ul>
</div>
<script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
mui.init()
mui.ready(function () {
mui.get(window.serv + '/get_list',{
},function(data){
for (var i=0; i<data.data.length; i++) {
get_data(data.data[i])
}
},'json'
);
function get_data(data) {
var li = document.createElement('li');
li.className = "mui-table-view-cell mui-media";
var a = document.createElement('a');
a.addEventListener('tap',function() {
mui.openWindow(
'player.html',
'player.html',
{
styles:{
top:'0px',//子页面顶部位置
bottom:'50px',//子页面底部位置
},
extras:data,
createnew:true,
})
});
var img = document.createElement('img');
img.className = "mui-media-object mui-pull-left"
img.src = window.serv_cover + '/' + data.music_file.split('.')[0] + '.jpg';
var div = document.createElement('div');
div.className = "mui-media-body"
div.innerText = data.title;
var p = document.createElement('p');
p.className = "mui-ellipsis"
p.innerText = data.title;
// 创建Dom层级结构
li.appendChild(a);
a.appendChild(img);
a.appendChild(div);
div.appendChild(p);
// 添加data_list中的Dom对象
document.getElementById('data_list').appendChild(li)
};
});
</script>
</body>
</html>
2.2.1.3 player.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<link rel="stylesheet" type="text/css" href="css/mui.css"/>
</head>
<body>
<header class="mui-bar mui-bar-nav">
<h1 class="mui-title" id="title"></h1>
</header>
<div class="mui-content">
<div class="mui-row" style="text-align: center; margin-top: 50px;">
<img id="cover" style="width: 250px; height: 250px; border-radius: 50%;" />
</div>
<div class="mui-row" style="text-align: center; margin-top: 50px;">
<audio autoplay controls id="player"></audio>
</div>
<div class="mui-row" style="text-align: center; margin-top: 15px;">
<button type="button" class="mui-btn mui-btn-blue" id="play">播放</button>
<button type="button" class="mui-btn mui-btn-red" id="pause">暂停</button>
<button type="button" class="mui-btn mui-btn-blue" id='resume'>继续</button>
</div>
<div class="mui-row" style="text-align: center;margin-top: 25px;" >
<button type="button" class="mui-btn mui-btn-purple mui-btn-block" id="send_music">发送歌曲</button>
</div>
</div>
<script src="js/mui.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
mui.init()
var play = null;
mui.plusReady(function () {
var player_wv = plus.webview.currentWebview();
console.log(JSON.stringify(player_wv))
document.getElementById('title').innerText = player_wv.title + '--正常播放';
document.getElementById('cover').src = window.serv_cover + '/'+player_wv.music_file.split('.')[0]+'.jpg';
palyer = document.getElementById("player");
player.src = window.serv_music + '/' + player_wv.music_file;
})
document.getElementById('play').addEventListener('tap',function () {
player.play();
});
document.getElementById('pause').addEventListener('tap',function () {
player.pause();
});
document.getElementById('resume').addEventListener('tap',function () {
player.resume();
});
</script>
</body>
</html>
2.2.2 后端
2.2.2.1 setting.py
HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36"
}
CONTENT_LIST_URL = "https://www.example.com/revision/album/v1/getTracksList?albumId=%s&pageNum=%s&sort=0&pageSize=30"
SOUND_URL = 'https://www.example.com/revision/play/v1/audio?id=%s&ptype=1'
IMG_HOST = 'http://imagev2.example.com/'
from pymongo import MongoClient
MC = MongoClient(host='127.0.0.1', port=27017)
MongoDB = MC['erge']
import os
COVER_PATH = os.path.join('data', 'cover')
MUSIC_PATH = os.path.join('data', 'music')
RET = {
"code": 0,
"msg": "",
"data": {}
}
2.2.2.2 bp/erge_display.py
from flask import Flask
from bp.users import users_bp
from bp.erge_display import display_bp
app = Flask(__name__)
app.config['DEBUG'] = True
app.register_blueprint(users_bp)
app.register_blueprint(display_bp)
if __name__ == '__main__':
app.run('0.0.0.0', 80)
2.2.2.3 bp/users.py
from flask import Blueprint, request, jsonify, render_template
from pro01.setting import MongoDB, RET
users_bp = Blueprint('users_bp', __name__)
@users_bp.route('/signin', methods=['POST'])
def register():
# 获取FormData中的数据
user_info = request.form.to_dict()
# 将数据转换成字典 直接存放在MongoDB中
res = MongoDB.users.insert_one(user_info)
if res.inserted_id:
RET["code"] = 0
RET["msg"] = "注册成功"
RET["data"] = {}
return jsonify(RET)
else:
RET["code"] = 1
RET["msg"] = "注册失败"
RET["data"] = {}
return jsonify(RET)
@users_bp.route("/login", methods=["POST"])
def login():
login_info = request.form.to_dict()
user_info = MongoDB.users.find_one(login_info)
print(login_info)
if not user_info:
# 登录失败
RET["code"] = 1
RET["msg"] = "用户名密码错误"
RET["data"] = {}
return jsonify(RET)
else:
user_info["_id"] = str(user_info.get("_id"))
user_info.pop("password") # 删除敏感字段
RET["code"] = 0
RET["msg"] = "登录成功"
RET["data"] = user_info
return jsonify(RET)
2.2.2.4 app.py
from flask import Flask
from bp.users import users_bp
from bp.erge_display import display_bp
app = Flask(__name__)
app.config['DEBUG'] = True
app.register_blueprint(users_bp)
app.register_blueprint(display_bp)
if __name__ == '__main__':
app.run('0.0.0.0', 80)