diff --git a/Action.php b/Action.php index a52cb58..7150b19 100644 --- a/Action.php +++ b/Action.php @@ -6,66 +6,154 @@ class Meting_Action extends Typecho_Widget implements Widget_Interface_Do { public function execute(){} public function action(){ - $this->on($this->request->is('do=musicjs'))->musicjs(); - $this->on($this->request->is('do=url'))->url(); - $this->on($this->request->is('do=pic'))->pic(); - $this->on($this->request->is('do=lrc'))->lrc(); $this->on($this->request->is('do=parse'))->shortcode(); + $this->on($this->request->isGet())->api(); + } + + private function check($a,$b){ + if(!in_array($a,array('netease','tencent','baidu','xiami','kugou')))return false; + if(!in_array($b,array('song','album','search','artist','playlist','lrc','url','pic')))return false; + return true; + } + + private function api(){ + $this->filterReferer(); + $server=$this->request->get('server'); + $type=$this->request->get('type'); + $id=$this->request->get('id'); + + if(!$this->check($server,$type)||empty($id))die('[]'); + + if(!extension_loaded('Meting'))include_once 'include/Meting.php'; + $api=new \Metowolf\Meting($server); + $api->format(true); + + $EID=md5($server.'/'.$type.'/'.$id); + $salt=Typecho_Widget::widget('Widget_Options')->plugin('Meting')->salt; + + if(in_array($type,array('lrc','pic','url'))){ + $auth1=md5($salt.$id.$salt); + $auth2=$this->request->get('auth'); + if(strcmp($auth1,$auth2)){ + http_response_code(403); + die(); + } + } + + if($type=='lrc'){ + $data=$this->cacheRead($EID,60*60*24); + if(empty($data)){ + $data=$api->lyric($id); + $this->cacheWrite($EID,$data); + } + $data=json_decode($data,true); + header("Content-Type: application/javascript"); + echo $data['lyric']; + } + elseif($type=='pic'){ + $data=$this->cacheRead($EID,60*60*24); + if(empty($data)){ + $data=$api->pic($id,90); + $this->cacheWrite($EID,$data); + } + $data=json_decode($data,true); + $this->response->redirect($data['url']); + } + elseif($type=='url'){ + $data=$this->cacheRead($EID,60*15); + if(empty($data)){ + $rate=Typecho_Widget::widget('Widget_Options')->plugin('Meting')->bitrate; + $cookie=Typecho_Widget::widget('Widget_Options')->plugin('Meting')->cookie; + if($server=='netease')$api->cookie($cookie); + $data=$api->url($id,$rate); + $this->cacheWrite($EID,$data); + } + $data=json_decode($data,true); + $url=$data['url']; + + $url=str_replace('http://m8','https://m8',$url); + $url=str_replace('http://m7','https://m8',$url); + $url=str_replace('http://m10','https://m10',$url); + + if(empty($url))$url='https://api.i-meto.com/Public/music/empty.mp3'; + $this->response->redirect($url); + } + else{ + $data=$this->cacheRead($EID,60*60*2); + if(empty($data)){ + $data=$api->$type($id); + $this->cacheWrite($EID,$data); + } + $data=json_decode($data,1); + $url=Typecho_Common::url('action/metingapi',Helper::options()->index); + + $music=array(); + foreach($data as $vo){ + $music[]=array( + 'title' => $vo['name'], + 'author' => implode(' / ',$vo['artist']), + 'url' => $url.'?server='.$vo['source'].'&type=url&id='.$vo['url_id'].'&auth='.md5($salt.$vo['url_id'].$salt), + 'pic' => $url.'?server='.$vo['source'].'&type=pic&id='.$vo['pic_id'].'&auth='.md5($salt.$vo['pic_id'].$salt), + 'lrc' => $url.'?server='.$vo['source'].'&type=lrc&id='.$vo['lyric_id'].'&auth='.md5($salt.$vo['lyric_id'].$salt), + ); + } + header("Content-Type: application/javascript"); + echo json_encode($music); + } + } private function shortcode(){ - $urls=$this->request->get('data'); - $urls=explode("\n",$urls); - echo "[Meting]\n"; - foreach($urls as $url){ - $url=trim($url); - if($url=="")continue; - $server='音乐平台';$id='编号';$type='类型'; - if(strpos($url,'163.com')!==false){ - $server='netease'; - if(preg_match('/playlist\?id=(\d+)/i',$url,$id))list($id,$type)=array($id[1],'playlist'); - elseif(preg_match('/toplist\?id=(\d+)/i',$url,$id))list($id,$type)=array($id[1],'playlist'); - elseif(preg_match('/album\?id=(\d+)/i',$url,$id))list($id,$type)=array($id[1],'album'); - elseif(preg_match('/song\?id=(\d+)/i',$url,$id))list($id,$type)=array($id[1],'song'); - elseif(preg_match('/artist\?id=(\d+)/i',$url,$id))list($id,$type)=array($id[1],'artist'); - } - elseif(strpos($url,'qq.com')!==false){ - $server='tencent'; - if(preg_match('/playlist\/([^\.]*)/i',$url,$id))list($id,$type)=array($id[1],'playlist'); - elseif(preg_match('/album\/([^\.]*)/i',$url,$id))list($id,$type)=array($id[1],'album'); - elseif(preg_match('/song\/([^\.]*)/i',$url,$id))list($id,$type)=array($id[1],'song'); - elseif(preg_match('/singer\/([^\.]*)/i',$url,$id))list($id,$type)=array($id[1],'artist'); - } - elseif(strpos($url,'xiami.com')!==false){ - $server='xiami'; - if(preg_match('/collect\/(\w+)/i',$url,$id))list($id,$type)=array($id[1],'playlist'); - elseif(preg_match('/album\/(\w+)/i',$url,$id))list($id,$type)=array($id[1],'album'); - elseif(preg_match('/[\/.]\w+\/[songdem]+\/(\w+)/i',$url,$id))list($id,$type)=array($id[1],'song'); - elseif(preg_match('/artist\/(\w+)/i',$url,$id))list($id,$type)=array($id[1],'artist'); - if(!preg_match('/^\d*$/i',$id,$t)){ - $data=self::curl($url); - preg_match('/'.$type.'\/(\d+)/i',$data,$id); - $id=$id[1]; - } - } - elseif(strpos($url,'kugou.com')!==false){ - $server='kugou'; - if(preg_match('/special\/single\/(\d+)/i',$url,$id))list($id,$type)=array($id[1],'playlist'); - elseif(preg_match('/song\/#hash\=(\w+)/i',$url,$id))list($id,$type)=array($id[1],'song'); - elseif(preg_match('/album\/[single\/]*(\d+)/i',$url,$id))list($id,$type)=array($id[1],'album'); - elseif(preg_match('/singer\/[home\/]*(\d+)/i',$url,$id))list($id,$type)=array($id[1],'artist'); - } - elseif(strpos($url,'baidu.com')!==false){ - $server='baidu'; - if(preg_match('/songlist\/(\d+)/i',$url,$id))list($id,$type)=array($id[1],'playlist'); - elseif(preg_match('/album\/(\d+)/i',$url,$id))list($id,$type)=array($id[1],'album'); - elseif(preg_match('/song\/(\d+)/i',$url,$id))list($id,$type)=array($id[1],'song'); - elseif(preg_match('/artist\/(\d+)/i',$url,$id))list($id,$type)=array($id[1],'artist'); - } - else list($id,$type)=array($url,'search'); - echo '[Music server="'.$server.'" id="'.$id.'" type="'.$type.'"/]'."\n"; + $url=$this->request->get('data'); + $url=trim($url); + if(empty($url))return; + $server='netease';$id='';$type=''; + if(strpos($url,'163.com')!==false){ + $server='netease'; + if(preg_match('/playlist\?id=(\d+)/i',$url,$id))list($id,$type)=array($id[1],'playlist'); + elseif(preg_match('/toplist\?id=(\d+)/i',$url,$id))list($id,$type)=array($id[1],'playlist'); + elseif(preg_match('/album\?id=(\d+)/i',$url,$id))list($id,$type)=array($id[1],'album'); + elseif(preg_match('/song\?id=(\d+)/i',$url,$id))list($id,$type)=array($id[1],'song'); + elseif(preg_match('/artist\?id=(\d+)/i',$url,$id))list($id,$type)=array($id[1],'artist'); } - echo "[/Meting]"; + elseif(strpos($url,'qq.com')!==false){ + $server='tencent'; + if(preg_match('/playlist\/([^\.]*)/i',$url,$id))list($id,$type)=array($id[1],'playlist'); + elseif(preg_match('/album\/([^\.]*)/i',$url,$id))list($id,$type)=array($id[1],'album'); + elseif(preg_match('/song\/([^\.]*)/i',$url,$id))list($id,$type)=array($id[1],'song'); + elseif(preg_match('/singer\/([^\.]*)/i',$url,$id))list($id,$type)=array($id[1],'artist'); + } + elseif(strpos($url,'xiami.com')!==false){ + $server='xiami'; + if(preg_match('/collect\/(\w+)/i',$url,$id))list($id,$type)=array($id[1],'playlist'); + elseif(preg_match('/album\/(\w+)/i',$url,$id))list($id,$type)=array($id[1],'album'); + elseif(preg_match('/[\/.]\w+\/[songdem]+\/(\w+)/i',$url,$id))list($id,$type)=array($id[1],'song'); + elseif(preg_match('/artist\/(\w+)/i',$url,$id))list($id,$type)=array($id[1],'artist'); + if(!preg_match('/^\d*$/i',$id,$t)){ + $data=self::curl($url); + preg_match('/'.$type.'\/(\d+)/i',$data,$id); + $id=$id[1]; + } + } + elseif(strpos($url,'kugou.com')!==false){ + $server='kugou'; + if(preg_match('/special\/single\/(\d+)/i',$url,$id))list($id,$type)=array($id[1],'playlist'); + elseif(preg_match('/song\/#hash\=(\w+)/i',$url,$id))list($id,$type)=array($id[1],'song'); + elseif(preg_match('/album\/[single\/]*(\d+)/i',$url,$id))list($id,$type)=array($id[1],'album'); + elseif(preg_match('/singer\/[home\/]*(\d+)/i',$url,$id))list($id,$type)=array($id[1],'artist'); + } + elseif(strpos($url,'baidu.com')!==false){ + $server='baidu'; + if(preg_match('/songlist\/(\d+)/i',$url,$id))list($id,$type)=array($id[1],'playlist'); + elseif(preg_match('/album\/(\d+)/i',$url,$id))list($id,$type)=array($id[1],'album'); + elseif(preg_match('/song\/(\d+)/i',$url,$id))list($id,$type)=array($id[1],'song'); + elseif(preg_match('/artist\/(\d+)/i',$url,$id))list($id,$type)=array($id[1],'artist'); + } + else{ + echo "[Meting]\n[Music title=\"歌曲名\" author=\"歌手\" url=\"{$url}\"/]\n[/Meting]\n"; + return; + } + echo "[Meting]\n[Music server=\"{$server}\" id=\"{$id}\" type=\"{$type}\"/]\n[/Meting]\n"; } private function curl($url){ @@ -80,143 +168,10 @@ class Meting_Action extends Typecho_Widget implements Widget_Interface_Do { return $result; } - private function musicjs(){ - if(!extension_loaded('Meting'))include_once 'include/Meting.php'; - self::filterReferer(); - $PID=$this->request->get('id'); - $data=$this->request->get('d'); - $data=json_decode(base64_decode($data),1); - $setting=$this->request->get('s'); - $setting=json_decode(base64_decode($setting),1); - $music=array(); - foreach($data as $vo){ - $EID=md5('js/'.$vo['server'].'/'.$vo['type'].'/'.$vo['id']); - $t=self::cacheRead($EID,60*60*24*3); - if(!$t){ - $API=(new \Metowolf\Meting($vo['server']))->format(true); - $t=call_user_func_array(array($API,$vo['type']),array($vo['id'])); - $t=json_decode($t,1); - self::cacheWrite($EID,$t); - } - $music=array_merge($music,$t); - } - $player=array( - 'theme' => isset($setting['theme'])?$setting['theme']:Typecho_Widget::widget('Widget_Options')->plugin('Meting')->theme?:'red', - 'preload' => isset($setting['preload'])?$setting['preload']:Typecho_Widget::widget('Widget_Options')->plugin('Meting')->preload?:'auto', - 'autoplay' => isset($setting['autoplay'])?$setting['autoplay']:Typecho_Widget::widget('Widget_Options')->plugin('Meting')->autoplay?:'false', - 'height' => isset($setting['height'])?$setting['height']:Typecho_Widget::widget('Widget_Options')->plugin('Meting')->height?:'340px', - 'mode' => isset($setting['mode'])?$setting['mode']:Typecho_Widget::widget('Widget_Options')->plugin('Meting')->mode?:'circulation', - 'music' => array(), - ); - foreach($music as $vo){ - $URI=Typecho_Common::url('action/metingapi',Helper::options()->index); - $player['music'][]=array( - 'title'=>$vo['name'], - 'author'=>implode(' / ',$vo['artist']), - 'url'=>$URI.'?site='.$vo['source'].'&do=url&id='.$vo['url_id'], - 'pic'=>$URI.'?site='.$vo['source'].'&do=pic&id='.$vo['pic_id'], - 'lrc'=>$URI.'?site='.$vo['source'].'&do=lrc&id='.$vo['lyric_id'], - ); - } - if(sizeof($player['music'])==1)$player['music']=$player['music'][0]; - $player['music']=json_encode($player['music']); - - header('content-type:application/javascript'); - echo " - var Meting{$PID} = new APlayer({ - element: document.getElementById('MetingPlayer'+{$PID}), - autoplay: ".$player['autoplay'].", - preload: \"".$player['preload']."\", - showlrc: 3, - mutex: true, - mode: '".$player['mode']."', - theme: \"".$player['theme']."\", - music: ".$player['music'].", - listmaxheight: '".$player['height']."', - }); - "; - } - - private function url(){ - if(!extension_loaded('Meting'))include_once 'include/Meting.php'; - self::filterReferer(); - $id=$this->request->get('id'); - $site=$this->request->get('site'); - $rate=Typecho_Widget::widget('Widget_Options')->plugin('Meting')->bitrate; - $cookie=Typecho_Widget::widget('Widget_Options')->plugin('Meting')->cookie; - - $cachekey="url/{$site}/{$id}/{$rate}"; - $data=self::cacheRead($cachekey,60*15); - if(!$data){ - $api=(new \Metowolf\Meting($site)); - if($cookie!='')$api->cookie($cookie); - $data=$api->format(true)->url($id,$rate); - $data=json_decode($data,1); - self::cacheWrite($cachekey,$data); - } - if(empty($data['url']))$data['url']="https://api.i-meto.com/Public/music/empty.mp3"; - if($site=='netease'){ - $data['url']=str_replace("http://","https://",$data['url']); - } - $this->response->redirect($data['url']); - } - - private function pic(){ - if(!extension_loaded('Meting'))include_once 'include/Meting.php'; - self::filterReferer(); - $id=$this->request->get('id'); - $site=$this->request->get('site'); - - $cachekey="pic/{$site}/{$id}"; - $data=self::cacheRead($cachekey,60*60*24*30); - if(!$data){ - $data=(new \Metowolf\Meting($site))->pic($id,90); - $data=json_decode($data,1); - self::cacheWrite($cachekey,$data); - } - $this->response->redirect($data['url']); - } - - private function lrc(){ - if(!extension_loaded('Meting'))include_once 'include/Meting.php'; - self::filterReferer(); - $id=$this->request->get('id'); - $site=$this->request->get('site'); - - $cachekey="lyric/{$site}/{$id}"; - $data=self::cacheRead($cachekey,60*60*24*10); - if(!$data){ - $data=(new \Metowolf\Meting($site))->format(true)->lyric($id); - $data=json_decode($data,1); - self::cacheWrite($cachekey,$data); - } - if(!empty($data['tlyric']))$text=$this->lrctran($data['lyric'],$data['tlyric']); - else $text=$data['lyric']; - if(strlen($text)==0)$text='[00:00.00]无歌词'; - echo $text; - } - - private function lrctran($lyric,$tlyric){ - preg_match_all('/\[(\d{2}:\d{2}\.\d+)\]([^\n]+)/i',$lyric,$t1); - preg_match_all('/\[(\d{2}:\d{2}\.\d+)\]([^\n]+)/i',$tlyric,$t2); - $from=$to=$t1[0]; - $len1=sizeof($t1[0]); - $len2=sizeof($t2[0]); - for($i=0,$j=0;$i<$len1;$i++){ - while($t1[1][$i]>$t2[1][$j]&&$j+1<$len2)$j++; - if($t1[1][$i]==$t2[1][$j]){ - $t=trim(str_replace('/','',$t2[2][$j])); - if($t)$to[$i].=" (".$t2[2][$j].")"; - $j++; - } - } - return str_replace($from,$to,$lyric); - } - private function cacheWrite($k,$v){ - if(!is_array($v)||is_null($v))return; + if(empty($v)||is_null($v))return; $db=Typecho_Db::get(); - $insert=$db->insert('table.metingv1')->rows(array('id'=>md5($k),'value'=>serialize($v),'last'=>time())); + $insert=$db->insert('table.metingv1')->rows(array('id'=>md5($k),'value'=>$v,'last'=>time())); return $db->query($insert); } @@ -231,21 +186,19 @@ class Meting_Action extends Typecho_Widget implements Widget_Interface_Do { $db->query($delete); return false; } - return unserialize($result['value']); + header("Meting-Cache: HIT"); + return $result['value']; + } + else{ + header("Meting-Cache: MISS"); + return false; } - else return false; } - /*private function cacheFlush(){ - $db=Typecho_Db::get(); - $delete=$db->delete('table.metingv1')->where('lastquery($delete); - }*/ - private function filterReferer(){ if(isset($_SERVER['HTTP_REFERER'])&&strpos($_SERVER['HTTP_REFERER'],$_SERVER['HTTP_HOST'])===false){ http_response_code(403); - die(); + die('[]'); } } } diff --git a/Plugin.php b/Plugin.php index 2521563..a445e0f 100644 --- a/Plugin.php +++ b/Plugin.php @@ -2,21 +2,20 @@ if(!defined('__TYPECHO_ROOT_DIR__'))exit; /** - * Meting for Typecho | 在 Typecho 中使用 APlayer 播放在线音乐吧~ + * APlayer for Typecho | 在 Typecho 中使用 APlayer 播放在线音乐吧~ * - * @package Meting + * @package APlayer for Typecho | Meting * @author METO - * @version 1.2.5 + * @version 2.0.0 * @dependence 14.10.10-* - * @link https://github.com/metowolf/Meting-Typecho-Plugin + * @link https://github.com/MoePlayer/APlayer-Typecho * */ -define('METING_VERSION','1.2.5'); +define('METING_VERSION','2.0.0'); class Meting_Plugin extends Typecho_Widget implements Typecho_Plugin_Interface { - protected static $PID = 0; /** * 激活插件方法,如果激活失败,直接抛出异常 * @@ -56,11 +55,6 @@ class Meting_Plugin extends Typecho_Widget implements Typecho_Plugin_Interface * @return void */ public static function config(Typecho_Widget_Helper_Form $form){ - $t = new Typecho_Widget_Helper_Form_Element_Radio( - 'cloudapi', array('true'=>_t('是'),'false'=>_t('否')),'false', - _t('METO 云解析 (beta)'), - _t('当插件无法正常工作时,可以勾选开启。歌单混播、音质调节将失效')); - $form->addInput($t); $t = new Typecho_Widget_Helper_Form_Element_Text( 'theme', null, '#ad7a86', _t('播放器颜色'), @@ -92,10 +86,44 @@ class Meting_Plugin extends Typecho_Widget implements Typecho_Plugin_Interface _t('')); $form->addInput($t); $t = new Typecho_Widget_Helper_Form_Element_Text( - 'cookie', null, '', - _t('自定义 Cookie (高级)'), - _t('通过更改 Cookie,使其享受与客户端一样的体验')); + 'api', null, Typecho_Common::url('action/metingapi',Helper::options()->index)."?server=:server&type=:type&id=:id&r=:r", + _t('云解析地址'), + _t('示例:https://api.i-meto.com/meting/api?server=:server&type=:type&id=:id&r=:r')); $form->addInput($t); + $t = new Typecho_Widget_Helper_Form_Element_Text( + 'salt', null, md5(time()."Meting"), + _t('接口保护'), + _t('加盐保护 API 接口不被滥用,自动生成无需设置。')); + $form->addInput($t); + $t = new Typecho_Widget_Helper_Form_Element_Textarea( + 'cookie', null, '', + _t('网易云音乐 Cookie (高级)'), + _t('如果您是网易云音乐的会员,可以将您的 cookie 填入此处来获取云盘等付费资源,听歌将不会计入下载次数。
如果不知道这是什么意思,忽略即可。')); + $form->addInput($t); + $t = new Typecho_Widget_Helper_Form_Element_Radio( + 'clean', array(_t('关闭'), _t('清除所有缓存')), 0, + _t('保存时清除所有缓存')); + $form->addInput($t); + } + + /** + * 手动保存配置句柄 + * @param $config array 插件配置 + * @param $is_init bool 是否初始化 + */ + public static function configHandle($config, $is_init) + { + if($is_init!=true){ + if($config['api']==""){ + $config['api']=Typecho_Common::url('action/metingapi',Helper::options()->index)."?server=:server&type=:type&id=:id&r=:r"; + } + if($config['clean']==1){ + self::clean(); + $config['clean']=0; + } + } + + Helper::configPlugin('Meting', $config); } public static function personalConfig(Typecho_Widget_Helper_Form $form){} @@ -108,22 +136,17 @@ class Meting_Plugin extends Typecho_Widget implements Typecho_Plugin_Interface * @return void */ public static function header(){ - $dir=Helper::options()->pluginUrl.'/Meting/assets/'; + $api=Typecho_Widget::widget('Widget_Options')->plugin('Meting')->api; + $dir=Helper::options()->pluginUrl.'/Meting/assets'; $ver=METING_VERSION; - echo "\n"; - echo "\n"; - echo "\n"; + echo "\n"; + echo ""; } public static function footer(){ + $dir=Helper::options()->pluginUrl.'/Meting/assets'; $ver=METING_VERSION; - if(Typecho_Widget::widget('Widget_Options')->plugin('Meting')->cloudapi=='true'){ - echo "\n"; - } - } - - public static function getPID(){ - return ++self::$PID; + echo "\n"; } public static function playerReplace($data,$widget,$last){ @@ -146,35 +169,36 @@ class Meting_Plugin extends Typecho_Widget implements Typecho_Plugin_Interface public static function parseMusic($matches,$setting){ $data=array(); + $str=""; foreach($matches as $vo){ $t=self::shortcode_parse_atts(htmlspecialchars_decode($vo)); - if(!in_array($t['server'],array('netease','tencent','xiami','baidu','kugou')))continue; - if(!in_array($t['type'],array('search','album','playlist','artist','song')))continue; - $data[]=$t; - } - $id=self::getPID(); - $dir=Typecho_Common::url('action/metingapi',Helper::options()->index); - if(Typecho_Widget::widget('Widget_Options')->plugin('Meting')->cloudapi=='true'){ - $str="
$setting['theme']?:Typecho_Widget::widget('Widget_Options')->plugin('Meting')->theme?:'red', - 'preload' => $setting['preload']?:Typecho_Widget::widget('Widget_Options')->plugin('Meting')->preload?:'auto', - 'autoplay' => $setting['autoplay']?:Typecho_Widget::widget('Widget_Options')->plugin('Meting')->autoplay?:'false', - 'height' => $setting['height']?:Typecho_Widget::widget('Widget_Options')->plugin('Meting')->height?:'340px', - 'mode' => $setting['mode']?:Typecho_Widget::widget('Widget_Options')->plugin('Meting')->mode?:'circulation', + 'theme' => Typecho_Widget::widget('Widget_Options')->plugin('Meting')->theme?:'red', + 'preload' => Typecho_Widget::widget('Widget_Options')->plugin('Meting')->preload?:'auto', + 'autoplay' => Typecho_Widget::widget('Widget_Options')->plugin('Meting')->autoplay?:'false', + 'height' => Typecho_Widget::widget('Widget_Options')->plugin('Meting')->height?:'340px', + 'mode' => Typecho_Widget::widget('Widget_Options')->plugin('Meting')->mode?:'circulation', ); - foreach($player as $key=>$vo){ - $str.=" data-{$key}=\"{$vo}\""; + if(isset($t['server'])){ + if(!in_array($t['server'],array('netease','tencent','xiami','baidu','kugou')))continue; + if(!in_array($t['type'],array('search','album','playlist','artist','song')))continue; + $data=$t; + + $str.="
$vo)$player[$key]=$vo; + foreach($player as $key=>$vo)$str.=" data-{$key}=\"{$vo}\""; + $str.=">
\n"; + } + else{ + $data=$t; + + $str.="
$vo)$player[$key]=$vo; + foreach($player as $key=>$vo)$str.=" data-{$key}=\"{$vo}\""; + $str.=">
\n"; } - $str.=">
\n"; - return $str; - } - else{ - $setting=base64_encode(json_encode($setting)); - $data=base64_encode(json_encode($data)); - return "
- "; } + return $str; } public static function addButton(){ @@ -226,9 +250,9 @@ class Meting_Plugin extends Typecho_Widget implements Typecho_Plugin_Interface $dbname=$db->getPrefix().'metingv1'; try{ $db->query("CREATE TABLE IF NOT EXISTS {$dbname} ( - id CHAR(32) PRIMARY KEY NOT NULL UNIQUE, - value TEXT NOT NULL, - last int NOT NULL + id VARCHAR(32) PRIMARY KEY NOT NULL UNIQUE, + value TEXT NOT NULL, + last int NOT NULL )"); }catch(Typecho_Db_Exception $e){ $code=$e->getCode(); @@ -236,11 +260,18 @@ class Meting_Plugin extends Typecho_Widget implements Typecho_Plugin_Interface } } + private function clean(){ + $db=Typecho_Db::get(); + $dbname=$db->getPrefix().'metingv1'; + $delete=$db->delete($dbname); + $db->query($delete); + } + public static function uninstall(){ $db=Typecho_Db::get(); $dbname=$db->getPrefix().'metingv1'; try{ - $db->query("DROP TABLE IF EXISTS {$dbname};"); + $db->query("DROP TABLE IF EXISTS {$dbname}"); }catch(Typecho_Db_Exception $e){ $code=$e->getCode(); throw new Typecho_Plugin_Exception('插件禁用失败。错误号:'.$code); diff --git a/README.md b/README.md index 4e28852..6eddad5 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,18 @@

-Meting +Meting

-# APlayer for Typecho (Meting) +# APlayer for Typecho 在 Typecho 中使用 APlayer 播放在线音乐吧~ [发布页面](https://i-meto.com/meting-typecho/) ## 介绍 1. 支持国内五大音乐平台(网易云、QQ、虾米、百度、酷狗)的单曲/专辑/歌单播放 2. 简单快捷,复制音乐详情页面网址,后台自动生成播放代码 - 3. **支持不同音乐平台歌曲混合播放** - 4. 前端 APlayer,后端 Meting 及时更新,保证兼容性及 API 高可用性 - 5. 支持 MySql、SQLite 数据库 + 3. 前端 APlayer,后端 Meting 及时更新,保证兼容性及 API 高可用性 + 4. 支持 MySql、SQLite 数据库 + 5. 支持自定义歌曲播放 + 6. **自定义 API 支持** ## 声明 本作品仅供个人学习研究使用,请勿将其用作商业用途。 @@ -25,7 +26,6 @@ ## 使用 在文章编辑页面,点击编辑器上的 **音乐图标** 按钮,在弹出的窗口中输入音乐地址(见支持列表),最后点击确定即可 -**歌曲混合特性:** 允许添加多个音乐地址,每行一个,插件会自动将所有歌曲合并在同一个歌单进行播放。 ## 支持列表 网易云音乐 http://music.163.com @@ -67,4 +67,4 @@ A: 为了减少服务器压力,插件设置对歌单、歌词数据进行缓 更多问题可以通过 issue 页面提交,或者通过 Telegram、邮件向我反馈 ## LICENSE -APlayer-Typecho-Plugin is under the MIT license. +APlayer-Typecho is under the MIT license. diff --git a/assets/Meting.min.js b/assets/Meting.min.js new file mode 100644 index 0000000..46f75d7 --- /dev/null +++ b/assets/Meting.min.js @@ -0,0 +1,2 @@ +/*! meting.aplayer.js v1.2.1 | MIT License */ +!function(){function e(e,t){var a=[],r=e.dataset;a.element=e,a.music=t,a.showlrc=a.music[0].lrc?3:0,a.narrow="true"===r.narrow,a.autoplay="true"===r.autoplay,a.mutex="false"!==r.mutex,a.mode=r.mode||"circulation",a.preload=r.preload||"auto",a.listmaxheight=r.listmaxheight||"340px",a.theme=r.theme||"#ad7a86",new APlayer(a)}console.log("\n %c Meting 1.2.1 %c https://i-meto.com/ghost-aplayer/ \n\n","color: #fff; background-image: linear-gradient(90deg, rgb(47, 172, 178) 0%, rgb(45, 190, 96) 100%); padding:5px 1px;","background-image: linear-gradient(90deg, rgb(45, 190, 96) 0%, rgb(255, 255, 255) 100%); padding:5px 0;");var t="https://api.i-meto.com/meting/api?server=:server&type=:type&id=:id&r=:r";"undefined"!=typeof meting_api&&(t=meting_api);var a=document.querySelectorAll(".aplayer");Array.prototype.forEach.call(a,function(a,r){if(a.dataset.id){var i=new XMLHttpRequest,o=t;o=(o=(o=(o=o.replace(":server",a.dataset.server)).replace(":type",a.dataset.type)).replace(":id",a.dataset.id)).replace(":r",Math.random()),i.open("GET",o,!0),i.onload=function(){if(i.status>=200&&i.status<400){var t=JSON.parse(i.responseText);e(a,t)}},i.send()}else{var n=[];n.title=a.dataset.title,n.author=a.dataset.author,n.url=a.dataset.url,n.pic=a.dataset.pic,n.lrc=a.dataset.lrc,e(a,[n])}})}(); diff --git a/assets/editer.js b/assets/editer.js index 02682ff..ae23acc 100644 --- a/assets/editer.js +++ b/assets/editer.js @@ -8,7 +8,7 @@ $(function() { '
'+ '

插入音乐

'+ '

请在下方的输入框内输入要插入的音乐地址,如多个地址请用回车隔开'+ - '

'+ + '

'+ '
'+ '
'+ ''+ @@ -16,7 +16,7 @@ $(function() { '
'+ ''+ ''); - $('.wmd-prompt-dialog textarea').val('http://').select(); + $('.wmd-prompt-dialog input').val('http://').select(); }); $(document).on('click','#cancel',function() { $('#MetingPanel').remove(); @@ -26,7 +26,7 @@ $(function() { callback=$.ajax({ type:'POST', url:murl, - data:{data:$('.wmd-prompt-dialog textarea').val()}, + data:{data:$('.wmd-prompt-dialog input').val()}, async:false }); $('#MetingPanel').remove(); diff --git a/include/Meting.php b/include/Meting.php index fbedd3d..538a69e 100644 --- a/include/Meting.php +++ b/include/Meting.php @@ -3,7 +3,7 @@ * Meting music framework * https://i-meto.com * https://github.com/metowolf/Meting - * Version 1.3.8 + * Version 1.3.9 * * Copyright 2017, METO Sheel * Released under the MIT license @@ -153,15 +153,15 @@ class Meting 'method' => 'GET', 'url' => 'https://c.y.qq.com/soso/fcgi-bin/client_search_cp', 'body' => array( + 'format' => 'json', 'p' => $page, 'n' => $limit, 'w' => $keyword, 'aggr' => 1, 'lossless' => 1, 'cr' => 1, - 'platform' => 'yqq', + 'new_json' => 1, ), - 'decode' => 'jsonp2json', 'format' => 'data#song#list', ); break; @@ -321,12 +321,14 @@ class Meting case 'tencent': $API=array( 'method' => 'GET', - 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_album_info_cp.fcg', + 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_album_detail_cp.fcg', 'body' => array( 'albummid' => $id, - 'platform' => 'yqq', + 'platform' => 'mac', + 'format' => 'json', + 'newsong' => 1, ), - 'format' => 'data#list', + 'format' => 'data#getSongInfo', ); break; case 'xiami': @@ -406,7 +408,8 @@ class Meting 'begin' => 0, 'num' => $limit, 'order' => 'listen', - 'platform' => 'yqq', + 'platform' => 'mac', + 'newsong' => 1, ), 'format' => 'data#list', ); @@ -484,15 +487,14 @@ class Meting case 'tencent': $API=array( 'method' => 'GET', - 'url' => 'https://c.y.qq.com/qzone/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg', + 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_playlist_cp.fcg', 'body' => array( - 'disstid' => $id, - 'utf8' => 1, - 'type' => 1, - 'platform' => 'yqq', + 'id' => $id, + 'format' => 'json', + 'newsong' => 1, + 'platform' => 'jqspaframe.json', ), - 'decode' => 'jsonp2json', - 'format' => 'cdlist#0#songlist', + 'format' => 'data#cdlist#0#songlist', ); break; case 'xiami': @@ -653,7 +655,7 @@ class Meting 'url' => 'https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg', 'body' => array( 'songmid' => $id, - 'g_tk' => 5381, + 'g_tk' => '5381', ), 'decode' => 'tencent_lyric', ); @@ -751,7 +753,7 @@ class Meting ), 'tencent'=>array( 'referer' => 'https://y.qq.com/portal/player.html', - 'cookie' => 'pgv_pvi=3832878080; pgv_si=s4066364416; pgv_pvid=3938077488; yplayer_open=1; qqmusic_fromtag=66; ts_last=y.qq.com/portal/player.html; ts_uid=5141451452; player_exist=1; yq_index=1', + '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', 'useragent' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36', ), 'xiami'=>array( @@ -794,13 +796,6 @@ class Meting ); return $API; } - private function jsonp2json($jsonp) - { - if ($jsonp[0] !== '[' && $jsonp[0] !== '{') { - $jsonp = substr($jsonp, strpos($jsonp, '(')); - } - return trim($jsonp, '();'); - } private function tencent_singlesong($result) { $result=json_decode($result, 1); @@ -834,11 +829,9 @@ class Meting { $data=json_decode($result, 1); if (isset($data['data'][0]['uf']['url'])) { - $url=array( - 'url' => $data['data'][0]['uf']['url'], - 'br' =>$data['data'][0]['uf']['br']/1000, - ); - } elseif (isset($data['data'][0]['url'])) { + $data['data'][0]['url']=$data['data'][0]['uf']['url']; + } + if (isset($data['data'][0]['url'])) { $url=array( 'url' => $data['data'][0]['url'], 'br' => $data['data'][0]['br']/1000, @@ -859,10 +852,10 @@ class Meting 'method' => 'GET', 'url' => 'https://c.y.qq.com/base/fcgi-bin/fcg_musicexpress.fcg', 'body' => array( - 'json' => 3, - 'guid' => $GUID, + 'json' => 3, + 'guid' => $GUID, + 'format' => 'json', ), - 'decode' => 'jsonp2json', ); $KEY=json_decode($this->curl($API), 1); $KEY=$KEY['key']; @@ -918,8 +911,8 @@ class Meting } $urlt=str_replace('^', '0', urldecode($urlt)); $url=array( - 'url' => str_replace('http://','https://',urldecode($urlt)), - 'br' => 320, + 'url' => str_replace('http://','https://',urldecode($urlt)), + 'br' => 320, ); } else { $url=array( @@ -1002,7 +995,7 @@ class Meting } private function tencent_lyric($result) { - $result=$this->jsonp2json($result); + $result=substr($result,18,-1); if (!$this->_FORMAT) { return $result; } @@ -1098,13 +1091,13 @@ class Meting $data=$data['musicData']; } $result=array( - 'id' => $data['songmid'], - 'name' => $data['songname'], + 'id' => $data['mid'], + 'name' => $data['name'], 'artist' => array(), - 'album' => isset($data['albumname'])?$data['albumname']:$data['album']['name'], - 'pic_id' => $data['albummid'], - 'url_id' => $data['songmid'], - 'lyric_id' => $data['songmid'], + 'album' => trim($data['album']['title']), + 'pic_id' => $data['album']['mid'], + 'url_id' => $data['mid'], + 'lyric_id' => $data['mid'], 'source' => 'tencent', ); foreach ($data['singer'] as $vo) {