├── neteasemusic ├── download │ └── .gitkeep ├── README.md ├── run.php └── meting.php ├── LSB ├── README.md └── LSB.py ├── README.md ├── bilibili ├── README.md └── onlineHeart.php └── UVa ├── LICENSE ├── download.sh ├── README.md └── UVadownload.ps1 /neteasemusic/download/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LSB/README.md: -------------------------------------------------------------------------------- 1 | ### LSB.py 2 | 3 | LSB 图片隐写,待完善 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 一些有趣的脚本 2 | 3 | - [UVa](https://github.com/metowolf/script/tree/master/UVa) UVaOJ PDF 批量下载脚本 4 | - [bilibili](https://github.com/metowolf/script/tree/master/bilibili) B 站直播挂机脚本(旧) 5 | - 已经独立为 https://github.com/metowolf/BilibiliHelper 6 | - [LSB](https://github.com/metowolf/script/tree/master/LSB) 写到一半的 LSB 图片隐写 7 | - [neteasemusic](https://github.com/metowolf/script/tree/master/neteasemusic) 妈妈再也不用担心我的网易云音乐变灰了 8 | -------------------------------------------------------------------------------- /bilibili/README.md: -------------------------------------------------------------------------------- 1 | ### onlineHeart.php 2 | bilibili 直播挂机,通过不断向服务器发送心跳包,达到欺骗目的从而实现 24H 涨经验升级 3 | 4 | 说明:上传 PHP 文件后,在头部修改为自己的 B 站 Cookie,进行一次手动测试,访问该页面看到 5 | ``` 6 | [2016-10-04 22:34:06] 7 | > INFO: already send @ 2016-10-04 22:30:01 8 | =============================== 9 | name: 雪狼meto 10 | level: 21 11 | exp: 4573000/8000000 57.16% 12 | sign: 今天已签到过 13 | =============================== 14 | ``` 15 | 的字样即为成功,然后设置服务器 5 分钟访问一次该页面即可实现挂机(crontab 或者第三方监控服务) 16 | -------------------------------------------------------------------------------- /LSB/LSB.py: -------------------------------------------------------------------------------- 1 | from PIL import Image 2 | 3 | def loadImage(filename): 4 | img = Image.open(filename) 5 | width, height = img.size 6 | img = img.convert("RGB") 7 | pixel = img.load() 8 | return width, height, pixel 9 | 10 | w1,h1,p1=loadImage("old.png") 11 | 12 | img=Image.new("RGB",(w1,h1)) 13 | pix=img.load() 14 | 15 | for y in xrange(0,h1): 16 | for x in xrange(0,w1): 17 | r,g,b=p1[x,y] 18 | pix[x,y]=r,g|1,b 19 | 20 | w2,h2,p2=loadImage("1481021344.png") 21 | for y in xrange(0,h2): 22 | for x in xrange(0,w2): 23 | r,g,b=p1[x,y] 24 | rr,gg,bb=p2[x,y] 25 | if(rr<20): 26 | r,g,b=r,g-1,b 27 | pix[x,y]=r,g,b 28 | 29 | img.save("stage.png") 30 | -------------------------------------------------------------------------------- /UVa/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016-2017 METO, Chijun Sima 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. -------------------------------------------------------------------------------- /neteasemusic/README.md: -------------------------------------------------------------------------------- 1 | # 妈妈再也不用担心我的网易云音乐变灰了 2 | 3 | 批量从其它渠道下载网易云音乐下架的歌曲。~~以便后续传到网易云音乐云盘上~~ 4 | 5 | ## 使用指南 6 | 7 | 下载本目录下的所有文件,直接执行 `php run.php`,没错就是这么简单。 8 | 9 | 下载完成后可以在 `download` 文件夹下找到所有歌曲文件,自由发挥 10 | 11 | 注意这是在终端执行,那些扔到 PHP 虚拟主机后直接访问网页的不要来问我为什么不能用好吗~ 12 | 13 | ## 环境要求 14 | - PHP 15 | - cURL 16 | 17 | ## 效果 18 | ``` 19 | $ php run.php 20 | 请输入网易云音乐歌单编号: 14721111 21 | 请输入您的网易云音乐 cookie [可选]: 22 | 啊,找到 21 首灰色歌曲呢 23 | 24 | 正在点亮第 1 首歌曲《火锅底料》- GAI爷/火锅底料 25 | + check tencent 26 | + + 匹配到《火锅底料》- GAI/火锅底料,相似度 94% 27 | + check xiami 28 | + check kugou 29 | + check baidu 30 | % Total % Received % Xferd Average Speed Time Time Time Current 31 | Dload Upload Total Spent Left Speed 32 | 100 7375k 100 7375k 0 0 2112k 0 0:00:03 0:00:03 --:--:-- 2112k 33 | 34 | 正在点亮第 2 首歌曲《孤儿仔》- 陈奕迅/Eason 4 A Change & Hits 35 | + check tencent 36 | + + 匹配到《孤儿仔》- 陈奕迅/Eason 4 A Chance & Hits,相似度 97% 37 | + check xiami 38 | + + 匹配到《孤儿仔》- 陈奕迅/Eason 4 A Change & Hits,相似度 100% 39 | + check kugou 40 | + check baidu 41 | % Total % Received % Xferd Average Speed Time Time Time Current 42 | Dload Upload Total Spent Left Speed 43 | 100 3475k 100 3475k 0 0 1601k 0 0:00:02 0:00:02 --:--:-- 1602k 44 | 45 | ... 46 | ``` 47 | -------------------------------------------------------------------------------- /UVa/download.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | trap "echo -e \"\n\e[1;31m[Error]\e[0m The script is terminated unexpectedly.\" | tee -a ./errorlog" SIGINT 3 | maxthread=20 4 | if [ $(($1)) -gt 0 ] 5 | then 6 | maxthread=$(($1)) 7 | fi 8 | touch errorlog 9 | test -e /tmp/UVafifo.pipe && rm /tmp/UVafifo.pipe 10 | mkfifo /tmp/UVafifo.pipe && exec 9<>/tmp/UVafifo.pipe 11 | for ((i=0; i&9;done 12 | cat /dev/null > errorlog || { echo -e "\e[1;31m[Failed]\e[0m to access \e[4;34m errorlog \e[0m, please check your authorization."; exit 1; } 13 | beginattime=$(date +%s) 14 | echo -e "\e[1;32m[Starting]\e[0m to download with \e[4;34m $maxthread \e[0m threads." 15 | for ((volume=1;volume<=131;volume++)) 16 | do 17 | { 18 | if [ $volume -ge 10 ] && [ $volume -le 99 ] 19 | then 20 | exit 0 21 | fi 22 | echo -e "\e[5;35m[Starting]\e[0m Volume \e[4;34m $volume \e[0m..." 23 | mkdir $volume >&/dev/null 24 | cd $volume || { echo -e "\e[1;31m[Failed]\e[0m to access dir \e[4;34m $volume \e[0m, please check your authorization." | tee -a ../errorlog; exit 1; } 25 | L="$volume*100" 26 | R=$L+100 27 | begin=$(date +%s) 28 | for ((id=L;id&9 48 | }& 49 | } 50 | done 51 | wait 52 | end=$(date +%s) 53 | spend=$((end-begin)) 54 | echo -e "\e[5;35m[Finished]\e[0m Volume \e[4;34m $volume \e[0m in \e[4;36m $spend \e[0m seconds." 55 | cd .. 56 | }& 57 | done 58 | wait 59 | endattime=$(date +%s) 60 | spendattime=$((endattime-beginattime)) 61 | echo -e "\e[1;32m[ OK ]\e[0m Action Finished \e[4;34m\e[0m in \e[4;36m $spendattime \e[0m seconds." 62 | test -e /tmp/UVafifo.pipe && rm /tmp/UVafifo.pipe 63 | if grep -q Failed errorlog 64 | then 65 | echo -e "\e[1;31m[Error Log]\e[0m" 66 | cat errorlog 67 | fi 68 | exit 0 -------------------------------------------------------------------------------- /UVa/README.md: -------------------------------------------------------------------------------- 1 | # Download script for UVa Online Judge 2 | [![][license img]][license] 3 | 4 | UVa Online Judge 题目下载,批量拉取 PDF 题目。 5 | 6 | ## Function 7 | 8 | - [x] Multi-Thread using FIFO (bash-ver) (多线程) 9 | - [x] Errorlog (错误日志) 10 | - [x] Timing (下载计时) 11 | - [x] MultiPlatform 12 | 13 | ## Platform 14 | 15 | - [x] Windows (PowerShell-ver) 16 | - [x] WSL 17 | - [x] MinGW 18 | - [x] GNU/Linux 19 | - [x] MacOS 20 | - [x] BSDs 21 | 22 | ## Run 23 | 24 | 25 | + To run the bash script with a default number of 20 threads, do the following: 26 | 27 | ``` 28 | $ bash download.sh 29 | ``` 30 | To run the script with a customized number of threads, do the following: 31 | 32 | ``` 33 | $ bash download.sh "threads" (without quotes) 34 | ``` 35 | e.g. 36 | ``` 37 | $ bash download.sh 20 38 | ``` 39 | **Notice:** This bash script is incompatible with zsh. 40 | 41 | + To run the PowerShell script, do the following: 42 | 43 | ``` 44 | $ powershell -executionpolicy bypass -file UVadownload.ps1 45 | ``` 46 | 47 | ## License 48 | 49 | Download script for UVa Online Judge is available under the [MIT license](http://opensource.org/licenses/MIT). 50 | 51 | ``` 52 | MIT License 53 | 54 | Copyright (c) 2016-2017 METO, Chijun Sima 55 | 56 | Permission is hereby granted, free of charge, to any person obtaining a copy 57 | of this software and associated documentation files (the "Software"), to deal 58 | in the Software without restriction, including without limitation the rights 59 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 60 | copies of the Software, and to permit persons to whom the Software is 61 | furnished to do so, subject to the following conditions: 62 | 63 | The above copyright notice and this permission notice shall be included in all 64 | copies or substantial portions of the Software. 65 | 66 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 67 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 68 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 69 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 70 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 71 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 72 | SOFTWARE. 73 | ``` 74 | 75 | [license]:LICENSE 76 | [license img]:https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square -------------------------------------------------------------------------------- /neteasemusic/run.php: -------------------------------------------------------------------------------- 1 | cookie(trim($cookie)); 23 | } 24 | else $api->cookie('os=pc; osver=Microsoft-Windows-10-Professional-build-10586-64bit; appver=2.0.3.131777; channel=netease; __remember_me=true'); 25 | 26 | $data = $api->playlist($id); 27 | $data = json_decode($data, true); 28 | $jobs = array(); 29 | foreach($data['privileges'] as $key=>$vo){ 30 | if($vo['st']!=0) { 31 | $tmp = $data['playlist']['tracks'][$key]; 32 | $jobs[]=array( 33 | 'id' => $tmp['id'], 34 | 'name' => $tmp['name'], 35 | 'artist' => $tmp['ar'][0]['name'], 36 | 'album' => $tmp['al']['name'], 37 | ); 38 | } 39 | } 40 | 41 | printf("啊,找到 %d 首灰色歌曲呢\n",count($jobs)); 42 | 43 | $api = new Meting(); 44 | foreach($jobs as $index=>$job){ 45 | printf("\n正在点亮第 %d 首歌曲《%s》- %s/%s\n",$index+1,$job['name'],$job['artist'],$job['album']); 46 | $best = 0; 47 | foreach(array('tencent', 'xiami', 'kugou', 'baidu') as $server) { 48 | printf(" + check " . $server . "\n"); 49 | $api->site($server); 50 | $data = $api->format(true)->search($job['name'].' '.$job['artist']); 51 | $data = json_decode($data, true); 52 | foreach($data as $vo){ 53 | $ta = $job['name']; 54 | $tb = $vo['name']; 55 | similar_text($ta,$tb,$per); 56 | if($per < 60)continue; 57 | $ta = $job['name'].$job['album'].$job['artist']; 58 | $tb = $vo['name'].$vo['album'].$vo['artist'][0]; 59 | similar_text($ta,$tb,$per); 60 | if ($per > $best) { 61 | $url = $api->url($vo['url_id'], 320); 62 | $url = json_decode($url, true); 63 | if (!empty($url['url'])) { 64 | $best = $per; 65 | $ans = $vo; 66 | printf(" + + 匹配到《%s》- %s/%s,相似度 %d%%\n", $ans['name'], $ans['artist'][0], $ans['album'], $best); 67 | } 68 | } 69 | } 70 | } 71 | $api->site($ans['source']); 72 | $url = $api->url($ans['url_id'], 320); 73 | $url = json_decode($url, true); 74 | exec(sprintf("curl -o \"download/%s - %s.mp3\" \"%s\"", $ans['name'], implode(',', $ans['artist']), $url['url'])); 75 | 76 | sleep(2); 77 | } 78 | -------------------------------------------------------------------------------- /UVa/UVadownload.ps1: -------------------------------------------------------------------------------- 1 | if($Host.Version.Major -le 2) 2 | { 3 | Write-Host "Your Powershell Version is too low." -ForegroundColor Red 4 | Write-Host "Exiting..." -ForegroundColor Green 5 | Exit-PSHostProcess 1 6 | }; 7 | Trap 8 | { 9 | Write-Host "[Error]" -ForegroundColor Red -NoNewline 10 | Write-Host "The script is terminated unexpectedly." 11 | "$Error" 12 | } 13 | [datetime]$beginatttime=Get-Date 14 | for($volume=1;$volume -le 131 ;$volume++) 15 | { 16 | if(($volume -ge 10) -and ($volume -le 99)) 17 | { 18 | continue 19 | } 20 | Write-Host "[Starting]" -ForegroundColor Green -NoNewline 21 | Write-Host " Volume " -NoNewline 22 | Write-Host $volume -ForegroundColor Cyan -NoNewline 23 | Write-Host " ..." 24 | New-Item -ItemType Directory -Name $volume -ErrorAction "SilentlyContinue" | Out-Null 25 | Set-Location $volume 26 | $L=$volume*100 27 | $R=$L+100 28 | [datetime]$begin=Get-Date 29 | for($id=$L;$id -lt $R;$id++) 30 | { 31 | [datetime]$beginat=Get-Date 32 | Write-Host "[Starting]" -ForegroundColor Green -NoNewline 33 | Write-Host " to download " -NoNewline 34 | Write-Host $id -ForegroundColor Cyan -NoNewline 35 | Write-Host " in UVa Volume " -NoNewline 36 | Write-Host $volume -ForegroundColor Cyan -NoNewline 37 | Write-Host " ..." 38 | [string]$Site="https://uva.onlinejudge.org/external/$volume/$id.pdf" 39 | [String]$FileName=Split-Path -Leaf $Site 40 | Invoke-WebRequest -TimeoutSec 30 -OutFile $FileName -Uri $Site -ErrorAction "Continue" 41 | if($?) 42 | { 43 | [datetime]$endat=Get-Date 44 | [timespan]$spendat=$endat-$beginat 45 | Write-Host "[ OK ]" -ForegroundColor Green -NoNewline 46 | Write-Host " Downloaded " -NoNewline 47 | Write-Host $id -ForegroundColor Cyan -NoNewline 48 | Write-Host " in UVa Volume " -NoNewline 49 | Write-Host $volume -ForegroundColor Cyan -NoNewline 50 | Write-Host " in " -NoNewline 51 | Write-Host $spendat.Seconds -ForegroundColor Green -NoNewline 52 | Write-Host " seconds." 53 | } 54 | else 55 | { 56 | Write-Host "[Failed]" -ForegroundColor Red -NoNewline 57 | Write-Host " to download " -NoNewline 58 | Write-Host $id -ForegroundColor Cyan -NoNewline 59 | Write-Host " in UVa Volume " -NoNewline 60 | Write-Host $volume -ForegroundColor Cyan -NoNewline 61 | Write-Host " ." -NoNewline 62 | } 63 | } 64 | [datetime]$end=Get-Date 65 | [timespan]$spend=$end-$begin 66 | Write-Host "[Finished]" -ForegroundColor Green -NoNewline 67 | Write-Host " Volume " -NoNewline 68 | Write-Host $volume -ForegroundColor Cyan -NoNewline 69 | Write-Host " in " -NoNewline 70 | Write-Host $spend.Seconds -ForegroundColor Green -NoNewline 71 | Write-Host " seconds." 72 | Set-Location .. 73 | } 74 | [datetime]$endattime=Get-Date 75 | [timespan]$spendattime=$endattime-$beginatttime 76 | Write-Host "[ OK ]" -ForegroundColor Green -NoNewline 77 | Write-Host " Action Finished in " -NoNewline 78 | Write-Host $spendattime.Minutes -ForegroundColor Cyan -NoNewline 79 | Write-Host " minutes." 80 | "$Error" -------------------------------------------------------------------------------- /bilibili/onlineHeart.php: -------------------------------------------------------------------------------- 1 | '填写用户cookie', 11 | 'status' => 1, 12 | ), 13 | array( 14 | 'cookie' => '第二个用户cookie', 15 | 'status' => 0, // 0 表示禁用 16 | ), 17 | // 多用户以此类推 18 | ); 19 | 20 | public function display(){ 21 | header('Content-Type: text/txt; charset=UTF-8'); 22 | echo "===============================\n"; 23 | foreach($this->user as $result){ 24 | if($result['status']){ 25 | $data=$result['data']; 26 | $a=$data['data']['user_intimacy']; 27 | $b=$data['data']['user_next_intimacy']; 28 | $per=round($a/$b*100,2); 29 | if(!isset($result['cron']['data'][1]))$msg='OK'; 30 | else $msg='@'.date('Y-m-d H:i:s',$result['cron']['data'][1]); 31 | 32 | echo "name : {$data['data']['uname']} \n"; 33 | echo "level : {$data['data']['user_level']} \n"; 34 | echo "exp : {$a}/{$b} [{$per}%]\n"; 35 | echo "status : {$msg}\n"; 36 | echo "===============================\n"; 37 | } 38 | else{ 39 | echo "status : {$result['data']['msg']}\n"; 40 | echo "===============================\n"; 41 | } 42 | } 43 | } 44 | 45 | public function cron(){ 46 | $mh=curl_multi_init(); 47 | foreach($this->user as $id=>$user){ 48 | if($user['status']!=1)continue; 49 | $curl[$id]=$this->create('http://live.bilibili.com/User/userOnlineHeart',$user['cookie']); 50 | curl_multi_add_handle($mh,$curl[$id]); 51 | } 52 | do{ 53 | curl_multi_exec($mh,$running); 54 | curl_multi_select($mh); 55 | }while($running>0); 56 | foreach($curl as $id=>$c){ 57 | $result[$id]=curl_multi_getcontent($c); 58 | curl_multi_remove_handle($mh,$c); 59 | } 60 | curl_multi_close($mh); 61 | foreach($result as $id=>$vo){ 62 | $vo=json_decode($vo,1); 63 | $this->user[$id]['cron']=$vo; 64 | } 65 | } 66 | 67 | public function check(){ 68 | $mh=curl_multi_init(); 69 | foreach($this->user as $id=>$user){ 70 | if($user['status']!=1)continue; 71 | $curl[$id]=$this->create('http://live.bilibili.com/User/getUserInfo',$user['cookie']); 72 | curl_multi_add_handle($mh,$curl[$id]); 73 | } 74 | do{ 75 | curl_multi_exec($mh,$running); 76 | curl_multi_select($mh); 77 | }while($running>0); 78 | foreach($curl as $id=>$c){ 79 | $result[$id]=curl_multi_getcontent($c); 80 | curl_multi_remove_handle($mh,$c); 81 | } 82 | curl_multi_close($mh); 83 | foreach($result as $id=>$vo){ 84 | $vo=json_decode($vo,1); 85 | if($vo['code']<0)$this->user[$id]['status']=0; 86 | $this->user[$id]['data']=$vo; 87 | } 88 | } 89 | 90 | private function create($url,$cookie){ 91 | $curl=curl_init(); 92 | curl_setopt($curl,CURLOPT_URL,$url); 93 | curl_setopt($curl,CURLOPT_COOKIE,$cookie); 94 | curl_setopt($curl,CURLOPT_RETURNTRANSFER, 1); 95 | curl_setopt($curl,CURLOPT_CONNECTTIMEOUT, 10); 96 | curl_setopt($curl,CURLOPT_REFERER,'http://live.bilibili.com/'); 97 | curl_setopt($curl,CURLOPT_USERAGENT,'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.56 Safari/536.5'); 98 | return $curl; 99 | } 100 | } 101 | 102 | $API=new bilibili; 103 | $API->check(); 104 | $API->cron(); 105 | $API->display(); 106 | -------------------------------------------------------------------------------- /neteasemusic/meting.php: -------------------------------------------------------------------------------- 1 | 9 | * Released under the MIT license 10 | */ 11 | 12 | namespace Metowolf; 13 | 14 | class Meting 15 | { 16 | protected $_SITE; 17 | protected $_TEMP; 18 | protected $_RETRY = 3; 19 | protected $_FORMAT = false; 20 | 21 | public function __construct($v = 'netease') 22 | { 23 | $this->site($v); 24 | } 25 | 26 | public function site($v) 27 | { 28 | $suppose = array('netease', 'tencent', 'xiami', 'kugou', 'baidu'); 29 | $this->_SITE = in_array($v,$suppose) ? $v : 'netease'; 30 | return $this; 31 | } 32 | 33 | public function cookie($v = '') 34 | { 35 | $this->_TEMP['cookie'] = $v; 36 | return $this; 37 | } 38 | 39 | public function format($v = true) 40 | { 41 | $this->_FORMAT = $v; 42 | return $this; 43 | } 44 | 45 | private function curl($API) 46 | { 47 | if (isset($API['encode'])) { 48 | $API=call_user_func_array(array($this,$API['encode']), array($API)); 49 | } 50 | $BASE = $this->curlset(); 51 | $curl = curl_init(); 52 | if ($API['method'] == 'POST') { 53 | if (is_array($API['body'])) { 54 | $API['body'] = http_build_query($API['body']); 55 | } 56 | curl_setopt($curl, CURLOPT_POST, 1); 57 | curl_setopt($curl, CURLOPT_POSTFIELDS, $API['body']); 58 | } elseif ($API['method'] == 'GET') { 59 | if (isset($API['body'])) { 60 | $API['url'] = $API['url'].'?'.http_build_query($API['body']); 61 | } 62 | } 63 | curl_setopt($curl, CURLOPT_HEADER, 0); 64 | curl_setopt($curl, CURLOPT_TIMEOUT, 20); 65 | curl_setopt($curl, CURLOPT_ENCODING, 'gzip'); 66 | curl_setopt($curl, CURLOPT_IPRESOLVE, 1); 67 | curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); 68 | curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); 69 | curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10); 70 | curl_setopt($curl, CURLOPT_URL, $API['url']); 71 | curl_setopt($curl, CURLOPT_COOKIE, isset($this->_TEMP['cookie'])?$this->_TEMP['cookie']:$BASE['cookie']); 72 | curl_setopt($curl, CURLOPT_HTTPHEADER, array( 73 | 'Accept: */*', 74 | 'Accept-Encoding: gzip, deflate', 75 | 'Accept-Language: zh-CN,zh;q=0.8,gl;q=0.6,zh-TW;q=0.4', 76 | 'Connection: keep-alive', 77 | 'Content-Type: application/x-www-form-urlencoded', 78 | 'Referer: ' . $BASE['referer'], 79 | 'User-Agent: ' . $BASE['useragent'] 80 | )); 81 | for ($i=0;$i<=$this->_RETRY;$i++) { 82 | $data = curl_exec($curl); 83 | $info = curl_getinfo($curl); 84 | $error = curl_errno($curl); 85 | $status = $error ? curl_error($curl) : ''; 86 | if (!$error) { 87 | break; 88 | } 89 | } 90 | curl_close($curl); 91 | if ($error) { 92 | return json_encode( 93 | array( 94 | 'error' => $error, 95 | 'info' => $info, 96 | 'status' => $status, 97 | ) 98 | ); 99 | } 100 | if ($this->_FORMAT && isset($API['decode'])) { 101 | $data = call_user_func_array(array($this,$API['decode']), array($data)); 102 | } 103 | if ($this->_FORMAT && isset($API['format'])) { 104 | $data = json_decode($data, 1); 105 | $data = $this->clean($data, $API['format']); 106 | $data = json_encode($data); 107 | } 108 | return $data; 109 | } 110 | 111 | private function pickup($array, $rule) 112 | { 113 | $t = explode('#', $rule); 114 | foreach ($t as $vo) { 115 | if (!isset($array[$vo])){ 116 | return array(); 117 | } 118 | $array = $array[$vo]; 119 | } 120 | return $array; 121 | } 122 | 123 | private function clean($raw, $rule) 124 | { 125 | if (!empty($rule)) { 126 | $raw = $this->pickup($raw, $rule); 127 | } 128 | if (!isset($raw[0]) && sizeof($raw)) { 129 | $raw = array($raw); 130 | } 131 | $result = array_map(array($this,'format_'.$this->_SITE), $raw); 132 | return $result; 133 | } 134 | 135 | public function search($keyword, $option = null) 136 | { 137 | switch ($this->_SITE) { 138 | case 'netease': 139 | $API = array( 140 | 'method' => 'POST', 141 | 'url' => 'http://music.163.com/api/linux/forward', 142 | 'body' => array( 143 | 'method' => 'POST', 144 | 'params' => array( 145 | 's' => $keyword, 146 | 'type' => isset($option['type']) ? $option['type'] : 1, 147 | 'limit' => isset($option['limit']) ? $option['limit'] : 30, 148 | 'total' => 'true', 149 | 'offset' => isset($option['page']) && isset($option['limit']) ? ($option['page'] - 1) * $option['limit'] : 0, 150 | ), 151 | 'url' => 'http://music.163.com/api/cloudsearch/pc', 152 | ), 153 | 'encode' => 'netease_AESECB', 154 | 'format' => 'result#songs', 155 | ); 156 | break; 157 | case 'tencent': 158 | $API = array( 159 | 'method' => 'GET', 160 | 'url' => 'https://c.y.qq.com/soso/fcgi-bin/client_search_cp', 161 | 'body' => array( 162 | 'format' => 'json', 163 | 'p' => isset($option['page']) ? $option['page'] : 1, 164 | 'n' => isset($option['limit']) ? $option['limit'] : 30, 165 | 'w' => $keyword, 166 | 'aggr' => 1, 167 | 'lossless' => 1, 168 | 'cr' => 1, 169 | 'new_json' => 1, 170 | ), 171 | 'format' => 'data#song#list', 172 | ); 173 | break; 174 | case 'xiami': 175 | $API = array( 176 | 'method' => 'GET', 177 | 'url' => 'http://api.xiami.com/web', 178 | 'body' => array( 179 | 'v' => '2.0', 180 | 'app_key' => '1', 181 | 'key' => $keyword, 182 | 'page' => isset($option['page']) ? $option['page'] : 1, 183 | 'limit' => isset($option['limit']) ? $option['limit'] : 30, 184 | 'r' => 'search/songs', 185 | ), 186 | 'format' => 'data#songs', 187 | ); 188 | break; 189 | case 'kugou': 190 | $API = array( 191 | 'method' => 'GET', 192 | 'url' => 'http://ioscdn.kugou.com/api/v3/search/song', 193 | 'body' => array( 194 | 'iscorrect' => 1, 195 | 'pagesize' => isset($option['limit']) ? $option['limit'] : 30, 196 | 'plat' => 2, 197 | 'tag' => 1, 198 | 'sver' => 5, 199 | 'showtype' => 10, 200 | 'page' => isset($option['page']) ? $option['page'] : 1, 201 | 'keyword' => $keyword, 202 | 'version' => 8550 203 | ), 204 | 'format' => 'data#info', 205 | ); 206 | break; 207 | case 'baidu': 208 | $API = array( 209 | 'method' => 'GET', 210 | 'url' => 'http://tingapi.ting.baidu.com/v1/restserver/ting', 211 | 'body' => array( 212 | 'from' => 'qianqianmini', 213 | 'method' => 'baidu.ting.search.merge', 214 | 'isNew' => 1, 215 | 'platform' => 'darwin', 216 | 'page_no' => isset($option['page']) ? $option['page'] : 1, 217 | 'query' => $keyword, 218 | 'version' => '11.0.2', 219 | 'page_size' => isset($option['limit']) ? $option['limit'] : 30 220 | ), 221 | 'format' => 'result#song_info#song_list', 222 | ); 223 | break; 224 | } 225 | return $this->curl($API); 226 | } 227 | 228 | public function song($id) 229 | { 230 | switch ($this->_SITE) { 231 | case 'netease': 232 | $API = array( 233 | 'method' => 'POST', 234 | 'url' => 'http://music.163.com/api/linux/forward', 235 | 'body' => array( 236 | 'method' => 'POST', 237 | 'params' => array( 238 | 'c' => '[{"id":'.$id.',"v":0}]', 239 | ), 240 | 'url' => 'http://music.163.com/api/v3/song/detail/', 241 | ), 242 | 'encode' => 'netease_AESECB', 243 | 'format' => 'songs', 244 | ); 245 | break; 246 | case 'tencent': 247 | $API = array( 248 | 'method' => 'GET', 249 | 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_play_single_song.fcg', 250 | 'body' => array( 251 | 'songmid' => $id, 252 | 'platform' => 'yqq', 253 | 'format' => 'json', 254 | ), 255 | 'decode' => 'tencent_singlesong', 256 | 'format' => 'data', 257 | ); 258 | break; 259 | case 'xiami': 260 | $API = array( 261 | 'method' => 'GET', 262 | 'url' => 'http://api.xiami.com/web', 263 | 'body' => array( 264 | 'v' => '2.0', 265 | 'app_key' => '1', 266 | 'id' => $id, 267 | 'r' => 'song/detail', 268 | ), 269 | 'format' => 'data#song', 270 | ); 271 | break; 272 | case 'kugou': 273 | $API = array( 274 | 'method' => 'POST', 275 | 'url' => 'http://m.kugou.com/app/i/getSongInfo.php', 276 | 'body' => array( 277 | "cmd" => "playInfo", 278 | "hash" => $id, 279 | "from" => "mkugou", 280 | ), 281 | 'format' => '', 282 | ); 283 | break; 284 | case 'baidu': 285 | $API = array( 286 | 'method' => 'GET', 287 | 'url' => 'http://tingapi.ting.baidu.com/v1/restserver/ting', 288 | 'body' => array( 289 | 'from' => 'qianqianmini', 290 | 'method' => 'baidu.ting.song.getInfos', 291 | 'songid' => $id, 292 | 'res' => 1, 293 | 'platform' => 'darwin', 294 | 'version' => '1.0.0' 295 | ), 296 | 'encode' => 'baidu_AESCBC', 297 | 'format' => 'songinfo', 298 | ); 299 | break; 300 | } 301 | return $this->curl($API); 302 | } 303 | 304 | public function album($id) 305 | { 306 | switch ($this->_SITE) { 307 | case 'netease': 308 | $API = array( 309 | 'method' => 'POST', 310 | 'url' => 'http://music.163.com/api/linux/forward', 311 | 'body' => array( 312 | 'method' => 'GET', 313 | 'params' => array( 314 | "total" => "true", 315 | "offset" => "0", 316 | "id" => $id, 317 | "limit" => "1000", 318 | "ext" => "true", 319 | "private_cloud" => "true" 320 | ), 321 | 'url' => 'http://music.163.com/api/v1/album/'.$id, 322 | ), 323 | 'encode' => 'netease_AESECB', 324 | 'format' => 'songs', 325 | ); 326 | break; 327 | case 'tencent': 328 | $API = array( 329 | 'method' => 'GET', 330 | 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_album_detail_cp.fcg', 331 | 'body' => array( 332 | 'albummid' => $id, 333 | 'platform' => 'mac', 334 | 'format' => 'json', 335 | 'newsong' => 1, 336 | ), 337 | 'format' => 'data#getSongInfo', 338 | ); 339 | break; 340 | case 'xiami': 341 | $API = array( 342 | 'method' => 'GET', 343 | 'url' => 'http://api.xiami.com/web', 344 | 'body' => array( 345 | 'v' => '2.0', 346 | 'app_key' => '1', 347 | 'id' => $id, 348 | 'r' => 'album/detail', 349 | ), 350 | 'format' => 'data#songs', 351 | ); 352 | break; 353 | case 'kugou': 354 | $API = array( 355 | 'method' => 'GET', 356 | 'url' => 'http://mobilecdn.kugou.com/api/v3/album/song', 357 | 'body' => array( 358 | 'albumid' => $id, 359 | 'plat' => 2, 360 | 'page' => 1, 361 | 'pagesize' => -1, 362 | 'version' => 8550, 363 | ), 364 | 'format' => 'data#info', 365 | ); 366 | break; 367 | case 'baidu': 368 | $API = array( 369 | 'method' => 'GET', 370 | 'url' => 'http://tingapi.ting.baidu.com/v1/restserver/ting', 371 | 'body' => array( 372 | 'from' => 'qianqianmini', 373 | 'method' => 'baidu.ting.album.getAlbumInfo', 374 | 'album_id' => $id, 375 | 'platform' => 'darwin', 376 | 'version' => '11.0.2' 377 | ), 378 | 'format' => 'songlist', 379 | ); 380 | break; 381 | } 382 | return $this->curl($API); 383 | } 384 | 385 | public function artist($id, $limit=50) 386 | { 387 | switch ($this->_SITE) { 388 | case 'netease': 389 | $API = array( 390 | 'method' => 'POST', 391 | 'url' => 'http://music.163.com/api/linux/forward', 392 | 'body' => array( 393 | 'method' => 'GET', 394 | 'params' => array( 395 | "ext" => "true", 396 | "private_cloud" => "true", 397 | "ext" => "true", 398 | "top" => $limit, 399 | "id" => $id 400 | ), 401 | 'url' => 'http://music.163.com/api/v1/artist/'.$id, 402 | ), 403 | 'encode' => 'netease_AESECB', 404 | 'format' => 'hotSongs', 405 | ); 406 | break; 407 | case 'tencent': 408 | $API = array( 409 | 'method' => 'GET', 410 | 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_singer_track_cp.fcg', 411 | 'body' => array( 412 | 'singermid' => $id, 413 | 'begin' => 0, 414 | 'num' => $limit, 415 | 'order' => 'listen', 416 | 'platform' => 'mac', 417 | 'newsong' => 1, 418 | ), 419 | 'format' => 'data#list', 420 | ); 421 | break; 422 | case 'xiami': 423 | $API = array( 424 | 'method' => 'GET', 425 | 'url' => 'http://api.xiami.com/web', 426 | 'body' => array( 427 | 'v' => '2.0', 428 | 'app_key' => '1', 429 | 'id' => $id, 430 | 'limit' => $limit, 431 | 'page' => 1, 432 | 'r' => 'artist/hot-songs', 433 | ), 434 | 'format' => 'data', 435 | ); 436 | break; 437 | case 'kugou': 438 | $API = array( 439 | 'method' => 'GET', 440 | 'url' => 'http://mobilecdn.kugou.com/api/v3/singer/song', 441 | 'body' => array( 442 | 'singerid' => $id, 443 | 'page' => 1, 444 | 'plat' => 0, 445 | 'pagesize' => $limit, 446 | 'version' => 8400, 447 | ), 448 | 'format' => 'data#info', 449 | ); 450 | break; 451 | case 'baidu': 452 | $API = array( 453 | 'method' => 'GET', 454 | 'url' => 'http://tingapi.ting.baidu.com/v1/restserver/ting', 455 | 'body' => array( 456 | 'from' => 'qianqianmini', 457 | 'method' => 'baidu.ting.artist.getSongList', 458 | 'artistid' => $id, 459 | 'limits' => 20, 460 | 'platform' => 'darwin', 461 | 'offset' => 0, 462 | 'tinguid' => 0, 463 | 'version' => '11.0.2' 464 | ), 465 | 'format' => 'songlist', 466 | ); 467 | break; 468 | } 469 | return $this->curl($API); 470 | } 471 | 472 | public function playlist($id) 473 | { 474 | switch ($this->_SITE) { 475 | case 'netease': 476 | $API = array( 477 | 'method' => 'POST', 478 | 'url' => 'http://music.163.com/api/linux/forward', 479 | 'body' => array( 480 | 'method' => 'POST', 481 | 'params' => array( 482 | "s" => "0", 483 | "id" => $id, 484 | "n" => "1000", 485 | "t" => "0" 486 | ), 487 | 'url' => 'http://music.163.com/api/v3/playlist/detail', 488 | ), 489 | 'encode' => 'netease_AESECB', 490 | 'format' => 'playlist#tracks', 491 | ); 492 | break; 493 | case 'tencent': 494 | $API = array( 495 | 'method' => 'GET', 496 | 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_playlist_cp.fcg', 497 | 'body' => array( 498 | 'id' => $id, 499 | 'format' => 'json', 500 | 'newsong' => 1, 501 | 'platform' => 'jqspaframe.json', 502 | ), 503 | 'format' => 'data#cdlist#0#songlist', 504 | ); 505 | break; 506 | case 'xiami': 507 | $API = array( 508 | 'method' => 'GET', 509 | 'url' => 'http://api.xiami.com/web', 510 | 'body' => array( 511 | 'v' => '2.0', 512 | 'app_key' => '1', 513 | 'id' => $id, 514 | 'r' => 'collect/detail', 515 | ), 516 | 'format' => 'data#songs', 517 | ); 518 | break; 519 | case 'kugou': 520 | $API = array( 521 | 'method' => 'GET', 522 | 'url' => 'http://mobilecdn.kugou.com/api/v3/special/song', 523 | 'body' => array( 524 | 'specialid' => $id, 525 | 'page' => 1, 526 | 'plat' => 2, 527 | 'pagesize' => -1, 528 | 'version' => 8400, 529 | ), 530 | 'format' => 'data#info', 531 | ); 532 | break; 533 | case 'baidu': 534 | $API = array( 535 | 'method' => 'GET', 536 | 'url' => 'http://tingapi.ting.baidu.com/v1/restserver/ting', 537 | 'body' => array( 538 | 'from' => 'qianqianmini', 539 | 'method' => 'baidu.ting.diy.gedanInfo', 540 | 'listid' => $id, 541 | 'platform' => 'darwin', 542 | 'version' => '11.0.2' 543 | ), 544 | 'format' => 'content', 545 | ); 546 | break; 547 | } 548 | return $this->curl($API); 549 | } 550 | 551 | public function url($id, $br=320) 552 | { 553 | switch ($this->_SITE) { 554 | case 'netease': 555 | $API = array( 556 | 'method' => 'POST', 557 | 'url' => 'http://music.163.com/api/linux/forward', 558 | 'body' => array( 559 | 'method' => 'POST', 560 | 'params' => array( 561 | 'ids' => array($id), 562 | 'br' => $br*1000, 563 | ), 564 | 'url' => 'http://music.163.com/api/song/enhance/player/url', 565 | ), 566 | 'encode' => 'netease_AESECB', 567 | 'decode' => 'netease_url', 568 | ); 569 | break; 570 | case 'tencent': 571 | $API = array( 572 | 'method' => 'GET', 573 | 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_play_single_song.fcg', 574 | 'body' => array( 575 | 'songmid' => $id, 576 | 'platform' => 'yqq', 577 | 'format' => 'json', 578 | ), 579 | 'decode' => 'tencent_url', 580 | ); 581 | break; 582 | case 'xiami': 583 | $API = array( 584 | 'method' => 'GET', 585 | 'url' => 'http://www.xiami.com/song/gethqsong/sid/'.$id, 586 | 'body' => array( 587 | 'v' => '2.0', 588 | 'app_key' => '1', 589 | 'id' => $id, 590 | 'r' => 'song/detail', 591 | ), 592 | 'decode' => 'xiami_url', 593 | ); 594 | break; 595 | case 'kugou': 596 | $API = array( 597 | 'method' => 'POST', 598 | 'url' => 'http://media.store.kugou.com/v1/get_res_privilege', 599 | 'body' => json_encode(array( 600 | "relate" => 1, 601 | "userid" => 0, 602 | "vip" => 0, 603 | "appid" => 1005, 604 | "token" => "", 605 | "behavior" => "download", 606 | "clientver" => "8493", 607 | "resource" => array(array( 608 | "id" => 0, 609 | "type" => "audio", 610 | "hash" => $id, 611 | ))) 612 | ), 613 | 'decode' => 'kugou_url', 614 | ); 615 | break; 616 | case 'baidu': 617 | $API = array( 618 | 'method' => 'GET', 619 | 'url' => 'http://tingapi.ting.baidu.com/v1/restserver/ting', 620 | 'body' => array( 621 | 'from' => 'qianqianmini', 622 | 'method' => 'baidu.ting.song.getInfos', 623 | 'songid' => $id, 624 | 'res' => 1, 625 | 'platform' => 'darwin', 626 | 'version' => '1.0.0' 627 | ), 628 | 'encode' => 'baidu_AESCBC', 629 | 'decode' => 'baidu_url', 630 | ); 631 | break; 632 | } 633 | $this->_TEMP['br'] = $br; 634 | return $this->curl($API); 635 | } 636 | 637 | public function lyric($id) 638 | { 639 | switch ($this->_SITE) { 640 | case 'netease': 641 | $API = array( 642 | 'method' => 'POST', 643 | 'url' => 'http://music.163.com/api/linux/forward', 644 | 'body' => array( 645 | 'method' => 'POST', 646 | 'params' => array( 647 | 'id' => $id, 648 | 'os' => 'linux', 649 | 'lv' => -1, 650 | 'kv' => -1, 651 | 'tv' => -1, 652 | ), 653 | 'url' => 'http://music.163.com/api/song/lyric', 654 | ), 655 | 'encode' => 'netease_AESECB', 656 | 'decode' => 'netease_lyric', 657 | ); 658 | break; 659 | case 'tencent': 660 | $API = array( 661 | 'method' => 'GET', 662 | 'url' => 'https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg', 663 | 'body' => array( 664 | 'songmid' => $id, 665 | 'g_tk' => '5381', 666 | ), 667 | 'decode' => 'tencent_lyric', 668 | ); 669 | break; 670 | case 'xiami': 671 | $API = array( 672 | 'method' => 'GET', 673 | 'url' => 'http://api.xiami.com/web', 674 | 'body' => array( 675 | 'v' => '2.0', 676 | 'app_key' => '1', 677 | 'id' => $id, 678 | 'r' => 'song/detail', 679 | ), 680 | 'decode' => 'xiami_lyric', 681 | ); 682 | break; 683 | case 'kugou': 684 | $API = array( 685 | 'method' => 'GET', 686 | 'url' => 'http://m.kugou.com/app/i/krc.php', 687 | 'body' => array( 688 | 'keyword' => '%20-%20', 689 | 'timelength' => 1000000, 690 | 'cmd' => 100, 691 | 'hash' => $id, 692 | ), 693 | 'decode' => 'kugou_lyric' 694 | ); 695 | break; 696 | case 'baidu': 697 | $API = array( 698 | 'method' => 'GET', 699 | 'url' => 'http://tingapi.ting.baidu.com/v1/restserver/ting', 700 | 'body' => array( 701 | 'from' => 'qianqianmini', 702 | 'method' => 'baidu.ting.song.lry', 703 | 'songid' => $id, 704 | 'platform' => 'darwin', 705 | 'version' => '1.0.0' 706 | ), 707 | 'decode' => 'baidu_lyric', 708 | ); 709 | break; 710 | } 711 | return $this->curl($API); 712 | } 713 | 714 | public function pic($id, $size=300) 715 | { 716 | switch ($this->_SITE) { 717 | case 'netease': 718 | $url='https://p3.music.126.net/'.$this->netease_pickey($id).'/'.$id.'.jpg?param='.$size.'y'.$size; 719 | break; 720 | case 'tencent': 721 | $url='https://y.gtimg.cn/music/photo_new/T002R'.$size.'x'.$size.'M000'.$id.'.jpg?max_age=2592000'; 722 | break; 723 | case 'xiami': 724 | $format=$this->_FORMAT; 725 | $data=$this->format(false)->song($id); 726 | $this->format($format); 727 | $data=json_decode($data, 1); 728 | $url=$data['data']['song']['logo']; 729 | $url=str_replace(array('_1.','http:','img.'), array('.','https:','pic.'), $url).'@'.$size.'h_'.$size.'w_100q_1c.jpg'; 730 | break; 731 | case 'kugou': 732 | $format=$this->_FORMAT; 733 | $data=$this->format(false)->song($id); 734 | $this->format($format); 735 | $data=json_decode($data, 1); 736 | $url=$data['imgUrl']; 737 | $url=str_replace('{size}', '400', $url); 738 | break; 739 | case 'baidu': 740 | $format=$this->_FORMAT; 741 | $data=$this->format(false)->song($id); 742 | $this->format($format); 743 | $data=json_decode($data, 1); 744 | $url=isset($data['songinfo']['pic_radio'])?$data['songinfo']['pic_radio']:$data['songinfo']['pic_small']; 745 | break; 746 | } 747 | return json_encode(array('url'=>$url)); 748 | } 749 | 750 | private function curlset() 751 | { 752 | switch ($this->_SITE) { 753 | case 'netease': 754 | return array( 755 | 'referer' => 'https://music.163.com/', 756 | 'cookie' => 'os=linux; deviceId=' . $this->getRandomHex(52) . '; osver=Ubuntu%2016.04.3%20LTS; appver=1.1.0.1232; channel=netease; MUSIC_U=255b19fea4bdec0a0011f855c3708e3e97b229707fccab67d74da902317635b4f866558227e6c3335d9bd72ef1abb9ea77749c2dda21047b; __csrf=' . $this->getRandomHex(32), 757 | 'useragent' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36', 758 | ); 759 | case 'tencent': 760 | return array( 761 | 'referer' => 'https://y.qq.com/portal/player.html', 762 | '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', 763 | 'useragent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36', 764 | ); 765 | case 'xiami': 766 | return array( 767 | 'referer' => 'http://h.xiami.com/', 768 | 'cookie' => '_xiamitoken=' . $this->getRandomHex(32) . '; _unsign_token=' . $this->getRandomHex(32), 769 | 'useragent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36', 770 | ); 771 | case 'kugou': 772 | return array( 773 | 'referer' => 'http://www.kugou.com/webkugouplayer/flash/webKugou.swf', 774 | 'cookie' => 'kg_mid=' . $this->getRandomHex(32), 775 | 'useragent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36', 776 | ); 777 | case 'baidu': 778 | return array( 779 | 'referer' => '', 780 | 'cookie' => 'BAIDUID=' . $this->getRandomHex(32) . ':FG=1', 781 | 'useragent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) baidu-music/1.0.2 Chrome/56.0.2924.87 Electron/1.6.11 Safari/537.36', 782 | ); 783 | } 784 | } 785 | 786 | private function getRandomHex($length) 787 | { 788 | if (function_exists('openssl_random_pseudo_bytes')) { 789 | return bin2hex(openssl_random_pseudo_bytes($length)); 790 | } else { 791 | return bin2hex(mcrypt_create_iv($length, MCRYPT_DEV_URANDOM)); 792 | } 793 | } 794 | 795 | /** 796 | * 乱七八糟的函数,加密解密... 797 | * 正在努力重构这些代码 TAT 798 | */ 799 | private function netease_AESECB($API) 800 | { 801 | $KEY='7246674226682325323F5E6544673A51'; 802 | $body=json_encode($API['body']); 803 | if (function_exists('openssl_encrypt')) { 804 | $body=openssl_encrypt($body, 'aes-128-ecb', pack('H*', $KEY)); 805 | } else { 806 | $PAD=16-(strlen($body)%16); 807 | $body=base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, hex2bin($KEY), $body.str_repeat(chr($PAD), $PAD), MCRYPT_MODE_ECB)); 808 | } 809 | $body=strtoupper(bin2hex(base64_decode($body))); 810 | 811 | $API['body']=array( 812 | 'eparams'=>$body, 813 | ); 814 | return $API; 815 | } 816 | private function baidu_AESCBC($API) 817 | { 818 | $key = 'DBEECF8C50FD160E'; 819 | $vi = '1231021386755796'; 820 | 821 | $data = 'songid='.$API['body']['songid'].'&ts='.intval(microtime(true)*1000); 822 | 823 | if (function_exists('openssl_encrypt')) { 824 | $data = openssl_encrypt($data, 'aes-128-cbc', $key, false, $vi); 825 | } else { 826 | $PAD = 16-(strlen($data)%16); 827 | $data = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data.str_repeat(chr($PAD), $PAD), MCRYPT_MODE_CBC, $vi)); 828 | } 829 | 830 | $API['body']['e'] = $data; 831 | return $API; 832 | } 833 | private function tencent_singlesong($result) 834 | { 835 | $result=json_decode($result, 1); 836 | $data=$result['data'][0]; 837 | $t=array( 838 | 'songmid' => $data['mid'], 839 | 'songname' => $data['name'], 840 | 'albummid' => $data['album']['mid'], 841 | ); 842 | foreach ($t as $key=>$vo) { 843 | $result['data'][0][$key]=$vo; 844 | } 845 | return json_encode($result); 846 | } 847 | private function netease_pickey($id) 848 | { 849 | $magic=str_split('3go8&$8*3*3h0k(2)2'); 850 | $song_id=str_split($id); 851 | for ($i=0;$i $data['data'][0]['url'], 871 | 'br' => $data['data'][0]['br']/1000, 872 | ); 873 | } else { 874 | $url=array( 875 | 'url' => '', 876 | 'br' => -1, 877 | ); 878 | } 879 | return json_encode($url); 880 | } 881 | private function tencent_url($result) 882 | { 883 | $data=json_decode($result, 1); 884 | $GUID=mt_rand()%10000000000; 885 | $API=array( 886 | 'method' => 'GET', 887 | 'url' => 'https://c.y.qq.com/base/fcgi-bin/fcg_musicexpress.fcg', 888 | 'body' => array( 889 | 'json' => 3, 890 | 'guid' => $GUID, 891 | 'format' => 'json', 892 | ), 893 | ); 894 | $KEY=json_decode($this->curl($API), 1); 895 | $KEY=$KEY['key']; 896 | 897 | $type=array( 898 | 'size_320mp3' => array(320,'M800','mp3'), 899 | 'size_192aac' => array(192,'C600','m4a'), 900 | 'size_128mp3' => array(128,'M500','mp3'), 901 | 'size_96aac' => array(96 ,'C400','m4a'), 902 | 'size_48aac' => array(48 ,'C200','m4a'), 903 | ); 904 | foreach ($type as $key=>$vo) { 905 | if ($data['data'][0]['file'][$key]&&$vo[0]<=$this->_TEMP['br']) { 906 | $url=array( 907 | 'url' => 'https://dl.stream.qqmusic.qq.com/'.$vo[1].$data['data'][0]['file']['media_mid'].'.'.$vo[2].'?vkey='.$KEY.'&guid='.$GUID.'&uid=0&fromtag=30', 908 | 'br' => $vo[0], 909 | ); 910 | break; 911 | } 912 | } 913 | if (!isset($url['url'])) { 914 | $url=array( 915 | 'url' => '', 916 | 'br' => -1, 917 | ); 918 | } 919 | return json_encode($url); 920 | } 921 | private function xiami_url($result) 922 | { 923 | $data=json_decode($result, 1); 924 | if (!empty($data['location'])) { 925 | $location = $data['location']; 926 | $num = (int)$location[0]; 927 | $str = substr($location, 1); 928 | $len = floor(strlen($str)/$num); 929 | $sub = strlen($str) % $num; 930 | $qrc = array(); 931 | $tmp = 0; 932 | $urlt = ''; 933 | for (;$tmp<$sub;$tmp++) { 934 | $qrc[$tmp] = substr($str, $tmp*($len+1), $len+1); 935 | } 936 | for (;$tmp<$num;$tmp++) { 937 | $qrc[$tmp] = substr($str, $len*$tmp+$sub, $len); 938 | } 939 | for ($tmpa=0;$tmpa<$len+1;$tmpa++) { 940 | for ($tmpb=0;$tmpb<$num;$tmpb++) { 941 | if (isset($qrc[$tmpb][$tmpa])) { 942 | $urlt.=$qrc[$tmpb][$tmpa]; 943 | } 944 | } 945 | } 946 | $urlt=str_replace('^', '0', urldecode($urlt)); 947 | $url=array( 948 | 'url' => str_replace('http://','https://',urldecode($urlt)), 949 | 'br' => 320, 950 | ); 951 | } else { 952 | $url=array( 953 | 'url' => '', 954 | 'br' => -1, 955 | ); 956 | } 957 | return json_encode($url); 958 | } 959 | private function kugou_url($result) 960 | { 961 | $data=json_decode($result, 1); 962 | 963 | $max=0; 964 | $url=array(); 965 | foreach ($data['data'][0]['relate_goods'] as $vo) { 966 | if ($vo['info']['bitrate']<=$this->_TEMP['br']&&$vo['info']['bitrate']>$max) { 967 | $API=array( 968 | 'method' => 'GET', 969 | 'url' => 'http://trackercdn.kugou.com/i/v2/', 970 | 'body' => array( 971 | 'hash' => $vo['hash'], 972 | 'key' => md5($vo['hash'].'kgcloudv2'), 973 | 'pid' => 1, 974 | 'behavior' => 'play', 975 | 'cmd' => '23', 976 | 'version' => 8400, 977 | ), 978 | ); 979 | $t=json_decode($this->curl($API), 1); 980 | if (isset($t['url'])) { 981 | $max=$t['bitRate']/1000; 982 | $url=array( 983 | 'url' => $t['url'], 984 | 'br' => $t['bitRate']/1000, 985 | ); 986 | } 987 | } 988 | } 989 | if (!isset($url['url'])) { 990 | $url=array( 991 | 'url' => '', 992 | 'br' => -1, 993 | ); 994 | } 995 | return json_encode($url); 996 | } 997 | private function baidu_url($result) 998 | { 999 | $data=json_decode($result, true); 1000 | 1001 | $max=0; 1002 | $url=array(); 1003 | foreach ($data['songurl']['url'] as $vo) { 1004 | if ($vo['file_bitrate']<=$this->_TEMP['br']&&$vo['file_bitrate']>$max) { 1005 | $url=array( 1006 | 'url' => $vo['file_link'], 1007 | 'br' => $vo['file_bitrate'], 1008 | ); 1009 | } 1010 | } 1011 | if (!isset($url['url'])) { 1012 | $url=array( 1013 | 'url' => '', 1014 | 'br' => -1, 1015 | ); 1016 | } 1017 | return json_encode($url); 1018 | } 1019 | /** 1020 | * 歌词处理模块 1021 | * 用于规范化歌词输出 1022 | */ 1023 | private function netease_lyric($result) 1024 | { 1025 | if (!$this->_FORMAT) { 1026 | return $result; 1027 | } 1028 | $result=json_decode($result, 1); 1029 | $data=array( 1030 | 'lyric' => isset($result['lrc']['lyric'])?$result['lrc']['lyric']:'', 1031 | 'tlyric' => isset($result['tlyric']['lyric'])?$result['tlyric']['lyric']:'', 1032 | ); 1033 | return json_encode($data); 1034 | } 1035 | private function tencent_lyric($result) 1036 | { 1037 | $result=substr($result,18,-1); 1038 | if (!$this->_FORMAT) { 1039 | return $result; 1040 | } 1041 | $result=json_decode($result, 1); 1042 | $data=array( 1043 | 'lyric' => isset($result['lyric'])?base64_decode($result['lyric']):'', 1044 | 'tlyric' => isset($result['trans'])?base64_decode($result['trans']):'', 1045 | ); 1046 | return json_encode($data); 1047 | } 1048 | private function xiami_lyric($result) 1049 | { 1050 | if (!$this->_FORMAT) { 1051 | return $result; 1052 | } 1053 | $result=json_decode($result, 1); 1054 | $data=''; 1055 | if(!empty($result['data']['song']['lyric'])){ 1056 | $API=array('method'=>'GET','url'=>$result['data']['song']['lyric']); 1057 | $data=$this->curl($API); 1058 | $data=preg_replace('/<[^>]+>/', '', $data); 1059 | } 1060 | preg_match_all('/\[([\d:\.]+)\](.*)\s\[x-trans\](.*)/i',$data,$match); 1061 | if(sizeof($match[0])){ 1062 | for($i=0;$i str_replace($match[0],$A,$data), 1068 | 'tlyric' => str_replace($match[0],$B,$data), 1069 | ); 1070 | } 1071 | else{ 1072 | $arr=array( 1073 | 'lyric' => $data, 1074 | 'tlyric' => '', 1075 | ); 1076 | } 1077 | return json_encode($arr); 1078 | } 1079 | private function kugou_lyric($result) 1080 | { 1081 | if (!$this->_FORMAT) { 1082 | return $result; 1083 | } 1084 | $arr=array( 1085 | 'lyric' => $result, 1086 | 'tlyric' => '', 1087 | ); 1088 | return json_encode($arr); 1089 | } 1090 | private function baidu_lyric($result) 1091 | { 1092 | if (!$this->_FORMAT) { 1093 | return $result; 1094 | } 1095 | $result=json_decode($result, 1); 1096 | $data=array( 1097 | 'lyric' => isset($result['lrcContent'])?$result['lrcContent']:'', 1098 | 'tlyric' => '', 1099 | ); 1100 | return json_encode($data); 1101 | } 1102 | /** 1103 | * Format - 规范化函数 1104 | * 用于统一返回的参数,可用 ->format() 一次性开关开启 1105 | */ 1106 | private function format_netease($data) 1107 | { 1108 | $result=array( 1109 | 'id' => $data['id'], 1110 | 'name' => $data['name'], 1111 | 'artist' => array(), 1112 | 'album' => $data['al']['name'], 1113 | 'pic_id' => isset($data['al']['pic_str'])?$data['al']['pic_str']:$data['al']['pic'], 1114 | 'url_id' => $data['id'], 1115 | 'lyric_id' => $data['id'], 1116 | 'source' => 'netease', 1117 | ); 1118 | if (isset($data['al']['picUrl'])) { 1119 | preg_match('/\/(\d+)\./', $data['al']['picUrl'], $match); 1120 | $result['pic_id']=$match[1]; 1121 | } 1122 | foreach ($data['ar'] as $vo) { 1123 | $result['artist'][]=$vo['name']; 1124 | } 1125 | return $result; 1126 | } 1127 | private function format_tencent($data) 1128 | { 1129 | if (isset($data['musicData'])) { 1130 | $data=$data['musicData']; 1131 | } 1132 | $result=array( 1133 | 'id' => $data['mid'], 1134 | 'name' => $data['name'], 1135 | 'artist' => array(), 1136 | 'album' => trim($data['album']['title']), 1137 | 'pic_id' => $data['album']['mid'], 1138 | 'url_id' => $data['mid'], 1139 | 'lyric_id' => $data['mid'], 1140 | 'source' => 'tencent', 1141 | ); 1142 | foreach ($data['singer'] as $vo) { 1143 | $result['artist'][]=$vo['name']; 1144 | } 1145 | return $result; 1146 | } 1147 | private function format_xiami($data) 1148 | { 1149 | $result=array( 1150 | 'id' => $data['song_id'], 1151 | 'name' => $data['song_name'], 1152 | 'artist' => explode(';', isset($data['singers'])?$data['singers']:$data['artist_name']), 1153 | 'album' => $data['album_name'], 1154 | 'pic_id' => $data['song_id'], 1155 | 'url_id' => $data['song_id'], 1156 | 'lyric_id' => $data['song_id'], 1157 | 'source' => 'xiami', 1158 | ); 1159 | return $result; 1160 | } 1161 | private function format_kugou($data) 1162 | { 1163 | $result=array( 1164 | 'id' => $data['hash'], 1165 | 'name' => isset($data['filename'])?$data['filename']:$data['fileName'], 1166 | 'artist' => array(), 1167 | 'album' => isset($data['album_name'])?$data['album_name']:'', 1168 | 'url_id' => $data['hash'], 1169 | 'pic_id' => $data['hash'], 1170 | 'lyric_id' => $data['hash'], 1171 | 'source' => 'kugou', 1172 | ); 1173 | list($result['artist'], $result['name'])=explode(' - ', $result['name'], 2); 1174 | $result['artist']=explode('、', $result['artist']); 1175 | return $result; 1176 | } 1177 | private function format_baidu($data) 1178 | { 1179 | $result=array( 1180 | 'id' => $data['song_id'], 1181 | 'name' => $data['title'], 1182 | 'artist' => explode(',', $data['author']), 1183 | 'album' => $data['album_title'], 1184 | 'pic_id' => $data['song_id'], 1185 | 'url_id' => $data['song_id'], 1186 | 'lyric_id' => $data['song_id'], 1187 | 'source' => 'baidu', 1188 | ); 1189 | return $result; 1190 | } 1191 | } 1192 | --------------------------------------------------------------------------------