预览
migu.py
# -*- coding: utf-8 -*-
import os
import threading
import webbrowser
import requests
from flask import Flask
from flask import render_template, send_from_directory
from flask import request
from flask_cors import CORS
# html同级
app = Flask(__name__, template_folder=".")
CORS(app, resources='/*')
app.jinja_env.variable_start_string = '{['
app.jinja_env.variable_end_string = ']}'
def request_parse():
if request.method == 'POST' or request.method == 'PUT':
return request.json
elif request.method == 'GET' or request.method == 'DELETE':
return request.args
@app.route('/getList', methods=['GET'])
def getList():
# region 参数
data = request_parse()
pageNum = data.get("pageNum")
pageSize = data.get("pageSize")
keyword = data.get("keyword")
if not keyword:
return {
"resultCode": 400,
"msg": "未输入歌手|歌名"
}
params = {
'feature': '1111000000',
'isCopyright': 1,
'isCorrect': 1,
'pageIndex': pageNum,
'pageSize': pageSize,
'searchSwitch': '{"song":1,"album":0,"singer":0,"tagSong":1,"mvSong":0,"songlist":0,"bestShow":1,"lyricSong":0,"concert":0,"periodical":0,"ticket":0,"bit24":0,"verticalVideoTone":0}',
'sid': 'E02D5216B02446F0BB85363041291C22B8EAB6797442459B9C1C5B29DEED3612',
'sort': 0,
'text': keyword,
'uiVersion': 'I_music_3.0.2',
}
headers = {
"User-Agent": "MGMobileMusic/6.9.9 (iPhone; iOS 13.1.3; Scale/2.00)",
"version": "6.9.9",
"uiVersion": "I_music_3.0.2",
"timeStamp": "1605096959",
"sign": "8a560d2511c002186d2dfa0bac44b9b7",
}
resp = requests.get('http://jadeite.migu.cn:7090/music_search/v2/search/searchAll', params=params, headers=headers)
print(resp.url)
resultList = resp.json()["songResultData"]["resultList"]
resultNum = resp.json()["resultNum"]
result = []
for itemList in resultList:
for item in itemList:
singers = ','.join([singer.get("name", "") for singer in item.get('singers')])
song = {
'song_name': item.get('name'), # 歌名
'singers': singers # 歌手字符串集合
}
# rate_list = item.get('rateFormats', [])
rate_list = item.get('newRateFormats', [])
urls = {}
for x in rate_list:
if x.get('url', None):
urls[x.get('formatType')] = x.get('url').replace('ftp://218.200.160.122:21',
'http://freetyst.nf.migu.cn')
urls[x.get('formatType') + "_size"] = int(x.get('size')) / 1024 / 1024
urls[x.get('formatType') + "_size"] = round(urls[x.get('formatType') + "_size"], 2)
else:
format_type = x.get('formatType')
if format_type == 'SQ':
urls['SQ'] = x.get('androidUrl').replace('ftp://218.200.160.122:21',
'http://freetyst.nf.migu.cn')
urls["SQ_size"] = int(x.get('androidSize')) / 1024 / 1024
urls["SQ_size"] = round(urls["SQ_size"], 2)
elif format_type == 'ZQ':
urls['ZQ'] = x.get('androidUrl').replace('ftp://218.200.160.122:21',
'http://freetyst.nf.migu.cn')
urls["ZQ_size"] = int(x.get('androidSize')) / 1024 / 1024
urls["ZQ_size"] = round(urls["ZQ_size"], 2)
song['urls'] = urls
result.append(song)
return {
"resultCode": 200,
"total": resultNum,
"rows": result,
}
@app.route('/downloadSong', methods=['GET'])
def downloadSong():
data = request_parse()
singers = data.get("singers")
song_name = data.get("song_name").strip()
url = data.get("url")
size = data.get("size")
# static/down/歌曲名/大小/文件
dir_path = "static/down/" + song_name + "/" + size
if not os.path.exists(dir_path):
os.makedirs(dir_path)
file_name = singers + " - " + song_name + url[url.rfind("."):] # 起风了.mp3
file_path = dir_path + "/" + file_name
if not os.path.exists(file_path):
print("开始下载...")
with open(file_path, mode="wb") as f:
f.write(requests.get(url).content)
print("下载成功:", file_path)
else:
print("文件存在,直接返回")
return send_from_directory(dir_path, file_name, as_attachment=True)
@app.route("/")
def index():
return render_template('index.html')
def openUrl(port):
if os.path.exists("static/down"):
for root, dirs, files in os.walk("static/down"):
for file in files:
file_path = os.path.join(root, file)
if os.path.getsize(file_path) == 0:
os.remove(file_path)
print("清理空文件:", file_path)
webbrowser.open("http://127.0.0.1:{}".format(port), new=0)
@app.errorhandler(Exception)
def error_handler(e):
print("全局异常捕获: {}".format(e))
data = {
"resultCode": 500,
"msg": str(e)
}
return data
if __name__ == '__main__':
port = 777
if not os.environ.get('WERKZEUG_RUN_MAIN'):
th = threading.Thread(target=openUrl, args=(port,))
th.start()
else:
print("热加载\n")
app.run(host="0.0.0.0", port=port, debug=True)
index.html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>咪咕音乐</title>
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js"></script>
<link rel="shortcut icon" href="static/favicon.ico" type="image/x-icon"/>
</head>
<style>
body {
width: 70%;
margin: auto;
margin-top: 20px;
}
::-webkit-scrollbar {
width: 0;
}
</style>
<body>
<div id="app">
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form-item label="" prop="keyword">
<el-input
v-model="queryParams.keyword"
placeholder="请输入歌曲|歌手"
clearable
size="mini"
@keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
</el-form-item>
<el-form-item style="margin-top: 5px">
<el-pagination
background
:current-page.sync="queryParams.pageNum"
:page-sizes="[10, 15, 20, 25]"
:page-size.sync="queryParams.pageSize"
layout="total, sizes, prev, pager, next"
@size-change="getList"
@current-change="getList"
:total="total">
</el-pagination>
</el-form-item>
</el-form>
<el-table v-loading="loading" element-loading-text="正在进行中,请等待..." :data="songList">
<el-table-column label="歌名" align="center" prop="song_name"></el-table-column>
<el-table-column label="歌手" align="center" prop="singers"></el-table-column>
<el-table-column label="流畅" align="center">
<template slot-scope="scope" v-if="scope.row.urls && scope.row.urls.LQ">
<el-link type="primary" :underline="false" target="_blank"
:href="`/downloadSong?singers=${scope.row.singers}&size=${scope.row.urls.LQ_size}&song_name=${scope.row.song_name}&url=${scope.row.urls.LQ}`">
{{scope.row.urls.LQ_size}}M
</el-link>
</template>
</el-table-column>
<el-table-column label="普通" align="center">
<template slot-scope="scope" v-if="scope.row.urls && scope.row.urls.PQ">
<el-link type="primary" :underline="false" target="_blank"
:href="`/downloadSong?singers=${scope.row.singers}&size=${scope.row.urls.PQ_size}&song_name=${scope.row.song_name}&url=${scope.row.urls.PQ}`">
{{scope.row.urls.PQ_size}}M
</el-link>
</template>
</el-table-column>
<el-table-column label="高清" align="center">
<template slot-scope="scope" v-if="scope.row.urls && scope.row.urls.HQ">
<el-link type="primary" :underline="false" target="_blank"
:href="`/downloadSong?singers=${scope.row.singers}&size=${scope.row.urls.HQ_size}&song_name=${scope.row.song_name}&url=${scope.row.urls.HQ}`">
{{scope.row.urls.HQ_size}}M
</el-link>
</template>
</el-table-column>
<el-table-column label="无损" align="center">
<template slot-scope="scope" v-if="scope.row.urls && scope.row.urls.SQ">
<el-link type="primary" :underline="false" target="_blank"
:href="`/downloadSong?singers=${scope.row.singers}&size=${scope.row.urls.SQ_size}&song_name=${scope.row.song_name}&url=${scope.row.urls.SQ}`">
{{scope.row.urls.SQ_size}}M
</el-link>
</template>
</el-table-column>
<el-table-column label="至臻" align="center">
<template slot-scope="scope" v-if="scope.row.urls && scope.row.urls.ZQ">
<el-link type="primary" :underline="false" target="_blank"
:href="`/downloadSong?singers=${scope.row.singers}&size=${scope.row.urls.ZQ_size}&song_name=${scope.row.song_name}&url=${scope.row.urls.ZQ}`">
{{scope.row.urls.ZQ_size}}M
</el-link>
</template>
</el-table-column>
</el-table>
</div>
</div>
</body>
<script>
baseUrl = "http://127.0.0.1:777"
new Vue({
el: '#app',
data() {
return {
// 遮罩层
loading: false,
// 总条数
total: 0,
songList: [],
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
keyword: "起风了",
},
};
},
created() {
},
methods: {
// 查询列表
getList() {
this.loading = true;
axios({
method: 'get',
url: baseUrl + '/getList',
params: this.queryParams,
}).then(res => {
const response = res.data;
const resultCode = response.resultCode
if (resultCode === 200) {
this.songList = response.rows;
this.total = response.total;
} else {
this.$message({
message: '查询失败,' + response.msg,
type: 'error'
});
}
this.loading = false;
}).catch(function (error) {
console.log(error);
});
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
downloadSong(singers, song_name, url) {
axios({
method: 'get',
url: baseUrl + '/downloadSong',
params: {
"singers": singers,
"song_name": song_name,
"url": url
},
}).then(res => {
/*const response = res.data;
const resultCode = response.resultCode
if (resultCode === 200) {
} else {
this.$message({
message: '下载失败,' + response.msg,
type: 'error'
});
}*/
}).catch(function (error) {
console.log(error);
});
},
changeLink(link) {
window.location.href = link
}
}
})
</script>
</html>