├── .gitignore
├── .editorconfig
├── .travis.yml
├── composer.json
├── LICENSE
├── README.md
└── src
└── Meting.php
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor/
2 | composer.lock
3 | .idea/
4 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | insert_final_newline = true
7 | indent_style = space
8 | indent_size = 2
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
14 | [*.yml]
15 | indent_style = space
16 | indent_size = 2
17 |
18 | [*.php]
19 | indent_style = space
20 | indent_size = 4
21 |
22 | [*.sh]
23 | indent_style = space
24 | indent_size = 4
25 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | matrix:
4 | fast_finish: true
5 |
6 | include:
7 | - php: '5.4'
8 | - php: '5.5'
9 | - php: '5.6'
10 | - php: '7.0'
11 | - php: '7.1'
12 | - php: '7.2'
13 | - php: '7.3'
14 | - php: '7.4'
15 | - php: 'nightly'
16 | - php: 'hhvm'
17 |
18 | allow_failures:
19 | - php: '5.4'
20 | - php: '5.5'
21 | - php: '5.6'
22 | - php: '7.0'
23 | - php: '7.1'
24 | - php: 'nightly'
25 | - php: 'hhvm'
26 |
27 | sudo: false
28 |
29 | script:
30 | - find -L . -name '*.php' -print0 | xargs -0 -n 1 -P 4 php -l
31 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "metowolf/meting",
3 | "type": "library",
4 | "description": "A powerful music API framework to accelerate development.",
5 | "keywords": [
6 | "php music",
7 | "music api",
8 | "lighty",
9 | "lightweight"
10 | ],
11 | "homepage": "https://github.com/metowolf/Meting",
12 | "license": "MIT",
13 | "authors": [
14 | {
15 | "name": "metowolf",
16 | "email": "i@i-meto.com",
17 | "homepage": "https://i-meto.com"
18 | }
19 | ],
20 | "support": {
21 | "issues": "https://github.com/metowolf/Meting/issues",
22 | "source": "https://github.com/metowolf/Meting"
23 | },
24 | "require": {
25 | "php": ">=5.4.0",
26 | "ext-curl": "*",
27 | "ext-openssl": "*"
28 | },
29 | "suggest": {
30 | "ext-bcmath": "Required to use BC Math calculate RSA.",
31 | "ext-openssl": "Required to use OpenSSL encrypt params."
32 | },
33 | "autoload": {
34 | "psr-4": {
35 | "Metowolf\\" : "src/"
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 METO
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | > :cake: Wow, such a powerful music API framework
14 |
15 | ## Introduction
16 | A powerful music API framework to accelerate your development
17 | + **Elegant** - Easy to use, a standardized format for all music platforms.
18 | + **Lightweight** - A single-file library that's less than 46KB.
19 | + **Powerful** - Support various music platforms, including Tencent, NetEase, Xiami, KuGou, Baidu and more.
20 | + **Free** - Under MIT license, need I say more?
21 |
22 | ## Requirement
23 | PHP 5.4+ and BCMath, Curl, OpenSSL extension installed.
24 |
25 | ## Installation
26 | Require this package, with [Composer](https://getcomposer.org), in the root directory of your project.
27 |
28 | ```bash
29 | $ composer require metowolf/meting
30 | ```
31 |
32 | Then you can import the class into your application:
33 |
34 | ```php
35 | use Metowolf\Meting;
36 |
37 | $api = new Meting('netease');
38 |
39 | $data = $api->format(true)->search('Soldier');
40 | ```
41 |
42 | > **Note:** Meting requires [BCMath](http://php.net/manual/en/book.bc.php), [cURL](http://php.net/manual/en/book.curl.php) and [OpenSSL](http://php.net/manual/en/book.openssl.php) extension in order to work.
43 |
44 |
45 | ## Quick Start
46 | ```php
47 | require 'vendor/autoload.php';
48 | // require 'Meting.php';
49 |
50 | use Metowolf\Meting;
51 |
52 | // Initialize to netease API
53 | $api = new Meting('netease');
54 |
55 | // Use custom cookie (option)
56 | // $api->cookie('paste your cookie');
57 |
58 | // Get data
59 | $data = $api->format(true)->search('Soldier', [
60 | 'page' => 1,
61 | 'limit' => 50
62 | ]);
63 |
64 | echo $data;
65 | // [{"id":35847388,"name":"Hello","artist":["Adele"],"album":"Hello","pic_id":"1407374890649284","url_id":35847388,"lyric_id":35847388,"source":"netease"},{"id":33211676,"name":"Hello","artist":["OMFG"],"album":"Hello",...
66 |
67 | // Parse link
68 | $data = $api->format(true)->url(35847388);
69 |
70 | echo $data;
71 | // {"url":"http:\/\/...","size":4729252,"br":128}
72 | ```
73 |
74 | ## More usage
75 | - [docs](https://github.com/metowolf/Meting/wiki)
76 | - [special for netease](https://github.com/metowolf/Meting/wiki/special-for-netease)
77 |
78 | ## Join the Discussion
79 | - [Telegram Group](https://t.me/adplayer)
80 | - [Official website](https://i-meto.com)
81 |
82 | ## Related Projects
83 | - [Hermit-X (Wordpress)](https://github.com/MoePlayer/Hermit-X)
84 | - [APlayer-Typecho](https://github.com/MoePlayer/APlayer-Typecho)
85 | - [MKOnlineMusicPlayer](https://github.com/mengkunsoft/MKOnlineMusicPlayer)
86 | - [WP-Player](https://github.com/webjyh/WP-Player)
87 | - [Meting4Net](https://github.com/yiyungent/Meting4Net)
88 |
89 | ## Author
90 |
91 | **Meting** © [metowolf](https://github.com/metowolf), Released under the [MIT](./LICENSE) License.
92 |
93 | > Blog [@meto](https://i-meto.com) · GitHub [@metowolf](https://github.com/metowolf) · Twitter [@metowolf](https://twitter.com/metowolf) · Telegram Channel [@metooooo](https://t.me/metooooo)
94 |
--------------------------------------------------------------------------------
/src/Meting.php:
--------------------------------------------------------------------------------
1 |
9 | * Released under the MIT license
10 | */
11 |
12 | namespace Metowolf;
13 |
14 | class Meting
15 | {
16 | const VERSION = '1.5.7';
17 |
18 | public $raw;
19 | public $data;
20 | public $info;
21 | public $error;
22 | public $status;
23 |
24 | public $server;
25 | public $proxy = null;
26 | public $format = false;
27 | public $header;
28 |
29 | public function __construct($value = 'netease')
30 | {
31 | $this->site($value);
32 | }
33 |
34 | public function site($value)
35 | {
36 | $suppose = array('netease', 'tencent', 'xiami', 'kugou', 'baidu');
37 | $this->server = in_array($value, $suppose) ? $value : 'netease';
38 | $this->header = $this->curlset();
39 |
40 | return $this;
41 | }
42 |
43 | public function cookie($value)
44 | {
45 | $this->header['Cookie'] = $value;
46 |
47 | return $this;
48 | }
49 |
50 | public function format($value = true)
51 | {
52 | $this->format = $value;
53 |
54 | return $this;
55 | }
56 |
57 | public function proxy($value)
58 | {
59 | $this->proxy = $value;
60 |
61 | return $this;
62 | }
63 |
64 | private function exec($api)
65 | {
66 | if (isset($api['encode'])) {
67 | $api = call_user_func_array(array($this, $api['encode']), array($api));
68 | }
69 | if ($api['method'] == 'GET') {
70 | if (isset($api['body'])) {
71 | $api['url'] .= '?'.http_build_query($api['body']);
72 | $api['body'] = null;
73 | }
74 | }
75 |
76 | $this->curl($api['url'], $api['body']);
77 |
78 | if (!$this->format) {
79 | return $this->raw;
80 | }
81 |
82 | $this->data = $this->raw;
83 |
84 | if (isset($api['decode'])) {
85 | $this->data = call_user_func_array(array($this, $api['decode']), array($this->data));
86 | }
87 | if (isset($api['format'])) {
88 | $this->data = $this->clean($this->data, $api['format']);
89 | }
90 |
91 | return $this->data;
92 | }
93 |
94 | private function curl($url, $payload = null, $headerOnly = 0)
95 | {
96 | $header = array_map(function ($k, $v) {
97 | return $k.': '.$v;
98 | }, array_keys($this->header), $this->header);
99 | $curl = curl_init();
100 | if (!is_null($payload)) {
101 | curl_setopt($curl, CURLOPT_POST, 1);
102 | curl_setopt($curl, CURLOPT_POSTFIELDS, is_array($payload) ? http_build_query($payload) : $payload);
103 | }
104 | curl_setopt($curl, CURLOPT_HEADER, $headerOnly);
105 | curl_setopt($curl, CURLOPT_TIMEOUT, 20);
106 | curl_setopt($curl, CURLOPT_ENCODING, 'gzip');
107 | curl_setopt($curl, CURLOPT_IPRESOLVE, 1);
108 | curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
109 | curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
110 | curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10);
111 | curl_setopt($curl, CURLOPT_URL, $url);
112 | curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
113 | if ($this->proxy) {
114 | curl_setopt($curl, CURLOPT_PROXY, $this->proxy);
115 | }
116 | for ($i = 0; $i < 3; $i++) {
117 | $this->raw = curl_exec($curl);
118 | $this->info = curl_getinfo($curl);
119 | $this->error = curl_errno($curl);
120 | $this->status = $this->error ? curl_error($curl) : '';
121 | if (!$this->error) {
122 | break;
123 | }
124 | }
125 | curl_close($curl);
126 |
127 | return $this;
128 | }
129 |
130 | private function pickup($array, $rule)
131 | {
132 | $t = explode('.', $rule);
133 | foreach ($t as $vo) {
134 | if (!isset($array[$vo])) {
135 | return array();
136 | }
137 | $array = $array[$vo];
138 | }
139 |
140 | return $array;
141 | }
142 |
143 | private function clean($raw, $rule)
144 | {
145 | $raw = json_decode($raw, true);
146 | if (!empty($rule)) {
147 | $raw = $this->pickup($raw, $rule);
148 | }
149 | if (!isset($raw[0]) && count($raw)) {
150 | $raw = array($raw);
151 | }
152 | $result = array_map(array($this, 'format_'.$this->server), $raw);
153 |
154 | return json_encode($result);
155 | }
156 |
157 | public function search($keyword, $option = null)
158 | {
159 | switch ($this->server) {
160 | case 'netease':
161 | $api = array(
162 | 'method' => 'POST',
163 | 'url' => 'http://music.163.com/api/cloudsearch/pc',
164 | 'body' => array(
165 | 's' => $keyword,
166 | 'type' => isset($option['type']) ? $option['type'] : 1,
167 | 'limit' => isset($option['limit']) ? $option['limit'] : 30,
168 | 'total' => 'true',
169 | 'offset' => isset($option['page']) && isset($option['limit']) ? ($option['page'] - 1) * $option['limit'] : 0,
170 | ),
171 | 'encode' => 'netease_AESCBC',
172 | 'format' => 'result.songs',
173 | );
174 | break;
175 | case 'tencent':
176 | $api = array(
177 | 'method' => 'GET',
178 | 'url' => 'https://c.y.qq.com/soso/fcgi-bin/client_search_cp',
179 | 'body' => array(
180 | 'format' => 'json',
181 | 'p' => isset($option['page']) ? $option['page'] : 1,
182 | 'n' => isset($option['limit']) ? $option['limit'] : 30,
183 | 'w' => $keyword,
184 | 'aggr' => 1,
185 | 'lossless' => 1,
186 | 'cr' => 1,
187 | 'new_json' => 1,
188 | ),
189 | 'format' => 'data.song.list',
190 | );
191 | break;
192 | case 'xiami':
193 | $api = array(
194 | 'method' => 'GET',
195 | 'url' => 'https://acs.m.xiami.com/h5/mtop.alimusic.search.searchservice.searchsongs/1.0/',
196 | 'body' => array(
197 | 'data' => array(
198 | 'key' => $keyword,
199 | 'pagingVO' => array(
200 | 'page' => isset($option['page']) ? $option['page'] : 1,
201 | 'pageSize' => isset($option['limit']) ? $option['limit'] : 30,
202 | ),
203 | ),
204 | 'r' => 'mtop.alimusic.search.searchservice.searchsongs',
205 | ),
206 | 'encode' => 'xiami_sign',
207 | 'format' => 'data.data.songs',
208 | );
209 | break;
210 | case 'kugou':
211 | $api = array(
212 | 'method' => 'GET',
213 | 'url' => 'http://mobilecdn.kugou.com/api/v3/search/song',
214 | 'body' => array(
215 | 'api_ver' => 1,
216 | 'area_code' => 1,
217 | 'correct' => 1,
218 | 'pagesize' => isset($option['limit']) ? $option['limit'] : 30,
219 | 'plat' => 2,
220 | 'tag' => 1,
221 | 'sver' => 5,
222 | 'showtype' => 10,
223 | 'page' => isset($option['page']) ? $option['page'] : 1,
224 | 'keyword' => $keyword,
225 | 'version' => 8990,
226 | ),
227 | 'format' => 'data.info',
228 | );
229 | break;
230 | case 'baidu':
231 | $api = array(
232 | 'method' => 'GET',
233 | 'url' => 'http://musicapi.taihe.com/v1/restserver/ting',
234 | 'body' => array(
235 | 'from' => 'qianqianmini',
236 | 'method' => 'baidu.ting.search.merge',
237 | 'isNew' => 1,
238 | 'platform' => 'darwin',
239 | 'page_no' => isset($option['page']) ? $option['page'] : 1,
240 | 'query' => $keyword,
241 | 'version' => '11.2.1',
242 | 'page_size' => isset($option['limit']) ? $option['limit'] : 30,
243 | ),
244 | 'format' => 'result.song_info.song_list',
245 | );
246 | break;
247 | }
248 |
249 | return $this->exec($api);
250 | }
251 |
252 | public function song($id)
253 | {
254 | switch ($this->server) {
255 | case 'netease':
256 | $api = array(
257 | 'method' => 'POST',
258 | 'url' => 'http://music.163.com/api/v3/song/detail/',
259 | 'body' => array(
260 | 'c' => '[{"id":'.$id.',"v":0}]',
261 | ),
262 | 'encode' => 'netease_AESCBC',
263 | 'format' => 'songs',
264 | );
265 | break;
266 | case 'tencent':
267 | $api = array(
268 | 'method' => 'GET',
269 | 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_play_single_song.fcg',
270 | 'body' => array(
271 | 'songmid' => $id,
272 | 'platform' => 'yqq',
273 | 'format' => 'json',
274 | ),
275 | 'format' => 'data',
276 | );
277 | break;
278 | case 'xiami':
279 | $api = array(
280 | 'method' => 'GET',
281 | 'url' => 'https://acs.m.xiami.com/h5/mtop.alimusic.music.songservice.getsongdetail/1.0/',
282 | 'body' => array(
283 | 'data' => array(
284 | 'songId' => $id,
285 | ),
286 | 'r' => 'mtop.alimusic.music.songservice.getsongdetail',
287 | ),
288 | 'encode' => 'xiami_sign',
289 | 'format' => 'data.data.songDetail',
290 | );
291 | break;
292 | case 'kugou':
293 | $api = array(
294 | 'method' => 'POST',
295 | 'url' => 'http://m.kugou.com/app/i/getSongInfo.php',
296 | 'body' => array(
297 | 'cmd' => 'playInfo',
298 | 'hash' => $id,
299 | 'from' => 'mkugou',
300 | ),
301 | 'format' => '',
302 | );
303 | break;
304 | case 'baidu':
305 | $api = array(
306 | 'method' => 'GET',
307 | 'url' => 'http://musicapi.taihe.com/v1/restserver/ting',
308 | 'body' => array(
309 | 'from' => 'qianqianmini',
310 | 'method' => 'baidu.ting.song.getInfos',
311 | 'songid' => $id,
312 | 'res' => 1,
313 | 'platform' => 'darwin',
314 | 'version' => '1.0.0',
315 | ),
316 | 'encode' => 'baidu_AESCBC',
317 | 'format' => 'songinfo',
318 | );
319 | break;
320 | }
321 |
322 | return $this->exec($api);
323 | }
324 |
325 | public function album($id)
326 | {
327 | switch ($this->server) {
328 | case 'netease':
329 | $api = array(
330 | 'method' => 'POST',
331 | 'url' => 'http://music.163.com/api/v1/album/'.$id,
332 | 'body' => array(
333 | 'total' => 'true',
334 | 'offset' => '0',
335 | 'id' => $id,
336 | 'limit' => '1000',
337 | 'ext' => 'true',
338 | 'private_cloud' => 'true',
339 | ),
340 | 'encode' => 'netease_AESCBC',
341 | 'format' => 'songs',
342 | );
343 | break;
344 | case 'tencent':
345 | $api = array(
346 | 'method' => 'GET',
347 | 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_album_detail_cp.fcg',
348 | 'body' => array(
349 | 'albummid' => $id,
350 | 'platform' => 'mac',
351 | 'format' => 'json',
352 | 'newsong' => 1,
353 | ),
354 | 'format' => 'data.getSongInfo',
355 | );
356 | break;
357 | case 'xiami':
358 | $api = array(
359 | 'method' => 'GET',
360 | 'url' => 'https://acs.m.xiami.com/h5/mtop.alimusic.music.albumservice.getalbumdetail/1.0/',
361 | 'body' => array(
362 | 'data' => array(
363 | 'albumId' => $id,
364 | ),
365 | 'r' => 'mtop.alimusic.music.albumservice.getalbumdetail',
366 | ),
367 | 'encode' => 'xiami_sign',
368 | 'format' => 'data.data.albumDetail.songs',
369 | );
370 | break;
371 | case 'kugou':
372 | $api = array(
373 | 'method' => 'GET',
374 | 'url' => 'http://mobilecdn.kugou.com/api/v3/album/song',
375 | 'body' => array(
376 | 'albumid' => $id,
377 | 'area_code' => 1,
378 | 'plat' => 2,
379 | 'page' => 1,
380 | 'pagesize' => -1,
381 | 'version' => 8990,
382 | ),
383 | 'format' => 'data.info',
384 | );
385 | break;
386 | case 'baidu':
387 | $api = array(
388 | 'method' => 'GET',
389 | 'url' => 'http://musicapi.taihe.com/v1/restserver/ting',
390 | 'body' => array(
391 | 'from' => 'qianqianmini',
392 | 'method' => 'baidu.ting.album.getAlbumInfo',
393 | 'album_id' => $id,
394 | 'platform' => 'darwin',
395 | 'version' => '11.2.1',
396 | ),
397 | 'format' => 'songlist',
398 | );
399 | break;
400 | }
401 |
402 | return $this->exec($api);
403 | }
404 |
405 | public function artist($id, $limit = 50)
406 | {
407 | switch ($this->server) {
408 | case 'netease':
409 | $api = array(
410 | 'method' => 'POST',
411 | 'url' => 'http://music.163.com/api/v1/artist/'.$id,
412 | 'body' => array(
413 | 'ext' => 'true',
414 | 'private_cloud' => 'true',
415 | 'ext' => 'true',
416 | 'top' => $limit,
417 | 'id' => $id,
418 | ),
419 | 'encode' => 'netease_AESCBC',
420 | 'format' => 'hotSongs',
421 | );
422 | break;
423 | case 'tencent':
424 | $api = array(
425 | 'method' => 'GET',
426 | 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_singer_track_cp.fcg',
427 | 'body' => array(
428 | 'singermid' => $id,
429 | 'begin' => 0,
430 | 'num' => $limit,
431 | 'order' => 'listen',
432 | 'platform' => 'mac',
433 | 'newsong' => 1,
434 | ),
435 | 'format' => 'data.list',
436 | );
437 | break;
438 | case 'xiami':
439 | $api = array(
440 | 'method' => 'GET',
441 | 'url' => 'https://acs.m.xiami.com/h5/mtop.alimusic.music.songservice.getartistsongs/1.0/',
442 | 'body' => array(
443 | 'data' => array(
444 | 'artistId' => $id,
445 | 'pagingVO' => array(
446 | 'page' => 1,
447 | 'pageSize' => $limit,
448 | ),
449 | ),
450 | 'r' => 'mtop.alimusic.music.songservice.getartistsongs',
451 | ),
452 | 'encode' => 'xiami_sign',
453 | 'format' => 'data.data.songs',
454 | );
455 | break;
456 | case 'kugou':
457 | $api = array(
458 | 'method' => 'GET',
459 | 'url' => 'http://mobilecdn.kugou.com/api/v3/singer/song',
460 | 'body' => array(
461 | 'singerid' => $id,
462 | 'area_code' => 1,
463 | 'page' => 1,
464 | 'plat' => 0,
465 | 'pagesize' => $limit,
466 | 'version' => 8990,
467 | ),
468 | 'format' => 'data.info',
469 | );
470 | break;
471 | case 'baidu':
472 | $api = array(
473 | 'method' => 'GET',
474 | 'url' => 'http://musicapi.taihe.com/v1/restserver/ting',
475 | 'body' => array(
476 | 'from' => 'qianqianmini',
477 | 'method' => 'baidu.ting.artist.getSongList',
478 | 'artistid' => $id,
479 | 'limits' => $limit,
480 | 'platform' => 'darwin',
481 | 'offset' => 0,
482 | 'tinguid' => 0,
483 | 'version' => '11.2.1',
484 | ),
485 | 'format' => 'songlist',
486 | );
487 | break;
488 | }
489 |
490 | return $this->exec($api);
491 | }
492 |
493 | public function playlist($id)
494 | {
495 | switch ($this->server) {
496 | case 'netease':
497 | $api = array(
498 | 'method' => 'POST',
499 | 'url' => 'http://music.163.com/api/v6/playlist/detail',
500 | 'body' => array(
501 | 's' => '0',
502 | 'id' => $id,
503 | 'n' => '1000',
504 | 't' => '0',
505 | ),
506 | 'encode' => 'netease_AESCBC',
507 | 'format' => 'playlist.tracks',
508 | );
509 | break;
510 | case 'tencent':
511 | $api = array(
512 | 'method' => 'GET',
513 | 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_playlist_cp.fcg',
514 | 'body' => array(
515 | 'id' => $id,
516 | 'format' => 'json',
517 | 'newsong' => 1,
518 | 'platform' => 'jqspaframe.json',
519 | ),
520 | 'format' => 'data.cdlist.0.songlist',
521 | );
522 | break;
523 | case 'xiami':
524 | $api = array(
525 | 'method' => 'GET',
526 | 'url' => 'https://acs.m.xiami.com/h5/mtop.alimusic.music.list.collectservice.getcollectdetail/1.0/',
527 | 'body' => array(
528 | 'data' => array(
529 | 'listId' => $id,
530 | 'isFullTags' => false,
531 | 'pagingVO' => array(
532 | 'page' => 1,
533 | 'pageSize' => 1000,
534 | ),
535 | ),
536 | 'r' => 'mtop.alimusic.music.list.collectservice.getcollectdetail',
537 | ),
538 | 'encode' => 'xiami_sign',
539 | 'format' => 'data.data.collectDetail.songs',
540 | );
541 | break;
542 | case 'kugou':
543 | $api = array(
544 | 'method' => 'GET',
545 | 'url' => 'http://mobilecdn.kugou.com/api/v3/special/song',
546 | 'body' => array(
547 | 'specialid' => $id,
548 | 'area_code' => 1,
549 | 'page' => 1,
550 | 'plat' => 2,
551 | 'pagesize' => -1,
552 | 'version' => 8990,
553 | ),
554 | 'format' => 'data.info',
555 | );
556 | break;
557 | case 'baidu':
558 | $api = array(
559 | 'method' => 'GET',
560 | 'url' => 'http://musicapi.taihe.com/v1/restserver/ting',
561 | 'body' => array(
562 | 'from' => 'qianqianmini',
563 | 'method' => 'baidu.ting.diy.gedanInfo',
564 | 'listid' => $id,
565 | 'platform' => 'darwin',
566 | 'version' => '11.2.1',
567 | ),
568 | 'format' => 'content',
569 | );
570 | break;
571 | }
572 |
573 | return $this->exec($api);
574 | }
575 |
576 | public function url($id, $br = 320)
577 | {
578 | switch ($this->server) {
579 | case 'netease':
580 | $api = array(
581 | 'method' => 'POST',
582 | 'url' => 'http://music.163.com/api/song/enhance/player/url',
583 | 'body' => array(
584 | 'ids' => array($id),
585 | 'br' => $br * 1000,
586 | ),
587 | 'encode' => 'netease_AESCBC',
588 | 'decode' => 'netease_url',
589 | );
590 | break;
591 | case 'tencent':
592 | $api = array(
593 | 'method' => 'GET',
594 | 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_play_single_song.fcg',
595 | 'body' => array(
596 | 'songmid' => $id,
597 | 'platform' => 'yqq',
598 | 'format' => 'json',
599 | ),
600 | 'decode' => 'tencent_url',
601 | );
602 | break;
603 | case 'xiami':
604 | $api = array(
605 | 'method' => 'GET',
606 | 'url' => 'https://acs.m.xiami.com/h5/mtop.alimusic.music.songservice.getsongs/1.0/',
607 | 'body' => array(
608 | 'data' => array(
609 | 'songIds' => array(
610 | $id,
611 | ),
612 | ),
613 | 'r' => 'mtop.alimusic.music.songservice.getsongs',
614 | ),
615 | 'encode' => 'xiami_sign',
616 | 'decode' => 'xiami_url',
617 | );
618 | break;
619 | case 'kugou':
620 | $api = array(
621 | 'method' => 'POST',
622 | 'url' => 'http://media.store.kugou.com/v1/get_res_privilege',
623 | 'body' => json_encode(
624 | array(
625 | 'relate' => 1,
626 | 'userid' => '0',
627 | 'vip' => 0,
628 | 'appid' => 1000,
629 | 'token' => '',
630 | 'behavior' => 'download',
631 | 'area_code' => '1',
632 | 'clientver' => '8990',
633 | 'resource' => array(array(
634 | 'id' => 0,
635 | 'type' => 'audio',
636 | 'hash' => $id,
637 | )), )
638 | ),
639 | 'decode' => 'kugou_url',
640 | );
641 | break;
642 | case 'baidu':
643 | $api = array(
644 | 'method' => 'GET',
645 | 'url' => 'http://musicapi.taihe.com/v1/restserver/ting',
646 | 'body' => array(
647 | 'from' => 'qianqianmini',
648 | 'method' => 'baidu.ting.song.getInfos',
649 | 'songid' => $id,
650 | 'res' => 1,
651 | 'platform' => 'darwin',
652 | 'version' => '1.0.0',
653 | ),
654 | 'encode' => 'baidu_AESCBC',
655 | 'decode' => 'baidu_url',
656 | );
657 | break;
658 | }
659 | $this->temp['br'] = $br;
660 |
661 | return $this->exec($api);
662 | }
663 |
664 | public function lyric($id)
665 | {
666 | switch ($this->server) {
667 | case 'netease':
668 | $api = array(
669 | 'method' => 'POST',
670 | 'url' => 'http://music.163.com/api/song/lyric',
671 | 'body' => array(
672 | 'id' => $id,
673 | 'os' => 'linux',
674 | 'lv' => -1,
675 | 'kv' => -1,
676 | 'tv' => -1,
677 | ),
678 | 'encode' => 'netease_AESCBC',
679 | 'decode' => 'netease_lyric',
680 | );
681 | break;
682 | case 'tencent':
683 | $api = array(
684 | 'method' => 'GET',
685 | 'url' => 'https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg',
686 | 'body' => array(
687 | 'songmid' => $id,
688 | 'g_tk' => '5381',
689 | ),
690 | 'decode' => 'tencent_lyric',
691 | );
692 | break;
693 | case 'xiami':
694 | $api = array(
695 | 'method' => 'GET',
696 | 'url' => 'https://acs.m.xiami.com/h5/mtop.alimusic.music.lyricservice.getsonglyrics/1.0/',
697 | 'body' => array(
698 | 'data' => array(
699 | 'songId' => $id,
700 | ),
701 | 'r' => 'mtop.alimusic.music.lyricservice.getsonglyrics',
702 | ),
703 | 'encode' => 'xiami_sign',
704 | 'decode' => 'xiami_lyric',
705 | );
706 | break;
707 | case 'kugou':
708 | $api = array(
709 | 'method' => 'GET',
710 | 'url' => 'http://krcs.kugou.com/search',
711 | 'body' => array(
712 | 'keyword' => '%20-%20',
713 | 'ver' => 1,
714 | 'hash' => $id,
715 | 'client' => 'mobi',
716 | 'man' => 'yes',
717 | ),
718 | 'decode' => 'kugou_lyric',
719 | );
720 | break;
721 | case 'baidu':
722 | $api = array(
723 | 'method' => 'GET',
724 | 'url' => 'http://musicapi.taihe.com/v1/restserver/ting',
725 | 'body' => array(
726 | 'from' => 'qianqianmini',
727 | 'method' => 'baidu.ting.song.lry',
728 | 'songid' => $id,
729 | 'platform' => 'darwin',
730 | 'version' => '1.0.0',
731 | ),
732 | 'decode' => 'baidu_lyric',
733 | );
734 | break;
735 | }
736 |
737 | return $this->exec($api);
738 | }
739 |
740 | public function pic($id, $size = 300)
741 | {
742 | switch ($this->server) {
743 | case 'netease':
744 | $url = 'https://p3.music.126.net/'.$this->netease_encryptId($id).'/'.$id.'.jpg?param='.$size.'y'.$size;
745 | break;
746 | case 'tencent':
747 | $url = 'https://y.gtimg.cn/music/photo_new/T002R'.$size.'x'.$size.'M000'.$id.'.jpg?max_age=2592000';
748 | break;
749 | case 'xiami':
750 | $format = $this->format;
751 | $data = $this->format(false)->song($id);
752 | $this->format = $format;
753 | $data = json_decode($data, true);
754 | $url = $data['data']['data']['songDetail']['albumLogo'];
755 | $url = str_replace('http:', 'https:', $url).'@1e_1c_100Q_'.$size.'h_'.$size.'w';
756 | break;
757 | case 'kugou':
758 | $format = $this->format;
759 | $data = $this->format(false)->song($id);
760 | $this->format = $format;
761 | $data = json_decode($data, true);
762 | $url = $data['imgUrl'];
763 | $url = str_replace('{size}', '400', $url);
764 | break;
765 | case 'baidu':
766 | $format = $this->format;
767 | $data = $this->format(false)->song($id);
768 | $this->format = $format;
769 | $data = json_decode($data, true);
770 | $url = isset($data['songinfo']['pic_radio']) ? $data['songinfo']['pic_radio'] : $data['songinfo']['pic_small'];
771 | break;
772 | }
773 |
774 | return json_encode(array('url' => $url));
775 | }
776 |
777 | private function curlset()
778 | {
779 | switch ($this->server) {
780 | case 'netease':
781 | return array(
782 | 'Referer' => 'https://music.163.com/',
783 | 'Cookie' => 'appver=1.5.9; os=osx; __remember_me=true; osver=%E7%89%88%E6%9C%AC%2010.13.5%EF%BC%88%E7%89%88%E5%8F%B7%2017F77%EF%BC%89;',
784 | 'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/605.1.15 (KHTML, like Gecko)',
785 | 'X-Real-IP' => long2ip(mt_rand(1884815360, 1884890111)),
786 | 'Accept' => '*/*',
787 | 'Accept-Language' => 'zh-CN,zh;q=0.8,gl;q=0.6,zh-TW;q=0.4',
788 | 'Connection' => 'keep-alive',
789 | 'Content-Type' => 'application/x-www-form-urlencoded',
790 | );
791 | case 'tencent':
792 | return array(
793 | 'Referer' => 'http://y.qq.com',
794 | 'Cookie' => 'pgv_pvi=22038528; pgv_si=s3156287488; pgv_pvid=5535248600; yplayer_open=1; ts_last=y.qq.com/portal/player.html; ts_uid=4847550686; yq_index=0; qqmusic_fromtag=66; player_exist=1',
795 | 'User-Agent' => 'QQ%E9%9F%B3%E4%B9%90/54409 CFNetwork/901.1 Darwin/17.6.0 (x86_64)',
796 | 'Accept' => '*/*',
797 | 'Accept-Language' => 'zh-CN,zh;q=0.8,gl;q=0.6,zh-TW;q=0.4',
798 | 'Connection' => 'keep-alive',
799 | 'Content-Type' => 'application/x-www-form-urlencoded',
800 | );
801 | case 'xiami':
802 | return array(
803 | 'Cookie' => '_m_h5_tk=15d3402511a022796d88b249f83fb968_1511163656929; _m_h5_tk_enc=b6b3e64d81dae577fc314b5c5692df3c',
804 | 'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) XIAMI-MUSIC/3.1.1 Chrome/56.0.2924.87 Electron/1.6.11 Safari/537.36',
805 | 'Accept' => 'application/json',
806 | 'Content-type' => 'application/x-www-form-urlencoded',
807 | 'Accept-Language' => 'zh-CN',
808 | );
809 | case 'kugou':
810 | return array(
811 | 'User-Agent' => 'IPhone-8990-searchSong',
812 | 'UNI-UserAgent' => 'iOS11.4-Phone8990-1009-0-WiFi',
813 | );
814 | case 'baidu':
815 | return array(
816 | 'Cookie' => 'BAIDUID='.$this->getRandomHex(32).':FG=1',
817 | 'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) baidu-music/1.2.1 Chrome/66.0.3359.181 Electron/3.0.5 Safari/537.36',
818 | 'Accept' => '*/*',
819 | 'Content-type' => 'application/json;charset=UTF-8',
820 | 'Accept-Language' => 'zh-CN',
821 | );
822 | }
823 | }
824 |
825 | private function getRandomHex($length)
826 | {
827 | if (function_exists('random_bytes')) {
828 | return bin2hex(random_bytes($length / 2));
829 | }
830 | if (function_exists('mcrypt_create_iv')) {
831 | return bin2hex(mcrypt_create_iv($length / 2, MCRYPT_DEV_URANDOM));
832 | }
833 | if (function_exists('openssl_random_pseudo_bytes')) {
834 | return bin2hex(openssl_random_pseudo_bytes($length / 2));
835 | }
836 | }
837 |
838 | private function bchexdec($hex)
839 | {
840 | $dec = 0;
841 | $len = strlen($hex);
842 | for ($i = 1; $i <= $len; $i++) {
843 | $dec = bcadd($dec, bcmul(strval(hexdec($hex[$i - 1])), bcpow('16', strval($len - $i))));
844 | }
845 |
846 | return $dec;
847 | }
848 |
849 | private function bcdechex($dec)
850 | {
851 | $hex = '';
852 | do {
853 | $last = bcmod($dec, 16);
854 | $hex = dechex($last).$hex;
855 | $dec = bcdiv(bcsub($dec, $last), 16);
856 | } while ($dec > 0);
857 |
858 | return $hex;
859 | }
860 |
861 | private function str2hex($string)
862 | {
863 | $hex = '';
864 | for ($i = 0; $i < strlen($string); $i++) {
865 | $ord = ord($string[$i]);
866 | $hexCode = dechex($ord);
867 | $hex .= substr('0'.$hexCode, -2);
868 | }
869 |
870 | return $hex;
871 | }
872 |
873 | private function netease_AESCBC($api)
874 | {
875 | $modulus = '157794750267131502212476817800345498121872783333389747424011531025366277535262539913701806290766479189477533597854989606803194253978660329941980786072432806427833685472618792592200595694346872951301770580765135349259590167490536138082469680638514416594216629258349130257685001248172188325316586707301643237607';
876 | $pubkey = '65537';
877 | $nonce = '0CoJUm6Qyw8W8jud';
878 | $vi = '0102030405060708';
879 |
880 | if (extension_loaded('bcmath')) {
881 | $skey = $this->getRandomHex(16);
882 | } else {
883 | $skey = 'B3v3kH4vRPWRJFfH';
884 | }
885 |
886 | $body = json_encode($api['body']);
887 |
888 | if (function_exists('openssl_encrypt')) {
889 | $body = openssl_encrypt($body, 'aes-128-cbc', $nonce, false, $vi);
890 | $body = openssl_encrypt($body, 'aes-128-cbc', $skey, false, $vi);
891 | } else {
892 | $pad = 16 - (strlen($body) % 16);
893 | $body = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $nonce, $body.str_repeat(chr($pad), $pad), MCRYPT_MODE_CBC, $vi));
894 | $pad = 16 - (strlen($body) % 16);
895 | $body = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $skey, $body.str_repeat(chr($pad), $pad), MCRYPT_MODE_CBC, $vi));
896 | }
897 |
898 | if (extension_loaded('bcmath')) {
899 | $skey = strrev(utf8_encode($skey));
900 | $skey = $this->bchexdec($this->str2hex($skey));
901 | $skey = bcpowmod($skey, $pubkey, $modulus);
902 | $skey = $this->bcdechex($skey);
903 | $skey = str_pad($skey, 256, '0', STR_PAD_LEFT);
904 | } else {
905 | $skey = '85302b818aea19b68db899c25dac229412d9bba9b3fcfe4f714dc016bc1686fc446a08844b1f8327fd9cb623cc189be00c5a365ac835e93d4858ee66f43fdc59e32aaed3ef24f0675d70172ef688d376a4807228c55583fe5bac647d10ecef15220feef61477c28cae8406f6f9896ed329d6db9f88757e31848a6c2ce2f94308';
906 | }
907 |
908 | $api['url'] = str_replace('/api/', '/weapi/', $api['url']);
909 | $api['body'] = array(
910 | 'params' => $body,
911 | 'encSecKey' => $skey,
912 | );
913 |
914 | return $api;
915 | }
916 |
917 | private function baidu_AESCBC($api)
918 | {
919 | $key = 'DBEECF8C50FD160E';
920 | $vi = '1231021386755796';
921 |
922 | $data = 'songid='.$api['body']['songid'].'&ts='.intval(microtime(true) * 1000);
923 |
924 | if (function_exists('openssl_encrypt')) {
925 | $data = openssl_encrypt($data, 'aes-128-cbc', $key, false, $vi);
926 | } else {
927 | $pad = 16 - (strlen($data) % 16);
928 | $data = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data.str_repeat(chr($pad), $pad), MCRYPT_MODE_CBC, $vi));
929 | }
930 |
931 | $api['body']['e'] = $data;
932 |
933 | return $api;
934 | }
935 |
936 | private function xiami_sign($api)
937 | {
938 | $data = $this->curl('https://acs.m.xiami.com/h5/mtop.alimusic.recommend.songservice.getdailysongs/1.0/?appKey=12574478&t=1560663823000&dataType=json&data=%7B%22requestStr%22%3A%22%7B%5C%22header%5C%22%3A%7B%5C%22platformId%5C%22%3A%5C%22mac%5C%22%7D%2C%5C%22model%5C%22%3A%5B%5D%7D%22%7D&api=mtop.alimusic.recommend.songservice.getdailysongs&v=1.0&type=originaljson&sign=22ad1377ee193f3e2772c17c6192b17c', null, 1);
939 | preg_match_all('/_m_h5[^;]+/', $data->raw, $match);
940 | $this->header['Cookie'] = $match[0][0].'; '.$match[0][1];
941 | $data = json_encode(array(
942 | 'requestStr' => json_encode(array(
943 | 'header' => array(
944 | 'platformId' => 'mac',
945 | ),
946 | 'model' => $api['body']['data'],
947 | )),
948 | ));
949 | $appkey = '12574478';
950 | $cookie = $this->header['Cookie'];
951 | preg_match('/_m_h5_tk=([^_]+)/', $cookie, $match);
952 | $token = $match[1];
953 | $t = time() * 1000;
954 | $sign = md5(sprintf('%s&%s&%s&%s', $token, $t, $appkey, $data));
955 | $api['body'] = array(
956 | 'appKey' => $appkey,
957 | 't' => $t,
958 | 'dataType' => 'json',
959 | 'data' => $data,
960 | 'api' => $api['body']['r'],
961 | 'v' => '1.0',
962 | 'type' => 'originaljson',
963 | 'sign' => $sign,
964 | );
965 |
966 | return $api;
967 | }
968 |
969 | private function netease_encryptId($id)
970 | {
971 | $magic = str_split('3go8&$8*3*3h0k(2)2');
972 | $song_id = str_split($id);
973 | for ($i = 0; $i < count($song_id); $i++) {
974 | $song_id[$i] = chr(ord($song_id[$i]) ^ ord($magic[$i % count($magic)]));
975 | }
976 | $result = base64_encode(md5(implode('', $song_id), 1));
977 | $result = str_replace(array('/', '+'), array('_', '-'), $result);
978 |
979 | return $result;
980 | }
981 |
982 | private function netease_url($result)
983 | {
984 | $data = json_decode($result, true);
985 | if (isset($data['data'][0]['uf']['url'])) {
986 | $data['data'][0]['url'] = $data['data'][0]['uf']['url'];
987 | }
988 | if (isset($data['data'][0]['url'])) {
989 | $url = array(
990 | 'url' => $data['data'][0]['url'],
991 | 'size' => $data['data'][0]['size'],
992 | 'br' => $data['data'][0]['br'] / 1000,
993 | );
994 | } else {
995 | $url = array(
996 | 'url' => '',
997 | 'size' => 0,
998 | 'br' => -1,
999 | );
1000 | }
1001 |
1002 | return json_encode($url);
1003 | }
1004 |
1005 | private function tencent_url($result)
1006 | {
1007 | $data = json_decode($result, true);
1008 | $guid = mt_rand() % 10000000000;
1009 |
1010 | $type = array(
1011 | array('size_320mp3', 320, 'M800', 'mp3'),
1012 | array('size_192aac', 192, 'C600', 'm4a'),
1013 | array('size_128mp3', 128, 'M500', 'mp3'),
1014 | array('size_96aac', 96, 'C400', 'm4a'),
1015 | array('size_48aac', 48, 'C200', 'm4a'),
1016 | array('size_24aac', 24, 'C100', 'm4a'),
1017 | );
1018 |
1019 | $payload = array(
1020 | 'req_0' => array(
1021 | 'module' => 'vkey.GetVkeyServer',
1022 | 'method' => 'CgiGetVkey',
1023 | 'param' => array(
1024 | 'guid' => (string) $guid,
1025 | 'songmid' => array(),
1026 | 'filename' => array(),
1027 | 'songtype' => array(),
1028 | 'uin' => '0',
1029 | 'loginflag' => 1,
1030 | 'platform' => '20',
1031 | ),
1032 | ),
1033 | );
1034 |
1035 | foreach ($type as $vo) {
1036 | $payload['req_0']['param']['songmid'][] = $data['data'][0]['mid'];
1037 | $payload['req_0']['param']['filename'][] = $vo[2].$data['data'][0]['file']['media_mid'].'.'.$vo[3];
1038 | $payload['req_0']['param']['songtype'][] = $data['data'][0]['type'];
1039 | }
1040 |
1041 | $api = array(
1042 | 'method' => 'GET',
1043 | 'url' => 'https://u.y.qq.com/cgi-bin/musicu.fcg',
1044 | 'body' => array(
1045 | 'format' => 'json',
1046 | 'platform' => 'yqq.json',
1047 | 'needNewCode' => 0,
1048 | 'data' => json_encode($payload),
1049 | ),
1050 | );
1051 | $response = json_decode($this->exec($api), true);
1052 | $vkeys = $response['req_0']['data']['midurlinfo'];
1053 |
1054 | foreach ($type as $index => $vo) {
1055 | if ($data['data'][0]['file'][$vo[0]] && $vo[1] <= $this->temp['br']) {
1056 | if (!empty($vkeys[$index]['vkey'])) {
1057 | $url = array(
1058 | 'url' => $response['req_0']['data']['sip'][0].$vkeys[$index]['purl'],
1059 | 'size' => $data['data'][0]['file'][$vo[0]],
1060 | 'br' => $vo[1],
1061 | );
1062 | break;
1063 | }
1064 | }
1065 | }
1066 | if (!isset($url['url'])) {
1067 | $url = array(
1068 | 'url' => '',
1069 | 'size' => 0,
1070 | 'br' => -1,
1071 | );
1072 | }
1073 |
1074 | return json_encode($url);
1075 | }
1076 |
1077 | private function xiami_url($result)
1078 | {
1079 | $data = json_decode($result, true);
1080 |
1081 | $type = array(
1082 | 's' => 740,
1083 | 'h' => 320,
1084 | 'l' => 128,
1085 | 'f' => 64,
1086 | 'e' => 32,
1087 | );
1088 | $max = 0;
1089 | $url = array();
1090 | foreach ($data['data']['data']['songs'][0]['listenFiles'] as $vo) {
1091 | if ($type[$vo['quality']] <= $this->temp['br'] && $type[$vo['quality']] > $max) {
1092 | $max = $type[$vo['quality']];
1093 | $url = array(
1094 | 'url' => $vo['listenFile'],
1095 | 'size' => $vo['fileSize'],
1096 | 'br' => $type[$vo['quality']],
1097 | );
1098 | }
1099 | }
1100 | if (!isset($url['url'])) {
1101 | $url = array(
1102 | 'url' => '',
1103 | 'size' => 0,
1104 | 'br' => -1,
1105 | );
1106 | }
1107 |
1108 | return json_encode($url);
1109 | }
1110 |
1111 | private function kugou_url($result)
1112 | {
1113 | $data = json_decode($result, true);
1114 |
1115 | $max = 0;
1116 | $url = array();
1117 | foreach ($data['data'][0]['relate_goods'] as $vo) {
1118 | if ($vo['info']['bitrate'] <= $this->temp['br'] && $vo['info']['bitrate'] > $max) {
1119 | $api = array(
1120 | 'method' => 'GET',
1121 | 'url' => 'http://trackercdn.kugou.com/i/v2/',
1122 | 'body' => array(
1123 | 'hash' => $vo['hash'],
1124 | 'key' => md5($vo['hash'].'kgcloudv2'),
1125 | 'pid' => 3,
1126 | 'behavior' => 'play',
1127 | 'cmd' => '25',
1128 | 'version' => 8990,
1129 | ),
1130 | );
1131 | $t = json_decode($this->exec($api), true);
1132 | if (isset($t['url'])) {
1133 | $max = $t['bitRate'] / 1000;
1134 | $url = array(
1135 | 'url' => reset($t['url']),
1136 | 'size' => $t['fileSize'],
1137 | 'br' => $t['bitRate'] / 1000,
1138 | );
1139 | }
1140 | }
1141 | }
1142 | if (!isset($url['url'])) {
1143 | $url = array(
1144 | 'url' => '',
1145 | 'size' => 0,
1146 | 'br' => -1,
1147 | );
1148 | }
1149 |
1150 | return json_encode($url);
1151 | }
1152 |
1153 | private function baidu_url($result)
1154 | {
1155 | $data = json_decode($result, true);
1156 |
1157 | $max = 0;
1158 | $url = array();
1159 | foreach ($data['songurl']['url'] as $vo) {
1160 | if ($vo['file_bitrate'] <= $this->temp['br'] && $vo['file_bitrate'] > $max) {
1161 | $url = array(
1162 | 'url' => $vo['file_link'],
1163 | 'br' => $vo['file_bitrate'],
1164 | );
1165 | }
1166 | }
1167 | if (!isset($url['url'])) {
1168 | $url = array(
1169 | 'url' => '',
1170 | 'br' => -1,
1171 | );
1172 | }
1173 |
1174 | return json_encode($url);
1175 | }
1176 |
1177 | private function netease_lyric($result)
1178 | {
1179 | $result = json_decode($result, true);
1180 | $data = array(
1181 | 'lyric' => isset($result['lrc']['lyric']) ? $result['lrc']['lyric'] : '',
1182 | 'tlyric' => isset($result['tlyric']['lyric']) ? $result['tlyric']['lyric'] : '',
1183 | );
1184 |
1185 | return json_encode($data, JSON_UNESCAPED_UNICODE);
1186 | }
1187 |
1188 | private function tencent_lyric($result)
1189 | {
1190 | $result = substr($result, 18, -1);
1191 | $result = json_decode($result, true);
1192 | $data = array(
1193 | 'lyric' => isset($result['lyric']) ? base64_decode($result['lyric']) : '',
1194 | 'tlyric' => isset($result['trans']) ? base64_decode($result['trans']) : '',
1195 | );
1196 |
1197 | return json_encode($data, JSON_UNESCAPED_UNICODE);
1198 | }
1199 |
1200 | private function xiami_lyric($result)
1201 | {
1202 | $result = json_decode($result, true);
1203 |
1204 | if (count($result['data']['data']['lyrics'])) {
1205 | $data = $result['data']['data']['lyrics'][0]['content'];
1206 | $data = preg_replace('/<[^>]+>/', '', $data);
1207 | preg_match_all('/\[([\d:\.]+)\](.*)\s\[x-trans\](.*)/i', $data, $match);
1208 | if (count($match[0])) {
1209 | for ($i = 0; $i < count($match[0]); $i++) {
1210 | $A[] = '['.$match[1][$i].']'.$match[2][$i];
1211 | $B[] = '['.$match[1][$i].']'.$match[3][$i];
1212 | }
1213 | $arr = array(
1214 | 'lyric' => str_replace($match[0], $A, $data),
1215 | 'tlyric' => str_replace($match[0], $B, $data),
1216 | );
1217 | } else {
1218 | $arr = array(
1219 | 'lyric' => $data,
1220 | 'tlyric' => '',
1221 | );
1222 | }
1223 | } else {
1224 | $arr = array(
1225 | 'lyric' => '',
1226 | 'tlyric' => '',
1227 | );
1228 | }
1229 |
1230 | return json_encode($arr, JSON_UNESCAPED_UNICODE);
1231 | }
1232 |
1233 | private function kugou_lyric($result)
1234 | {
1235 | $result = json_decode($result, true);
1236 | $api = array(
1237 | 'method' => 'GET',
1238 | 'url' => 'http://lyrics.kugou.com/download',
1239 | 'body' => array(
1240 | 'charset' => 'utf8',
1241 | 'accesskey' => $result['candidates'][0]['accesskey'],
1242 | 'id' => $result['candidates'][0]['id'],
1243 | 'client' => 'mobi',
1244 | 'fmt' => 'lrc',
1245 | 'ver' => 1,
1246 | ),
1247 | );
1248 | $data = json_decode($this->exec($api), true);
1249 | $arr = array(
1250 | 'lyric' => base64_decode($data['content']),
1251 | 'tlyric' => '',
1252 | );
1253 |
1254 | return json_encode($arr, JSON_UNESCAPED_UNICODE);
1255 | }
1256 |
1257 | private function baidu_lyric($result)
1258 | {
1259 | $result = json_decode($result, true);
1260 | $data = array(
1261 | 'lyric' => isset($result['lrcContent']) ? $result['lrcContent'] : '',
1262 | 'tlyric' => '',
1263 | );
1264 |
1265 | return json_encode($data, JSON_UNESCAPED_UNICODE);
1266 | }
1267 |
1268 | private function format_netease($data)
1269 | {
1270 | $result = array(
1271 | 'id' => $data['id'],
1272 | 'name' => $data['name'],
1273 | 'artist' => array(),
1274 | 'album' => $data['al']['name'],
1275 | 'pic_id' => isset($data['al']['pic_str']) ? $data['al']['pic_str'] : $data['al']['pic'],
1276 | 'url_id' => $data['id'],
1277 | 'lyric_id' => $data['id'],
1278 | 'source' => 'netease',
1279 | );
1280 | if (isset($data['al']['picUrl'])) {
1281 | preg_match('/\/(\d+)\./', $data['al']['picUrl'], $match);
1282 | $result['pic_id'] = $match[1];
1283 | }
1284 | foreach ($data['ar'] as $vo) {
1285 | $result['artist'][] = $vo['name'];
1286 | }
1287 |
1288 | return $result;
1289 | }
1290 |
1291 | private function format_tencent($data)
1292 | {
1293 | if (isset($data['musicData'])) {
1294 | $data = $data['musicData'];
1295 | }
1296 | $result = array(
1297 | 'id' => $data['mid'],
1298 | 'name' => $data['name'],
1299 | 'artist' => array(),
1300 | 'album' => trim($data['album']['title']),
1301 | 'pic_id' => $data['album']['mid'],
1302 | 'url_id' => $data['mid'],
1303 | 'lyric_id' => $data['mid'],
1304 | 'source' => 'tencent',
1305 | );
1306 | foreach ($data['singer'] as $vo) {
1307 | $result['artist'][] = $vo['name'];
1308 | }
1309 |
1310 | return $result;
1311 | }
1312 |
1313 | private function format_xiami($data)
1314 | {
1315 | $result = array(
1316 | 'id' => $data['songId'],
1317 | 'name' => $data['songName'],
1318 | 'artist' => array(),
1319 | 'album' => $data['albumName'],
1320 | 'pic_id' => $data['songId'],
1321 | 'url_id' => $data['songId'],
1322 | 'lyric_id' => $data['songId'],
1323 | 'source' => 'xiami',
1324 | );
1325 | foreach ($data['singerVOs'] as $vo) {
1326 | $result['artist'][] = $vo['artistName'];
1327 | }
1328 |
1329 | return $result;
1330 | }
1331 |
1332 | private function format_kugou($data)
1333 | {
1334 | $result = array(
1335 | 'id' => $data['hash'],
1336 | 'name' => isset($data['filename']) ? $data['filename'] : $data['fileName'],
1337 | 'artist' => array(),
1338 | 'album' => isset($data['album_name']) ? $data['album_name'] : '',
1339 | 'url_id' => $data['hash'],
1340 | 'pic_id' => $data['hash'],
1341 | 'lyric_id' => $data['hash'],
1342 | 'source' => 'kugou',
1343 | );
1344 | list($result['artist'], $result['name']) = explode(' - ', $result['name'], 2);
1345 | $result['artist'] = explode('、', $result['artist']);
1346 |
1347 | return $result;
1348 | }
1349 |
1350 | private function format_baidu($data)
1351 | {
1352 | $result = array(
1353 | 'id' => $data['song_id'],
1354 | 'name' => $data['title'],
1355 | 'artist' => explode(',', $data['author']),
1356 | 'album' => $data['album_title'],
1357 | 'pic_id' => $data['song_id'],
1358 | 'url_id' => $data['song_id'],
1359 | 'lyric_id' => $data['song_id'],
1360 | 'source' => 'baidu',
1361 | );
1362 |
1363 | return $result;
1364 | }
1365 | }
1366 |
--------------------------------------------------------------------------------