diff --git a/Action.php b/Action.php index fc1faf0..ab7ceeb 100644 --- a/Action.php +++ b/Action.php @@ -1,206 +1,320 @@ on($this->request->is('do=update'))->update(); $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; + 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(){ + private function api() + { $this->filterReferer(); - $server=$this->request->get('server'); - $type=$this->request->get('type'); - $id=$this->request->get('id'); + $server = $this->request->get('server'); + $type = $this->request->get('type'); + $id = $this->request->get('id'); - if(!$this->check($server,$type)||empty($id))die('[]'); + if (!$this->check($server, $type) || empty($id)) { + die('[]'); + } - if(!extension_loaded('Meting'))include_once 'include/Meting.php'; - $api=new \Metowolf\Meting($server); + 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 (!extension_loaded('Meting')) { + $cachetype = Typecho_Widget::widget('Widget_Options')->plugin('Meting')->cachetype; + if ($cachetype != 'none') { + $cachehost = Typecho_Widget::widget('Widget_Options')->plugin('Meting')->cachehost; + $cacheport = Typecho_Widget::widget('Widget_Options')->plugin('Meting')->cacheport; + include_once 'driver/cache.interface.php'; + include_once 'driver/'.$cachetype.'.class.php'; + $this->cache = new MetingCache(array( + 'host' => $cachehost, + 'port' => $cacheport + )); + } + } + $api = new \Metowolf\Meting($server); + $api->format(true); + $cookie = Typecho_Widget::widget('Widget_Options')->plugin('Meting')->cookie; + if ($server == 'netease' && !empty($cookie)) { + $api->cookie($cookie); + } - if(in_array($type,array('lrc','pic','url'))){ - $auth1=md5($salt.$id.$salt); - $auth2=$this->request->get('auth'); - if(strcmp($auth1,$auth2)){ + $EID = $server.'/'.$type.'/'.$id; + $salt = Typecho_Widget::widget('Widget_Options')->plugin('Meting')->salt; + + if (!empty($salt) && in_array($type, array('lrc','pic','url'))) { + $auth1 = md5($salt.$type.$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); + if ($type == 'lrc') { + $data = $this->cacheRead($EID); + if (empty($data)) { + $data = $api->lyric($id); + $this->cacheWrite($EID, $data, 86400); } - $data=json_decode($data,true); + $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); + } elseif ($type == 'pic') { + $data = $this->cacheRead($EID); + if (empty($data)) { + $data = $api->pic($id, 90); + $this->cacheWrite($EID, $data, 86400); } - $data=json_decode($data,true); + $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'&&!empty($cookie))$api->cookie($cookie); - $data=$api->url($id,$rate); - $this->cacheWrite($EID,$data); + } elseif ($type == 'url') { + $data = $this->cacheRead($EID); + if (empty($data)) { + $rate = Typecho_Widget::widget('Widget_Options')->plugin('Meting')->bitrate; + $data = $api->url($id, $rate); + $this->cacheWrite($EID, $data, 1200); } - $data=json_decode($data,true); - $url=$data['url']; + $data = json_decode($data, true); + $url = $data['url']; - if($server=='netease'){ - $url=str_replace('://m7c.','://m8.',$url); - $url=str_replace('://m8c.','://m8.',$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 ($server == 'netease') { + $url = str_replace('://m7c.', '://m7.', $url); + $url = str_replace('://m8c.', '://m8.', $url); + $url = str_replace('http://m8.', 'https://m9.', $url); + $url = str_replace('http://m7.', 'https://m9.', $url); + $url = str_replace('http://m10.', 'https://m10.', $url); } - if(empty($url))$url='https://api.i-meto.com/Public/music/empty.mp3'; + if ($server == 'baidu') { + $url = str_replace('http://zhangmenshiting.qianqian.com', 'https://gss3.baidu.com/y0s1hSulBw92lNKgpU_Z2jR7b2w6buu', $url); + } + + if (empty($url)) { + $url = 'https://coding.meting.api.i-meto.com/empty.mp3'; + if ($server == 'netease') { + $url = 'https://music.163.com/song/media/outer/url?id='.$id.'.mp3'; + } + } $this->response->redirect($url); - } - else{ - $data=$this->cacheRead($EID,60*60*2); - if(empty($data)){ - $data=$api->$type($id); - $this->cacheWrite($EID,$data); + } else { + $data = $this->cacheRead($EID); + if (empty($data)) { + $data = $api->$type($id); + $this->cacheWrite($EID, $data, 7200); } - $data=json_decode($data,1); - $url=Typecho_Common::url('action/metingapi',Helper::options()->index); + $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), + $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.'url'.$vo['url_id'].$salt), + 'pic' => $url.'?server='.$vo['source'].'&type=pic&id='.$vo['pic_id'].'&auth='.md5($salt.'pic'.$vo['pic_id'].$salt), + 'lrc' => $url.'?server='.$vo['source'].'&type=lrc&id='.$vo['lyric_id'].'&auth='.md5($salt.'lrc'.$vo['lyric_id'].$salt), ); } header("Content-Type: application/javascript"); echo json_encode($music); } - } - private function shortcode(){ - $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'); - } - 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}\" pic=\"图片文件URL\" lrc=\"歌词文件URL\"/]\n[/Meting]\n"; + private function shortcode() + { + $url = $this->request->get('data'); + $url = trim($url); + if (empty($url)) { return; } - echo "[Meting]\n[Music server=\"{$server}\" id=\"{$id}\" type=\"{$type}\"/]\n[/Meting]\n"; + $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'); + } + } elseif (strpos($url, 'qq.com') !== false) { + $server = 'tencent'; + if (preg_match('/playsquare\/([^\.]*)/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('/#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 { + die("[Meting]\n[Music title=\"歌曲名\" author=\"歌手\" url=\"{$url}\" pic=\"图片文件URL\" lrc=\"歌词文件URL\"/]\n[/Meting]\n"); + return; + } + die("[Meting]\n[Music server=\"{$server}\" id=\"{$id}\" type=\"{$type}\"/]\n[/Meting]\n"); + } - private function curl($url){ - $curl=curl_init(); - curl_setopt($curl,CURLOPT_URL,$url); - curl_setopt($curl,CURLOPT_RETURNTRANSFER,1); - curl_setopt($curl,CURLOPT_CONNECTTIMEOUT,10); - curl_setopt($curl,CURLOPT_TIMEOUT,10); - curl_setopt($curl,CURLOPT_REFERER,$url); - $result=curl_exec($curl); + private function update() + { + $isAdmin = call_user_func(function () { + $hasLogin = $this->widget('Widget_User')->hasLogin(); + $isAdmin = false; + if (!$hasLogin) { + return false; + } + $isAdmin = $this->widget('Widget_User')->pass('administrator', true); + return $isAdmin; + }, $this); + if (!$isAdmin) { + die('非管理员,禁止操作!'); + } + + header("Content-Type: application/javascript"); + + $shasum = $this->curl('https://raw.githubusercontent.com/MoePlayer/APlayer-Typecho/master/shasum.txt'); + + echo "获取最新特征库...\n"; + echo $shasum."\n\n"; + + $shasum = explode("\n", $shasum); + array_pop($shasum); + + echo "开始检查本地文件...\n"; + + foreach ($shasum as $remote) { + list($remote_sha256, $filename) = explode(' ', $remote); + if (!file_exists(__DIR__.'/'.$filename)) { + continue; + } + $local_sha256 = hash('sha256', file_get_contents(__DIR__.'/'.$filename)); + if (!hash_equals($local_sha256, $remote_sha256)) { + echo "下载 ".$filename; + $url = 'https://raw.githubusercontent.com/MoePlayer/APlayer-Typecho/master'.substr($filename, 1); + + if (file_put_contents(__DIR__.'/'.$filename, $this->curl($url))) { + echo " (OK)\n"; + } else { + die("\n下载失败,错误信息: $url\n"); + } + } else { + echo "无需更新 ".$filename."\n"; + } + } + + echo "\n\n如果插件出现错误,建议禁用再启用一次插件完成升级。"; + die(); + } + + private function curl($url) + { + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10); + curl_setopt($curl, CURLOPT_TIMEOUT, 10); + curl_setopt($curl, CURLOPT_REFERER, $url); + $result = curl_exec($curl); curl_close($curl); return $result; } - private function cacheWrite($k,$v){ - if(empty($v)||is_null($v))return; - $db=Typecho_Db::get(); - $insert=$db->insert('table.metingv1')->rows(array('id'=>md5($k),'value'=>$v,'last'=>time())); - return $db->query($insert); + private function cacheWrite($k, $v, $t) + { + if (!isset($this->cache)) { + return; + } + return $this->cache->set($k, $v, $t); } - private function cacheRead($k,$t=3600){ - $db=Typecho_Db::get(); - $query=$db->select('value','last')->from('table.metingv1')->where('id=?',md5($k)); - $result=$db->fetchRow($query); - - if(isset($result['value'])){ - if(time()-$result['last']>$t){ - $delete=$db->delete('table.metingv1')->where('lastquery($delete); - return false; - } - header("Meting-Cache: HIT"); - return $result['value']; - } - else{ - header("Meting-Cache: MISS"); + private function cacheRead($k) + { + if (!isset($this->cache)) { return false; } + return $this->cache->get($k); } - private function filterReferer(){ - if(isset($_SERVER['HTTP_REFERER'])&&strpos($_SERVER['HTTP_REFERER'],$_SERVER['HTTP_HOST'])===false){ + private function filterReferer() + { + $salt = Typecho_Widget::widget('Widget_Options')->plugin('Meting')->salt; + if (empty($salt)) { + header("Access-Control-Allow-Origin: *"); + header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Connection, User-Agent, Cookie"); + return; + } + if (isset($_SERVER['HTTP_REFERER']) && strpos($_SERVER['HTTP_REFERER'], $_SERVER['HTTP_HOST']) === false) { http_response_code(403); die('[]'); } diff --git a/LICENSE b/LICENSE index 1a5c137..81809b5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2017 METO +Copyright (c) 2018 METO Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Plugin.php b/Plugin.php index fb29b37..46c0465 100644 --- a/Plugin.php +++ b/Plugin.php @@ -1,18 +1,20 @@ contentEx=array('Meting_Plugin','playerReplace'); - Typecho_Plugin::factory('Widget_Abstract_Contents')->excerptEx=array('Meting_Plugin','playerReplace'); - Typecho_Plugin::factory('Widget_Archive')->header=array('Meting_Plugin','header'); - Typecho_Plugin::factory('Widget_Archive')->footer=array('Meting_Plugin','footer'); + Typecho_Plugin::factory('Widget_Abstract_Contents')->contentEx = array('Meting_Plugin','playerReplace'); + Typecho_Plugin::factory('Widget_Abstract_Contents')->excerptEx = array('Meting_Plugin','playerReplace'); + Typecho_Plugin::factory('Widget_Archive')->header = array('Meting_Plugin','header'); + Typecho_Plugin::factory('Widget_Archive')->footer = array('Meting_Plugin','footer'); Typecho_Plugin::factory('admin/write-post.php')->bottom = array('Meting_Plugin', 'addButton'); Typecho_Plugin::factory('admin/write-page.php')->bottom = array('Meting_Plugin', 'addButton'); } @@ -42,8 +45,8 @@ class Meting_Plugin extends Typecho_Widget implements Typecho_Plugin_Interface * @return void * @throws Typecho_Plugin_Exception */ - public static function deactivate(){ - Meting_Plugin::uninstall(); + public static function deactivate() + { Helper::removeAction("metingapi"); } @@ -54,56 +57,114 @@ class Meting_Plugin extends Typecho_Widget implements Typecho_Plugin_Interface * @param Typecho_Widget_Helper_Form $form 配置面板 * @return void */ - public static function config(Typecho_Widget_Helper_Form $form){ + public static function config(Typecho_Widget_Helper_Form $form) + { $t = new Typecho_Widget_Helper_Form_Element_Text( - 'theme', null, '#ad7a86', + 'theme', + null, + '#ad7a86', _t('播放器颜色'), - _t('播放器默认的主题颜色,支持如 #372e21、#75c、red,该设定会被[Meting]标签中的theme属性覆盖,默认为 #ad7a86')); + _t('播放器默认的主题颜色,支持如 #372e21、#75c、red,该设定会被[Meting]标签中的theme属性覆盖,默认为 #ad7a86') + ); $form->addInput($t); $t = new Typecho_Widget_Helper_Form_Element_Text( - 'height', null, '340px', + 'height', + null, + '340px', _t('播放器列表最大高度'), - _t('')); + _t('') + ); $form->addInput($t); $t = new Typecho_Widget_Helper_Form_Element_Radio( - 'autoplay', array('true'=>_t('是'),'false'=>_t('否')),'false', + 'autoplay', + array('true' => _t('是'),'false' => _t('否')), + 'false', _t('全局自动播放'), - _t('')); + _t('') + ); $form->addInput($t); $t = new Typecho_Widget_Helper_Form_Element_Radio( - 'mode', array('circulation'=>_t('循环'),'single'=>_t('单曲'),'order'=>_t('列表'),'random'=>_t('随机')),'circulation', + 'mode', + array('circulation' => _t('循环'),'single' => _t('单曲'),'order' => _t('列表'),'random' => _t('随机')), + 'circulation', _t('全局播放模式'), - _t('')); + _t('') + ); $form->addInput($t); - $t= new Typecho_Widget_Helper_Form_Element_Radio( - 'preload', array('auto'=>_t('自动'),'none'=>_t('不加载'),'metadata'=>_t('加载元数据')), 'auto', + $t = new Typecho_Widget_Helper_Form_Element_Radio( + 'preload', + array('auto' => _t('自动'),'none' => _t('不加载'),'metadata' => _t('加载元数据')), + 'auto', _t('预加载属性'), - _t('')); + _t('') + ); $form->addInput($t); - $t= new Typecho_Widget_Helper_Form_Element_Radio( - 'bitrate', array('128'=>_t('流畅品质'),'192'=>_t('清晰品质'),'320'=>_t('高品质')), '192', + + $list = array( + 'none' => _t('关闭'), + 'redis' => _t('Redis'), + 'mysql' => _t('Mysql'), + 'sqlite' => _t('SQLite') + ); + $t = new Typecho_Widget_Helper_Form_Element_Radio( + 'cachetype', + $list, + 'none', + _t('缓存驱动'), + _t('缓存歌曲解析信息,降低服务器压力') + ); + $form->addInput($t); + $t = new Typecho_Widget_Helper_Form_Element_Text( + 'cachehost', + null, + '127.0.0.1', + _t('缓存服务地址'), + _t('通常为 localhost, 127.0.0.1') + ); + $form->addInput($t); + $t = new Typecho_Widget_Helper_Form_Element_Text( + 'cacheport', + null, + '6379', + _t('缓存服务端口'), + _t('默认端口 memcache: 11211, Redis: 6379, Mysql: 3306') + ); + $form->addInput($t); + + $t = new Typecho_Widget_Helper_Form_Element_Radio( + 'bitrate', + array('128' => _t('流畅品质 128K'),'192' => _t('清晰品质 192K'),'320' => _t('高品质 320K')), + '192', _t('默认音质'), - _t('')); + _t('') + ); $form->addInput($t); $t = new Typecho_Widget_Helper_Form_Element_Text( - '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')); + '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 接口不被滥用,自动生成无需设置。')); + 'salt', + null, + Typecho_Common::randString(32), + _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('保存时清除所有缓存')); + 'cookie', + null, + '', + _t('* 网易云音乐 Cookie'), + _t('如果您是网易云音乐的会员,可以将您的 cookie 填入此处来获取云盘等付费资源,听歌将不会计入下载次数。
如果不知道这是什么意思,忽略即可。') + ); $form->addInput($t); + + echo ''; } /** @@ -113,20 +174,32 @@ class Meting_Plugin extends Typecho_Widget implements Typecho_Plugin_Interface */ 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 (!$is_init) { + if (empty($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; + if ($config['cachetype'] != 'none') { + require_once 'driver/cache.interface.php'; + require_once 'driver/'.$config['cachetype'].'.class.php'; + try { + $cache = new MetingCache(array( + 'host' => $config['cachehost'], + 'port' => $config['cacheport'] + )); + $cache->install(); + $cache->flush(); + } catch (Exception $e) { + throw new Typecho_Plugin_Exception(_t($e->getMessage())); + } } } Helper::configPlugin('Meting', $config); } - public static function personalConfig(Typecho_Widget_Helper_Form $form){} + public static function personalConfig(Typecho_Widget_Helper_Form $form) + { + } /** * 获取插件配置面板 @@ -135,100 +208,125 @@ class Meting_Plugin extends Typecho_Widget implements Typecho_Plugin_Interface * @param Typecho_Widget_Helper_Form $form 配置面板 * @return void */ - public static function header(){ - $api=Typecho_Widget::widget('Widget_Options')->plugin('Meting')->api; - $dir=Helper::options()->pluginUrl.'/Meting/assets'; - $ver=METING_VERSION; + public static function header() + { + $api = Typecho_Widget::widget('Widget_Options')->plugin('Meting')->api; + $dir = Helper::options()->pluginUrl.'/Meting/assets'; + $ver = METING_VERSION; echo "\n"; echo ""; } - public static function footer(){ - $dir=Helper::options()->pluginUrl.'/Meting/assets'; - $ver=METING_VERSION; + public static function footer() + { + $dir = Helper::options()->pluginUrl.'/Meting/assets'; + $ver = METING_VERSION; echo "\n"; } - public static function playerReplace($data,$widget,$last){ - $text=empty($last)?$data:$last; - if($widget instanceof Widget_Archive){ - $data=$text; - $pattern=self::get_shortcode_regex(array('Meting')); - $text=preg_replace_callback("/$pattern/",array('Meting_Plugin','parseCallback'),$data); + public static function playerReplace($data, $widget, $last) + { + $text = empty($last)?$data:$last; + if ($widget instanceof Widget_Archive) { + $data = $text; + $pattern = self::get_shortcode_regex(array('Meting')); + $text = preg_replace_callback("/$pattern/", array('Meting_Plugin','parseCallback'), $data); } return $text; } - public static function parseCallback($matches){ - $setting=self::shortcode_parse_atts(htmlspecialchars_decode($matches[3])); - $matches[5]=htmlspecialchars_decode($matches[5]); - $pattern=self::get_shortcode_regex(array('Music')); - preg_match_all("/$pattern/",$matches[5],$all); - if(sizeof($all[3]))return Meting_Plugin::parseMusic($all[3],$setting); + public static function parseCallback($matches) + { + $setting = self::shortcode_parse_atts(htmlspecialchars_decode($matches[3])); + $matches[5] = htmlspecialchars_decode($matches[5]); + $pattern = self::get_shortcode_regex(array('Music')); + preg_match_all("/$pattern/", $matches[5], $all); + if (sizeof($all[3])) { + return Meting_Plugin::parseMusic($all[3], $setting); + } } - public static function parseMusic($matches,$setting){ - $data=array(); - $str=""; - foreach($matches as $vo){ - $t=self::shortcode_parse_atts(htmlspecialchars_decode($vo)); - $player=array( - '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', + public static function parseMusic($matches, $setting) + { + $data = array(); + $str = ""; + foreach ($matches as $vo) { + $t = self::shortcode_parse_atts(htmlspecialchars_decode($vo)); + $player = array( + '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', 'listmaxheight' => Typecho_Widget::widget('Widget_Options')->plugin('Meting')->height?:'340px', - 'mode' => Typecho_Widget::widget('Widget_Options')->plugin('Meting')->mode?:'circulation', + 'mode' => Typecho_Widget::widget('Widget_Options')->plugin('Meting')->mode?:'circulation', ); - 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; + 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"; + } else { + $data = $t; - $str.="
$vo)$player[$key]=$vo; - foreach($player as $key=>$vo)$str.=" data-{$key}=\"{$vo}\""; - $str.=">
\n"; + $str .= "
$vo) { + $player[$key] = $vo; + } + } + foreach ($player as $key => $vo) { + $str .= " data-{$key}=\"{$vo}\""; + } + $str .= ">
\n"; } } return $str; } - public static function addButton(){ - $url=Typecho_Common::url('action/metingapi',Helper::options()->index).'?do=parse'; - $dir=Helper::options()->pluginUrl.'/Meting/assets/editer.js?v='.METING_VERSION; - echo " + public static function addButton() + { + $url = Typecho_Common::url('action/metingapi', Helper::options()->index).'?do=parse'; + $dir = Helper::options()->pluginUrl.'/Meting/assets/editer.js?v='.METING_VERSION; + echo " "; } # https://github.com/WordPress/WordPress/blob/master/wp-includes/shortcodes.php#L508 - private static function shortcode_parse_atts($text) { + private static function shortcode_parse_atts($text) + { $atts = array(); $pattern = '/([\w-]+)\s*=\s*"([^"]*)"(?:\s|$)|([\w-]+)\s*=\s*\'([^\']*)\'(?:\s|$)|([\w-]+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/'; $text = preg_replace("/[\x{00a0}\x{200b}]+/u", " ", $text); - if ( preg_match_all($pattern, $text, $match, PREG_SET_ORDER) ) { + if (preg_match_all($pattern, $text, $match, PREG_SET_ORDER)) { foreach ($match as $m) { - if (!empty($m[1])) + if (!empty($m[1])) { $atts[strtolower($m[1])] = stripcslashes($m[2]); - elseif (!empty($m[3])) - $atts[strtolower($m[3])] = stripcslashes($m[4]); - elseif (!empty($m[5])) - $atts[strtolower($m[5])] = stripcslashes($m[6]); - elseif (isset($m[7]) && strlen($m[7])) - $atts[] = stripcslashes($m[7]); - elseif (isset($m[8])) - $atts[] = stripcslashes($m[8]); + } elseif (!empty($m[3])) { + $atts[strtolower($m[3])] = stripcslashes($m[4]); + } elseif (!empty($m[5])) { + $atts[strtolower($m[5])] = stripcslashes($m[6]); + } elseif (isset($m[7]) && strlen($m[7])) { + $atts[] = stripcslashes($m[7]); + } elseif (isset($m[8])) { + $atts[] = stripcslashes($m[8]); + } } - foreach( $atts as &$value ) { - if ( false !== strpos( $value, '<' ) ) { - if ( 1 !== preg_match( '/^[^<]*+(?:<[^>]*+>[^<]*+)*+$/', $value ) ) { + foreach ($atts as &$value) { + if (false !== strpos($value, '<')) { + if (1 !== preg_match('/^[^<]*+(?:<[^>]*+>[^<]*+)*+$/', $value)) { $value = ''; } } @@ -240,41 +338,19 @@ class Meting_Plugin extends Typecho_Widget implements Typecho_Plugin_Interface } # https://github.com/WordPress/WordPress/blob/master/wp-includes/shortcodes.php#L254 - private static function get_shortcode_regex( $tagnames = null ) { - $tagregexp = join( '|', array_map('preg_quote', $tagnames) ); + private static function get_shortcode_regex($tagnames = null) + { + $tagregexp = join('|', array_map('preg_quote', $tagnames)); return '\[(\[?)('.$tagregexp.')(?![\w-])([^\]\/]*(?:\/(?!\])[^\]\/]*)*?)(?:(\/)\]|\](?:([^\[]*+(?:\[(?!\/\2\])[^\[]*+)*+)\[\/\2\])?)(\]?)'; } - public static function install(){ - $db=Typecho_Db::get(); - $dbname=$db->getPrefix().'metingv1'; - try{ - $db->query("CREATE TABLE IF NOT EXISTS {$dbname} ( - id VARCHAR(32) PRIMARY KEY NOT NULL UNIQUE, - value TEXT NOT NULL, - last int NOT NULL - )"); - }catch(Typecho_Db_Exception $e){ - $code=$e->getCode(); - throw new Typecho_Plugin_Exception('插件启用失败。错误号:'.$code); + public static function installCheck() + { + if (!extension_loaded('curl')) { + throw new Typecho_Plugin_Exception(_t('缺少 cURL 拓展')); } - } - - 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}"); - }catch(Typecho_Db_Exception $e){ - $code=$e->getCode(); - throw new Typecho_Plugin_Exception('插件禁用失败。错误号:'.$code); + if (!(extension_loaded('openssl') || extension_loaded('mcrypt'))) { + throw new Typecho_Plugin_Exception(_t('缺少 openssl/mcrypt 拓展')); } } } diff --git a/README.md b/README.md index 6eddad5..f639ea5 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,7 @@ Meting

-# APlayer for Typecho -在 Typecho 中使用 APlayer 播放在线音乐吧~ + > 在 Typecho 中使用 APlayer 播放在线音乐吧~ [发布页面](https://i-meto.com/meting-typecho/) ## 介绍 @@ -11,8 +10,9 @@ 2. 简单快捷,复制音乐详情页面网址,后台自动生成播放代码 3. 前端 APlayer,后端 Meting 及时更新,保证兼容性及 API 高可用性 4. 支持 MySql、SQLite 数据库 - 5. 支持自定义歌曲播放 - 6. **自定义 API 支持** + 5. **支持 Redis 缓存** + 6. 支持自定义歌曲播放 + 7. **自定义 API 支持** ## 声明 本作品仅供个人学习研究使用,请勿将其用作商业用途。 @@ -35,11 +35,11 @@ - 歌单 http://music.163.com/#/playlist?id=436843836 - 榜单 http://music.163.com/#/discover/toplist?id=60198 -QQ 音乐 http://y.qq.com -- 单曲 https://y.qq.com/portal/song/000jDQWP4JiB3y.html -- 专辑 https://y.qq.com/portal/album/003rytri2FHG3V.html -- 歌手 https://y.qq.com/portal/singer/003Nz2So3XXYek.html -- 歌单 https://y.qq.com/portal/playlist/1144188779.html +QQ 音乐 https://y.qq.com +- 单曲 https://y.qq.com/n/yqq/song/000jDQWP4JiB3y.html +- 专辑 https://y.qq.com/n/yqq/album/003rytri2FHG3V.html +- 歌手 https://y.qq.com/n/yqq/singer/003Nz2So3XXYek.html +- 歌单 https://y.qq.com/n/yqq/playlist/1144188779.html 虾米音乐 http://www.xiami.com or http://h.xiami.com - 单曲 http://www.xiami.com/song/bf08DNT3035f @@ -48,7 +48,7 @@ QQ 音乐 http://y.qq.com - 歌单 http://www.xiami.com/collect/254478782 酷狗音乐 http://www.kugou.com -- 单曲 暂不支持直接解析,可直接修改短代码实现 +- 单曲 http://www.kugou.com/song/#hash=09E8DE70A24C97B92A29F6A19F3528A2 - 专辑 http://www.kugou.com/yy/album/single/1645030.html - 歌手 http://www.kugou.com/yy/singer/home/3520.html - 歌单 http://www.kugou.com/yy/special/single/119859.html @@ -60,9 +60,21 @@ QQ 音乐 http://y.qq.com - 歌单 http://music.baidu.com/songlist/364201689 ## FAQ -Q: 如何清除歌单、歌词缓存? -A: 为了减少服务器压力,插件设置对歌单、歌词数据进行缓存,缓存会根据时间周期自动更新管理,无需人工干预。**如果需要强制清除,可以通过禁用再启用插件实现,不影响文章中歌曲信息** -... +Q: pjax 页面切换无法停止播放? +A: 需要另外在主题的回调函数中添加 +``` +if (typeof aplayers !== 'undefined'){ + for (var i = 0; i < aplayers.length; i++) { + try {aplayers[i].destroy()} catch(e){} + } +} +``` + +Q: 不支持混合歌单? +A: 由于 2.0 版本重写了实现方式,旧的混合歌单将不再支持,建议通过各音乐平台创建歌单的方式添加。 + +Q: 部分歌曲失效? +A: 可能 API 失效导致的,可以尝试点击插件升级按钮升级到最新,或填写 cookie 信息。 更多问题可以通过 issue 页面提交,或者通过 Telegram、邮件向我反馈 diff --git a/assets/APlayer.min.js b/assets/APlayer.min.js index eae8e04..a64f448 100644 --- a/assets/APlayer.min.js +++ b/assets/APlayer.min.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("APlayer",[],t):"object"==typeof exports?exports.APlayer=t():e.APlayer=t()}(this,function(){return function(e){function t(n){if(a[n])return a[n].exports;var r=a[n]={i:n,l:!1,exports:{}};return e[n].call(r.exports,r,r.exports,t),r.l=!0,r.exports}var a={};return t.m=e,t.c=a,t.i=function(e){return e},t.d=function(e,a,n){t.o(e,a)||Object.defineProperty(e,a,{configurable:!1,enumerable:!0,get:n})},t.n=function(e){var a=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(a,"a",a),a},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=1)}([function(e,t,a){var n=a(2);"string"==typeof n&&(n=[[e.i,n,""]]);var r={};r.transform=void 0;a(4)(n,r);n.locals&&(e.exports=n.locals)},function(e,t,a){"use strict";function n(e){if(Array.isArray(e)){for(var t=0,a=Array(e.length);t\n \n \n \n '},this.isMobile=/mobile/i.test(window.navigator.userAgent),this.isMobile&&(t.autoplay=!1);var s={element:document.getElementsByClassName("aplayer")[0],narrow:!1,autoplay:!1,mutex:!0,showlrc:0,theme:"#b7daff",mode:"circulation"};for(var p in s)s.hasOwnProperty(p)&&!t.hasOwnProperty(p)&&(t[p]=s[p]);if(this.option=t,this.audios=[],this.mode=t.mode,this.secondToTime=function(e){if(isNaN(e))return"00:00";var t=function(e){return e<10?"0"+e:""+e},a=parseInt(e/60),n=parseInt(e-60*a),r=parseInt(a/60),i=parseInt(e/60-60*parseInt(e/60/60));return e>=3600?t(r)+":"+t(i)+":"+t(n):t(a)+":"+t(n)},this.element=this.option.element,2===this.option.showlrc||!0===this.option.showlrc){this.savelrc=[];for(var c=0;c0?t:0,t=t<1?t:1,m[e+"Bar"].style[a]=100*t+"%"},this.updateLrc=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:i.audio.currentTime;if(i.lrcIndex>i.lrc.length-1||e=i.lrc[i.lrcIndex+1][0])for(var t=0;t=i.lrc[t][0]&&(!i.lrc[t+1]||e1&&this.element.classList.add("aplayer-withlist"),this.multiple||"circulation"===this.mode||"order"===this.mode||(this.mode="circulation"),this.getRandomOrder();for(var y='\n
\n
\n \n
\n
\n
\n
\n \n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n
\n
\n
\n
\n \n - 00:00 / 00:00\n \n
\n \n
\n
\n
\n
\n
\n
\n \n \n
\n
\n
\n
\n
    ',h=0;h\n \n '+(h+1)+'\n '+this.option.music[h].title+'\n '+this.option.music[h].author+"\n ";y+="\n
\n
",this.element.innerHTML=y,this.element.offsetWidth<300&&(this.element.getElementsByClassName("aplayer-icon-mode")[0].style.display="none"),this.ptime=this.element.getElementsByClassName("aplayer-ptime")[0],this.element.getElementsByClassName("aplayer-info")[0].offsetWidth<200&&this.element.getElementsByClassName("aplayer-time")[0].classList.add("aplayer-time-narrow");var m={};m.barWrap=this.element.getElementsByClassName("aplayer-bar-wrap")[0],this.option.narrow&&this.element.classList.add("aplayer-narrow"),this.button=this.element.getElementsByClassName("aplayer-button")[0],this.button.addEventListener("click",function(e){i.toggle()});var f=this.element.getElementsByClassName("aplayer-list")[0];f.addEventListener("click",function(e){var t=void 0;t="LI"===e.target.tagName.toUpperCase()?e.target:e.target.parentElement;var a=parseInt(t.getElementsByClassName("aplayer-list-index")[0].innerHTML)-1;a!==i.playIndex?(i.setMusic(a),i.play()):i.toggle()}),m.playedBar=this.element.getElementsByClassName("aplayer-played")[0],m.loadedBar=this.element.getElementsByClassName("aplayer-loaded")[0];var v=this.element.getElementsByClassName("aplayer-thumb")[0],g=void 0;m.barWrap.addEventListener("click",function(e){var t=e||window.event;g=m.barWrap.clientWidth;var n=(t.clientX-a(m.barWrap))/g;isNaN(i.audio.duration)?i.updateBar("played",0,"width"):(i.updateBar("played",n,"width"),i.element.getElementsByClassName("aplayer-ptime")[0].innerHTML=i.secondToTime(n*i.audio.duration),i.audio.currentTime=parseFloat(m.playedBar.style.width)/100*i.audio.duration)}),v.addEventListener("mouseover",function(){v.style.background=i.option.theme}),v.addEventListener("mouseout",function(){v.style.background="#fff"});var b=function(e){var t=e||window.event,n=(t.clientX-a(m.barWrap))/g;n=n>0?n:0,n=n<1?n:1,i.updateBar("played",n,"width"),i.option.showlrc&&i.updateLrc(parseFloat(m.playedBar.style.width)/100*i.audio.duration),i.element.getElementsByClassName("aplayer-ptime")[0].innerHTML=i.secondToTime(n*i.audio.duration)},x=function e(){document.removeEventListener("mouseup",e),document.removeEventListener("mousemove",b),isNaN(i.audio.duration)?i.updateBar("played",0,"width"):(i.audio.currentTime=parseFloat(m.playedBar.style.width)/100*i.audio.duration,i.playedTime=setInterval(function(){i.updateBar("played",i.audio.currentTime/i.audio.duration,"width"),i.option.showlrc&&i.updateLrc(),i.element.getElementsByClassName("aplayer-ptime")[0].innerHTML=i.secondToTime(i.audio.currentTime),i.trigger("playing")},100))};v.addEventListener("mousedown",function(){g=m.barWrap.clientWidth,clearInterval(i.playedTime),document.addEventListener("mousemove",b),document.addEventListener("mouseup",x)}),m.volumeBar=this.element.getElementsByClassName("aplayer-volume")[0];var w=this.element.getElementsByClassName("aplayer-volume-bar")[0];this.volumeicon=this.element.getElementsByClassName("aplayer-time")[0].getElementsByTagName("button")[0];this.element.getElementsByClassName("aplayer-volume-bar-wrap")[0].addEventListener("click",function(e){var t=e||window.event,a=(35-t.clientY+n(w))/35;a=a>0?a:0,a=a<1?a:1,i.volume(a)}),this.volumeicon.addEventListener("click",function(){i.audio.muted?(i.audio.muted=!1,i.volumeicon.className=1===i.audio.volume?"aplayer-icon aplayer-icon-volume-up":"aplayer-icon aplayer-icon-volume-down",1===i.audio.volume?(i.volumeicon.className="aplayer-icon aplayer-icon-volume-up",i.volumeicon.innerHTML=i.getSVG("volume-up")):(i.volumeicon.className="aplayer-icon aplayer-icon-volume-down",i.volumeicon.innerHTML=i.getSVG("volume-down")),i.updateBar("volume",i.audio.volume,"height")):(i.audio.muted=!0,i.volumeicon.className="aplayer-icon aplayer-icon-volume-off",i.volumeicon.innerHTML=i.getSVG("volume-off"),i.updateBar("volume",0,"height"))});var A=this.element.getElementsByClassName("aplayer-icon-mode")[0];A.addEventListener("click",function(){i.multiple?"random"===i.mode?i.mode="single":"single"===i.mode?i.mode="order":"order"===i.mode?i.mode="circulation":"circulation"===i.mode&&(i.mode="random"):"circulation"===i.mode?i.mode="order":i.mode="circulation",A.innerHTML=i.getSVG(i.mode),i.audio.loop=!(i.multiple||"order"===i.mode)}),f.style.height=f.offsetHeight+"px",this.element.getElementsByClassName("aplayer-icon-menu")[0].addEventListener("click",function(){f.classList.contains("aplayer-list-hide")?f.classList.remove("aplayer-list-hide"):f.classList.add("aplayer-list-hide")}),"random"===this.mode?this.setMusic(this.randomOrder[0]):this.setMusic(0),l.push(this)}return i(e,[{key:"setMusic",value:function(e){var t=this;void 0!==e&&(this.playIndex=e);var a=this.playIndex;this.music=this.option.music[a],this.music.pic&&(this.element.getElementsByClassName("aplayer-pic")[0].style.backgroundImage="url('"+this.music.pic+"')"),this.element.getElementsByClassName("aplayer-title")[0].innerHTML=this.music.title,this.element.getElementsByClassName("aplayer-author")[0].innerHTML=" - "+this.music.author,this.element.getElementsByClassName("aplayer-list-light")[0]&&this.element.getElementsByClassName("aplayer-list-light")[0].classList.remove("aplayer-list-light"),this.element.getElementsByClassName("aplayer-list")[0].getElementsByTagName("li")[a].classList.add("aplayer-list-light"),!this.isMobile&&this.audio&&(this.pause(),this.audio.currentTime=0),this.element.getElementsByClassName("aplayer-list")[0].scrollTop=33*a,this.isMobile&&this.audio?(this.audio.src=this.music.url,this.play()):!this.isMobile&&this.audios[a]?(this.audio=this.audios[a],this.audio.volume=parseInt(this.element.getElementsByClassName("aplayer-volume")[0].style.height)/100,this.audio.currentTime=0):(this.audio=document.createElement("audio"),this.audio.src=this.music.url,this.audio.preload=this.option.preload?this.option.preload:"auto",this.audio.addEventListener("play",function(){if(t.button.classList.contains("aplayer-play")){if(t.button.classList.remove("aplayer-play"),t.button.classList.add("aplayer-pause"),t.button.innerHTML="",setTimeout(function(){t.button.innerHTML='\n "},100),t.option.mutex)for(var e=0;e'+t.getSVG("play")+" "},100),clearInterval(t.playedTime),t.trigger("pause"))}),this.audio.addEventListener("durationchange",function(){1!==t.audio.duration&&(t.element.getElementsByClassName("aplayer-dtime")[0].innerHTML=t.secondToTime(t.audio.duration))}),this.audio.addEventListener("progress",function(){var e=t.audio.buffered.length?t.audio.buffered.end(t.audio.buffered.length-1)/t.audio.duration:0;t.updateBar("loaded",e,"width")}),this.audio.addEventListener("error",function(){t.element.getElementsByClassName("aplayer-author")[0].innerHTML=" - Error happens ╥﹏╥",t.trigger("pause")}),this.audio.addEventListener("canplay",function(){t.trigger("canplay")}),this.ended=!1,this.audio.addEventListener("ended",function(){t.multiple?0!==t.audio.currentTime&&("random"===t.mode?t.setMusic(t.nextRandomNum()):"single"===t.mode?t.setMusic(t.playIndex):"order"===t.mode?t.playIndex=200&&o.status<300||304===o.status?(i=o.responseText,t.lrcs[r]=n(i)):(console.log("Request was unsuccessful: "+o.status),t.lrcs[r]=[["00:00","Not available"]]),t.lrc=t.lrcs[r];var e="";t.lrcContents=t.element.getElementsByClassName("aplayer-lrc-contents")[0];for(var a=0;a"+t.lrc[a][1]+"

";t.lrcContents.innerHTML=e,t.lrcIndex||(t.lrcIndex=0),t.lrcContents.getElementsByTagName("p")[0].classList.add("aplayer-lrc-current"),t.lrcContents.style.transform="translateY(0px)",t.lrcContents.style.webkitTransform="translateY(0px)"}};var s=void 0;s=this.option.music[r].lrc,o.open("get",s,!0),o.send(null)}i?this.lrcs[r]=n(i):3===this.option.showlrc?this.lrcs[r]=[["00:00","Loading"]]:this.lrcs[r]=[["00:00","Not available"]]}this.lrc=this.lrcs[r];var p="";this.lrcContents=this.element.getElementsByClassName("aplayer-lrc-contents")[0];for(var c=0;c"+this.lrc[c][1]+"

";this.lrcContents.innerHTML=p,this.lrcIndex||(this.lrcIndex=0),this.lrcContents.getElementsByTagName("p")[0].classList.add("aplayer-lrc-current"),this.lrcContents.style.transform="translateY(0px)",this.lrcContents.style.webkitTransform="translateY(0px)"}1!==this.audio.duration&&(this.element.getElementsByClassName("aplayer-dtime")[0].innerHTML=this.audio.duration?this.secondToTime(this.audio.duration):"00:00"),this.option.autoplay&&!this.isMobile&&this.play(),this.option.autoplay=!0}},{key:"play",value:function(e){"[object Number]"===Object.prototype.toString.call(e)&&(this.audio.currentTime=e),this.audio.paused&&this.audio.play()}},{key:"pause",value:function(){this.audio.paused||this.audio.pause()}},{key:"volume",value:function(e){this.updateBar("volume",e,"height"),this.audio.volume=e,this.audio.muted&&(this.audio.muted=!1),1===e?(this.volumeicon.className="aplayer-icon aplayer-icon-volume-up",this.volumeicon.innerHTML=this.getSVG("volume-up")):(this.volumeicon.className="aplayer-icon aplayer-icon-volume-down",this.volumeicon.innerHTML=this.getSVG("volume-down"))}},{key:"on",value:function(e,t){"function"==typeof t&&this.event[e].push(t)}},{key:"toggle",value:function(){this.button.classList.contains("aplayer-play")?this.play():this.button.classList.contains("aplayer-pause")&&this.pause()}},{key:"getRandomOrder",value:function(){function e(e,t){return null==t&&(t=e,e=0),e+Math.floor(Math.random()*(t-e+1))}this.multiple&&(this.randomOrder=function(t){for(var a,n=t.length,r=new Array(n),i=0;i\n \n '+(this.option.music.length-e.length+r+1)+'\n '+e[r].title+'\n '+e[r].author+"\n ";a.innerHTML+=n,this.multiple||(this.multiple=!0,this.element.classList.add("aplayer-withlist"),this.audio.loop=!1),t.style.height="auto",t.style.height=t.offsetHeight+"px",this.getRandomOrder()}}]),e}();e.exports=o},function(e,t,a){t=e.exports=a(3)(void 0),t.push([e.i,".aplayer-narrow {\n width: 66px; }\n .aplayer-narrow .aplayer-info {\n display: none; }\n\n.aplayer-withlrc.aplayer-narrow {\n width: 90px; }\n\n.aplayer-withlrc.aplayer .aplayer-pic {\n height: 90px;\n width: 90px; }\n\n.aplayer-withlrc.aplayer .aplayer-info {\n margin-left: 90px;\n height: 90px; }\n\n.aplayer-withlrc.aplayer .aplayer-lrc {\n display: block; }\n\n.aplayer-withlrc.aplayer .aplayer-info {\n padding: 10px 7px 0 7px; }\n\n.aplayer-withlist.aplayer .aplayer-info {\n border-bottom: 1px solid #e9e9e9; }\n\n.aplayer-withlist.aplayer .aplayer-list {\n display: block; }\n\n.aplayer-withlist.aplayer .aplayer-icon-menu {\n display: inline !important; }\n\n.aplayer {\n font-family: Arial, Helvetica, sans-serif;\n margin: 5px;\n -webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12);\n box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12);\n border-radius: 2px;\n overflow: hidden;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n line-height: initial; }\n .aplayer * {\n -webkit-box-sizing: content-box;\n box-sizing: content-box; }\n .aplayer .aplayer-icon {\n width: 15px;\n height: 15px;\n border: none;\n background-color: transparent;\n outline: none;\n cursor: pointer;\n opacity: .8;\n vertical-align: middle;\n padding: 0;\n font-size: 12px;\n margin: 0;\n display: inline; }\n .aplayer .aplayer-icon .aplayer-fill {\n -webkit-transition: all .2s ease-in-out;\n transition: all .2s ease-in-out; }\n .aplayer .aplayer-lrc-content {\n display: none; }\n .aplayer .aplayer-pic {\n position: relative;\n float: left;\n height: 66px;\n width: 66px;\n background-image: url("+a(6)+");\n background-size: 100%;\n -webkit-transition: all 0.3s ease;\n transition: all 0.3s ease; }\n .aplayer .aplayer-pic .aplayer-button {\n position: absolute;\n border-radius: 50%;\n opacity: 0.8;\n cursor: pointer;\n text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);\n -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);\n box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);\n background: rgba(0, 0, 0, 0.2);\n -webkit-transition: all 0.1s ease;\n transition: all 0.1s ease; }\n .aplayer .aplayer-pic .aplayer-button:hover {\n opacity: 1; }\n .aplayer .aplayer-pic .aplayer-button .aplayer-fill {\n fill: #fff; }\n .aplayer .aplayer-pic .aplayer-hide {\n display: none; }\n .aplayer .aplayer-pic .aplayer-play {\n width: 26px;\n height: 26px;\n border: 2px solid #fff;\n bottom: 50%;\n right: 50%;\n margin: 0 -15px -15px 0; }\n .aplayer .aplayer-pic .aplayer-play .aplayer-icon-play {\n position: absolute;\n top: 3px;\n left: 4px;\n height: 20px;\n width: 20px; }\n .aplayer .aplayer-pic .aplayer-pause {\n width: 16px;\n height: 16px;\n border: 2px solid #fff;\n bottom: 4px;\n right: 4px; }\n .aplayer .aplayer-pic .aplayer-pause .aplayer-icon-pause {\n position: absolute;\n top: 2px;\n left: 2px;\n height: 12px;\n width: 12px; }\n .aplayer .aplayer-info {\n margin-left: 66px;\n padding: 14px 7px 0 10px;\n height: 66px;\n -webkit-box-sizing: border-box;\n box-sizing: border-box; }\n .aplayer .aplayer-info .aplayer-music {\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n margin: 0 0 13px 5px;\n -webkit-user-select: text;\n -moz-user-select: text;\n -ms-user-select: text;\n user-select: text;\n cursor: default;\n padding-bottom: 2px; }\n .aplayer .aplayer-info .aplayer-music .aplayer-title {\n font-size: 14px; }\n .aplayer .aplayer-info .aplayer-music .aplayer-author {\n font-size: 12px;\n color: #666; }\n .aplayer .aplayer-info .aplayer-controller {\n position: relative;\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap {\n margin: 0 0 0 5px;\n padding: 4px 0;\n cursor: pointer !important;\n -webkit-box-flex: 1;\n -ms-flex: 1;\n flex: 1; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar {\n position: relative;\n height: 2px;\n width: 100%;\n background: #cdcdcd; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-loaded {\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n background: #aaa;\n height: 2px;\n -webkit-transition: all 0.5s ease;\n transition: all 0.5s ease; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-played {\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n height: 2px; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-played .aplayer-thumb {\n position: absolute;\n top: 0;\n right: 5px;\n margin-top: -4px;\n margin-right: -10px;\n height: 8px;\n width: 8px;\n border-radius: 50%;\n background: #fff;\n cursor: pointer !important; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-time {\n position: relative;\n right: 0;\n bottom: 3px;\n height: 17px;\n color: #999;\n font-size: 11px;\n padding-left: 7px; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-time-inner {\n vertical-align: middle; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon {\n cursor: pointer;\n -webkit-transition: all 0.2s ease;\n transition: all 0.2s ease; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon .aplayer-fill {\n fill: #666; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon.aplayer-icon-mode {\n margin-right: 4px; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon:hover .aplayer-fill {\n fill: #000; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon.aplayer-icon-menu {\n display: none; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-time.aplayer-time-narrow .aplayer-icon-mode {\n display: none; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-time.aplayer-time-narrow .aplayer-icon-menu {\n display: none; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap {\n position: relative;\n display: inline-block;\n margin-left: 3px;\n cursor: pointer !important; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap:hover .aplayer-volume-bar-wrap {\n display: block; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap .aplayer-volume-bar-wrap {\n display: none;\n position: absolute;\n bottom: 15px;\n right: -3px;\n width: 25px;\n height: 40px;\n z-index: 99; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap .aplayer-volume-bar-wrap .aplayer-volume-bar {\n position: absolute;\n bottom: 0;\n right: 10px;\n width: 5px;\n height: 35px;\n background: #aaa; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap .aplayer-volume-bar-wrap .aplayer-volume-bar .aplayer-volume {\n position: absolute;\n bottom: 0;\n right: 0;\n width: 5px;\n -webkit-transition: all 0.1s ease;\n transition: all 0.1s ease; }\n .aplayer .aplayer-lrc {\n display: none;\n position: relative;\n height: 30px;\n text-align: center;\n overflow: hidden;\n margin: -10px 0 7px; }\n .aplayer .aplayer-lrc:before {\n position: absolute;\n top: 0;\n z-index: 1;\n display: block;\n overflow: hidden;\n width: 100%;\n height: 10%;\n content: ' ';\n background: -webkit-gradient(linear, left top, left bottom, from(white), to(rgba(255, 255, 255, 0)));\n background: linear-gradient(to bottom, white 0%, rgba(255, 255, 255, 0) 100%);\n filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#00ffffff',GradientType=0 ); }\n .aplayer .aplayer-lrc:after {\n position: absolute;\n bottom: 0;\n z-index: 1;\n display: block;\n overflow: hidden;\n width: 100%;\n height: 33%;\n content: ' ';\n background: -webkit-gradient(linear, left top, left bottom, from(rgba(255, 255, 255, 0)), to(rgba(255, 255, 255, 0.8)));\n background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.8) 100%);\n filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00ffffff', endColorstr='#ccffffff',GradientType=0 ); }\n .aplayer .aplayer-lrc p {\n font-size: 12px;\n color: #666;\n line-height: 16px !important;\n height: 16px !important;\n padding: 0 !important;\n margin: 0 !important;\n -webkit-transition: all 0.5s ease-out;\n transition: all 0.5s ease-out;\n opacity: 0.4;\n overflow: hidden; }\n .aplayer .aplayer-lrc p.aplayer-lrc-current {\n opacity: 1;\n overflow: visible;\n height: initial !important; }\n .aplayer .aplayer-lrc .aplayer-lrc-contents {\n width: 100%;\n -webkit-transition: all 0.5s ease-out;\n transition: all 0.5s ease-out;\n -webkit-user-select: text;\n -moz-user-select: text;\n -ms-user-select: text;\n user-select: text;\n cursor: default; }\n .aplayer .aplayer-list {\n overflow: auto;\n -webkit-transition: all 0.5s ease;\n transition: all 0.5s ease;\n will-change: height;\n display: none; }\n .aplayer .aplayer-list.aplayer-list-hide {\n height: 0 !important; }\n .aplayer .aplayer-list::-webkit-scrollbar {\n width: 5px; }\n .aplayer .aplayer-list::-webkit-scrollbar-track {\n background-color: #f9f9f9; }\n .aplayer .aplayer-list::-webkit-scrollbar-thumb {\n border-radius: 3px;\n background-color: #eee; }\n .aplayer .aplayer-list::-webkit-scrollbar-thumb:hover {\n background-color: #ccc; }\n .aplayer .aplayer-list ol {\n list-style-type: none;\n margin: 0;\n padding: 0; }\n .aplayer .aplayer-list ol li {\n position: relative;\n height: 32px;\n line-height: 32px;\n padding: 0 15px;\n font-size: 12px;\n border-top: 1px solid #e9e9e9;\n cursor: pointer;\n -webkit-transition: all 0.2s ease;\n transition: all 0.2s ease;\n overflow: hidden; }\n .aplayer .aplayer-list ol li:first-child {\n border-top: none; }\n .aplayer .aplayer-list ol li:hover {\n background: #efefef; }\n .aplayer .aplayer-list ol li.aplayer-list-light {\n background: #e9e9e9; }\n .aplayer .aplayer-list ol li.aplayer-list-light .aplayer-list-cur {\n display: inline-block; }\n .aplayer .aplayer-list ol li .aplayer-list-cur {\n display: none;\n width: 3px;\n height: 22px;\n position: absolute;\n left: 0;\n top: 5px;\n cursor: pointer; }\n .aplayer .aplayer-list ol li .aplayer-list-index {\n color: #666;\n margin-right: 12px;\n cursor: pointer; }\n .aplayer .aplayer-list ol li .aplayer-list-author {\n color: #666;\n float: right;\n cursor: pointer; }\n\n@-webkit-keyframes aplayer-roll {\n 0% {\n left: 0; }\n 100% {\n left: -100%; } }\n\n@keyframes aplayer-roll {\n 0% {\n left: 0; }\n 100% {\n left: -100%; } }\n",""])},function(e,t){function a(e,t){var a=e[1]||"",r=e[3];if(!r)return a;if(t&&"function"==typeof btoa){var i=n(r);return[a].concat(r.sources.map(function(e){return"/*# sourceURL="+r.sourceRoot+e+" */"})).concat([i]).join("\n")}return[a].join("\n")}function n(e){return"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(e))))+" */"}e.exports=function(e){var t=[];return t.toString=function(){return this.map(function(t){var n=a(t,e);return t[2]?"@media "+t[2]+"{"+n+"}":n}).join("")},t.i=function(e,a){"string"==typeof e&&(e=[[null,e,""]]);for(var n={},r=0;r=0&&b.splice(t,1)}function o(e){var t=document.createElement("style");return e.attrs.type="text/css",p(t,e.attrs),i(e,t),t}function s(e){var t=document.createElement("link");return e.attrs.type="text/css",e.attrs.rel="stylesheet",p(t,e.attrs),i(e,t),t}function p(e,t){Object.keys(t).forEach(function(a){e.setAttribute(a,t[a])})}function c(e,t){var a,n,r,i;if(t.transform&&e.css){if(!(i=t.transform(e.css)))return function(){};e.css=i}if(t.singleton){var p=g++;a=v||(v=o(t)),n=u.bind(null,a,p,!1),r=u.bind(null,a,p,!0)}else e.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(a=s(t),n=y.bind(null,a,t),r=function(){l(a),a.href&&URL.revokeObjectURL(a.href)}):(a=o(t),n=d.bind(null,a),r=function(){l(a)});return n(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;n(e=t)}else r()}}function u(e,t,a,n){var r=a?"":n.css;if(e.styleSheet)e.styleSheet.cssText=w(t,r);else{var i=document.createTextNode(r),l=e.childNodes;l[t]&&e.removeChild(l[t]),l.length?e.insertBefore(i,l[t]):e.appendChild(i)}}function d(e,t){var a=t.css,n=t.media;if(n&&e.setAttribute("media",n),e.styleSheet)e.styleSheet.cssText=a;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(a))}}function y(e,t,a){var n=a.css,r=a.sourceMap,i=void 0===t.convertToAbsoluteUrls&&r;(t.convertToAbsoluteUrls||i)&&(n=x(n)),r&&(n+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(r))))+" */");var l=new Blob([n],{type:"text/css"}),o=e.href;e.href=URL.createObjectURL(l),o&&URL.revokeObjectURL(o)}var h={},m=function(e){var t;return function(){return void 0===t&&(t=e.apply(this,arguments)),t}}(function(){return window&&document&&document.all&&!window.atob}),f=function(e){var t={};return function(a){return void 0===t[a]&&(t[a]=e.call(this,a)),t[a]}}(function(e){return document.querySelector(e)}),v=null,g=0,b=[],x=a(5);e.exports=function(e,t){if("undefined"!=typeof DEBUG&&DEBUG&&"object"!=typeof document)throw new Error("The style-loader cannot be used in a non-browser environment");t=t||{},t.attrs="object"==typeof t.attrs?t.attrs:{},t.singleton||(t.singleton=m()),t.insertInto||(t.insertInto="head"),t.insertAt||(t.insertAt="bottom");var a=r(e,t);return n(a,t),function(e){for(var i=[],l=0;l\n \n \n \n '},this.isMobile=/mobile/i.test(window.navigator.userAgent),this.isMobile&&(t.autoplay=!1);var s={element:document.getElementsByClassName("aplayer")[0],narrow:!1,autoplay:!1,mutex:!0,showlrc:0,theme:"#b7daff",mode:"circulation"};for(var p in s)s.hasOwnProperty(p)&&!t.hasOwnProperty(p)&&(t[p]=s[p]);if(this.option=t,this.audios=[],this.mode=t.mode,this.secondToTime=function(e){if(isNaN(e))return"00:00";var t=function(e){return e<10?"0"+e:""+e},a=parseInt(e/60),n=parseInt(e-60*a),r=parseInt(a/60),i=parseInt(e/60-60*parseInt(e/60/60));return e>=3600?t(r)+":"+t(i)+":"+t(n):t(a)+":"+t(n)},this.element=this.option.element,2===this.option.showlrc||!0===this.option.showlrc){this.savelrc=[];for(var c=0;c0?t:0,t=t<1?t:1,m[e+"Bar"].style[a]=100*t+"%"},this.updateLrc=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:i.audio.currentTime;if(i.lrcIndex>i.lrc.length-1||e=i.lrc[i.lrcIndex+1][0])for(var t=0;t=i.lrc[t][0]&&(!i.lrc[t+1]||e1&&this.element.classList.add("aplayer-withlist"),this.multiple||"circulation"===this.mode||"order"===this.mode||(this.mode="circulation"),this.getRandomOrder();for(var y='\n
\n
\n \n
\n
\n
\n
\n \n \n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n
\n
\n
\n
\n \n - 00:00 / 00:00\n \n
\n \n
\n
\n
\n
\n
\n
\n \n \n
\n
\n
\n
\n
    ",h=0;h\n \n '+(h+1)+'\n '+this.option.music[h].title+'\n '+this.option.music[h].author+"\n ";y+="\n
\n
",this.element.innerHTML=y,this.element.offsetWidth<300&&(this.element.getElementsByClassName("aplayer-icon-mode")[0].style.display="none"),this.ptime=this.element.getElementsByClassName("aplayer-ptime")[0],this.element.getElementsByClassName("aplayer-info")[0].offsetWidth<200&&this.element.getElementsByClassName("aplayer-time")[0].classList.add("aplayer-time-narrow");var m={};m.barWrap=this.element.getElementsByClassName("aplayer-bar-wrap")[0],this.option.narrow&&this.element.classList.add("aplayer-narrow"),this.button=this.element.getElementsByClassName("aplayer-button")[0],this.button.addEventListener("click",function(e){i.toggle()});var f=this.element.getElementsByClassName("aplayer-list")[0];f.addEventListener("click",function(e){var t=void 0;t="LI"===e.target.tagName.toUpperCase()?e.target:e.target.parentElement;var a=parseInt(t.getElementsByClassName("aplayer-list-index")[0].innerHTML)-1;a!==i.playIndex?(i.setMusic(a),i.play()):i.toggle()}),m.playedBar=this.element.getElementsByClassName("aplayer-played")[0],m.loadedBar=this.element.getElementsByClassName("aplayer-loaded")[0];var v=this.element.getElementsByClassName("aplayer-thumb")[0],g=void 0;m.barWrap.addEventListener("click",function(e){var t=e||window.event;g=m.barWrap.clientWidth;var n=(t.clientX-a(m.barWrap))/g;isNaN(i.audio.duration)?i.updateBar("played",0,"width"):(i.updateBar("played",n,"width"),i.element.getElementsByClassName("aplayer-ptime")[0].innerHTML=i.secondToTime(n*i.audio.duration),i.audio.currentTime=parseFloat(m.playedBar.style.width)/100*i.audio.duration)}),v.addEventListener("mouseover",function(){v.style.background=i.option.theme}),v.addEventListener("mouseout",function(){v.style.background="#fff"});var b=function(e){var t=e||window.event,n=(t.clientX-a(m.barWrap))/g;n=n>0?n:0,n=n<1?n:1,i.updateBar("played",n,"width"),i.option.showlrc&&i.updateLrc(parseFloat(m.playedBar.style.width)/100*i.audio.duration),i.element.getElementsByClassName("aplayer-ptime")[0].innerHTML=i.secondToTime(n*i.audio.duration)},x=function e(){document.removeEventListener("mouseup",e),document.removeEventListener("mousemove",b),isNaN(i.audio.duration)?i.updateBar("played",0,"width"):(i.audio.currentTime=parseFloat(m.playedBar.style.width)/100*i.audio.duration,i.playedTime=setInterval(function(){i.updateBar("played",i.audio.currentTime/i.audio.duration,"width"),i.option.showlrc&&i.updateLrc(),i.element.getElementsByClassName("aplayer-ptime")[0].innerHTML=i.secondToTime(i.audio.currentTime),i.trigger("playing")},100))};v.addEventListener("mousedown",function(){g=m.barWrap.clientWidth,clearInterval(i.playedTime),document.addEventListener("mousemove",b),document.addEventListener("mouseup",x)}),m.volumeBar=this.element.getElementsByClassName("aplayer-volume")[0];var w=this.element.getElementsByClassName("aplayer-volume-bar")[0];this.volumeicon=this.element.getElementsByClassName("aplayer-time")[0].getElementsByTagName("button")[0];this.element.getElementsByClassName("aplayer-volume-bar-wrap")[0].addEventListener("click",function(e){var t=e||window.event,a=(35-t.clientY+n(w))/35;a=a>0?a:0,a=a<1?a:1,i.volume(a)}),this.volumeicon.addEventListener("click",function(){i.audio.muted?(i.audio.muted=!1,i.volumeicon.className=1===i.audio.volume?"aplayer-icon aplayer-icon-volume-up":"aplayer-icon aplayer-icon-volume-down",1===i.audio.volume?(i.volumeicon.className="aplayer-icon aplayer-icon-volume-up",i.volumeicon.innerHTML=i.getSVG("volume-up")):(i.volumeicon.className="aplayer-icon aplayer-icon-volume-down",i.volumeicon.innerHTML=i.getSVG("volume-down")),i.updateBar("volume",i.audio.volume,"height")):(i.audio.muted=!0,i.volumeicon.className="aplayer-icon aplayer-icon-volume-off",i.volumeicon.innerHTML=i.getSVG("volume-off"),i.updateBar("volume",0,"height"))});var A=this.element.getElementsByClassName("aplayer-icon-mode")[0];A.addEventListener("click",function(){i.multiple?"random"===i.mode?i.mode="single":"single"===i.mode?i.mode="order":"order"===i.mode?i.mode="circulation":"circulation"===i.mode&&(i.mode="random"):"circulation"===i.mode?i.mode="order":i.mode="circulation",A.innerHTML=i.getSVG(i.mode),i.audio.loop=!(i.multiple||"order"===i.mode)}),f.style.height=f.offsetHeight+"px",this.element.getElementsByClassName("aplayer-icon-menu")[0].addEventListener("click",function(){f.classList.contains("aplayer-list-hide")?f.classList.remove("aplayer-list-hide"):f.classList.add("aplayer-list-hide")}),"random"===this.mode?this.setMusic(this.randomOrder[0]):this.setMusic(0),l.push(this)}return i(e,[{key:"setMusic",value:function(e){var t=this;void 0!==e&&(this.playIndex=e);var a=this.playIndex;this.music=this.option.music[a],this.music.pic&&(this.element.getElementsByClassName("aplayer-pic")[0].style.backgroundImage="url('"+this.music.pic+"')"),this.element.getElementsByClassName("aplayer-title")[0].innerHTML=this.music.title,this.element.getElementsByClassName("aplayer-author")[0].innerHTML=" - "+this.music.author,this.element.getElementsByClassName("aplayer-list-light")[0]&&this.element.getElementsByClassName("aplayer-list-light")[0].classList.remove("aplayer-list-light"),this.element.getElementsByClassName("aplayer-list")[0].getElementsByTagName("li")[a].classList.add("aplayer-list-light"),!this.isMobile&&this.audio&&(this.pause(),this.audio.currentTime=0),this.element.getElementsByClassName("aplayer-list")[0].scrollTop=33*a,this.isMobile&&this.audio?(this.audio.src=this.music.url,this.play()):!this.isMobile&&this.audios[a]?(this.audio=this.audios[a],this.audio.volume=parseInt(this.element.getElementsByClassName("aplayer-volume")[0].style.height)/100,this.audio.currentTime=0):(this.audio=document.createElement("audio"),this.audio.src=this.music.url,this.audio.preload=this.option.preload?this.option.preload:"auto",this.audio.addEventListener("play",function(){if(t.button.classList.contains("aplayer-play")){if(t.button.classList.remove("aplayer-play"),t.button.classList.add("aplayer-pause"),t.button.innerHTML="",setTimeout(function(){t.button.innerHTML='\n "},100),t.option.mutex)for(var e=0;e'+t.getSVG("play")+" "},100),clearInterval(t.playedTime),t.trigger("pause"))}),this.audio.addEventListener("durationchange",function(){1!==t.audio.duration&&(t.element.getElementsByClassName("aplayer-dtime")[0].innerHTML=t.secondToTime(t.audio.duration))}),this.audio.addEventListener("progress",function(){var e=t.audio.buffered.length?t.audio.buffered.end(t.audio.buffered.length-1)/t.audio.duration:0;t.updateBar("loaded",e,"width")}),this.audio.addEventListener("error",function(){t.element.getElementsByClassName("aplayer-author")[0].innerHTML=" - Error happens ╥﹏╥",t.trigger("pause")}),this.audio.addEventListener("canplay",function(){t.trigger("canplay")}),this.ended=!1,this.audio.addEventListener("ended",function(){t.multiple?0!==t.audio.currentTime&&("random"===t.mode?t.setMusic(t.nextRandomNum()):"single"===t.mode?t.setMusic(t.playIndex):"order"===t.mode?t.playIndex=200&&o.status<300||304===o.status?(i=o.responseText,t.lrcs[r]=n(i)):(console.log("Request was unsuccessful: "+o.status),t.lrcs[r]=[["00:00","Not available"]]),t.lrc=t.lrcs[r];var e="";t.lrcContents=t.element.getElementsByClassName("aplayer-lrc-contents")[0];for(var a=0;a"+t.lrc[a][1]+"

";t.lrcContents.innerHTML=e,t.lrcIndex||(t.lrcIndex=0),t.lrcContents.getElementsByTagName("p")[0].classList.add("aplayer-lrc-current"),t.lrcContents.style.transform="translateY(0px)",t.lrcContents.style.webkitTransform="translateY(0px)"}};var s=void 0;s=this.option.music[r].lrc,o.open("get",s,!0),o.send(null)}i?this.lrcs[r]=n(i):3===this.option.showlrc?this.lrcs[r]=[["00:00","Loading"]]:this.lrcs[r]=[["00:00","Not available"]]}this.lrc=this.lrcs[r];var p="";this.lrcContents=this.element.getElementsByClassName("aplayer-lrc-contents")[0];for(var c=0;c"+this.lrc[c][1]+"

";this.lrcContents.innerHTML=p,this.lrcIndex||(this.lrcIndex=0),this.lrcContents.getElementsByTagName("p")[0].classList.add("aplayer-lrc-current"),this.lrcContents.style.transform="translateY(0px)",this.lrcContents.style.webkitTransform="translateY(0px)"}1!==this.audio.duration&&(this.element.getElementsByClassName("aplayer-dtime")[0].innerHTML=this.audio.duration?this.secondToTime(this.audio.duration):"00:00"),this.option.autoplay&&!this.isMobile&&this.play(),this.option.autoplay=!0}},{key:"play",value:function(e){"[object Number]"===Object.prototype.toString.call(e)&&(this.audio.currentTime=e),this.audio.paused&&this.audio.play()}},{key:"pause",value:function(){this.audio.paused||this.audio.pause()}},{key:"volume",value:function(e){this.updateBar("volume",e,"height"),this.audio.volume=e,this.audio.muted&&(this.audio.muted=!1),1===e?(this.volumeicon.className="aplayer-icon aplayer-icon-volume-up",this.volumeicon.innerHTML=this.getSVG("volume-up")):(this.volumeicon.className="aplayer-icon aplayer-icon-volume-down",this.volumeicon.innerHTML=this.getSVG("volume-down"))}},{key:"on",value:function(e,t){"function"==typeof t&&this.event[e].push(t)}},{key:"toggle",value:function(){this.button.classList.contains("aplayer-play")?this.play():this.button.classList.contains("aplayer-pause")&&this.pause()}},{key:"getRandomOrder",value:function(){function e(e,t){return null==t&&(t=e,e=0),e+Math.floor(Math.random()*(t-e+1))}this.multiple&&(this.randomOrder=function(t){for(var a,n=t.length,r=new Array(n),i=0;i\n \n '+(this.option.music.length-e.length+r+1)+'\n '+e[r].title+'\n '+e[r].author+"\n ";a.innerHTML+=n,this.multiple||(this.multiple=!0,this.element.classList.add("aplayer-withlist"),this.audio.loop=!1),t.style.height="auto",t.style.height=t.offsetHeight+"px",this.getRandomOrder()}}]),e}();e.exports=o},function(e,t,a){t=e.exports=a(3)(void 0),t.push([e.i,".aplayer-narrow {\n width: 66px; }\n .aplayer-narrow .aplayer-info {\n display: none; }\n\n.aplayer-withlrc.aplayer-narrow {\n width: 90px; }\n\n.aplayer-withlrc.aplayer .aplayer-pic {\n height: 90px;\n width: 90px; }\n\n.aplayer-withlrc.aplayer .aplayer-info {\n margin-left: 90px;\n height: 90px; }\n\n.aplayer-withlrc.aplayer .aplayer-lrc {\n display: block; }\n\n.aplayer-withlrc.aplayer .aplayer-info {\n padding: 10px 7px 0 7px; }\n\n.aplayer-withlist.aplayer .aplayer-info {\n border-bottom: 1px solid #e9e9e9; }\n\n.aplayer-withlist.aplayer .aplayer-list {\n display: block; }\n\n.aplayer-withlist.aplayer .aplayer-icon-menu {\n display: inline !important; }\n\n.aplayer {\n font-family: Arial, Helvetica, sans-serif;\n margin: 5px;\n -webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12);\n box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12);\n border-radius: 2px;\n overflow: hidden;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n line-height: initial; }\n .aplayer * {\n -webkit-box-sizing: content-box;\n box-sizing: content-box; }\n .aplayer .aplayer-icon {\n width: 15px;\n height: 15px;\n border: none;\n background-color: transparent;\n outline: none;\n cursor: pointer;\n opacity: .8;\n vertical-align: middle;\n padding: 0;\n font-size: 12px;\n margin: 0;\n display: inline; }\n .aplayer .aplayer-icon .aplayer-fill {\n -webkit-transition: all .2s ease-in-out;\n transition: all .2s ease-in-out; }\n .aplayer .aplayer-lrc-content {\n display: none; }\n .aplayer .aplayer-pic {\n position: relative;\n float: left;\n height: 66px;\n width: 66px;\n background-image: url("+a(6)+");\n background-size: 100%;\n -webkit-transition: all 0.3s ease;\n transition: all 0.3s ease; }\n .aplayer .aplayer-pic .aplayer-button {\n position: absolute;\n border-radius: 50%;\n opacity: 0.8;\n cursor: pointer;\n text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);\n -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);\n box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);\n background: rgba(0, 0, 0, 0.2);\n -webkit-transition: all 0.1s ease;\n transition: all 0.1s ease; }\n .aplayer .aplayer-pic .aplayer-button:hover {\n opacity: 1; }\n .aplayer .aplayer-pic .aplayer-button .aplayer-fill {\n fill: #fff; }\n .aplayer .aplayer-pic .aplayer-hide {\n display: none; }\n .aplayer .aplayer-pic .aplayer-play {\n width: 26px;\n height: 26px;\n border: 2px solid #fff;\n bottom: 50%;\n right: 50%;\n margin: 0 -15px -15px 0; }\n .aplayer .aplayer-pic .aplayer-play .aplayer-icon-play {\n position: absolute;\n top: 3px;\n left: 4px;\n height: 20px;\n width: 20px; }\n .aplayer .aplayer-pic .aplayer-pause {\n width: 16px;\n height: 16px;\n border: 2px solid #fff;\n bottom: 4px;\n right: 4px; }\n .aplayer .aplayer-pic .aplayer-pause .aplayer-icon-pause {\n position: absolute;\n top: 2px;\n left: 2px;\n height: 12px;\n width: 12px; }\n .aplayer .aplayer-info {\n margin-left: 66px;\n padding: 14px 7px 0 10px;\n height: 66px;\n -webkit-box-sizing: border-box;\n box-sizing: border-box; }\n .aplayer .aplayer-info .aplayer-music {\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n margin: 0 0 13px 5px;\n -webkit-user-select: text;\n -moz-user-select: text;\n -ms-user-select: text;\n user-select: text;\n cursor: default;\n padding-bottom: 2px; }\n .aplayer .aplayer-info .aplayer-music .aplayer-title {\n font-size: 14px; }\n .aplayer .aplayer-info .aplayer-music .aplayer-author {\n font-size: 12px;\n color: #666; }\n .aplayer .aplayer-info .aplayer-controller {\n position: relative;\n display: -webkit-box;\n display: -ms-flexbox;\n display: flex; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap {\n margin: 0 0 0 5px;\n padding: 4px 0;\n cursor: pointer !important;\n -webkit-box-flex: 1;\n -ms-flex: 1;\n flex: 1; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar {\n position: relative;\n height: 2px;\n width: 100%;\n background: #cdcdcd; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-loaded {\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n background: #aaa;\n height: 2px;\n -webkit-transition: all 0.5s ease;\n transition: all 0.5s ease; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-played {\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n height: 2px; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-played .aplayer-thumb {\n position: absolute;\n top: 0;\n right: 5px;\n margin-top: -4px;\n margin-right: -10px;\n height: 8px;\n width: 8px;\n border-radius: 50%;\n background: #fff;\n cursor: pointer !important; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-time {\n position: relative;\n right: 0;\n bottom: 3px;\n height: 17px;\n color: #999;\n font-size: 11px;\n padding-left: 7px; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-time-inner {\n vertical-align: middle; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon {\n cursor: pointer;\n -webkit-transition: all 0.2s ease;\n transition: all 0.2s ease; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon .aplayer-fill {\n fill: #666; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon.aplayer-icon-mode {\n margin-right: 4px; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon:hover .aplayer-fill {\n fill: #000; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon.aplayer-icon-menu {\n display: none; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-time.aplayer-time-narrow .aplayer-icon-mode {\n display: none; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-time.aplayer-time-narrow .aplayer-icon-menu {\n display: none; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap {\n position: relative;\n display: inline-block;\n margin-left: 3px;\n cursor: pointer !important; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap:hover .aplayer-volume-bar-wrap {\n display: block; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap .aplayer-volume-bar-wrap {\n display: none;\n position: absolute;\n bottom: 15px;\n right: -3px;\n width: 25px;\n height: 40px;\n z-index: 99; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap .aplayer-volume-bar-wrap .aplayer-volume-bar {\n position: absolute;\n bottom: 0;\n right: 10px;\n width: 5px;\n height: 35px;\n background: #aaa; }\n .aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap .aplayer-volume-bar-wrap .aplayer-volume-bar .aplayer-volume {\n position: absolute;\n bottom: 0;\n right: 0;\n width: 5px;\n -webkit-transition: all 0.1s ease;\n transition: all 0.1s ease; }\n .aplayer .aplayer-lrc {\n display: none;\n position: relative;\n height: 30px;\n text-align: center;\n overflow: hidden;\n margin: -10px 0 7px; }\n .aplayer .aplayer-lrc:before {\n position: absolute;\n top: 0;\n z-index: 1;\n display: block;\n overflow: hidden;\n width: 100%;\n height: 10%;\n content: ' ';\n background: -webkit-gradient(linear, left top, left bottom, from(white), to(rgba(255, 255, 255, 0)));\n background: linear-gradient(to bottom, white 0%, rgba(255, 255, 255, 0) 100%);\n filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#00ffffff',GradientType=0 ); }\n .aplayer .aplayer-lrc:after {\n position: absolute;\n bottom: 0;\n z-index: 1;\n display: block;\n overflow: hidden;\n width: 100%;\n height: 33%;\n content: ' ';\n background: -webkit-gradient(linear, left top, left bottom, from(rgba(255, 255, 255, 0)), to(rgba(255, 255, 255, 0.8)));\n background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.8) 100%);\n filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00ffffff', endColorstr='#ccffffff',GradientType=0 ); }\n .aplayer .aplayer-lrc p {\n font-size: 12px;\n color: #666;\n line-height: 16px !important;\n height: 16px !important;\n padding: 0 !important;\n margin: 0 !important;\n -webkit-transition: all 0.5s ease-out;\n transition: all 0.5s ease-out;\n opacity: 0.4;\n overflow: hidden; }\n .aplayer .aplayer-lrc p.aplayer-lrc-current {\n opacity: 1;\n overflow: visible;\n height: initial !important; }\n .aplayer .aplayer-lrc .aplayer-lrc-contents {\n width: 100%;\n -webkit-transition: all 0.5s ease-out;\n transition: all 0.5s ease-out;\n -webkit-user-select: text;\n -moz-user-select: text;\n -ms-user-select: text;\n user-select: text;\n cursor: default; }\n .aplayer .aplayer-list {\n overflow: auto;\n -webkit-transition: all 0.5s ease;\n transition: all 0.5s ease;\n will-change: height;\n display: none; }\n .aplayer .aplayer-list.aplayer-list-hide {\n height: 0 !important; }\n .aplayer .aplayer-list::-webkit-scrollbar {\n width: 5px; }\n .aplayer .aplayer-list::-webkit-scrollbar-track {\n background-color: #f9f9f9; }\n .aplayer .aplayer-list::-webkit-scrollbar-thumb {\n border-radius: 3px;\n background-color: #eee; }\n .aplayer .aplayer-list::-webkit-scrollbar-thumb:hover {\n background-color: #ccc; }\n .aplayer .aplayer-list ol {\n list-style-type: none;\n margin: 0;\n padding: 0; }\n .aplayer .aplayer-list ol li {\n position: relative;\n height: 32px;\n line-height: 32px;\n padding: 0 15px;\n font-size: 12px;\n border-top: 1px solid #e9e9e9;\n cursor: pointer;\n -webkit-transition: all 0.2s ease;\n transition: all 0.2s ease;\n overflow: hidden; }\n .aplayer .aplayer-list ol li:first-child {\n border-top: none; }\n .aplayer .aplayer-list ol li:hover {\n background: #efefef; }\n .aplayer .aplayer-list ol li.aplayer-list-light {\n background: #e9e9e9; }\n .aplayer .aplayer-list ol li.aplayer-list-light .aplayer-list-cur {\n display: inline-block; }\n .aplayer .aplayer-list ol li .aplayer-list-cur {\n display: none;\n width: 3px;\n height: 22px;\n position: absolute;\n left: 0;\n top: 5px;\n cursor: pointer; }\n .aplayer .aplayer-list ol li .aplayer-list-index {\n color: #666;\n margin-right: 12px;\n cursor: pointer; }\n .aplayer .aplayer-list ol li .aplayer-list-author {\n color: #666;\n float: right;\n cursor: pointer; }\n\n@-webkit-keyframes aplayer-roll {\n 0% {\n left: 0; }\n 100% {\n left: -100%; } }\n\n@keyframes aplayer-roll {\n 0% {\n left: 0; }\n 100% {\n left: -100%; } }\n",""])},function(e,t){function a(e,t){var a=e[1]||"",r=e[3];if(!r)return a;if(t&&"function"==typeof btoa){var i=n(r);return[a].concat(r.sources.map(function(e){return"/*# sourceURL="+r.sourceRoot+e+" */"})).concat([i]).join("\n")}return[a].join("\n")}function n(e){return"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(e))))+" */"}e.exports=function(e){var t=[];return t.toString=function(){return this.map(function(t){var n=a(t,e);return t[2]?"@media "+t[2]+"{"+n+"}":n}).join("")},t.i=function(e,a){"string"==typeof e&&(e=[[null,e,""]]);for(var n={},r=0;r=0&&b.splice(t,1)}function o(e){var t=document.createElement("style");return e.attrs.type="text/css",p(t,e.attrs),i(e,t),t}function s(e){var t=document.createElement("link");return e.attrs.type="text/css",e.attrs.rel="stylesheet",p(t,e.attrs),i(e,t),t}function p(e,t){Object.keys(t).forEach(function(a){e.setAttribute(a,t[a])})}function c(e,t){var a,n,r,i;if(t.transform&&e.css){if(!(i=t.transform(e.css)))return function(){};e.css=i}if(t.singleton){var p=g++;a=v||(v=o(t)),n=u.bind(null,a,p,!1),r=u.bind(null,a,p,!0)}else e.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(a=s(t),n=y.bind(null,a,t),r=function(){l(a),a.href&&URL.revokeObjectURL(a.href)}):(a=o(t),n=d.bind(null,a),r=function(){l(a)});return n(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;n(e=t)}else r()}}function u(e,t,a,n){var r=a?"":n.css;if(e.styleSheet)e.styleSheet.cssText=w(t,r);else{var i=document.createTextNode(r),l=e.childNodes;l[t]&&e.removeChild(l[t]),l.length?e.insertBefore(i,l[t]):e.appendChild(i)}}function d(e,t){var a=t.css,n=t.media;if(n&&e.setAttribute("media",n),e.styleSheet)e.styleSheet.cssText=a;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(a))}}function y(e,t,a){var n=a.css,r=a.sourceMap,i=void 0===t.convertToAbsoluteUrls&&r;(t.convertToAbsoluteUrls||i)&&(n=x(n)),r&&(n+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(r))))+" */");var l=new Blob([n],{type:"text/css"}),o=e.href;e.href=URL.createObjectURL(l),o&&URL.revokeObjectURL(o)}var h={},m=function(e){var t;return function(){return void 0===t&&(t=e.apply(this,arguments)),t}}(function(){return window&&document&&document.all&&!window.atob}),f=function(e){var t={};return function(a){return void 0===t[a]&&(t[a]=e.call(this,a)),t[a]}}(function(e){return document.querySelector(e)}),v=null,g=0,b=[],x=a(5);e.exports=function(e,t){if("undefined"!=typeof DEBUG&&DEBUG&&"object"!=typeof document)throw new Error("The style-loader cannot be used in a non-browser environment");t=t||{},t.attrs="object"==typeof t.attrs?t.attrs:{},t.singleton||(t.singleton=m()),t.insertInto||(t.insertInto="head"),t.insertAt||(t.insertAt="bottom");var a=r(e,t);return n(a,t),function(e){for(var i=[],l=0;l=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])}})}); +"use strict";console.log("\n %c MetingJS 1.0.1 %c https://github.com/metowolf/MetingJS \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 aplayers=[];document.addEventListener("DOMContentLoaded",function(){function a(a,b){var c=[],d=a.dataset;c.element=a,c.music=b,c.showlrc=c.music[0].lrc?3:0,c.narrow="true"===d.narrow,c.autoplay="true"===d.autoplay,c.mutex="false"!==d.mutex,c.mode=d.mode||"circulation",c.preload=d.preload||"auto",c.listmaxheight=d.listmaxheight||"340px",c.theme=d.theme||"#ad7a86",aplayers.push(new APlayer(c))}var b="https://api.i-meto.com/meting/api?server=:server&type=:type&id=:id&r=:r";"undefined"!=typeof meting_api&&(b=meting_api);var c=document.querySelectorAll(".aplayer"),d=!0,e=!1,f=void 0;try{for(var g,h=function(){var c=g.value,d=c.dataset.id;if(d){var e=b;e=e.replace(":server",c.dataset.server),e=e.replace(":type",c.dataset.type),e=e.replace(":id",c.dataset.id),e=e.replace(":r",Math.random());var f=new XMLHttpRequest;f.onreadystatechange=function(){if(4===f.readyState&&(200<=f.status&&300>f.status||304===f.status)){var b=JSON.parse(f.responseText);a(c,b)}},f.open("get",e,!0),f.send(null)}else{var h=[{title:c.dataset.title,author:c.dataset.author,url:c.dataset.url,pic:c.dataset.pic,lrc:c.dataset.lrc}];a(c,h)}},i=c[Symbol.iterator]();!(d=(g=i.next()).done);d=!0)h()}catch(a){e=!0,f=a}finally{try{!d&&i.return&&i.return()}finally{if(e)throw f}}},!1); diff --git a/assets/editer.js b/assets/editer.js index ae23acc..e9b28d7 100644 --- a/assets/editer.js +++ b/assets/editer.js @@ -7,7 +7,7 @@ $(function() { '
'+ '
'+ '

插入音乐

'+ - '

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

请在下方的输入框内输入要插入的音乐地址'+ '

'+ '
'+ '
'+ diff --git a/driver/cache.interface.php b/driver/cache.interface.php new file mode 100644 index 0000000..4b9ba38 --- /dev/null +++ b/driver/cache.interface.php @@ -0,0 +1,8 @@ +db = Typecho_Db::get(); + $dbname = $this->db->getPrefix() . 'metingcache'; + $sql = "SHOW TABLES LIKE '%" . $dbname . "%'"; + if (count($this->db->fetchAll($sql)) == 0) { + $this->install(); + } else { + $this->db->query($this->db->delete('table.metingcache')->where('time <= ?', time())); + } + } + public function install() + { + $sql = ' +DROP TABLE IF EXISTS `%dbname%`; +CREATE TABLE `%dbname%` ( + `key` char(32) NOT NULL, + `data` mediumtext, + `time` bigint(20) DEFAULT NULL, + PRIMARY KEY (`key`) +) ENGINE=MyISAM DEFAULT CHARSET=%charset%'; + $dbname = $this->db->getPrefix() . 'metingcache'; + $search = array('%dbname%', '%charset%'); + $replace = array($dbname, str_replace('UTF-8', 'utf8', Helper::options()->charset)); + + $sql = str_replace($search, $replace, $sql); + $sqls = explode(';', $sql); + foreach ($sqls as $sql) { + $this->db->query($sql); + } + } + public function set($key, $value, $expire = 86400) + { + $this->db->query($this->db->insert('table.metingcache')->rows(array( + 'key' => md5($key), + 'data' => $value, + 'time' => time() + $expire + ))); + } + public function get($key) + { + $rs = $this->db->fetchRow($this->db->select('data')->from('table.metingcache')->where('key = ?', md5($key))); + if (count($rs) == 0) { + return false; + } else { + return $rs['data']; + } + } + public function flush() + { + return $this->db->query($this->db->delete('table.metingcache')); + } +} diff --git a/driver/redis.class.php b/driver/redis.class.php new file mode 100644 index 0000000..73d1b7f --- /dev/null +++ b/driver/redis.class.php @@ -0,0 +1,25 @@ +redis = new Redis(); + $this->redis->connect($option['host'], $option['port']); + } + public function install() + { + } + public function set($key, $value, $expire = 86400) + { + return $this->redis->set($key, $value, $expire); + } + public function get($key) + { + return $this->redis->get($key); + } + public function flush() + { + return $this->redis->flushDb(); + } +} diff --git a/driver/sqlite.class.php b/driver/sqlite.class.php new file mode 100644 index 0000000..72e10be --- /dev/null +++ b/driver/sqlite.class.php @@ -0,0 +1,56 @@ +db = Typecho_Db::get(); + $dbname = $this->db->getPrefix() . 'metingcache'; + $sql = "SELECT name FROM sqlite_master WHERE type='table' AND name= '" . $dbname . "'"; + if (count($this->db->fetchAll($sql)) == 0) { + $this->install(); + } else { + $this->db->query($this->db->delete('table.metingcache')->where('time <= ?', time())); + } + } + public function install() + { + $sql = ' +DROP TABLE IF EXISTS `%dbname%`; +CREATE TABLE `%dbname%` ( + `key` varchar(32) NOT NULL PRIMARY KEY, + `data` text, + `time` int(20) DEFAULT NULL +);'; + $dbname = $this->db->getPrefix() . 'metingcache'; + $search = array('%dbname%'); + $replace = array($dbname); + + $sql = str_replace($search, $replace, $sql); + $sqls = explode(';', $sql); + foreach ($sqls as $sql) { + $this->db->query($sql); + } + } + public function set($key, $value, $expire = 86400) + { + $this->db->query($this->db->insert('table.metingcache')->rows(array( + 'key' => md5($key), + 'data' => $value, + 'time' => time() + $expire + ))); + } + public function get($key) + { + $rs = $this->db->fetchRow($this->db->select('data')->from('table.metingcache')->where('key = ?', md5($key))); + if (count($rs) == 0) { + return false; + } else { + return $rs['data']; + } + } + public function flush() + { + return $this->db->query($this->db->delete('table.metingcache')); + } +} diff --git a/include/Meting.php b/include/Meting.php index 538a69e..57d1615 100644 --- a/include/Meting.php +++ b/include/Meting.php @@ -1,11 +1,11 @@ + * Copyright 2018, METO Sheel * Released under the MIT license */ @@ -13,924 +13,1058 @@ namespace Metowolf; class Meting { - protected $_SITE; - protected $_TEMP; - protected $_RETRY = 3; - protected $_FORMAT = false; + const VERSION = '1.5.0'; + const DEFAULT_TIMEOUT = 30; - public function __construct($v = 'netease') + public $raw; + public $data; + public $info; + public $error; + public $status; + + public $server; + public $format = false; + + public function __construct($value = 'netease') { - $this->site($v); + $this->site($value); } - public function site($v) + public function site($value) { - $suppose=array('netease','tencent','xiami','kugou','baidu'); - $this->_SITE=in_array($v,$suppose)?$v:'netease'; + $suppose = array('netease', 'tencent', 'xiami', 'kugou', 'baidu'); + $this->server = in_array($value, $suppose) ? $value : 'netease'; + $data = $this->curlset(); + $this->cookie = $data['cookie']; + $this->referer = $data['referer']; + $this->useragent = $data['useragent']; + return $this; } - public function cookie($v = '') + public function cookie($value) { - if (!empty($v)) { - $this->_TEMP['cookie']=$v; - } - } + $this->cookie = $value; - public function format($v = true) - { - $this->_FORMAT=$v; return $this; } - private function curl($API) + public function format($value = true) { - if (isset($API['encode'])) { - $API=call_user_func_array(array($this,$API['encode']), array($API)); + $this->format = $value; + + return $this; + } + + private function exec($api) + { + if (isset($api['encode'])) { + $api = call_user_func_array(array($this, $api['encode']), array($api)); } - $BASE=$this->curlset(); - $curl=curl_init(); - if ($API['method']=='POST') { - if (is_array($API['body'])) { - $API['body']=http_build_query($API['body']); + if ($api['method'] == 'GET') { + if (isset($api['body'])) { + $api['url'] .= '?'.http_build_query($api['body']); + $api['body'] = null; } + } + + $this->curl($api['url'], $api['body']); + + if (!$this->format) { + return $this->raw; + } + + $this->data = $this->raw; + + if (isset($api['decode'])) { + $this->data = call_user_func_array(array($this, $api['decode']), array($this->data)); + } + if (isset($api['format'])) { + $this->data = $this->clean($this->data, $api['format']); + } + + return $this->data; + } + + private function curl($url, $payload = null, $header = 0) + { + $curl = curl_init(); + if (!is_null($payload)) { curl_setopt($curl, CURLOPT_POST, 1); - curl_setopt($curl, CURLOPT_POSTFIELDS, $API['body']); - } elseif ($API['method']=='GET') { - if (isset($API['body'])) { - $API['url']=$API['url'].'?'.http_build_query($API['body']); - } + curl_setopt($curl, CURLOPT_POSTFIELDS, is_array($payload) ? http_build_query($payload) : $payload); } - curl_setopt($curl, CURLOPT_HEADER, 0); + curl_setopt($curl, CURLOPT_HEADER, $header); curl_setopt($curl, CURLOPT_TIMEOUT, 20); curl_setopt($curl, CURLOPT_ENCODING, 'gzip'); curl_setopt($curl, CURLOPT_IPRESOLVE, 1); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10); - curl_setopt($curl, CURLOPT_URL, $API['url']); - curl_setopt($curl, CURLOPT_COOKIE, isset($this->_TEMP['cookie'])?$this->_TEMP['cookie']:$BASE['cookie']); - curl_setopt($curl, CURLOPT_REFERER, $BASE['referer']); - curl_setopt($curl, CURLOPT_USERAGENT, $BASE['useragent']); - for ($i=0;$i<=$this->_RETRY;$i++) { - $data=curl_exec($curl); - $info=curl_getinfo($curl); - $error=curl_errno($curl); - $status=$error?curl_error($curl):''; - if (!$error) { + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_COOKIE, $this->cookie); + curl_setopt($curl, CURLOPT_HTTPHEADER, array( + 'Accept: */*', + 'Accept-Encoding: gzip, deflate', + 'Accept-Language: zh-CN,zh;q=0.8,gl;q=0.6,zh-TW;q=0.4', + 'Connection: keep-alive', + 'Content-Type: application/x-www-form-urlencoded', + 'Referer: '.$this->referer, + 'User-Agent: '.$this->useragent, + )); + for ($i = 0; $i < 3; $i++) { + $this->raw = curl_exec($curl); + $this->info = curl_getinfo($curl); + $this->error = curl_errno($curl); + $this->status = $this->error ? curl_error($curl) : ''; + if (!$this->error) { break; } } curl_close($curl); - if ($error) { - return json_encode( - array( - 'error' => $error, - 'info' => $info, - 'status' => $status, - ) - ); - } - if ($this->_FORMAT&&isset($API['decode'])) { - $data=call_user_func_array(array($this,$API['decode']), array($data)); - } - if ($this->_FORMAT&&isset($API['format'])) { - $data=json_decode($data, 1); - $data=$this->clean($data, $API['format']); - $data=json_encode($data); - } - return $data; + + return $this; } private function pickup($array, $rule) { - $t=explode('#', $rule); + $t = explode('.', $rule); foreach ($t as $vo) { - if (!isset($array[$vo])){ + if (!isset($array[$vo])) { return array(); } - $array=$array[$vo]; + $array = $array[$vo]; } + return $array; } private function clean($raw, $rule) { + $raw = json_decode($raw, true); if (!empty($rule)) { - $raw=$this->pickup($raw, $rule); + $raw = $this->pickup($raw, $rule); } - if (!isset($raw[0])&&sizeof($raw)) { - $raw=array($raw); + if (!isset($raw[0]) && count($raw)) { + $raw = array($raw); } - $result=array_map(array($this,'format_'.$this->_SITE), $raw); - return $result; + $result = array_map(array($this, 'format_'.$this->server), $raw); + + return json_encode($result); } - public function search($keyword, $page=1, $limit=30) + public function search($keyword, $option = null) { - switch ($this->_SITE) { + switch ($this->server) { case 'netease': - $API=array( - 'method' => 'POST', - 'url' => 'http://music.163.com/api/linux/forward', - 'body' => array( - 'method' => 'POST', - 'params' => array( - 's' => $keyword, - 'type' => 1, - 'limit' => $limit, - 'total' => 'true', - 'offset' => ($page-1)*$limit, - ), - 'url' => 'http://music.163.com/api/cloudsearch/pc', - ), - 'encode' => 'netease_AESECB', - 'format' => 'result#songs', - ); - break; + $api = array( + 'method' => 'POST', + 'url' => 'http://music.163.com/api/cloudsearch/pc', + 'body' => array( + 's' => $keyword, + 'type' => isset($option['type']) ? $option['type'] : 1, + 'limit' => isset($option['limit']) ? $option['limit'] : 30, + 'total' => 'true', + 'offset' => isset($option['page']) && isset($option['limit']) ? ($option['page'] - 1) * $option['limit'] : 0, + ), + 'encode' => 'netease_AESCBC', + 'format' => 'result.songs', + ); + break; case 'tencent': - $API=array( - '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, - 'new_json' => 1, - ), - 'format' => 'data#song#list', - ); - break; + $api = array( + 'method' => 'GET', + 'url' => 'https://c.y.qq.com/soso/fcgi-bin/client_search_cp', + 'body' => array( + 'format' => 'json', + 'p' => isset($option['page']) ? $option['page'] : 1, + 'n' => isset($option['limit']) ? $option['limit'] : 30, + 'w' => $keyword, + 'aggr' => 1, + 'lossless' => 1, + 'cr' => 1, + 'new_json' => 1, + ), + 'format' => 'data.song.list', + ); + break; case 'xiami': - $API=array( - 'method' => 'GET', - 'url' => 'http://api.xiami.com/web', - 'body' => array( - 'v' => '2.0', - 'app_key' => '1', - 'key' => $keyword, - 'page' => $page, - 'limit' => $limit, - 'r' => 'search/songs', + $api = array( + 'method' => 'GET', + 'url' => 'http://h5api.m.xiami.com/h5/mtop.alimusic.search.searchservice.searchsongs/1.0/', + 'body' => array( + 'data' => array( + 'key' => $keyword, + 'pagingVO' => array( + 'page' => isset($option['page']) ? $option['page'] : 1, + 'pageSize' => isset($option['limit']) ? $option['limit'] : 30, + ), ), - 'format' => 'data#songs', - ); - break; + 'r' => 'mtop.alimusic.search.searchservice.searchsongs', + ), + 'encode' => 'xiami_sign', + 'format' => 'data.data.songs', + ); + break; case 'kugou': - $API=array( - 'method' => 'GET', - 'url' => 'http://ioscdn.kugou.com/api/v3/search/song', - 'body' => array( - 'iscorrect' => 1, - 'pagesize' => $limit, - 'plat' => 2, - 'tag' => 1, - 'sver' => 5, - 'showtype' => 10, - 'page' => $page, - 'keyword' => $keyword, - 'version' => 8550 - ), - 'format' => 'data#info', - ); - break; + $api = array( + 'method' => 'GET', + 'url' => 'http://ioscdn.kugou.com/api/v3/search/song', + 'body' => array( + 'iscorrect' => 1, + 'pagesize' => isset($option['limit']) ? $option['limit'] : 30, + 'plat' => 2, + 'tag' => 1, + 'sver' => 5, + 'showtype' => 10, + 'page' => isset($option['page']) ? $option['page'] : 1, + 'keyword' => $keyword, + 'version' => 8550, + ), + 'format' => 'data.info', + ); + break; case 'baidu': - $API=array( - 'method' => 'GET', - 'url' => 'https://musicapi.qianqian.com/v1/restserver/ting', - 'body' => array( - 'method' => 'baidu.ting.search.merge', - 'isNew' => 1, - 'query' => $keyword, - 'page_size' => $limit, - 'page_no' => $page, - 'type' => 0, - 'format' => 'json', - 'from' => 'ios', - 'channel' => '(null)', - 'cuid' => 'appstore', - 'from' => 'ios', - 'version' => '5.9.12', - ), - 'format' => 'result#song_info#song_list', - ); - break; + $api = array( + 'method' => 'GET', + 'url' => 'https://gss2.baidu.com/6Ls1aze90MgYm2Gp8IqW0jdnxx1xbK/v1/restserver/ting', + 'body' => array( + 'from' => 'qianqianmini', + 'method' => 'baidu.ting.search.merge', + 'isNew' => 1, + 'platform' => 'darwin', + 'page_no' => isset($option['page']) ? $option['page'] : 1, + 'query' => $keyword, + 'version' => '11.0.2', + 'page_size' => isset($option['limit']) ? $option['limit'] : 30, + ), + 'format' => 'result.song_info.song_list', + ); + break; } - return $this->curl($API); + + return $this->exec($api); } public function song($id) { - switch ($this->_SITE) { + switch ($this->server) { case 'netease': - $API=array( - 'method' => 'POST', - 'url' => 'http://music.163.com/api/linux/forward', - 'body' => array( - 'method' => 'POST', - 'params' => array( - 'c' => '[{"id":'.$id.'}]', - ), - 'url' => 'http://music.163.com/api/v3/song/detail', - ), - 'encode' => 'netease_AESECB', - 'format' => 'songs', - ); - break; + $api = array( + 'method' => 'POST', + 'url' => 'http://music.163.com/api/v3/song/detail/', + 'body' => array( + 'c' => '[{"id":'.$id.',"v":0}]', + ), + 'encode' => 'netease_AESCBC', + 'format' => 'songs', + ); + break; case 'tencent': - $API=array( - 'method' => 'GET', - 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_play_single_song.fcg', - 'body' => array( - 'songmid' => $id, - 'platform' => 'yqq', - 'format' => 'json', - ), - 'decode' => 'tencent_singlesong', - 'format' => 'data', - ); - break; + $api = array( + 'method' => 'GET', + 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_play_single_song.fcg', + 'body' => array( + 'songmid' => $id, + 'platform' => 'yqq', + 'format' => 'json', + ), + 'decode' => 'tencent_singlesong', + 'format' => 'data', + ); + break; case 'xiami': - $API=array( - 'method' => 'GET', - 'url' => 'http://api.xiami.com/web', - 'body' => array( - 'v' => '2.0', - 'app_key' => '1', - 'id' => $id, - 'r' => 'song/detail', + $api = array( + 'method' => 'GET', + 'url' => 'http://h5api.m.xiami.com/h5/mtop.alimusic.music.songservice.getsongdetail/1.0/', + 'body' => array( + 'data' => array( + 'songId' => $id, ), - 'format' => 'data#song', - ); - break; + 'r' => 'mtop.alimusic.music.songservice.getsongdetail', + ), + 'encode' => 'xiami_sign', + 'format' => 'data.data.songDetail', + ); + break; case 'kugou': - $API=array( - 'method' => 'POST', - 'url' => 'http://m.kugou.com/app/i/getSongInfo.php', - 'body' => array( - "cmd" => "playInfo", - "hash" => $id, - "from" => "mkugou", - ), - 'format' => '', - ); - break; + $api = array( + 'method' => 'POST', + 'url' => 'http://m.kugou.com/app/i/getSongInfo.php', + 'body' => array( + 'cmd' => 'playInfo', + 'hash' => $id, + 'from' => 'mkugou', + ), + 'format' => '', + ); + break; case 'baidu': - $API=array( - 'method' => 'GET', - 'url' => 'https://musicapi.qianqian.com/v1/restserver/ting', - 'body' => array( - 'method' => 'baidu.ting.song.play', - 'songid' => $id, - 'format' => 'json', - 'from' => 'ios', - 'channel' => '(null)', - 'cuid' => 'appstore', - 'from' => 'ios', - 'version' => '5.9.12', - ), - 'format' => 'songinfo', - ); - break; + $api = array( + 'method' => 'GET', + 'url' => 'https://gss2.baidu.com/6Ls1aze90MgYm2Gp8IqW0jdnxx1xbK/v1/restserver/ting', + 'body' => array( + 'from' => 'qianqianmini', + 'method' => 'baidu.ting.song.getInfos', + 'songid' => $id, + 'res' => 1, + 'platform' => 'darwin', + 'version' => '1.0.0', + ), + 'encode' => 'baidu_AESCBC', + 'format' => 'songinfo', + ); + break; } - return $this->curl($API); + + return $this->exec($api); } public function album($id) { - switch ($this->_SITE) { + switch ($this->server) { case 'netease': - $API=array( - 'method' => 'POST', - 'url' => 'http://music.163.com/api/linux/forward', - 'body' => array( - 'method' => 'GET', - 'params' => array( - 'id' => $id, - ), - 'url' => 'http://music.163.com/api/v1/album/'.$id, - ), - 'encode' => 'netease_AESECB', - 'format' => 'songs', - ); - break; + $api = array( + 'method' => 'POST', + 'url' => 'http://music.163.com/api/v1/album/'.$id, + 'body' => array( + 'total' => 'true', + 'offset' => '0', + 'id' => $id, + 'limit' => '1000', + 'ext' => 'true', + 'private_cloud' => 'true', + ), + 'encode' => 'netease_AESCBC', + 'format' => 'songs', + ); + break; case 'tencent': - $API=array( - 'method' => 'GET', - 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_album_detail_cp.fcg', - 'body' => array( - 'albummid' => $id, - 'platform' => 'mac', - 'format' => 'json', - 'newsong' => 1, - ), - 'format' => 'data#getSongInfo', - ); - break; + $api = array( + 'method' => 'GET', + 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_album_detail_cp.fcg', + 'body' => array( + 'albummid' => $id, + 'platform' => 'mac', + 'format' => 'json', + 'newsong' => 1, + ), + 'format' => 'data.getSongInfo', + ); + break; case 'xiami': - $API=array( - 'method' => 'GET', - 'url' => 'http://api.xiami.com/web', - 'body' => array( - 'v' => '2.0', - 'app_key' => '1', - 'id' => $id, - 'r' => 'album/detail', + $api = array( + 'method' => 'GET', + 'url' => 'http://h5api.m.xiami.com/h5/mtop.alimusic.music.albumservice.getalbumdetail/1.0/', + 'body' => array( + 'data' => array( + 'albumId' => $id, ), - 'format' => 'data#songs', - ); - break; + 'r' => 'mtop.alimusic.music.albumservice.getalbumdetail', + ), + 'encode' => 'xiami_sign', + 'format' => 'data.data.albumDetail.songs', + ); + break; case 'kugou': - $API=array( - 'method' => 'GET', - 'url' => 'http://mobilecdn.kugou.com/api/v3/album/song', - 'body' => array( - 'albumid' => $id, - 'plat' => 2, - 'page' => 1, - 'pagesize' => -1, - 'version' => 8550, - ), - 'format' => 'data#info', - ); - break; + $api = array( + 'method' => 'GET', + 'url' => 'http://mobilecdn.kugou.com/api/v3/album/song', + 'body' => array( + 'albumid' => $id, + 'plat' => 2, + 'page' => 1, + 'pagesize' => -1, + 'version' => 8550, + ), + 'format' => 'data.info', + ); + break; case 'baidu': - $API=array( - 'method' => 'GET', - 'url' => 'https://musicapi.qianqian.com/v1/restserver/ting', - 'body' => array( - 'method' => 'baidu.ting.album.getAlbumInfo', - 'album_id' => $id, - 'format' => 'json', - 'from' => 'ios', - 'channel' => '(null)', - 'cuid' => 'appstore', - 'from' => 'ios', - 'version' => '5.9.12', - ), - 'format' => 'songlist', - ); - break; + $api = array( + 'method' => 'GET', + 'url' => 'https://gss2.baidu.com/6Ls1aze90MgYm2Gp8IqW0jdnxx1xbK/v1/restserver/ting', + 'body' => array( + 'from' => 'qianqianmini', + 'method' => 'baidu.ting.album.getAlbumInfo', + 'album_id' => $id, + 'platform' => 'darwin', + 'version' => '11.0.2', + ), + 'format' => 'songlist', + ); + break; } - return $this->curl($API); + + return $this->exec($api); } - public function artist($id, $limit=50) + public function artist($id, $limit = 50) { - switch ($this->_SITE) { + switch ($this->server) { case 'netease': - $API=array( - 'method' => 'POST', - 'url' => 'http://music.163.com/api/linux/forward', - 'body' => array( - 'method' => 'GET', - 'params' => array( - 'top' => $limit, - "id" => $id, - "ext" => "true", - ), - 'url' => 'http://music.163.com/api/v1/artist/'.$id, - ), - 'encode' => 'netease_AESECB', - 'format' => 'hotSongs', - ); - break; + $api = array( + 'method' => 'POST', + 'url' => 'http://music.163.com/api/v1/artist/'.$id, + 'body' => array( + 'ext' => 'true', + 'private_cloud' => 'true', + 'ext' => 'true', + 'top' => $limit, + 'id' => $id, + ), + 'encode' => 'netease_AESCBC', + 'format' => 'hotSongs', + ); + break; case 'tencent': - $API=array( - 'method' => 'GET', - 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_singer_track_cp.fcg', - 'body' => array( - 'singermid' => $id, - 'begin' => 0, - 'num' => $limit, - 'order' => 'listen', - 'platform' => 'mac', - 'newsong' => 1, - ), - 'format' => 'data#list', - ); - break; + $api = array( + 'method' => 'GET', + 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_singer_track_cp.fcg', + 'body' => array( + 'singermid' => $id, + 'begin' => 0, + 'num' => $limit, + 'order' => 'listen', + 'platform' => 'mac', + 'newsong' => 1, + ), + 'format' => 'data.list', + ); + break; case 'xiami': - $API=array( - 'method' => 'GET', - 'url' => 'http://api.xiami.com/web', - 'body' => array( - 'v' => '2.0', - 'app_key' => '1', - 'id' => $id, - 'limit' => $limit, - 'page' => 1, - 'r' => 'artist/hot-songs', + $api = array( + 'method' => 'GET', + 'url' => 'http://h5api.m.xiami.com/h5/mtop.alimusic.music.songservice.getartistsongs/1.0/', + 'body' => array( + 'data' => array( + 'artistId' => $id, + 'pagingVO' => array( + 'page' => 1, + 'pageSize' => $limit, + ), ), - 'format' => 'data', - ); - break; + 'r' => 'mtop.alimusic.music.songservice.getartistsongs', + ), + 'encode' => 'xiami_sign', + 'format' => 'data.data.songs', + ); + break; case 'kugou': - $API=array( - 'method' => 'GET', - 'url' => 'http://mobilecdn.kugou.com/api/v3/singer/song', - 'body' => array( - 'singerid' => $id, - 'page' => 1, - 'plat' => 0, - 'pagesize' => $limit, - 'version' => 8400, - ), - 'format' => 'data#info', - ); - break; + $api = array( + 'method' => 'GET', + 'url' => 'http://mobilecdn.kugou.com/api/v3/singer/song', + 'body' => array( + 'singerid' => $id, + 'page' => 1, + 'plat' => 0, + 'pagesize' => $limit, + 'version' => 8400, + ), + 'format' => 'data.info', + ); + break; case 'baidu': - $API=array( - 'method' => 'GET', - 'url' => 'https://musicapi.qianqian.com/v1/restserver/ting', - 'body' => array( - 'method' => 'baidu.ting.artist.getSongList', - 'tinguid' => $id, - 'limits' => $limit, - 'format' => 'json', - 'from' => 'ios', - 'channel' => '(null)', - 'cuid' => 'appstore', - 'from' => 'ios', - 'version' => '5.9.12', - ), - 'format' => 'songlist', - ); - break; + $api = array( + 'method' => 'GET', + 'url' => 'https://gss2.baidu.com/6Ls1aze90MgYm2Gp8IqW0jdnxx1xbK/v1/restserver/ting', + 'body' => array( + 'from' => 'qianqianmini', + 'method' => 'baidu.ting.artist.getSongList', + 'artistid' => $id, + 'limits' => $limit, + 'platform' => 'darwin', + 'offset' => 0, + 'tinguid' => 0, + 'version' => '11.0.2', + ), + 'format' => 'songlist', + ); + break; } - return $this->curl($API); + + return $this->exec($api); } public function playlist($id) { - switch ($this->_SITE) { + switch ($this->server) { case 'netease': - $API=array( - 'method' => 'POST', - 'url' => 'http://music.163.com/api/linux/forward', - 'body' => array( - 'method' => 'POST', - 'params' => array( - 'id' => $id, - "n" => 1000, - ), - 'url' => 'http://music.163.com/api/v3/playlist/detail', - ), - 'encode' => 'netease_AESECB', - 'format' => 'playlist#tracks', - ); - break; + $api = array( + 'method' => 'POST', + 'url' => 'http://music.163.com/api/v3/playlist/detail', + 'body' => array( + 's' => '0', + 'id' => $id, + 'n' => '1000', + 't' => '0', + ), + 'encode' => 'netease_AESCBC', + 'format' => 'playlist.tracks', + ); + break; case 'tencent': - $API=array( - 'method' => 'GET', - 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_playlist_cp.fcg', - 'body' => array( - 'id' => $id, - 'format' => 'json', - 'newsong' => 1, - 'platform' => 'jqspaframe.json', - ), - 'format' => 'data#cdlist#0#songlist', - ); - break; + $api = array( + 'method' => 'GET', + 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_playlist_cp.fcg', + 'body' => array( + 'id' => $id, + 'format' => 'json', + 'newsong' => 1, + 'platform' => 'jqspaframe.json', + ), + 'format' => 'data.cdlist.0.songlist', + ); + break; case 'xiami': - $API=array( - 'method' => 'GET', - 'url' => 'http://api.xiami.com/web', - 'body' => array( - 'v' => '2.0', - 'app_key' => '1', - 'id' => $id, - 'r' => 'collect/detail', + $api = array( + 'method' => 'GET', + 'url' => 'http://h5api.m.xiami.com/h5/mtop.alimusic.music.list.collectservice.getcollectdetail/1.0/', + 'body' => array( + 'data' => array( + 'listId' => $id, + 'isFullTags' => false, + 'pagingVO' => array( + 'page' => 1, + 'pageSize' => 1000, + ), ), - 'format' => 'data#songs', - ); - break; + 'r' => 'mtop.alimusic.music.list.collectservice.getcollectdetail', + ), + 'encode' => 'xiami_sign', + 'format' => 'data.data.collectDetail.songs', + ); + break; case 'kugou': - $API=array( - 'method' => 'GET', - 'url' => 'http://mobilecdn.kugou.com/api/v3/special/song', - 'body' => array( - 'specialid' => $id, - 'page' => 1, - 'plat' => 2, - 'pagesize' => -1, - 'version' => 8400, - ), - 'format' => 'data#info', - ); - break; + $api = array( + 'method' => 'GET', + 'url' => 'http://mobilecdn.kugou.com/api/v3/special/song', + 'body' => array( + 'specialid' => $id, + 'page' => 1, + 'plat' => 2, + 'pagesize' => -1, + 'version' => 8400, + ), + 'format' => 'data.info', + ); + break; case 'baidu': - $API=array( - 'method' => 'GET', - 'url' => 'https://musicapi.qianqian.com/v1/restserver/ting', - 'body' => array( - 'method' => 'baidu.ting.diy.gedanInfo', - 'listid' => $id, - 'format' => 'json', - 'from' => 'ios', - 'channel' => '(null)', - 'cuid' => 'appstore', - 'from' => 'ios', - 'version' => '5.9.12', - ), - 'format' => 'content', - ); - break; + $api = array( + 'method' => 'GET', + 'url' => 'https://gss2.baidu.com/6Ls1aze90MgYm2Gp8IqW0jdnxx1xbK/v1/restserver/ting', + 'body' => array( + 'from' => 'qianqianmini', + 'method' => 'baidu.ting.diy.gedanInfo', + 'listid' => $id, + 'platform' => 'darwin', + 'version' => '11.0.2', + ), + 'format' => 'content', + ); + break; } - return $this->curl($API); + + return $this->exec($api); } - public function url($id, $br=320) + public function url($id, $br = 320) { - switch ($this->_SITE) { + switch ($this->server) { case 'netease': - $API=array( - 'method' => 'POST', - 'url' => 'http://music.163.com/api/linux/forward', - 'body' => array( - 'method' => 'POST', - 'params' => array( - 'ids' => array($id), - 'br' => $br*1000, - ), - 'url' => 'http://music.163.com/api/song/enhance/player/url', - ), - 'encode' => 'netease_AESECB', - 'decode' => 'netease_url', - ); - break; + $api = array( + 'method' => 'POST', + 'url' => 'http://music.163.com/api/song/enhance/player/url', + 'body' => array( + 'ids' => array($id), + 'br' => $br * 1000, + ), + 'encode' => 'netease_AESCBC', + 'decode' => 'netease_url', + ); + break; case 'tencent': - $API=array( - 'method' => 'GET', - 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_play_single_song.fcg', - 'body' => array( - 'songmid' => $id, - 'platform' => 'yqq', - 'format' => 'json', - ), - 'decode' => 'tencent_url', - ); - break; + $api = array( + 'method' => 'GET', + 'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_play_single_song.fcg', + 'body' => array( + 'songmid' => $id, + 'platform' => 'yqq', + 'format' => 'json', + ), + 'decode' => 'tencent_url', + ); + break; case 'xiami': - $API=array( - 'method' => 'GET', - 'url' => 'http://www.xiami.com/song/gethqsong/sid/'.$id, - 'body' => array( - 'v' => '2.0', - 'app_key' => '1', - 'id' => $id, - 'r' => 'song/detail', + $api = array( + 'method' => 'GET', + 'url' => 'http://h5api.m.xiami.com/h5/mtop.alimusic.music.songservice.getsongdetail/1.0/', + 'body' => array( + 'data' => array( + 'songId' => $id, ), - 'decode' => 'xiami_url', - ); - break; + 'r' => 'mtop.alimusic.music.songservice.getsongdetail', + ), + 'encode' => 'xiami_sign', + 'decode' => 'xiami_url', + ); + break; case 'kugou': - $API=array( - 'method' => 'POST', - 'url' => 'http://media.store.kugou.com/v1/get_res_privilege', - 'body' => json_encode(array( - "relate" => 1, - "userid" => 0, - "vip" => 0, - "appid" => 1005, - "token" => "", - "behavior" => "download", - "clientver" => "8493", - "resource" => array(array( - "id" => 0, - "type" => "audio", - "hash" => $id, - ))) - ), - 'decode' => 'kugou_url', - ); - break; + $api = array( + 'method' => 'POST', + 'url' => 'http://media.store.kugou.com/v1/get_res_privilege', + 'body' => json_encode( + array( + 'relate' => 1, + 'userid' => 0, + 'vip' => 0, + 'appid' => 1005, + 'token' => '', + 'behavior' => 'download', + 'clientver' => '8493', + 'resource' => array(array( + 'id' => 0, + 'type' => 'audio', + 'hash' => $id, + )), ) + ), + 'decode' => 'kugou_url', + ); + break; case 'baidu': - $API=array( - 'method' => 'GET', - 'url' => 'http://music.baidu.com/data/music/fmlink', - 'body' => array( - 'songIds' => $id, - 'rate' => $br, - 'type' => 'mp3', - ), - 'decode' => 'baidu_url', - ); - break; + $api = array( + 'method' => 'GET', + 'url' => 'https://gss2.baidu.com/6Ls1aze90MgYm2Gp8IqW0jdnxx1xbK/v1/restserver/ting', + 'body' => array( + 'from' => 'qianqianmini', + 'method' => 'baidu.ting.song.getInfos', + 'songid' => $id, + 'res' => 1, + 'platform' => 'darwin', + 'version' => '1.0.0', + ), + 'encode' => 'baidu_AESCBC', + 'decode' => 'baidu_url', + ); + break; } - $this->_TEMP['br']=$br; - return $this->curl($API); + $this->temp['br'] = $br; + + return $this->exec($api); } public function lyric($id) { - switch ($this->_SITE) { + switch ($this->server) { case 'netease': - $API=array( - 'method' => 'POST', - 'url' => 'http://music.163.com/api/linux/forward', - 'body' => array( - 'method' => 'POST', - 'params' => array( - 'id' => $id, - 'os' => 'linux', - 'lv' => -1, - 'kv' => -1, - 'tv' => -1, - ), - 'url' => 'http://music.163.com/api/song/lyric', - ), - 'encode' => 'netease_AESECB', - 'decode' => 'netease_lyric', - ); - break; + $api = array( + 'method' => 'POST', + 'url' => 'http://music.163.com/api/song/lyric', + 'body' => array( + 'id' => $id, + 'os' => 'linux', + 'lv' => -1, + 'kv' => -1, + 'tv' => -1, + ), + 'encode' => 'netease_AESCBC', + 'decode' => 'netease_lyric', + ); + break; case 'tencent': - $API=array( - 'method' => 'GET', - 'url' => 'https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg', - 'body' => array( - 'songmid' => $id, - 'g_tk' => '5381', - ), - 'decode' => 'tencent_lyric', - ); - break; + $api = array( + 'method' => 'GET', + 'url' => 'https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg', + 'body' => array( + 'songmid' => $id, + 'g_tk' => '5381', + ), + 'decode' => 'tencent_lyric', + ); + break; case 'xiami': - $API=array( - 'method' => 'GET', - 'url' => 'http://api.xiami.com/web', - 'body' => array( - 'v' => '2.0', - 'app_key' => '1', - 'id' => $id, - 'r' => 'song/detail', + $api = array( + 'method' => 'GET', + 'url' => 'http://h5api.m.xiami.com/h5/mtop.alimusic.music.lyricservice.getsonglyrics/1.0/', + 'body' => array( + 'data' => array( + 'songId' => $id, ), - 'decode' => 'xiami_lyric', - ); - break; + 'r' => 'mtop.alimusic.music.lyricservice.getsonglyrics', + ), + 'encode' => 'xiami_sign', + 'decode' => 'xiami_lyric', + ); + break; case 'kugou': - $API=array( - 'method' => 'GET', - 'url' => 'http://m.kugou.com/app/i/krc.php', - 'body' => array( - 'keyword' => '%20-%20', - 'timelength' => 1000000, - 'cmd' => 100, - 'hash' => $id, - ), - 'decode' => 'kugou_lyric' - ); - break; + $api = array( + 'method' => 'GET', + 'url' => 'http://lyrics.kugou.com/search', + 'body' => array( + 'keyword' => '%20-%20', + 'ver' => 1, + 'hash' => $id, + 'client' => 'pc', + 'man' => 'no', + 'duration' => 295058, + ), + 'decode' => 'kugou_lyric', + ); + break; case 'baidu': - $API=array( - 'method' => 'GET', - 'url' => 'https://musicapi.qianqian.com/v1/restserver/ting', - 'body' => array( - 'method' => 'baidu.ting.song.lry', - 'songid' => $id, - 'format' => 'json', - 'from' => 'ios', - 'channel' => '(null)', - 'cuid' => 'appstore', - 'from' => 'ios', - 'version' => '5.9.12', - ), - 'decode' => 'baidu_lyric' - ); - break; + $api = array( + 'method' => 'GET', + 'url' => 'https://gss2.baidu.com/6Ls1aze90MgYm2Gp8IqW0jdnxx1xbK/v1/restserver/ting', + 'body' => array( + 'from' => 'qianqianmini', + 'method' => 'baidu.ting.song.lry', + 'songid' => $id, + 'platform' => 'darwin', + 'version' => '1.0.0', + ), + 'decode' => 'baidu_lyric', + ); + break; } - return $this->curl($API); + + return $this->exec($api); } - public function pic($id, $size=300) + public function pic($id, $size = 300) { - switch ($this->_SITE) { + switch ($this->server) { case 'netease': - $url='https://p3.music.126.net/'.$this->netease_pickey($id).'/'.$id.'.jpg?param='.$size.'y'.$size; - break; + $url = 'https://p3.music.126.net/'.$this->netease_encryptId($id).'/'.$id.'.jpg?param='.$size.'y'.$size; + break; case 'tencent': - $url='https://y.gtimg.cn/music/photo_new/T002R'.$size.'x'.$size.'M000'.$id.'.jpg?max_age=2592000'; - break; + $url = 'https://y.gtimg.cn/music/photo_new/T002R'.$size.'x'.$size.'M000'.$id.'.jpg?max_age=2592000'; + break; case 'xiami': - $format=$this->_FORMAT; - $data=$this->format(false)->song($id); - $this->format($format); - $data=json_decode($data, 1); - $url=$data['data']['song']['logo']; - $url=str_replace(array('_1.','http:','img.'), array('.','https:','pic.'), $url).'@'.$size.'h_'.$size.'w_100q_1c.jpg'; - break; + $format = $this->format; + $data = $this->format(false)->song($id); + $this->format = $format; + $data = json_decode($data, true); + $url = $data['data']['data']['songDetail']['albumLogo']; + $url = str_replace('http:', 'https:', $url).'@1e_1c_100Q_'.$size.'h_'.$size.'w'; + break; case 'kugou': - $format=$this->_FORMAT; - $data=$this->format(false)->song($id); - $this->format($format); - $data=json_decode($data, 1); - $url=$data['imgUrl']; - $url=str_replace('{size}', '400', $url); - break; + $format = $this->format; + $data = $this->format(false)->song($id); + $this->format = $format; + $data = json_decode($data, true); + $url = $data['imgUrl']; + $url = str_replace('{size}', '400', $url); + break; case 'baidu': - $format=$this->_FORMAT; - $data=$this->format(false)->song($id); - $this->format($format); - $data=json_decode($data, 1); - $url=isset($data['songinfo']['pic_big'])?$data['songinfo']['pic_big']:$data['songinfo']['pic_small']; - break; + $format = $this->format; + $data = $this->format(false)->song($id); + $this->format = $format; + $data = json_decode($data, true); + $url = isset($data['songinfo']['pic_radio']) ? $data['songinfo']['pic_radio'] : $data['songinfo']['pic_small']; + break; } - return json_encode(array('url'=>$url)); + + return json_encode(array('url' => $url)); } private function curlset() { - $BASE=array( - 'netease'=>array( + switch ($this->server) { + case 'netease': + return array( 'referer' => 'https://music.163.com/', - 'cookie' => 'os=linux; appver=1.0.0.1026; osver=Ubuntu%2016.10; MUSIC_U=78d411095f4b022667bc8ec49e9a44cca088df057d987f5feaf066d37458e41c4a7d9447977352cf27ea9fee03f6ec4441049cea1c6bb9b6; __remember_me=true', - 'useragent' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36', - ), - 'tencent'=>array( + 'cookie' => 'os=pc; osver=Microsoft-Windows-10-Professional-build-10586-64bit; appver=2.0.3.131777; channel=netease; __remember_me=true', + 'useragent' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36', + ); + case 'tencent': + return array( 'referer' => 'https://y.qq.com/portal/player.html', '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( - 'referer' => 'http://h.xiami.com/', - 'cookie' => 'user_from=2;XMPLAYER_addSongsToggler=0;XMPLAYER_isOpen=0;_xiamitoken=123456789;', - 'useragent' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36', - ), - 'kugou'=>array( + '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', + ); + case 'xiami': + return array( + 'referer' => 'http://h5api.m.xiami.com/', + 'cookie' => '_m_h5_tk=15d3402511a022796d88b249f83fb968_1511163656929; _m_h5_tk_enc=b6b3e64d81dae577fc314b5c5692df3c', + 'useragent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) XIAMI-MUSIC/3.0.9 Chrome/56.0.2924.87 Electron/1.6.11 Safari/537.36', + ); + case 'kugou': + return array( 'referer' => 'http://www.kugou.com/webkugouplayer/flash/webKugou.swf', - 'cookie' => '_WCMID=123456789', - 'useragent' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36', - ), - 'baidu'=>array( - 'referer' => 'http://ting.baidu.com/', - 'cookie' => 'BAIDUID=123456789', - 'useragent' => 'ios_5.9.12', - ), - ); - return $BASE[$this->_SITE]; - } - - /** - * 乱七八糟的函数,加密解密... - * 正在努力重构这些代码 TAT - */ - private function netease_AESECB($API) - { - $KEY='7246674226682325323F5E6544673A51'; - $body=json_encode($API['body']); - if (function_exists('openssl_encrypt')) { - $body=openssl_encrypt($body, 'aes-128-ecb', pack('H*', $KEY)); - } else { - $PAD=16-(strlen($body)%16); - $body=base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, hex2bin($KEY), $body.str_repeat(chr($PAD), $PAD), MCRYPT_MODE_ECB)); + 'cookie' => 'kg_mid='.$this->getRandomHex(32), + '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', + ); + case 'baidu': + return array( + 'referer' => '', + 'cookie' => 'BAIDUID='.$this->getRandomHex(32).':FG=1', + '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', + ); } - $body=strtoupper(bin2hex(base64_decode($body))); - - $API['body']=array( - 'eparams'=>$body, - ); - return $API; } + + private function getRandomHex($length) + { + if (function_exists('openssl_random_pseudo_bytes')) { + return bin2hex(openssl_random_pseudo_bytes($length / 2)); + } else { + return bin2hex(mcrypt_create_iv($length / 2, MCRYPT_DEV_URANDOM)); + } + } + + private function bchexdec($hex) + { + $dec = 0; + $len = strlen($hex); + for ($i = 1; $i <= $len; $i++) { + $dec = bcadd($dec, bcmul(strval(hexdec($hex[$i - 1])), bcpow('16', strval($len - $i)))); + } + + return $dec; + } + + private function bcdechex($dec) + { + $hex = ''; + do { + $last = bcmod($dec, 16); + $hex = dechex($last).$hex; + $dec = bcdiv(bcsub($dec, $last), 16); + } while ($dec > 0); + + return $hex; + } + + private function str2hex($string) + { + $hex = ''; + for ($i = 0; $i < strlen($string); $i++) { + $ord = ord($string[$i]); + $hexCode = dechex($ord); + $hex .= substr('0'.$hexCode, -2); + } + + return $hex; + } + + private function netease_AESCBC($api) + { + $modulus = '157794750267131502212476817800345498121872783333389747424011531025366277535262539913701806290766479189477533597854989606803194253978660329941980786072432806427833685472618792592200595694346872951301770580765135349259590167490536138082469680638514416594216629258349130257685001248172188325316586707301643237607'; + $pubkey = '65537'; + $nonce = '0CoJUm6Qyw8W8jud'; + $vi = '0102030405060708'; + $skey = $this->getRandomHex(16); + + $body = json_encode($api['body']); + $body = openssl_encrypt($body, 'aes-128-cbc', $nonce, false, $vi); + $body = openssl_encrypt($body, 'aes-128-cbc', $skey, false, $vi); + + $skey = strrev(utf8_encode($skey)); + $skey = $this->bchexdec($this->str2hex($skey)); + $skey = bcpowmod($skey, $pubkey, $modulus); + $skey = $this->bcdechex($skey); + $skey = str_pad($skey, 256, '0', STR_PAD_LEFT); + + $api['url'] = str_replace('/api/', '/weapi/', $api['url']); + $api['body'] = array( + 'params' => $body, + 'encSecKey' => $skey, + ); + + return $api; + } + + private function baidu_AESCBC($api) + { + $key = 'DBEECF8C50FD160E'; + $vi = '1231021386755796'; + + $data = 'songid='.$api['body']['songid'].'&ts='.intval(microtime(true) * 1000); + + if (function_exists('openssl_encrypt')) { + $data = openssl_encrypt($data, 'aes-128-cbc', $key, false, $vi); + } else { + $PAD = 16 - (strlen($data) % 16); + $data = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data.str_repeat(chr($PAD), $PAD), MCRYPT_MODE_CBC, $vi)); + } + + $api['body']['e'] = $data; + + return $api; + } + + private function xiami_sign($api) + { + $data = $this->curl('http://h5api.m.xiami.com/h5/mtop.alimusic.search.searchservice.searchsongs/1.0/?appKey=12574478&t=1511168684000&dataType=json&data=%7B%22requestStr%22%3A%22%7B%5C%22model%5C%22%3A%7B%5C%22key%5C%22%3A%5C%22Dangerous+Woman%5C%22%2C%5C%22pagingVO%5C%22%3A%7B%5C%22page%5C%22%3A1%2C%5C%22pageSize%5C%22%3A30%7D%7D%7D%22%7D&api=mtop.alimusic.search.searchservice.searchsongs&v=1.0&type=originaljson&sign=f6c99a429e9ef703ea955f7cd113a467', null, 1); + preg_match_all('/_m_h5[^;]+/', $data->raw, $match); + $this->cookie = $match[0][0].'; '.$match[0][1]; + $data = json_encode(array( + 'requestStr' => json_encode(array( + 'header' => array( + 'platformId' => 'mac', + ), + 'model' => $api['body']['data'], + )), + )); + $appkey = '12574478'; + $cookie = $this->cookie; + preg_match('/_m_h5_tk=([^_]+)/', $cookie, $match); + $token = $match[1]; + $t = time() * 1000; + $sign = md5(sprintf('%s&%s&%s&%s', $token, $t, $appkey, $data)); + $api['body'] = array( + 'appKey' => $appkey, + 't' => $t, + 'dataType' => 'json', + 'data' => $data, + 'api' => $api['body']['r'], + 'v' => '1.0', + 'type' => 'originaljson', + 'sign' => $sign, + ); + + return $api; + } + private function tencent_singlesong($result) { - $result=json_decode($result, 1); - $data=$result['data'][0]; - $t=array( - 'songmid' => $data['mid'], + $result = json_decode($result, true); + $data = $result['data'][0]; + $t = array( + 'songmid' => $data['mid'], 'songname' => $data['name'], 'albummid' => $data['album']['mid'], ); - foreach ($t as $key=>$vo) { - $result['data'][0][$key]=$vo; + foreach ($t as $key => $vo) { + $result['data'][0][$key] = $vo; } + return json_encode($result); } - private function netease_pickey($id) + + private function netease_encryptId($id) { - $magic=str_split('3go8&$8*3*3h0k(2)2'); - $song_id=str_split($id); - for ($i=0;$i $data['data'][0]['url'], - 'br' => $data['data'][0]['br']/1000, + $url = array( + 'url' => $data['data'][0]['url'], + 'size' => $data['data'][0]['size'], + 'br' => $data['data'][0]['br'] / 1000, ); } else { - $url=array( - 'url' => '', - 'br' => -1, + $url = array( + 'url' => '', + 'size' => 0, + 'br' => -1, ); } + return json_encode($url); } + private function tencent_url($result) { - $data=json_decode($result, 1); - $GUID=mt_rand()%10000000000; - $API=array( + $data = json_decode($result, true); + $guid = mt_rand() % 10000000000; + $api = array( 'method' => 'GET', 'url' => 'https://c.y.qq.com/base/fcgi-bin/fcg_musicexpress.fcg', 'body' => array( 'json' => 3, - 'guid' => $GUID, + 'guid' => $guid, 'format' => 'json', ), ); - $KEY=json_decode($this->curl($API), 1); - $KEY=$KEY['key']; + $key = json_decode($this->exec($api), true); + $key = $key['key']; - $type=array( - 'size_320mp3' => array(320,'M800','mp3'), - 'size_192aac' => array(192,'C600','m4a'), - 'size_128mp3' => array(128,'M500','mp3'), - 'size_96aac' => array(96 ,'C400','m4a'), - 'size_48aac' => array(48 ,'C200','m4a'), + $type = array( + 'size_320mp3' => array(320, 'M800', 'mp3'), + 'size_192aac' => array(192, 'C600', 'm4a'), + 'size_128mp3' => array(128, 'M500', 'mp3'), + 'size_96aac' => array(96, 'C400', 'm4a'), + 'size_48aac' => array(48, 'C200', 'm4a'), + 'size_24aac' => array(24, 'C100', 'm4a'), ); - foreach ($type as $key=>$vo) { - if ($data['data'][0]['file'][$key]&&$vo[0]<=$this->_TEMP['br']) { - $url=array( - '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', - 'br' => $vo[0], + foreach ($type as $index => $vo) { + if ($data['data'][0]['file'][$index] && $vo[0] <= $this->temp['br']) { + $url = array( + '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', + 'size' => $data['data'][0]['file'][$index], + 'br' => $vo[0], ); break; } } if (!isset($url['url'])) { - $url=array( - 'url' => '', - 'br' => -1, + $url = array( + 'url' => '', + 'size' => 0, + 'br' => -1, ); } + return json_encode($url); } + private function xiami_url($result) { - $data=json_decode($result, 1); - if (!empty($data['location'])) { - $location = $data['location']; - $num = (int)$location[0]; - $str = substr($location, 1); - $len = floor(strlen($str)/$num); - $sub = strlen($str) % $num; - $qrc = array(); - $tmp = 0; - $urlt = ''; - for (;$tmp<$sub;$tmp++) { - $qrc[$tmp] = substr($str, $tmp*($len+1), $len+1); + $data = json_decode($result, true); + + $type = array( + 's' => 740, + 'h' => 320, + 'l' => 128, + 'f' => 64, + 'e' => 32, + ); + $max = 0; + $url = array(); + foreach ($data['data']['data']['songDetail']['listenFiles'] as $vo) { + if ($type[$vo['quality']] <= $this->temp['br'] && $type[$vo['quality']] > $max) { + $max = $type[$vo['quality']]; + $url = array( + 'url' => $vo['url'], + 'size' => $vo['filesize'], + 'br' => $type[$vo['quality']], + ); } - for (;$tmp<$num;$tmp++) { - $qrc[$tmp] = substr($str, $len*$tmp+$sub, $len); - } - for ($tmpa=0;$tmpa<$len+1;$tmpa++) { - for ($tmpb=0;$tmpb<$num;$tmpb++) { - if (isset($qrc[$tmpb][$tmpa])) { - $urlt.=$qrc[$tmpb][$tmpa]; - } - } - } - $urlt=str_replace('^', '0', urldecode($urlt)); - $url=array( - 'url' => str_replace('http://','https://',urldecode($urlt)), - 'br' => 320, - ); - } else { - $url=array( - 'url' => '', - 'br' => -1, + } + if (!isset($url['url'])) { + $url = array( + 'url' => '', + 'size' => 0, + 'br' => -1, ); } + return json_encode($url); } + private function kugou_url($result) { - $data=json_decode($result, 1); + $data = json_decode($result, true); - $max=0; - $url=array(); + $max = 0; + $url = array(); foreach ($data['data'][0]['relate_goods'] as $vo) { - if ($vo['info']['bitrate']<=$this->_TEMP['br']&&$vo['info']['bitrate']>$max) { - $API=array( + if ($vo['info']['bitrate'] <= $this->temp['br'] && $vo['info']['bitrate'] > $max) { + $api = array( 'method' => 'GET', 'url' => 'http://trackercdn.kugou.com/i/v2/', 'body' => array( @@ -942,202 +1076,228 @@ class Meting 'version' => 8400, ), ); - $t=json_decode($this->curl($API), 1); + $t = json_decode($this->exec($api), true); if (isset($t['url'])) { - $max=$t['bitRate']/1000; - $url=array( - 'url' => $t['url'], - 'br' => $t['bitRate']/1000, + $max = $t['bitRate'] / 1000; + $url = array( + 'url' => $t['url'], + 'size' => $t['fileSize'], + 'br' => $t['bitRate'] / 1000, ); } } } if (!isset($url['url'])) { - $url=array( - 'url' => '', - 'br' => -1, + $url = array( + 'url' => '', + 'size' => 0, + 'br' => -1, ); } + return json_encode($url); } + private function baidu_url($result) { - $data=json_decode($result, 1); - if (isset($data['data']['songList'][0]['songLink'])) { - $url=array( - 'url' => $data['data']['songList'][0]['songLink'], - 'br' => $data['data']['songList'][0]['rate'], - ); - $url['url']=str_replace('http://yinyueshiting.baidu.com', 'https://gss0.bdstatic.com/y0s1hSulBw92lNKgpU_Z2jR7b2w6buu', $url['url']); - } else { - $url=array( + $data = json_decode($result, true); + + $max = 0; + $url = array(); + foreach ($data['songurl']['url'] as $vo) { + if ($vo['file_bitrate'] <= $this->temp['br'] && $vo['file_bitrate'] > $max) { + $url = array( + 'url' => $vo['file_link'], + 'br' => $vo['file_bitrate'], + ); + } + } + if (!isset($url['url'])) { + $url = array( 'url' => '', 'br' => -1, ); } + return json_encode($url); } - /** - * 歌词处理模块 - * 用于规范化歌词输出 - */ + private function netease_lyric($result) { - if (!$this->_FORMAT) { - return $result; - } - $result=json_decode($result, 1); - $data=array( - 'lyric' => isset($result['lrc']['lyric'])?$result['lrc']['lyric']:'', - 'tlyric' => isset($result['tlyric']['lyric'])?$result['tlyric']['lyric']:'', + $result = json_decode($result, true); + $data = array( + 'lyric' => isset($result['lrc']['lyric']) ? $result['lrc']['lyric'] : '', + 'tlyric' => isset($result['tlyric']['lyric']) ? $result['tlyric']['lyric'] : '', ); + return json_encode($data); } + private function tencent_lyric($result) { - $result=substr($result,18,-1); - if (!$this->_FORMAT) { - return $result; - } - $result=json_decode($result, 1); - $data=array( - 'lyric' => isset($result['lyric'])?base64_decode($result['lyric']):'', - 'tlyric' => isset($result['trans'])?base64_decode($result['trans']):'', - ); + $result = substr($result, 18, -1); + $result = json_decode($result, true); + $data = array( + 'lyric' => isset($result['lyric']) ? base64_decode($result['lyric']) : '', + 'tlyric' => isset($result['trans']) ? base64_decode($result['trans']) : '', + ); + return json_encode($data); } + private function xiami_lyric($result) { - if (!$this->_FORMAT) { - return $result; - } - $result=json_decode($result, 1); - $data=''; - if(!empty($result['data']['song']['lyric'])){ - $API=array('method'=>'GET','url'=>$result['data']['song']['lyric']); - $data=$this->curl($API); - $data=preg_replace('/<[^>]+>/', '', $data); - } - preg_match_all('/\[([\d:\.]+)\](.*)\s\[x-trans\](.*)/i',$data,$match); - if(sizeof($match[0])){ - for($i=0;$i]+>/', '', $data); + preg_match_all('/\[([\d:\.]+)\](.*)\s\[x-trans\](.*)/i', $data, $match); + if (count($match[0])) { + for ($i = 0; $i < count($match[0]); $i++) { + $A[] = '['.$match[1][$i].']'.$match[2][$i]; + $B[] = '['.$match[1][$i].']'.$match[3][$i]; + } + $arr = array( + 'lyric' => str_replace($match[0], $A, $data), + 'tlyric' => str_replace($match[0], $B, $data), + ); + } else { + $arr = array( + 'lyric' => $data, + 'tlyric' => '', + ); } - $arr=array( - 'lyric' => str_replace($match[0],$A,$data), - 'tlyric' => str_replace($match[0],$B,$data), - ); - } - else{ - $arr=array( - 'lyric' => $data, + } else { + $arr = array( + 'lyric' => '', 'tlyric' => '', ); } + return json_encode($arr); } + private function kugou_lyric($result) { - if (!$this->_FORMAT) { - return $result; - } - $arr=array( - 'lyric' => $result, + $result = json_decode($result, true); + $api = array( + 'method' => 'GET', + 'url' => 'http://lyrics.kugou.com/download', + 'body' => array( + 'charset' => 'utf8', + 'accesskey' => $result['candidates'][0]['accesskey'], + 'id' => $result['candidates'][0]['id'], + 'client' => 'pc', + 'fmt' => 'lrc', + 'ver' => 1, + ), + ); + $data = json_decode($this->exec($api), true); + $arr = array( + 'lyric' => base64_decode($data['content']), 'tlyric' => '', ); + return json_encode($arr); } + private function baidu_lyric($result) { - if (!$this->_FORMAT) { - return $result; - } - $result=json_decode($result, 1); - $data=array( - 'lyric' => isset($result['lrcContent'])?$result['lrcContent']:'', + $result = json_decode($result, true); + $data = array( + 'lyric' => isset($result['lrcContent']) ? $result['lrcContent'] : '', 'tlyric' => '', ); + return json_encode($data); } - /** - * Format - 规范化函数 - * 用于统一返回的参数,可用 ->format() 一次性开关开启 - */ + private function format_netease($data) { - $result=array( - 'id' => $data['id'], - 'name' => $data['name'], - 'artist' => array(), - 'album' => $data['al']['name'], - 'pic_id' => isset($data['al']['pic_str'])?$data['al']['pic_str']:$data['al']['pic'], - 'url_id' => $data['id'], - 'lyric_id' => $data['id'], - 'source' => 'netease', + $result = array( + 'id' => $data['id'], + 'name' => $data['name'], + 'artist' => array(), + 'album' => $data['al']['name'], + 'pic_id' => isset($data['al']['pic_str']) ? $data['al']['pic_str'] : $data['al']['pic'], + 'url_id' => $data['id'], + 'lyric_id' => $data['id'], + 'source' => 'netease', ); if (isset($data['al']['picUrl'])) { preg_match('/\/(\d+)\./', $data['al']['picUrl'], $match); - $result['pic_id']=$match[1]; + $result['pic_id'] = $match[1]; } foreach ($data['ar'] as $vo) { - $result['artist'][]=$vo['name']; + $result['artist'][] = $vo['name']; } + return $result; } + private function format_tencent($data) { if (isset($data['musicData'])) { - $data=$data['musicData']; + $data = $data['musicData']; } - $result=array( - 'id' => $data['mid'], - 'name' => $data['name'], - 'artist' => array(), - 'album' => trim($data['album']['title']), - 'pic_id' => $data['album']['mid'], - 'url_id' => $data['mid'], - 'lyric_id' => $data['mid'], - 'source' => 'tencent', + $result = array( + 'id' => $data['mid'], + 'name' => $data['name'], + 'artist' => array(), + '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) { - $result['artist'][]=$vo['name']; + $result['artist'][] = $vo['name']; } + return $result; } + private function format_xiami($data) { - $result=array( - 'id' => $data['song_id'], - 'name' => $data['song_name'], - 'artist' => explode(';', isset($data['singers'])?$data['singers']:$data['artist_name']), - 'album' => $data['album_name'], - 'pic_id' => $data['song_id'], - 'url_id' => $data['song_id'], - 'lyric_id' => $data['song_id'], + $result = array( + 'id' => $data['songId'], + 'name' => $data['songName'], + 'artist' => array(), + 'album' => $data['albumName'], + 'pic_id' => $data['songId'], + 'url_id' => $data['songId'], + 'lyric_id' => $data['songId'], 'source' => 'xiami', ); + foreach ($data['singerVOs'] as $vo) { + $result['artist'][] = $vo['artistName']; + } + return $result; } + private function format_kugou($data) { - $result=array( + $result = array( 'id' => $data['hash'], - 'name' => isset($data['filename'])?$data['filename']:$data['fileName'], + 'name' => isset($data['filename']) ? $data['filename'] : $data['fileName'], 'artist' => array(), - 'album' => isset($data['album_name'])?$data['album_name']:'', + 'album' => isset($data['album_name']) ? $data['album_name'] : '', 'url_id' => $data['hash'], 'pic_id' => $data['hash'], 'lyric_id' => $data['hash'], 'source' => 'kugou', ); - list($result['artist'], $result['name'])=explode(' - ', $result['name'], 2); - $result['artist']=explode('、', $result['artist']); + list($result['artist'], $result['name']) = explode(' - ', $result['name'], 2); + $result['artist'] = explode('、', $result['artist']); + return $result; } + private function format_baidu($data) { - $result=array( + $result = array( 'id' => $data['song_id'], 'name' => $data['title'], 'artist' => explode(',', $data['author']), @@ -1147,6 +1307,7 @@ class Meting 'lyric_id' => $data['song_id'], 'source' => 'baidu', ); + return $result; } } diff --git a/shasum.txt b/shasum.txt new file mode 100644 index 0000000..ee43cc5 --- /dev/null +++ b/shasum.txt @@ -0,0 +1,12 @@ +87a137ef2b47308dc5815e173041b7f3afa02981d3ee1f6cd8fc5d3c1af7c71c ./Action.php +aa3c0deef2f5b5524f9e7cbd1809d14d51e0a5eae8f21e183483c84c28b86e46 ./assets/APlayer.min.js +6c1db3ae0b983df3e9395aa133875e64c7cb6321064c982d507fa7d82f7258f3 ./assets/editer.js +05394bccf0b72f8a57bdefc2dc7da1da38d6ebcf39b97185a89c359f9827a556 ./assets/Meting.min.js +c43462daad99f50a03ac36ab1f53249a0128548b0d13bacecda81812fd695c56 ./driver/cache.interface.php +cd8087c1c5b99d5343f07b5e78279bddeca35b8d3039c8946437271120695b5f ./driver/mysql.class.php +5bc1ce7e8b6629bd713c0c9287ac6eb3e91aae2a8f989c83028376da74876305 ./driver/redis.class.php +1b2791f8ced874d65b89d5014756cd23ddaca347965ef6c739ae40e2a7ba6b16 ./driver/sqlite.class.php +9439991d1f138e073c3cfeeca921539c0dc53d068ca4ec0c02e377c8397359da ./include/Meting.php +a237e65d8cc7c5b00008db5977b28e525caeffadfee0808408034f8959c6de20 ./LICENSE +ce6446965969e32bd3a98107e878fcef14acba6de697ae8782c3f0c3435bb448 ./Plugin.php +b854090ea5398d0b448ec23c06e5dee12d807610a9046a4eabfd31d15c9e38c5 ./README.md