无刷新浏览

看到网易音乐的无刷新浏览,于是也搞了一个,虽然有点小问题,勉勉OK.
百度过一个history.js,说的很强大,但是没弄懂,好像是用在hash方面,但是现在有 window.history.pushState 直接修改地址,真香.避免了复制的网址有问题.

var NengeNet = new class NengeApp{
    _DOM = new DOMParser();
    _FetchStateID = 0;
    _FetchStateData = {};
    _q    = d=>document.querySelector(d);
    _qAll = d=>document.querySelectorAll(d);
    _content = '#content';
   constructor(){//监听后退事件
        window.addEventListener('popstate',(e)=>{
            if(!this._FetchStateID) return;
            for (let index in this._FetchStateData) {
                const data = this._FetchStateData[index];
                console.log(history.state);
                if(data.url == location.href){
                    document.title = data.title;
                    this._q(this._content).innerHTML = data.page;
                    this._FetchStateID = data.state;
                    this.FetchBind();
                    return ;
                }
                
            }
            location.reload();
        },false);
        this.FetchBind();
    }
    FetchBind(){//对连接进行事件绑定 并且数据处理
        if(!this._FetchStateData[this._FetchStateID])this._FetchStateData[this._FetchStateID]={
            'state':this._FetchStateID++,
            'page':this._q(this._content).innerHTML,
            'title':document.title,
            'url':location.href
        };
        this._qAll('#page a').forEach(
            elm=>{
                if(elm.onclick) return;
                if(elm.target=='_blank') return;
                if(!elm.href) return ;
                let myURL = new URL(elm.href);
                if(myURL.host == location.host&&this.Fetch_CheckURL(myURL.pathname)){
                    elm.onclick = event=>{
                        if(elm.href){
                                event.preventDefault();
                                event.stopPropagation();
                                fetch(elm.href).then(v=>v.text()).then(text=>{
                                    let html = this.parseHTML(text),page = html.querySelector(this._content);
                                    if(page){
                                        this._q(this._content).innerHTML = page.innerHTML;
                                        document.title = html.title;
                                        html = null,page=null;
                                        window.history.pushState({'pageid':this._FetchStateID},document.title,elm.href);
                                        this.FetchBind();
                                        this.Fetch_Prism();
                                        let Timer = setInterval(()=>{
                                            let Y = window.scrollY,_Y=Y*.5;
                                            if(Y<=0)return clearInterval(Timer);
                                            window.scrollTo(0,_Y<10?0:_Y);
                                        },50)
                                    }else{
                                        alert('页面打开失败');
                                    }
                                });
                        }
                    }
                }
            }
        );
    }
    Fetch_Prism(){//因为我用了高亮代码
        if(!Prism){
            this.add_link('/wp-content/plugins/code-syntax-block/assets/prism-onedark.css');
            W['prism_settings'] = {"pluginUrl":"\/wp-content\/plugins\/code-syntax-block\/"};
            this.add_link('/wp-content/plugins/code-syntax-block/assets/prism/prism.js').onload=()=>{Prism.highlightAll();};
            return ;
        }
        Prism.highlightAll();
    }
    Fetch_CheckURL(path){
        var re = [
            /^\/index\.php$/,
            /^\/$/,
            /\/\d+\//,
            /\/date\/\d+\/\d+\//,
            /\/category\/[^\/]+?\//

        ];
        for(var i =0;i<re.length;i++){
            if(re[i].test(path))return true;
        }
        return false;
    }
    parseHTML(text){//把字符解释成HTML
        return this._DOM.parseFromString(text,"text/html");
    }
    _t(type){
        switch(type){
            case 'css':
                return ['link','href','text\/css','stylesheet'];
            break;
            case 'js':
                return ['script','src','text\/javascript',''];
            break;
        }
    }
    add_link(name,data){//插入连接
        let type = name.split('.').pop(),
            _t = this._t(type),
            elm  = document.createElement(_t[0]);
            if(data){
                data = window.URL.createObjectURL(new Blob([data],{type:_t[3]}));
            }
            elm[_t[1]] = data||(this.root_dir+name+'?'+(new Date()).getTime());
            elm.type = _t[2];
            elm.rel = _t[3]
            document.head.appendChild(elm);
            return elm;
    }
}

音乐JS

这是我修改过的,其中的’lrcType’:1 仅作为歌词是否开启.会根据其值判断是不地址,否则按字符歌词读取.
例如 ‘http’ ‘/’ 开头或者含有 ‘.lrc’被认为是地址进行读取.
有兴趣可以到https://nenge.lanzoui.com/b02cgajaf 密码 0000 APlayer.all.min.js
API文档在https://aplayer.js.org/#/zh-Hans/

        let elm  = document.createElement("div");
        document.body.appendChild(this.elm);
        elm.ap = await  new APlayer({
            'container': elm,
            'volume':1,
            'autoplay': false,
            //'preload':'auto',
            //'theme': '#FADFA3',
            'order':'random',
            'lrcType':1,
            'fixed': true,
            'loop': 'all',
            'mini':false,
            'mutex': true,
            'storageName': 'aplayer-setting',
            'audio': [
            {
                'name':'Proud of You(live)',
                'artist': '冯曦妤',
                'album':'Fiona Fung Live 2010',
                'cover':'//p1.music.126.net/MuHjjMWeUzkv4M3OTxYXfg==/18353048091611329.jpg?param=80y80',
                'url':'/api/mysound.php?s=qq&i=000ZnnlH4DcxYL&link',
                'lrc':'/api/mysound.php?s=qq&i=000ZnnlH4DcxYL&link&lrc'
            },
            {
                'name':'Proud of You(live)',
                'artist': '冯曦妤',
                'album':'Fiona Fung Live 2010',
                'cover':'//p1.music.126.net/MuHjjMWeUzkv4M3OTxYXfg==/18353048091611329.jpg?param=80y80',
                'url':'/api/mysound.php?s=qq&i=000ZnnlH4DcxYL&link',
                'lrc':'[ti:Proud Of You (Fiona Fung Live 2010)] [ar:冯曦妤] [al:Fiona Fung Live 2010] [by:] [offset:0] [00:00.00]Proud Of You (Fiona Fung Live 2010) - 冯曦妤 (Fiona Fung) [00:12.28]'
            }]
        });
        elm.oncontextmenu = ()=>false;

音乐连接获取API

可以到github找Meting.php

PHPAPI:https://github.com/metowolf/Meting
JS调用:https://github.com/metowolf/MetingJS (可以跨域使用)
当然我也做了一个基于Meting简化版

<?php

class SoundUrl{
    public $server;
    public $data;
    public $cookies = null;
    private function curlset()
    {
        switch ($this->server) {
            case 'netease':
            return array(
                'Referer'         => 'https://music.163.com/',
                'Cookie'          => 'appver=1.5.9; os=osx; __remember_me=true; osver=%E7%89%88%E6%9C%AC%2010.13.5%EF%BC%88%E7%89%88%E5%8F%B7%2017F77%EF%BC%89;',
                'User-Agent'      => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/605.1.15 (KHTML, like Gecko)',
                'X-Real-IP'       => long2ip(mt_rand(1884815360, 1884890111)),
                'Accept'          => '*/*',
                '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',
            );
            case 'tencent':
            return array(
                'Referer'         => 'http://y.qq.com',
                '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',
                'User-Agent'      => 'QQ%E9%9F%B3%E4%B9%90/54409 CFNetwork/901.1 Darwin/17.6.0 (x86_64)',
                'Accept'          => '*/*',
                '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',
            );
            case 'xiami':
            return array(
                'Cookie'          => '_m_h5_tk=15d3402511a022796d88b249f83fb968_1511163656929; _m_h5_tk_enc=b6b3e64d81dae577fc314b5c5692df3c',
                'User-Agent'      => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) AppleWebKit/537.36 (KHTML, like Gecko) XIAMI-MUSIC/3.1.1 Chrome/56.0.2924.87 Electron/1.6.11 Safari/537.36',
                'Accept'          => 'application/json',
                'Content-type'    => 'application/x-www-form-urlencoded',
                'Accept-Language' => 'zh-CN',
            );
            case 'kugou':
            return array(
                'User-Agent'      => 'IPhone-8990-searchSong',
                'UNI-UserAgent'   => 'iOS11.4-Phone8990-1009-0-WiFi',
            );
            case 'baidu':
            return array(
                'Cookie'          => 'BAIDUID='.$this->getRandomHex(32).':FG=1',
                'User-Agent'      => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) baidu-music/1.2.1 Chrome/66.0.3359.181 Electron/3.0.5 Safari/537.36',
                'Accept'          => '*/*',
                'Content-type'    => 'application/json;charset=UTF-8',
                'Accept-Language' => 'zh-CN',
            );
        }
    }

    private function getRandomHex($length)
    {
        if (function_exists('random_bytes')) {
            return bin2hex(random_bytes($length / 2));
        }
        if (function_exists('mcrypt_create_iv')) {
            return bin2hex(mcrypt_create_iv($length / 2, MCRYPT_DEV_URANDOM));
        }
        if (function_exists('openssl_random_pseudo_bytes')) {
            return bin2hex(openssl_random_pseudo_bytes($length / 2));
        }
    }

    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';

        if (extension_loaded('bcmath')) {
            $skey = $this->getRandomHex(16);
        } else {
            $skey = 'B3v3kH4vRPWRJFfH';
        }

        $body = json_encode($api['body']);

        if (function_exists('openssl_encrypt')) {
            $body = openssl_encrypt($body, 'aes-128-cbc', $nonce, false, $vi);
            $body = openssl_encrypt($body, 'aes-128-cbc', $skey, false, $vi);
        } else {
            $pad = 16 - (strlen($body) % 16);
            $body = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $nonce, $body.str_repeat(chr($pad), $pad), MCRYPT_MODE_CBC, $vi));
            $pad = 16 - (strlen($body) % 16);
            $body = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $skey, $body.str_repeat(chr($pad), $pad), MCRYPT_MODE_CBC, $vi));
        }

        if (extension_loaded('bcmath')) {
            $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);
        } else {
            $skey = '85302b818aea19b68db899c25dac229412d9bba9b3fcfe4f714dc016bc1686fc446a08844b1f8327fd9cb623cc189be00c5a365ac835e93d4858ee66f43fdc59e32aaed3ef24f0675d70172ef688d376a4807228c55583fe5bac647d10ecef15220feef61477c28cae8406f6f9896ed329d6db9f88757e31848a6c2ce2f94308';
        }

        $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;
    }
    function getRequest($api, $timeout = 20){
        $url_info = parse_url($api['url']);
        $ssl = $url_info['scheme'] == 'https' ? false : null;
        $curlObj = curl_init();
        $options = [
            CURLOPT_URL => $api['url'],
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_FOLLOWLOCATION => 1,
            CURLOPT_AUTOREFERER => 1,
            CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36',
            CURLOPT_TIMEOUT => $timeout,
            //CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_0,
            //请求头
            CURLOPT_HTTPHEADER => $this->header,
            //IP4
            CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4,
            CURLOPT_REFERER => isset($api['refer'])?$api['refer']:$url_info['host'], //伪造来路
            //CURLOPT_COOKIEFILE=>dirname(__FILE__).'/kugou.cookies.txt',
            //CURLOPT_COOKIEJAR=>dirname(__FILE__).'/kugou.cookies.txt',
            CURLOPT_POST=>$api['body']?true:false,
            CURLOPT_POSTFIELDS => $api['body'] ?(is_array($api['body'])?http_build_query($api['body']):$api['body']):null,
            CURLOPT_SSL_VERIFYHOST => $ssl,
            CURLOPT_SSL_VERIFYPEER => $ssl,
            CURLOPT_COOKIE=>isset($api['cookies'])?$api['cookies']:null,
        ];
        //print_r($options);exit;
        curl_setopt_array($curlObj, $options);
        $returnData = curl_exec($curlObj);
        if (curl_errno($curlObj)) {
            //error message
            $returnData = curl_error($curlObj);
        }
        curl_close($curlObj);
        return $returnData;
    }
    public function __construct(){
        if(isset($_GET['s']))return $this->site($_GET['s']);
    }
    public function site($value=''){
        switch ($value) {
            case 'netease':
            case '163':
            case '网易':
                $this->server = 'netease';
            break;
            case 'tencent':
            case 'qq':
                $this->server = 'tencent';
            break;
            case 'xiami':
            case 'mi':
            case '小米':
                $this->server = 'xiami';
            break;
            case 'kugou':
            case '酷狗':
                $this->server = 'kugou';
            break;
            case 'baidu':
            case '百度':
                $this->server = 'baidu';
            break;
        }
        $this->header = $this->curlset();
        if(isset($_GET['i'])){
            $url =  $this->url($_GET['i']);
            if(isset($_GET['link'])){
                header('Location: '.$url);

            }else echo $url;
        }
        return $this;
    }
    private function getApi($api){
        if (isset($api['encode'])) {
            $api = call_user_func_array(array($this, $api['encode']), array($api));
        }
        //print_r($api);
        if ($api['method'] == 'GET') {
            if (isset($api['body'])) {
                $api['url'] .= '?'.http_build_query($api['body']);
                $api['body'] = null;
            }
        }
        $this->data = $this->getRequest($api);
        if(!$this->data){
            return '{}';
        }
        return $this->data;
    }
    public function url($id,$br=30){
        switch ($this->server) {
            case 'netease':
                if(isset($_GET['lrc'])){
                    $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',
                    );
                    $data = json_decode($this->getApi($api),true);
                    if(isset($data['lrc'])&&isset($data['lrc']['lyric'])){
                        return $data['lrc']['lyric'];
                    }
                    print_r($data);exit;
                    return;
                }
                $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',
                );
                $data = json_decode($this->getApi($api),true)['data'];
                if($data&&$data[0]['url']){
                    return $data[0]['url'];
                }
            break;
            case 'tencent':
                if(isset($_GET['lrc'])){
                    $api = array(
                        'method'=>'POST',
                        'url'=>'https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg',
                        'body'=>array(
                            'songmid'=>$id,
                            'format'=>'json'
                        ),
                    );
                    $data = json_decode($this->getApi($api),true);
                    if(isset($data['lyric'])){
                        return base64_decode($data['lyric']);
                    }
                    //print_r($this->getApi($api));exit;
                    return;
                }
                $api = array(
                    'method' => 'POST',
                    'url'    => 'https://u.y.qq.com/cgi-bin/musicu.fcg',
                    'body'   => '{"comm":{"format":"json","inCharset":"utf-8","outCharset":"utf-8"},"data":{"module":"vkey.GetVkeyServer","method":"CgiGetVkey","param":{"guid":"'.(mt_rand() % 10000000000).'","songmid":["'.$id.'"],"songtype":[0],"loginflag":1,"platform":"20"}}}',
                );
                $data = json_decode($this->getApi($api),true);
                if(isset($data['data'])&&isset($data['data']['data'])){
                    $data = $data['data']['data'];
                    foreach($data['midurlinfo'] as $k=>$v){
                        if($v['purl']){
                            return 'https://dl.stream.qqmusic.qq.com/'.$v['purl'];
                            break;
                        }
                    }
                }
                //print_r($data);exit;
            break;
            case 'xiami':
                $this->server = 'xiami';
            break;
            case 'kugou':
                $api = array(
                    'method' => 'GET',
                    'url'    => 'https://wwwapi.kugou.com/yy/index.php',
                    'body'   => array(
                        'r' => 'play/getdata',
                        'hash'  => $id,
                    ),
                    'cookies' =>'kg_mid=1; kg_dfid=1; kg_dfid_collect=1;'
                );
                $data = json_decode($this->getApi($api),true)['data'] ;
                //print_r($data);exit;
                if($data['play_backup_url'] || $data['play_url']){
                    return $data['play_backup_url']?$data['play_backup_url']: $data['play_url'];
                }
            break;
            case 'baidu':
                $this->server = 'baidu';
            break;
        }
    }
}
new SoundUrl();
发布日期:
分类:随说