mirror of
https://github.com/MoePlayer/APlayer-Typecho.git
synced 2025-02-19 20:50:23 +08:00
🔥 2.0.0, 架构重写,支持自定义歌曲
- 重写前端逻辑 - 支持自定义 API - 支持自定义歌曲 - 去除 jQuery 依赖 - 升级 Meting 库
This commit is contained in:
parent
9ca611c898
commit
f1200960a5
351
Action.php
351
Action.php
@ -6,66 +6,154 @@ class Meting_Action extends Typecho_Widget implements Widget_Interface_Do {
|
||||
public function execute(){}
|
||||
|
||||
public function action(){
|
||||
$this->on($this->request->is('do=musicjs'))->musicjs();
|
||||
$this->on($this->request->is('do=url'))->url();
|
||||
$this->on($this->request->is('do=pic'))->pic();
|
||||
$this->on($this->request->is('do=lrc'))->lrc();
|
||||
$this->on($this->request->is('do=parse'))->shortcode();
|
||||
$this->on($this->request->isGet())->api();
|
||||
}
|
||||
|
||||
private function check($a,$b){
|
||||
if(!in_array($a,array('netease','tencent','baidu','xiami','kugou')))return false;
|
||||
if(!in_array($b,array('song','album','search','artist','playlist','lrc','url','pic')))return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private function api(){
|
||||
$this->filterReferer();
|
||||
$server=$this->request->get('server');
|
||||
$type=$this->request->get('type');
|
||||
$id=$this->request->get('id');
|
||||
|
||||
if(!$this->check($server,$type)||empty($id))die('[]');
|
||||
|
||||
if(!extension_loaded('Meting'))include_once 'include/Meting.php';
|
||||
$api=new \Metowolf\Meting($server);
|
||||
$api->format(true);
|
||||
|
||||
$EID=md5($server.'/'.$type.'/'.$id);
|
||||
$salt=Typecho_Widget::widget('Widget_Options')->plugin('Meting')->salt;
|
||||
|
||||
if(in_array($type,array('lrc','pic','url'))){
|
||||
$auth1=md5($salt.$id.$salt);
|
||||
$auth2=$this->request->get('auth');
|
||||
if(strcmp($auth1,$auth2)){
|
||||
http_response_code(403);
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
if($type=='lrc'){
|
||||
$data=$this->cacheRead($EID,60*60*24);
|
||||
if(empty($data)){
|
||||
$data=$api->lyric($id);
|
||||
$this->cacheWrite($EID,$data);
|
||||
}
|
||||
$data=json_decode($data,true);
|
||||
header("Content-Type: application/javascript");
|
||||
echo $data['lyric'];
|
||||
}
|
||||
elseif($type=='pic'){
|
||||
$data=$this->cacheRead($EID,60*60*24);
|
||||
if(empty($data)){
|
||||
$data=$api->pic($id,90);
|
||||
$this->cacheWrite($EID,$data);
|
||||
}
|
||||
$data=json_decode($data,true);
|
||||
$this->response->redirect($data['url']);
|
||||
}
|
||||
elseif($type=='url'){
|
||||
$data=$this->cacheRead($EID,60*15);
|
||||
if(empty($data)){
|
||||
$rate=Typecho_Widget::widget('Widget_Options')->plugin('Meting')->bitrate;
|
||||
$cookie=Typecho_Widget::widget('Widget_Options')->plugin('Meting')->cookie;
|
||||
if($server=='netease')$api->cookie($cookie);
|
||||
$data=$api->url($id,$rate);
|
||||
$this->cacheWrite($EID,$data);
|
||||
}
|
||||
$data=json_decode($data,true);
|
||||
$url=$data['url'];
|
||||
|
||||
$url=str_replace('http://m8','https://m8',$url);
|
||||
$url=str_replace('http://m7','https://m8',$url);
|
||||
$url=str_replace('http://m10','https://m10',$url);
|
||||
|
||||
if(empty($url))$url='https://api.i-meto.com/Public/music/empty.mp3';
|
||||
$this->response->redirect($url);
|
||||
}
|
||||
else{
|
||||
$data=$this->cacheRead($EID,60*60*2);
|
||||
if(empty($data)){
|
||||
$data=$api->$type($id);
|
||||
$this->cacheWrite($EID,$data);
|
||||
}
|
||||
$data=json_decode($data,1);
|
||||
$url=Typecho_Common::url('action/metingapi',Helper::options()->index);
|
||||
|
||||
$music=array();
|
||||
foreach($data as $vo){
|
||||
$music[]=array(
|
||||
'title' => $vo['name'],
|
||||
'author' => implode(' / ',$vo['artist']),
|
||||
'url' => $url.'?server='.$vo['source'].'&type=url&id='.$vo['url_id'].'&auth='.md5($salt.$vo['url_id'].$salt),
|
||||
'pic' => $url.'?server='.$vo['source'].'&type=pic&id='.$vo['pic_id'].'&auth='.md5($salt.$vo['pic_id'].$salt),
|
||||
'lrc' => $url.'?server='.$vo['source'].'&type=lrc&id='.$vo['lyric_id'].'&auth='.md5($salt.$vo['lyric_id'].$salt),
|
||||
);
|
||||
}
|
||||
header("Content-Type: application/javascript");
|
||||
echo json_encode($music);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function shortcode(){
|
||||
$urls=$this->request->get('data');
|
||||
$urls=explode("\n",$urls);
|
||||
echo "[Meting]\n";
|
||||
foreach($urls as $url){
|
||||
$url=trim($url);
|
||||
if($url=="")continue;
|
||||
$server='音乐平台';$id='编号';$type='类型';
|
||||
if(strpos($url,'163.com')!==false){
|
||||
$server='netease';
|
||||
if(preg_match('/playlist\?id=(\d+)/i',$url,$id))list($id,$type)=array($id[1],'playlist');
|
||||
elseif(preg_match('/toplist\?id=(\d+)/i',$url,$id))list($id,$type)=array($id[1],'playlist');
|
||||
elseif(preg_match('/album\?id=(\d+)/i',$url,$id))list($id,$type)=array($id[1],'album');
|
||||
elseif(preg_match('/song\?id=(\d+)/i',$url,$id))list($id,$type)=array($id[1],'song');
|
||||
elseif(preg_match('/artist\?id=(\d+)/i',$url,$id))list($id,$type)=array($id[1],'artist');
|
||||
}
|
||||
elseif(strpos($url,'qq.com')!==false){
|
||||
$server='tencent';
|
||||
if(preg_match('/playlist\/([^\.]*)/i',$url,$id))list($id,$type)=array($id[1],'playlist');
|
||||
elseif(preg_match('/album\/([^\.]*)/i',$url,$id))list($id,$type)=array($id[1],'album');
|
||||
elseif(preg_match('/song\/([^\.]*)/i',$url,$id))list($id,$type)=array($id[1],'song');
|
||||
elseif(preg_match('/singer\/([^\.]*)/i',$url,$id))list($id,$type)=array($id[1],'artist');
|
||||
}
|
||||
elseif(strpos($url,'xiami.com')!==false){
|
||||
$server='xiami';
|
||||
if(preg_match('/collect\/(\w+)/i',$url,$id))list($id,$type)=array($id[1],'playlist');
|
||||
elseif(preg_match('/album\/(\w+)/i',$url,$id))list($id,$type)=array($id[1],'album');
|
||||
elseif(preg_match('/[\/.]\w+\/[songdem]+\/(\w+)/i',$url,$id))list($id,$type)=array($id[1],'song');
|
||||
elseif(preg_match('/artist\/(\w+)/i',$url,$id))list($id,$type)=array($id[1],'artist');
|
||||
if(!preg_match('/^\d*$/i',$id,$t)){
|
||||
$data=self::curl($url);
|
||||
preg_match('/'.$type.'\/(\d+)/i',$data,$id);
|
||||
$id=$id[1];
|
||||
}
|
||||
}
|
||||
elseif(strpos($url,'kugou.com')!==false){
|
||||
$server='kugou';
|
||||
if(preg_match('/special\/single\/(\d+)/i',$url,$id))list($id,$type)=array($id[1],'playlist');
|
||||
elseif(preg_match('/song\/#hash\=(\w+)/i',$url,$id))list($id,$type)=array($id[1],'song');
|
||||
elseif(preg_match('/album\/[single\/]*(\d+)/i',$url,$id))list($id,$type)=array($id[1],'album');
|
||||
elseif(preg_match('/singer\/[home\/]*(\d+)/i',$url,$id))list($id,$type)=array($id[1],'artist');
|
||||
}
|
||||
elseif(strpos($url,'baidu.com')!==false){
|
||||
$server='baidu';
|
||||
if(preg_match('/songlist\/(\d+)/i',$url,$id))list($id,$type)=array($id[1],'playlist');
|
||||
elseif(preg_match('/album\/(\d+)/i',$url,$id))list($id,$type)=array($id[1],'album');
|
||||
elseif(preg_match('/song\/(\d+)/i',$url,$id))list($id,$type)=array($id[1],'song');
|
||||
elseif(preg_match('/artist\/(\d+)/i',$url,$id))list($id,$type)=array($id[1],'artist');
|
||||
}
|
||||
else list($id,$type)=array($url,'search');
|
||||
echo '[Music server="'.$server.'" id="'.$id.'" type="'.$type.'"/]'."\n";
|
||||
$url=$this->request->get('data');
|
||||
$url=trim($url);
|
||||
if(empty($url))return;
|
||||
$server='netease';$id='';$type='';
|
||||
if(strpos($url,'163.com')!==false){
|
||||
$server='netease';
|
||||
if(preg_match('/playlist\?id=(\d+)/i',$url,$id))list($id,$type)=array($id[1],'playlist');
|
||||
elseif(preg_match('/toplist\?id=(\d+)/i',$url,$id))list($id,$type)=array($id[1],'playlist');
|
||||
elseif(preg_match('/album\?id=(\d+)/i',$url,$id))list($id,$type)=array($id[1],'album');
|
||||
elseif(preg_match('/song\?id=(\d+)/i',$url,$id))list($id,$type)=array($id[1],'song');
|
||||
elseif(preg_match('/artist\?id=(\d+)/i',$url,$id))list($id,$type)=array($id[1],'artist');
|
||||
}
|
||||
echo "[/Meting]";
|
||||
elseif(strpos($url,'qq.com')!==false){
|
||||
$server='tencent';
|
||||
if(preg_match('/playlist\/([^\.]*)/i',$url,$id))list($id,$type)=array($id[1],'playlist');
|
||||
elseif(preg_match('/album\/([^\.]*)/i',$url,$id))list($id,$type)=array($id[1],'album');
|
||||
elseif(preg_match('/song\/([^\.]*)/i',$url,$id))list($id,$type)=array($id[1],'song');
|
||||
elseif(preg_match('/singer\/([^\.]*)/i',$url,$id))list($id,$type)=array($id[1],'artist');
|
||||
}
|
||||
elseif(strpos($url,'xiami.com')!==false){
|
||||
$server='xiami';
|
||||
if(preg_match('/collect\/(\w+)/i',$url,$id))list($id,$type)=array($id[1],'playlist');
|
||||
elseif(preg_match('/album\/(\w+)/i',$url,$id))list($id,$type)=array($id[1],'album');
|
||||
elseif(preg_match('/[\/.]\w+\/[songdem]+\/(\w+)/i',$url,$id))list($id,$type)=array($id[1],'song');
|
||||
elseif(preg_match('/artist\/(\w+)/i',$url,$id))list($id,$type)=array($id[1],'artist');
|
||||
if(!preg_match('/^\d*$/i',$id,$t)){
|
||||
$data=self::curl($url);
|
||||
preg_match('/'.$type.'\/(\d+)/i',$data,$id);
|
||||
$id=$id[1];
|
||||
}
|
||||
}
|
||||
elseif(strpos($url,'kugou.com')!==false){
|
||||
$server='kugou';
|
||||
if(preg_match('/special\/single\/(\d+)/i',$url,$id))list($id,$type)=array($id[1],'playlist');
|
||||
elseif(preg_match('/song\/#hash\=(\w+)/i',$url,$id))list($id,$type)=array($id[1],'song');
|
||||
elseif(preg_match('/album\/[single\/]*(\d+)/i',$url,$id))list($id,$type)=array($id[1],'album');
|
||||
elseif(preg_match('/singer\/[home\/]*(\d+)/i',$url,$id))list($id,$type)=array($id[1],'artist');
|
||||
}
|
||||
elseif(strpos($url,'baidu.com')!==false){
|
||||
$server='baidu';
|
||||
if(preg_match('/songlist\/(\d+)/i',$url,$id))list($id,$type)=array($id[1],'playlist');
|
||||
elseif(preg_match('/album\/(\d+)/i',$url,$id))list($id,$type)=array($id[1],'album');
|
||||
elseif(preg_match('/song\/(\d+)/i',$url,$id))list($id,$type)=array($id[1],'song');
|
||||
elseif(preg_match('/artist\/(\d+)/i',$url,$id))list($id,$type)=array($id[1],'artist');
|
||||
}
|
||||
else{
|
||||
echo "[Meting]\n[Music title=\"歌曲名\" author=\"歌手\" url=\"{$url}\"/]\n[/Meting]\n";
|
||||
return;
|
||||
}
|
||||
echo "[Meting]\n[Music server=\"{$server}\" id=\"{$id}\" type=\"{$type}\"/]\n[/Meting]\n";
|
||||
}
|
||||
|
||||
private function curl($url){
|
||||
@ -80,143 +168,10 @@ class Meting_Action extends Typecho_Widget implements Widget_Interface_Do {
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function musicjs(){
|
||||
if(!extension_loaded('Meting'))include_once 'include/Meting.php';
|
||||
self::filterReferer();
|
||||
$PID=$this->request->get('id');
|
||||
$data=$this->request->get('d');
|
||||
$data=json_decode(base64_decode($data),1);
|
||||
$setting=$this->request->get('s');
|
||||
$setting=json_decode(base64_decode($setting),1);
|
||||
$music=array();
|
||||
foreach($data as $vo){
|
||||
$EID=md5('js/'.$vo['server'].'/'.$vo['type'].'/'.$vo['id']);
|
||||
$t=self::cacheRead($EID,60*60*24*3);
|
||||
if(!$t){
|
||||
$API=(new \Metowolf\Meting($vo['server']))->format(true);
|
||||
$t=call_user_func_array(array($API,$vo['type']),array($vo['id']));
|
||||
$t=json_decode($t,1);
|
||||
self::cacheWrite($EID,$t);
|
||||
}
|
||||
$music=array_merge($music,$t);
|
||||
}
|
||||
$player=array(
|
||||
'theme' => isset($setting['theme'])?$setting['theme']:Typecho_Widget::widget('Widget_Options')->plugin('Meting')->theme?:'red',
|
||||
'preload' => isset($setting['preload'])?$setting['preload']:Typecho_Widget::widget('Widget_Options')->plugin('Meting')->preload?:'auto',
|
||||
'autoplay' => isset($setting['autoplay'])?$setting['autoplay']:Typecho_Widget::widget('Widget_Options')->plugin('Meting')->autoplay?:'false',
|
||||
'height' => isset($setting['height'])?$setting['height']:Typecho_Widget::widget('Widget_Options')->plugin('Meting')->height?:'340px',
|
||||
'mode' => isset($setting['mode'])?$setting['mode']:Typecho_Widget::widget('Widget_Options')->plugin('Meting')->mode?:'circulation',
|
||||
'music' => array(),
|
||||
);
|
||||
foreach($music as $vo){
|
||||
$URI=Typecho_Common::url('action/metingapi',Helper::options()->index);
|
||||
$player['music'][]=array(
|
||||
'title'=>$vo['name'],
|
||||
'author'=>implode(' / ',$vo['artist']),
|
||||
'url'=>$URI.'?site='.$vo['source'].'&do=url&id='.$vo['url_id'],
|
||||
'pic'=>$URI.'?site='.$vo['source'].'&do=pic&id='.$vo['pic_id'],
|
||||
'lrc'=>$URI.'?site='.$vo['source'].'&do=lrc&id='.$vo['lyric_id'],
|
||||
);
|
||||
}
|
||||
if(sizeof($player['music'])==1)$player['music']=$player['music'][0];
|
||||
$player['music']=json_encode($player['music']);
|
||||
|
||||
header('content-type:application/javascript');
|
||||
echo "
|
||||
var Meting{$PID} = new APlayer({
|
||||
element: document.getElementById('MetingPlayer'+{$PID}),
|
||||
autoplay: ".$player['autoplay'].",
|
||||
preload: \"".$player['preload']."\",
|
||||
showlrc: 3,
|
||||
mutex: true,
|
||||
mode: '".$player['mode']."',
|
||||
theme: \"".$player['theme']."\",
|
||||
music: ".$player['music'].",
|
||||
listmaxheight: '".$player['height']."',
|
||||
});
|
||||
";
|
||||
}
|
||||
|
||||
private function url(){
|
||||
if(!extension_loaded('Meting'))include_once 'include/Meting.php';
|
||||
self::filterReferer();
|
||||
$id=$this->request->get('id');
|
||||
$site=$this->request->get('site');
|
||||
$rate=Typecho_Widget::widget('Widget_Options')->plugin('Meting')->bitrate;
|
||||
$cookie=Typecho_Widget::widget('Widget_Options')->plugin('Meting')->cookie;
|
||||
|
||||
$cachekey="url/{$site}/{$id}/{$rate}";
|
||||
$data=self::cacheRead($cachekey,60*15);
|
||||
if(!$data){
|
||||
$api=(new \Metowolf\Meting($site));
|
||||
if($cookie!='')$api->cookie($cookie);
|
||||
$data=$api->format(true)->url($id,$rate);
|
||||
$data=json_decode($data,1);
|
||||
self::cacheWrite($cachekey,$data);
|
||||
}
|
||||
if(empty($data['url']))$data['url']="https://api.i-meto.com/Public/music/empty.mp3";
|
||||
if($site=='netease'){
|
||||
$data['url']=str_replace("http://","https://",$data['url']);
|
||||
}
|
||||
$this->response->redirect($data['url']);
|
||||
}
|
||||
|
||||
private function pic(){
|
||||
if(!extension_loaded('Meting'))include_once 'include/Meting.php';
|
||||
self::filterReferer();
|
||||
$id=$this->request->get('id');
|
||||
$site=$this->request->get('site');
|
||||
|
||||
$cachekey="pic/{$site}/{$id}";
|
||||
$data=self::cacheRead($cachekey,60*60*24*30);
|
||||
if(!$data){
|
||||
$data=(new \Metowolf\Meting($site))->pic($id,90);
|
||||
$data=json_decode($data,1);
|
||||
self::cacheWrite($cachekey,$data);
|
||||
}
|
||||
$this->response->redirect($data['url']);
|
||||
}
|
||||
|
||||
private function lrc(){
|
||||
if(!extension_loaded('Meting'))include_once 'include/Meting.php';
|
||||
self::filterReferer();
|
||||
$id=$this->request->get('id');
|
||||
$site=$this->request->get('site');
|
||||
|
||||
$cachekey="lyric/{$site}/{$id}";
|
||||
$data=self::cacheRead($cachekey,60*60*24*10);
|
||||
if(!$data){
|
||||
$data=(new \Metowolf\Meting($site))->format(true)->lyric($id);
|
||||
$data=json_decode($data,1);
|
||||
self::cacheWrite($cachekey,$data);
|
||||
}
|
||||
if(!empty($data['tlyric']))$text=$this->lrctran($data['lyric'],$data['tlyric']);
|
||||
else $text=$data['lyric'];
|
||||
if(strlen($text)==0)$text='[00:00.00]无歌词';
|
||||
echo $text;
|
||||
}
|
||||
|
||||
private function lrctran($lyric,$tlyric){
|
||||
preg_match_all('/\[(\d{2}:\d{2}\.\d+)\]([^\n]+)/i',$lyric,$t1);
|
||||
preg_match_all('/\[(\d{2}:\d{2}\.\d+)\]([^\n]+)/i',$tlyric,$t2);
|
||||
$from=$to=$t1[0];
|
||||
$len1=sizeof($t1[0]);
|
||||
$len2=sizeof($t2[0]);
|
||||
for($i=0,$j=0;$i<$len1;$i++){
|
||||
while($t1[1][$i]>$t2[1][$j]&&$j+1<$len2)$j++;
|
||||
if($t1[1][$i]==$t2[1][$j]){
|
||||
$t=trim(str_replace('/','',$t2[2][$j]));
|
||||
if($t)$to[$i].=" (".$t2[2][$j].")";
|
||||
$j++;
|
||||
}
|
||||
}
|
||||
return str_replace($from,$to,$lyric);
|
||||
}
|
||||
|
||||
private function cacheWrite($k,$v){
|
||||
if(!is_array($v)||is_null($v))return;
|
||||
if(empty($v)||is_null($v))return;
|
||||
$db=Typecho_Db::get();
|
||||
$insert=$db->insert('table.metingv1')->rows(array('id'=>md5($k),'value'=>serialize($v),'last'=>time()));
|
||||
$insert=$db->insert('table.metingv1')->rows(array('id'=>md5($k),'value'=>$v,'last'=>time()));
|
||||
return $db->query($insert);
|
||||
}
|
||||
|
||||
@ -231,21 +186,19 @@ class Meting_Action extends Typecho_Widget implements Widget_Interface_Do {
|
||||
$db->query($delete);
|
||||
return false;
|
||||
}
|
||||
return unserialize($result['value']);
|
||||
header("Meting-Cache: HIT");
|
||||
return $result['value'];
|
||||
}
|
||||
else{
|
||||
header("Meting-Cache: MISS");
|
||||
return false;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
/*private function cacheFlush(){
|
||||
$db=Typecho_Db::get();
|
||||
$delete=$db->delete('table.metingv1')->where('last<?',time());
|
||||
$db->query($delete);
|
||||
}*/
|
||||
|
||||
private function filterReferer(){
|
||||
if(isset($_SERVER['HTTP_REFERER'])&&strpos($_SERVER['HTTP_REFERER'],$_SERVER['HTTP_HOST'])===false){
|
||||
http_response_code(403);
|
||||
die();
|
||||
die('[]');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
135
Plugin.php
135
Plugin.php
@ -2,21 +2,20 @@
|
||||
if(!defined('__TYPECHO_ROOT_DIR__'))exit;
|
||||
|
||||
/**
|
||||
* Meting for Typecho | 在 Typecho 中使用 APlayer 播放在线音乐吧~
|
||||
* APlayer for Typecho | 在 Typecho 中使用 APlayer 播放在线音乐吧~
|
||||
*
|
||||
* @package Meting
|
||||
* @package APlayer for Typecho | Meting
|
||||
* @author METO
|
||||
* @version 1.2.5
|
||||
* @version 2.0.0
|
||||
* @dependence 14.10.10-*
|
||||
* @link https://github.com/metowolf/Meting-Typecho-Plugin
|
||||
* @link https://github.com/MoePlayer/APlayer-Typecho
|
||||
*
|
||||
*/
|
||||
|
||||
define('METING_VERSION','1.2.5');
|
||||
define('METING_VERSION','2.0.0');
|
||||
|
||||
class Meting_Plugin extends Typecho_Widget implements Typecho_Plugin_Interface
|
||||
{
|
||||
protected static $PID = 0;
|
||||
/**
|
||||
* 激活插件方法,如果激活失败,直接抛出异常
|
||||
*
|
||||
@ -56,11 +55,6 @@ class Meting_Plugin extends Typecho_Widget implements Typecho_Plugin_Interface
|
||||
* @return void
|
||||
*/
|
||||
public static function config(Typecho_Widget_Helper_Form $form){
|
||||
$t = new Typecho_Widget_Helper_Form_Element_Radio(
|
||||
'cloudapi', array('true'=>_t('是'),'false'=>_t('否')),'false',
|
||||
_t('METO 云解析 (beta)'),
|
||||
_t('当插件无法正常工作时,可以勾选开启。<b>歌单混播、音质调节将失效</b>'));
|
||||
$form->addInput($t);
|
||||
$t = new Typecho_Widget_Helper_Form_Element_Text(
|
||||
'theme', null, '#ad7a86',
|
||||
_t('播放器颜色'),
|
||||
@ -92,10 +86,44 @@ class Meting_Plugin extends Typecho_Widget implements Typecho_Plugin_Interface
|
||||
_t(''));
|
||||
$form->addInput($t);
|
||||
$t = new Typecho_Widget_Helper_Form_Element_Text(
|
||||
'cookie', null, '',
|
||||
_t('自定义 Cookie (高级)'),
|
||||
_t('通过更改 Cookie,使其享受与客户端一样的体验'));
|
||||
'api', null, Typecho_Common::url('action/metingapi',Helper::options()->index)."?server=:server&type=:type&id=:id&r=:r",
|
||||
_t('云解析地址'),
|
||||
_t('示例:https://api.i-meto.com/meting/api?server=:server&type=:type&id=:id&r=:r'));
|
||||
$form->addInput($t);
|
||||
$t = new Typecho_Widget_Helper_Form_Element_Text(
|
||||
'salt', null, md5(time()."Meting"),
|
||||
_t('接口保护'),
|
||||
_t('加盐保护 API 接口不被滥用,自动生成无需设置。'));
|
||||
$form->addInput($t);
|
||||
$t = new Typecho_Widget_Helper_Form_Element_Textarea(
|
||||
'cookie', null, '',
|
||||
_t('网易云音乐 Cookie (高级)'),
|
||||
_t('如果您是网易云音乐的会员,可以将您的 cookie 填入此处来获取云盘等付费资源,听歌将不会计入下载次数。<br><b>如果不知道这是什么意思,忽略即可。</b>'));
|
||||
$form->addInput($t);
|
||||
$t = new Typecho_Widget_Helper_Form_Element_Radio(
|
||||
'clean', array(_t('关闭'), _t('清除所有缓存')), 0,
|
||||
_t('保存时清除所有缓存'));
|
||||
$form->addInput($t);
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动保存配置句柄
|
||||
* @param $config array 插件配置
|
||||
* @param $is_init bool 是否初始化
|
||||
*/
|
||||
public static function configHandle($config, $is_init)
|
||||
{
|
||||
if($is_init!=true){
|
||||
if($config['api']==""){
|
||||
$config['api']=Typecho_Common::url('action/metingapi',Helper::options()->index)."?server=:server&type=:type&id=:id&r=:r";
|
||||
}
|
||||
if($config['clean']==1){
|
||||
self::clean();
|
||||
$config['clean']=0;
|
||||
}
|
||||
}
|
||||
|
||||
Helper::configPlugin('Meting', $config);
|
||||
}
|
||||
|
||||
public static function personalConfig(Typecho_Widget_Helper_Form $form){}
|
||||
@ -108,22 +136,17 @@ class Meting_Plugin extends Typecho_Widget implements Typecho_Plugin_Interface
|
||||
* @return void
|
||||
*/
|
||||
public static function header(){
|
||||
$dir=Helper::options()->pluginUrl.'/Meting/assets/';
|
||||
$api=Typecho_Widget::widget('Widget_Options')->plugin('Meting')->api;
|
||||
$dir=Helper::options()->pluginUrl.'/Meting/assets';
|
||||
$ver=METING_VERSION;
|
||||
echo "<!-- Meting Start -->\n";
|
||||
echo "<script type=\"text/javascript\" src=\"{$dir}APlayer.min.js?v={$ver}\"></script>\n";
|
||||
echo "<!-- Meting End -->\n";
|
||||
echo "<script type=\"text/javascript\" src=\"{$dir}/aplayer.min.js?v={$ver}\"></script>\n";
|
||||
echo "<script>var meting_api=\"{$api}\";</script>";
|
||||
}
|
||||
|
||||
public static function footer(){
|
||||
$dir=Helper::options()->pluginUrl.'/Meting/assets';
|
||||
$ver=METING_VERSION;
|
||||
if(Typecho_Widget::widget('Widget_Options')->plugin('Meting')->cloudapi=='true'){
|
||||
echo "<script type=\"text/javascript\" src=\"https://api.i-meto.com/music/aplayer.min.js?v={$ver}\"></script>\n";
|
||||
}
|
||||
}
|
||||
|
||||
public static function getPID(){
|
||||
return ++self::$PID;
|
||||
echo "<script type=\"text/javascript\" src=\"{$dir}/Meting.min.js?v={$ver}\"></script>\n";
|
||||
}
|
||||
|
||||
public static function playerReplace($data,$widget,$last){
|
||||
@ -146,35 +169,36 @@ class Meting_Plugin extends Typecho_Widget implements Typecho_Plugin_Interface
|
||||
|
||||
public static function parseMusic($matches,$setting){
|
||||
$data=array();
|
||||
$str="";
|
||||
foreach($matches as $vo){
|
||||
$t=self::shortcode_parse_atts(htmlspecialchars_decode($vo));
|
||||
if(!in_array($t['server'],array('netease','tencent','xiami','baidu','kugou')))continue;
|
||||
if(!in_array($t['type'],array('search','album','playlist','artist','song')))continue;
|
||||
$data[]=$t;
|
||||
}
|
||||
$id=self::getPID();
|
||||
$dir=Typecho_Common::url('action/metingapi',Helper::options()->index);
|
||||
if(Typecho_Widget::widget('Widget_Options')->plugin('Meting')->cloudapi=='true'){
|
||||
$str="<div class=\"aplayer\" data-id=\"{$data[0]['id']}\" data-server=\"{$data[0]['server']}\" data-type=\"{$data[0]['type']}\"";
|
||||
$player=array(
|
||||
'theme' => $setting['theme']?:Typecho_Widget::widget('Widget_Options')->plugin('Meting')->theme?:'red',
|
||||
'preload' => $setting['preload']?:Typecho_Widget::widget('Widget_Options')->plugin('Meting')->preload?:'auto',
|
||||
'autoplay' => $setting['autoplay']?:Typecho_Widget::widget('Widget_Options')->plugin('Meting')->autoplay?:'false',
|
||||
'height' => $setting['height']?:Typecho_Widget::widget('Widget_Options')->plugin('Meting')->height?:'340px',
|
||||
'mode' => $setting['mode']?:Typecho_Widget::widget('Widget_Options')->plugin('Meting')->mode?:'circulation',
|
||||
'theme' => Typecho_Widget::widget('Widget_Options')->plugin('Meting')->theme?:'red',
|
||||
'preload' => Typecho_Widget::widget('Widget_Options')->plugin('Meting')->preload?:'auto',
|
||||
'autoplay' => Typecho_Widget::widget('Widget_Options')->plugin('Meting')->autoplay?:'false',
|
||||
'height' => Typecho_Widget::widget('Widget_Options')->plugin('Meting')->height?:'340px',
|
||||
'mode' => Typecho_Widget::widget('Widget_Options')->plugin('Meting')->mode?:'circulation',
|
||||
);
|
||||
foreach($player as $key=>$vo){
|
||||
$str.=" data-{$key}=\"{$vo}\"";
|
||||
if(isset($t['server'])){
|
||||
if(!in_array($t['server'],array('netease','tencent','xiami','baidu','kugou')))continue;
|
||||
if(!in_array($t['type'],array('search','album','playlist','artist','song')))continue;
|
||||
$data=$t;
|
||||
|
||||
$str.="<div class=\"aplayer\" data-id=\"{$data['id']}\" data-server=\"{$data['server']}\" data-type=\"{$data['type']}\"";
|
||||
if(is_array($setting))foreach($setting as $key=>$vo)$player[$key]=$vo;
|
||||
foreach($player as $key=>$vo)$str.=" data-{$key}=\"{$vo}\"";
|
||||
$str.="></div>\n";
|
||||
}
|
||||
else{
|
||||
$data=$t;
|
||||
|
||||
$str.="<div class=\"aplayer\" data-title=\"{$data['title']}\" data-author=\"{$data['author']}\" data-url=\"{$data['url']}\"";
|
||||
if(is_array($setting))foreach($setting as $key=>$vo)$player[$key]=$vo;
|
||||
foreach($player as $key=>$vo)$str.=" data-{$key}=\"{$vo}\"";
|
||||
$str.="></div>\n";
|
||||
}
|
||||
$str.="></div>\n";
|
||||
return $str;
|
||||
}
|
||||
else{
|
||||
$setting=base64_encode(json_encode($setting));
|
||||
$data=base64_encode(json_encode($data));
|
||||
return "<div id=\"MetingPlayer{$id}\" class=\"aplayer\" /></div>
|
||||
<script type=\"text/javascript\" src=\"{$dir}?do=musicjs&s={$setting}&d={$data}&id={$id}\" async defer></script>";
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
public static function addButton(){
|
||||
@ -226,9 +250,9 @@ class Meting_Plugin extends Typecho_Widget implements Typecho_Plugin_Interface
|
||||
$dbname=$db->getPrefix().'metingv1';
|
||||
try{
|
||||
$db->query("CREATE TABLE IF NOT EXISTS {$dbname} (
|
||||
id CHAR(32) PRIMARY KEY NOT NULL UNIQUE,
|
||||
value TEXT NOT NULL,
|
||||
last int NOT NULL
|
||||
id VARCHAR(32) PRIMARY KEY NOT NULL UNIQUE,
|
||||
value TEXT NOT NULL,
|
||||
last int NOT NULL
|
||||
)");
|
||||
}catch(Typecho_Db_Exception $e){
|
||||
$code=$e->getCode();
|
||||
@ -236,11 +260,18 @@ class Meting_Plugin extends Typecho_Widget implements Typecho_Plugin_Interface
|
||||
}
|
||||
}
|
||||
|
||||
private function clean(){
|
||||
$db=Typecho_Db::get();
|
||||
$dbname=$db->getPrefix().'metingv1';
|
||||
$delete=$db->delete($dbname);
|
||||
$db->query($delete);
|
||||
}
|
||||
|
||||
public static function uninstall(){
|
||||
$db=Typecho_Db::get();
|
||||
$dbname=$db->getPrefix().'metingv1';
|
||||
try{
|
||||
$db->query("DROP TABLE IF EXISTS {$dbname};");
|
||||
$db->query("DROP TABLE IF EXISTS {$dbname}");
|
||||
}catch(Typecho_Db_Exception $e){
|
||||
$code=$e->getCode();
|
||||
throw new Typecho_Plugin_Exception('插件禁用失败。错误号:'.$code);
|
||||
|
14
README.md
14
README.md
@ -1,17 +1,18 @@
|
||||
<p align="center">
|
||||
<img src="https://user-images.githubusercontent.com/2666735/28999701-04c6ba7e-7a84-11e7-804b-3ffa4f7d5d95.png" alt="Meting">
|
||||
<img src="https://user-images.githubusercontent.com/2666735/30651452-58ae6c88-9deb-11e7-9e13-6beae3f6c54c.png" alt="Meting">
|
||||
</p>
|
||||
|
||||
# APlayer for Typecho (Meting)
|
||||
# APlayer for Typecho
|
||||
在 Typecho 中使用 APlayer 播放在线音乐吧~
|
||||
[发布页面](https://i-meto.com/meting-typecho/)
|
||||
|
||||
## 介绍
|
||||
1. 支持国内五大音乐平台(网易云、QQ、虾米、百度、酷狗)的单曲/专辑/歌单播放
|
||||
2. 简单快捷,复制音乐详情页面网址,后台自动生成播放代码
|
||||
3. **支持不同音乐平台歌曲混合播放**
|
||||
4. 前端 APlayer,后端 Meting 及时更新,保证兼容性及 API 高可用性
|
||||
5. 支持 MySql、SQLite 数据库
|
||||
3. 前端 APlayer,后端 Meting 及时更新,保证兼容性及 API 高可用性
|
||||
4. 支持 MySql、SQLite 数据库
|
||||
5. 支持自定义歌曲播放
|
||||
6. **自定义 API 支持**
|
||||
|
||||
## 声明
|
||||
本作品仅供个人学习研究使用,请勿将其用作商业用途。
|
||||
@ -25,7 +26,6 @@
|
||||
|
||||
## 使用
|
||||
在文章编辑页面,点击编辑器上的 **音乐图标** 按钮,在弹出的窗口中输入音乐地址(见支持列表),最后点击确定即可
|
||||
**歌曲混合特性:** 允许添加多个音乐地址,每行一个,插件会自动将所有歌曲合并在同一个歌单进行播放。
|
||||
|
||||
## 支持列表
|
||||
网易云音乐 http://music.163.com
|
||||
@ -67,4 +67,4 @@ A: 为了减少服务器压力,插件设置对歌单、歌词数据进行缓
|
||||
更多问题可以通过 issue 页面提交,或者通过 Telegram、邮件向我反馈
|
||||
|
||||
## LICENSE
|
||||
APlayer-Typecho-Plugin is under the MIT license.
|
||||
APlayer-Typecho is under the MIT license.
|
||||
|
2
assets/Meting.min.js
vendored
Normal file
2
assets/Meting.min.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/*! meting.aplayer.js v1.2.1 | MIT License */
|
||||
!function(){function e(e,t){var a=[],r=e.dataset;a.element=e,a.music=t,a.showlrc=a.music[0].lrc?3:0,a.narrow="true"===r.narrow,a.autoplay="true"===r.autoplay,a.mutex="false"!==r.mutex,a.mode=r.mode||"circulation",a.preload=r.preload||"auto",a.listmaxheight=r.listmaxheight||"340px",a.theme=r.theme||"#ad7a86",new APlayer(a)}console.log("\n %c Meting 1.2.1 %c https://i-meto.com/ghost-aplayer/ \n\n","color: #fff; background-image: linear-gradient(90deg, rgb(47, 172, 178) 0%, rgb(45, 190, 96) 100%); padding:5px 1px;","background-image: linear-gradient(90deg, rgb(45, 190, 96) 0%, rgb(255, 255, 255) 100%); padding:5px 0;");var t="https://api.i-meto.com/meting/api?server=:server&type=:type&id=:id&r=:r";"undefined"!=typeof meting_api&&(t=meting_api);var a=document.querySelectorAll(".aplayer");Array.prototype.forEach.call(a,function(a,r){if(a.dataset.id){var i=new XMLHttpRequest,o=t;o=(o=(o=(o=o.replace(":server",a.dataset.server)).replace(":type",a.dataset.type)).replace(":id",a.dataset.id)).replace(":r",Math.random()),i.open("GET",o,!0),i.onload=function(){if(i.status>=200&&i.status<400){var t=JSON.parse(i.responseText);e(a,t)}},i.send()}else{var n=[];n.title=a.dataset.title,n.author=a.dataset.author,n.url=a.dataset.url,n.pic=a.dataset.pic,n.lrc=a.dataset.lrc,e(a,[n])}})}();
|
@ -8,7 +8,7 @@ $(function() {
|
||||
'<div>'+
|
||||
'<p><b>插入音乐</b></p>'+
|
||||
'<p>请在下方的输入框内输入要插入的音乐地址,如多个地址请用回车隔开'+
|
||||
'<p><textarea type="text" rows="5" cols="40"></textarea></p>'+
|
||||
'<p><input type="text"></input></p>'+
|
||||
'</div>'+
|
||||
'<form>'+
|
||||
'<button type="button" class="btn btn-s primary" id="ok">确定</button>'+
|
||||
@ -16,7 +16,7 @@ $(function() {
|
||||
'</form>'+
|
||||
'</div>'+
|
||||
'</div>');
|
||||
$('.wmd-prompt-dialog textarea').val('http://').select();
|
||||
$('.wmd-prompt-dialog input').val('http://').select();
|
||||
});
|
||||
$(document).on('click','#cancel',function() {
|
||||
$('#MetingPanel').remove();
|
||||
@ -26,7 +26,7 @@ $(function() {
|
||||
callback=$.ajax({
|
||||
type:'POST',
|
||||
url:murl,
|
||||
data:{data:$('.wmd-prompt-dialog textarea').val()},
|
||||
data:{data:$('.wmd-prompt-dialog input').val()},
|
||||
async:false
|
||||
});
|
||||
$('#MetingPanel').remove();
|
||||
|
@ -3,7 +3,7 @@
|
||||
* Meting music framework
|
||||
* https://i-meto.com
|
||||
* https://github.com/metowolf/Meting
|
||||
* Version 1.3.8
|
||||
* Version 1.3.9
|
||||
*
|
||||
* Copyright 2017, METO Sheel <i@i-meto.com>
|
||||
* Released under the MIT license
|
||||
@ -153,15 +153,15 @@ class Meting
|
||||
'method' => 'GET',
|
||||
'url' => 'https://c.y.qq.com/soso/fcgi-bin/client_search_cp',
|
||||
'body' => array(
|
||||
'format' => 'json',
|
||||
'p' => $page,
|
||||
'n' => $limit,
|
||||
'w' => $keyword,
|
||||
'aggr' => 1,
|
||||
'lossless' => 1,
|
||||
'cr' => 1,
|
||||
'platform' => 'yqq',
|
||||
'new_json' => 1,
|
||||
),
|
||||
'decode' => 'jsonp2json',
|
||||
'format' => 'data#song#list',
|
||||
);
|
||||
break;
|
||||
@ -321,12 +321,14 @@ class Meting
|
||||
case 'tencent':
|
||||
$API=array(
|
||||
'method' => 'GET',
|
||||
'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_album_info_cp.fcg',
|
||||
'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_album_detail_cp.fcg',
|
||||
'body' => array(
|
||||
'albummid' => $id,
|
||||
'platform' => 'yqq',
|
||||
'platform' => 'mac',
|
||||
'format' => 'json',
|
||||
'newsong' => 1,
|
||||
),
|
||||
'format' => 'data#list',
|
||||
'format' => 'data#getSongInfo',
|
||||
);
|
||||
break;
|
||||
case 'xiami':
|
||||
@ -406,7 +408,8 @@ class Meting
|
||||
'begin' => 0,
|
||||
'num' => $limit,
|
||||
'order' => 'listen',
|
||||
'platform' => 'yqq',
|
||||
'platform' => 'mac',
|
||||
'newsong' => 1,
|
||||
),
|
||||
'format' => 'data#list',
|
||||
);
|
||||
@ -484,15 +487,14 @@ class Meting
|
||||
case 'tencent':
|
||||
$API=array(
|
||||
'method' => 'GET',
|
||||
'url' => 'https://c.y.qq.com/qzone/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg',
|
||||
'url' => 'https://c.y.qq.com/v8/fcg-bin/fcg_v8_playlist_cp.fcg',
|
||||
'body' => array(
|
||||
'disstid' => $id,
|
||||
'utf8' => 1,
|
||||
'type' => 1,
|
||||
'platform' => 'yqq',
|
||||
'id' => $id,
|
||||
'format' => 'json',
|
||||
'newsong' => 1,
|
||||
'platform' => 'jqspaframe.json',
|
||||
),
|
||||
'decode' => 'jsonp2json',
|
||||
'format' => 'cdlist#0#songlist',
|
||||
'format' => 'data#cdlist#0#songlist',
|
||||
);
|
||||
break;
|
||||
case 'xiami':
|
||||
@ -653,7 +655,7 @@ class Meting
|
||||
'url' => 'https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg',
|
||||
'body' => array(
|
||||
'songmid' => $id,
|
||||
'g_tk' => 5381,
|
||||
'g_tk' => '5381',
|
||||
),
|
||||
'decode' => 'tencent_lyric',
|
||||
);
|
||||
@ -751,7 +753,7 @@ class Meting
|
||||
),
|
||||
'tencent'=>array(
|
||||
'referer' => 'https://y.qq.com/portal/player.html',
|
||||
'cookie' => 'pgv_pvi=3832878080; pgv_si=s4066364416; pgv_pvid=3938077488; yplayer_open=1; qqmusic_fromtag=66; ts_last=y.qq.com/portal/player.html; ts_uid=5141451452; player_exist=1; yq_index=1',
|
||||
'cookie' => 'pgv_pvi=22038528; pgv_si=s3156287488; pgv_pvid=5535248600; yplayer_open=1; ts_last=y.qq.com/portal/player.html; ts_uid=4847550686; yq_index=0; qqmusic_fromtag=66; player_exist=1',
|
||||
'useragent' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36',
|
||||
),
|
||||
'xiami'=>array(
|
||||
@ -794,13 +796,6 @@ class Meting
|
||||
);
|
||||
return $API;
|
||||
}
|
||||
private function jsonp2json($jsonp)
|
||||
{
|
||||
if ($jsonp[0] !== '[' && $jsonp[0] !== '{') {
|
||||
$jsonp = substr($jsonp, strpos($jsonp, '('));
|
||||
}
|
||||
return trim($jsonp, '();');
|
||||
}
|
||||
private function tencent_singlesong($result)
|
||||
{
|
||||
$result=json_decode($result, 1);
|
||||
@ -834,11 +829,9 @@ class Meting
|
||||
{
|
||||
$data=json_decode($result, 1);
|
||||
if (isset($data['data'][0]['uf']['url'])) {
|
||||
$url=array(
|
||||
'url' => $data['data'][0]['uf']['url'],
|
||||
'br' =>$data['data'][0]['uf']['br']/1000,
|
||||
);
|
||||
} elseif (isset($data['data'][0]['url'])) {
|
||||
$data['data'][0]['url']=$data['data'][0]['uf']['url'];
|
||||
}
|
||||
if (isset($data['data'][0]['url'])) {
|
||||
$url=array(
|
||||
'url' => $data['data'][0]['url'],
|
||||
'br' => $data['data'][0]['br']/1000,
|
||||
@ -859,10 +852,10 @@ class Meting
|
||||
'method' => 'GET',
|
||||
'url' => 'https://c.y.qq.com/base/fcgi-bin/fcg_musicexpress.fcg',
|
||||
'body' => array(
|
||||
'json' => 3,
|
||||
'guid' => $GUID,
|
||||
'json' => 3,
|
||||
'guid' => $GUID,
|
||||
'format' => 'json',
|
||||
),
|
||||
'decode' => 'jsonp2json',
|
||||
);
|
||||
$KEY=json_decode($this->curl($API), 1);
|
||||
$KEY=$KEY['key'];
|
||||
@ -918,8 +911,8 @@ class Meting
|
||||
}
|
||||
$urlt=str_replace('^', '0', urldecode($urlt));
|
||||
$url=array(
|
||||
'url' => str_replace('http://','https://',urldecode($urlt)),
|
||||
'br' => 320,
|
||||
'url' => str_replace('http://','https://',urldecode($urlt)),
|
||||
'br' => 320,
|
||||
);
|
||||
} else {
|
||||
$url=array(
|
||||
@ -1002,7 +995,7 @@ class Meting
|
||||
}
|
||||
private function tencent_lyric($result)
|
||||
{
|
||||
$result=$this->jsonp2json($result);
|
||||
$result=substr($result,18,-1);
|
||||
if (!$this->_FORMAT) {
|
||||
return $result;
|
||||
}
|
||||
@ -1098,13 +1091,13 @@ class Meting
|
||||
$data=$data['musicData'];
|
||||
}
|
||||
$result=array(
|
||||
'id' => $data['songmid'],
|
||||
'name' => $data['songname'],
|
||||
'id' => $data['mid'],
|
||||
'name' => $data['name'],
|
||||
'artist' => array(),
|
||||
'album' => isset($data['albumname'])?$data['albumname']:$data['album']['name'],
|
||||
'pic_id' => $data['albummid'],
|
||||
'url_id' => $data['songmid'],
|
||||
'lyric_id' => $data['songmid'],
|
||||
'album' => trim($data['album']['title']),
|
||||
'pic_id' => $data['album']['mid'],
|
||||
'url_id' => $data['mid'],
|
||||
'lyric_id' => $data['mid'],
|
||||
'source' => 'tencent',
|
||||
);
|
||||
foreach ($data['singer'] as $vo) {
|
||||
|
Loading…
Reference in New Issue
Block a user