-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapi.php
More file actions
398 lines (328 loc) · 14.4 KB
/
api.php
File metadata and controls
398 lines (328 loc) · 14.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
<?php
/**************************************************
* MKOnlinePlayer v2.4
* 后台音乐数据抓取模块
* 编写:mengkun(https://mkblog.cn)
* 时间:2018-3-11
* 特别感谢 @metowolf 提供的 Meting.php
*************************************************/
/************ ↓↓↓↓↓ 如果网易云音乐歌曲获取失效,请将你的 COOKIE 放到这儿 ↓↓↓↓↓ ***************/
$netease_cookie = '';
/************ ↑↑↑↑↑ 如果网易云音乐歌曲获取失效,请将你的 COOKIE 放到这儿 ↑↑↑↑↑ ***************/
/**
* cookie 获取及使用方法见
* https://github.com/mengkunsoft/MKOnlineMusicPlayer/wiki/%E7%BD%91%E6%98%93%E4%BA%91%E9%9F%B3%E4%B9%90%E9%97%AE%E9%A2%98
*
* 更多相关问题可以查阅项目 wiki
* https://github.com/mengkunsoft/MKOnlineMusicPlayer/wiki
*
* 如果还有问题,可以提交 issues
* https://github.com/mengkunsoft/MKOnlineMusicPlayer/issues
**/
define('HTTPS', true); // 如果您的网站启用了https,请将此项置为“true”,如果你的网站未启用 https,建议将此项设置为“false”
define('DEBUG', false); // 是否开启调试模式,正常使用时请将此项置为“false”
define('JSONP', false); // 是否开启JSONP模式,使用远程api时请开启
define('CACHE_PATH', 'cache/'); // 文件缓存目录,请确保该目录存在且有读写权限。如无需缓存,可将此行注释掉
// 可选:将搜索/播放/歌词等请求代理到 gdstudio 的音乐 API
define('REMOTE_GDSTUDIO', 'https://music-api.gdstudio.xyz/api.php');
/*
如果遇到程序不能正常运行,请开启调试模式,然后访问 http://你的网站/音乐播放器地址/api.php ,进入服务器运行环境检测。
此外,开启调试模式后,程序将输出详细的运行错误信息,方便定位错误原因。
因为调试模式下程序会输出服务器环境信息,为了您的服务器安全,正常使用时请务必关闭调试。
*/
/*****************************************************************************************************/
if(!defined('DEBUG') || DEBUG !== true) error_reporting(0); // 屏蔽服务器错误
require_once('plugns/Meting.php');
require_once('plugns/Download.php');
use Metowolf\Meting;
use Mxue\Download;
$source = getParam('source', 'netease'); // 歌曲源
$API = new Meting($source);
$DOWNLOAD = new Download($source);
$API->format(true); // 启用格式化功能
/**
* 将部分请求代理到 gdstudio 的 music-api 服务。
* 该远端 API 使用与前端相同的参数名(types/source/name/id 等),
* 因此直接转发即可。代理的 types 包括:search, url, pic, lyric
*/
function proxy_to_gdstudio_if_needed($types) {
// 不代理歌词请求,歌词仍使用本地实现以保留缓存和原始格式
$remote_types = array('search','url','pic');
if(!defined('REMOTE_GDSTUDIO') || REMOTE_GDSTUDIO == '') return false;
if(!in_array($types, $remote_types)) return false;
// 合并参数(POST 优先覆盖 GET)
$params = array();
foreach($_GET as $k=>$v) $params[$k] = $v;
foreach($_POST as $k=>$v) $params[$k] = $v;
// 构建远端查询字符串(远端期望同名参数,例如 types/name/source/id)
$query = http_build_query($params);
$url = rtrim(REMOTE_GDSTUDIO, '?') . '?' . $query;
// 请求远端 API
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$err = curl_error($ch);
curl_close($ch);
if($response === false || $http_code >= 400) {
$errMsg = array('code' => -1, 'msg' => 'Remote gdstudio request failed', 'error' => $err, 'http_code' => $http_code);
echojson(json_encode($errMsg));
return true;
}
// 远端返回的 JSON 结构与前端期望的结构基本一致(search 返回数组,url/pic/lyric 返回对象),
// 直接返回远程响应给前端即可。
echojson($response);
return true;
}
if($source == 'kugou' || $source == 'baidu' || $source == 'tencent') {
define('NO_HTTPS', true); // 酷狗、百度音乐和QQ源暂不支持 https
} elseif(($source == 'netease') && $netease_cookie) {
$API->cookie($netease_cookie); // 解决网易云 Cookie 失效
}
// 没有缓存文件夹则创建
if(defined('CACHE_PATH') && !is_dir(CACHE_PATH)) createFolders(CACHE_PATH);
$types = getParam('types');
// 先判断是否需要将请求代理到 gdstudio 的远端 API
if($types && proxy_to_gdstudio_if_needed($types)) {
return; // 已输出远端响应,终止本地处理
}
switch($types) // 根据请求的 Api,执行相应操作
{
case 'url': // 获取歌曲链接
$id = getParam('id'); // 歌曲ID
$data = $API->url($id);
echojson($data);
break;
case 'pic': // 获取封面链接
$id = getParam('id'); // 歌曲ID
$data = $API->pic($id);
echojson($data);
break;
case 'lyric': // 获取歌词
$id = getParam('id'); // 歌曲ID
if(defined('CACHE_PATH')) {
$cache = CACHE_PATH.$source.'_'.$types.'_'.$id.'.json';
if(file_exists($cache)) { // 缓存存在,则读取缓存
$data = file_get_contents($cache);
} else {
$data = $API->lyric($id);
// 只缓存链接获取成功的歌曲
if(isset($data) && isset(json_decode($data)->lyric)) {
file_put_contents($cache, $data);
}
}
} else {
$data = $API->lyric($id);
}
echojson($data);
break;
case 'userlist': // 获取用户歌单列表
$uid = getParam('uid'); // 用户ID
if(defined('CACHE_PATH')) {
$cache = CACHE_PATH.$source.'_'.$types.'_'.$uid.'.json';
if(file_exists($cache)) { // 缓存存在,则读取缓存
$data = file_get_contents($cache);
} else {
$url= 'http://music.163.com/api/user/playlist/?offset=0&limit=1001&uid='.$uid;
$data = file_get_contents($url);
// 只缓存链接获取成功的用户列表
if(isset($data) && isset(json_decode($data)->playlist)) {
file_put_contents($cache, $data);
}
}
} else {
$url= 'http://music.163.com/api/user/playlist/?offset=0&limit=1001&uid='.$uid;
$data = file_get_contents($url);
}
echojson($data);
break;
case 'playlist': // 获取歌单中的歌曲
$id = getParam('id'); // 歌单ID
if(defined('CACHE_PATH')) {
$cache = CACHE_PATH.$source.'_'.$types.'_'.$id.'.json';
if(file_exists($cache)) { // 缓存存在,则读取缓存
$data = file_get_contents($cache);
} else {
$data = $API->format(false)->playlist($id);
// 只缓存链接获取成功的歌曲
if(isset($data) && isset(json_decode($data)->playlist->tracks)) {
file_put_contents($cache, $data);
}
}
} else {
$data = $API->format(false)->playlist($id);
}
echojson($data);
break;
case 'search': // 搜索歌曲
$s = getParam('name'); // 歌名
$limit = getParam('count', 20); // 每页显示数量
$pages = getParam('pages', 1); // 页码
if(defined('CACHE_PATH')) {
$cache = CACHE_PATH.$source.'_'.$types.'_'.md5($s).'_'.$pages.'_'.$limit.'.json';
if(file_exists($cache)) { // 缓存存在,则读取缓存
$data = file_get_contents($cache);
} else {
$data = $API->search($s, [
'page' => $pages,
'limit' => $limit
]);
// 只缓存链接获取成功的歌曲
if(isset($data) && json_decode($data)) {
file_put_contents($cache, $data);
}
}
} else {
$data = $API->search($s, [
'page' => $pages,
'limit' => $limit
]);
}
echojson($data);
break;
case 'comments': // 获取评论
$id = getParam('id'); // 歌曲id
$limit = getParam('count', 50); // 每页显示数量
$pages = getParam('pages', 1); // 页码
if(defined('CACHE_PATH')) {
$cache = CACHE_PATH.$source.'_'.$types.'_'.$id.'_'.$pages.'_'.$limit.'.json';
if(file_exists($cache)) { // 缓存存在,则读取缓存
$data = file_get_contents($cache);
} else {
$data = $API->comments($id, [
'page' => $pages,
'limit' => $limit
]);
// 只缓存链接获取成功的歌曲
if(isset($data) && (isset(json_decode($data)->hot_comment) || isset(json_decode($data)->comment))) {
file_put_contents($cache, $data);
}
}
} else {
$data = $API->comments($id, [
'page' => $pages,
'limit' => $limit
]);
}
echojson($data);
break;
case 'download': // 下载歌曲
$url = getParam('url');
$name = getParam('name');
$artist = getParam('artist');
$data = $DOWNLOAD->download($url, $name, $artist);
echojson($data);
break;
case 'cache':
$minute = getParam('minute', 30); // 删除几分钟之前的文件
date_default_timezone_set('Asia/Shanghai'); // 如果时区不同请自行设置时区
$list = scandir(CACHE_PATH);
$jsonList = array();
foreach ($list as $val) {
$filePath = CACHE_PATH.$val;
if (is_file($filePath) && pathinfo($filePath, PATHINFO_EXTENSION) === 'json') {
array_push($jsonList, $filePath);
}
}
$data = array(
'total_cache_files' => count($jsonList),
'deleted_files' => array(),
'failed_files' => array(),
'retained_files' => count($jsonList)
);
foreach($jsonList as $val) {
if (strtotime('+'.$minute.' minute', filemtime($val)) <= time()) {
$filetime = date('Y-m-d H:i:s', filemtime($val));
if (unlink($val)) {
array_push($data['deleted_files'], array(
'msg' => '删除成功。',
'time' => $filetime,
'file' => $val,
));
$data['retained_files']--;
} else {
array_push($data['failed_files'], array(
'msg' => '删除失败,请检查文件权限或其他问题。',
'time' => $filetime,
'file' => $val,
));
}
}
}
$data['status'] = 'success';
$data['message'] = '缓存清理完成。共 ' . count($data['deleted_files']) . ' 个文件被删除,' . $data['retained_files'] . ' 个文件被保留。';
echojson(json_encode($data));
break;
default:
echo '<!doctype html><html><head><meta charset="utf-8"><title>信息</title><style>* {font-family: microsoft yahei}</style></head><body> <h2>MKOnlinePlayer</h2><h3>Github: https://github.com/mengkunsoft/MKOnlineMusicPlayer</h3><br>';
if(!defined('DEBUG') || DEBUG !== true) { // 非调试模式
echo '<p>Api 调试模式已关闭</p>';
} else {
echo '<p><font color="red">您已开启 Api 调试功能,正常使用时请在 api.php 中关闭该选项!</font></p><br>';
echo '<p>PHP 版本:'.phpversion().' (本程序要求 PHP 5.4+)</p><br>';
echo '<p>服务器函数检查</p>';
echo '<p>curl_exec: '.checkfunc('curl_exec',true).' (用于获取音乐数据)</p>';
echo '<p>file_get_contents: '.checkfunc('file_get_contents',true).' (用于获取音乐数据)</p>';
echo '<p>json_decode: '.checkfunc('json_decode',true).' (用于后台数据格式化)</p>';
echo '<p>hex2bin: '.checkfunc('hex2bin',true).' (用于数据解析)</p>';
echo '<p>openssl_encrypt: '.checkfunc('openssl_encrypt',true).' (用于数据解析)</p>';
}
echo '</body></html>';
}
/**
* 创建多层文件夹
* @param $dir 路径
*/
function createFolders($dir) {
return is_dir($dir) or (createFolders(dirname($dir)) and mkdir($dir, 0755));
}
/**
* 检测服务器函数支持情况
* @param $f 函数名
* @param $m 是否为必须函数
* @return
*/
function checkfunc($f,$m = false) {
if (function_exists($f)) {
return '<font color="green">可用</font>';
} else {
if ($m == false) {
return '<font color="black">不支持</font>';
} else {
return '<font color="red">不支持</font>';
}
}
}
/**
* 获取GET或POST过来的参数
* @param $key 键值
* @param $default 默认值
* @return 获取到的内容(没有则为默认值)
*/
function getParam($key, $default='')
{
return trim($key && is_string($key) ? (isset($_POST[$key]) ? $_POST[$key] : (isset($_GET[$key]) ? $_GET[$key] : $default)) : $default);
}
/**
* 输出一个json或jsonp格式的内容
* @param $data 数组内容
*/
function echojson($data) //json和jsonp通用
{
header('Content-type: application/json');
$callback = getParam('callback');
if(defined('HTTPS') && HTTPS === true && !defined('NO_HTTPS')) { // 替换链接为 https
$data = str_replace('http:\/\/', 'https:\/\/', $data);
$data = str_replace('http://', 'https://', $data);
}
if(defined('JSONP') && JSONP === true && $callback) //输出jsonp格式
{
die(htmlspecialchars($callback).'('.$data.')');
} else {
die($data);
}
}