预览
migu.py
# -*- coding: utf-8 -*-import osimport threadingimport webbrowserimport requestsfrom flask import Flaskfrom flask import render_template, send_from_directoryfrom flask import requestfrom 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 dataif __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>