├── .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 | Meting 3 |

4 | 5 |

6 | Author 7 | Version 8 | Downloads 9 | Travis 10 | License 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 | --------------------------------------------------------------------------------