MENU

任意站点引入 APlayer 和 Meting 的简单方法

August 15, 2020 • Read: 116 • 代码笔记

APlayer 和 Meting,可播放 网易云,QQ 音乐,酷狗,虾米,百度 以及 自定义的 单曲和歌单,按需加载 JS,不依赖插件和服务器计算存储,任意站点都可使用。

引入JS

对于 本主题,依次进入 控制台 - 外观 - 设置外观 - 主题自定义扩展,将代码加入到 自定义 HTML 元素拓展 - 标签: head 头部 (meta 元素后)。其他主题,加入到主题对应的 header.php 中的 </head> 标签前。

Almost JavaScript Code

<script>

// APlayer API
document.addEventListener('DOMContentLoaded', initAplayer);
window.aplayers = window.aplayers || [];
function initAplayer(option) {
    const common = {
        loadResource: function (id, resource, type) {
            return new Promise(function (resolve, reject) {
                let loaded = document.head.querySelector('#' + id);
                if (loaded) {
                    resolve('success: ' + resource);
                    return;
                }
                const element = document.createElement(type);
                element.onload = element.onreadystatechange = () => {
                    if (!loaded && (!element.readyState || /loaded|complete/.test(element.readyState))) {
                        element.onload = element.onreadystatechange = null;
                        loaded = true;
                        resolve('success: ' + resource);
                    }
                }
                element.onerror = function () {
                    reject(Error(resource + ' load error!'));
                };
                if (type === 'link') {
                    element.rel = 'stylesheet';
                    element.href = resource;
                } else {
                    element.src = resource;
                }
                element.id = id;
                document.getElementsByTagName('head')[0].appendChild(element);
            });
        },
        loadResources: function (callback) {
            const loadResource = this.loadResource;
            const pt = '//s0.pstatp.com/cdn/expire-1-M/';
            const jd = '//cdn.jsdelivr.net/npm/';
            const resources = [
                pt + 'aplayer/1.10.1/APlayer.min.css',
                pt + 'aplayer/1.10.1/APlayer.min.js',
                jd + 'meting@2/dist/Meting.min.js'
            ];
            const loadPromises = [];
            resources.forEach(resource => {
                loadPromises.push(loadResource(btoa(resource).replace(/[=+\/]/g, ''), resource,
                    ({
                        'css': 'link',
                        'js': 'script'
                    })[resource.split('.').pop()]
                ));
            });
            Promise.all(loadPromises).then(
                function () {
                    if (typeof callback !== 'function') return;
                    let flag = false;
                    const waitAM = setInterval(() => {
                        if (!flag
                            && typeof APlayer === 'function'
                            && typeof MetingJSElement === 'function') {
                            flag = true;
                            callback();
                            clearInterval(waitAM);
                        }
                    }, 100);
                }
            );
        },
        createAplayers: function (sources) {
            for (let i = 0; i < sources.length; i++) {
                const child = document.createElement('div');
                sources[i].parentNode.insertBefore(child, sources[i]);
                sources[i].style.display = 'none';
                const songsTag = sources[i].querySelectorAll('s');
                const songs = [];
                songsTag.forEach(songTag => {
                    const song = {};
                    for (let i = 0; i < songTag.attributes.length; i++) {
                        song[songTag.attributes[i].name] = songTag.attributes[i].value;
                    }
                    songs.push(song);
                });
                const options = { container: child, preload: 'none', autoplay: false, audio: songs };
                const optionMap = sources[i].attributes;
                for (let i = 0; i < optionMap.length; i++) {
                    options[optionMap[i].name] = optionMap[i].value;
                }
                this.loadResources(() => window.aplayers.push(new APlayer(options)));
            }
        }
    };

    if (option == 'manual') return new Promise((resolve, reject) => {
        common.loadResources(() => resolve('success'));
    });

    const aps = document.querySelectorAll('ap');
    if (aps.length !== 0) common.createAplayers(aps);

    const mts = document.querySelectorAll('meting-js');
    if (!window.refreshing && mts.length !== 0) common.loadResources(
        function () {
            mts.forEach(mt => {
                if (!mt.aplayer) {
                    const html = mt.outerHTML;
                    mt.aplayer = { destroy: new Function(), list: { index: undefined } };
                    mt.outerHTML = '\n' + html;
                }
            });
            document.querySelectorAll('meting-js').forEach(mt => {
                let flag = false;
                const waitMT = setInterval(() => {
                    if (!flag && mt.aplayer) {
                        flag = true;
                        window.aplayers.push(mt.aplayer);
                        console.log('replaced unloaded aplayer.')
                        clearInterval(waitMT);
                    }
                }, 300);
            });
        }
    );
}

</script>

<script>

// PJAX 相关 BUG
document.addEventListener('DOMContentLoaded', function () {
    let flag = false;
    window.needReloadUrls = window.needReloadUrls || new Set();
    const jqueryWaitor = setInterval(() => {
        if (!flag && jQuery) {
            flag = true;
            $(document).on('pjax:start', function () {
                if (!window.refreshing || !window.pjaxStarted) {
                    window.pjaxStarted = true;
                    console.log('pjax:start');
                    window.aplayers.forEach(ap => {
                        ap.list.index = undefined;
                        ap.destroy();
                    });
                    window.aplayers = [];
                    setTimeout(() => window.pjaxStarted = false, 2000);
                }
            });
            $(document).on('pjax:end', function () {
                if (document.querySelector('meting-js')
                    || document.querySelector('.collapse-block')
                    || document.querySelector('#toggle-menu-tree')
                    || document.querySelectorAll('.content-tab-title').length > 1
                ) {
                    if (!window.needReloadUrls.has(location.href)) {
                        window.needReloadUrls.add(location.href);
                        console.log('captured a neededReloadUrl.');
                    }
                }
            });
            $(document).on('pjax:popstate', function (event) {
                if (event.state && window.needReloadUrls.has(event.state.url) && !window.refreshing) {
                    window.refreshing = true;
                    console.log('back-forward handler.');
                    $.pjax.reload({
                        url: location.href,
                        container: '#body',
                        fragment: '#body',
                        scrollTo: false,
                        timeout: 8000
                    });
                    setTimeout(() => window.refreshing = false, 2000);
                }
            });
            clearInterval(jqueryWaitor);
        }
    }, 500);
});

</script>


如果你开启了 PJAX,可能需要单独加入回调函数。对于本主题,依次进入 控制台 - 外观 - 设置外观 - PJAX(BETA) - PJAX RELOAD,将 initAplayer(); 添加进入即可。

演示效果

在文章所需位置以 HTML 形式插入代码,即可添加播放器。

!!!
<!-- 引入方式 -->
<meting-js auto="https://music.163.com/#/playlist?id=3134064854"></meting-js>
!!!
!!!
<!-- 引入方式 -->
<meting-js auto="https://y.qq.com/n/yqq/playlist/1167623725.html"></meting-js>
!!!
!!!
<!-- 标签引入 -->
<ap>
<s
    name="rainymood"
    artist="rainymood"
    url="https://rainymood.com/audio1110/0.m4a"
    cover="https://rainymood.com/i/badge.jpg">
</s>
</ap>
!!!

!!!
<!-- 或编程引入 -->
<div id="ap"></div>
<script>
    initAplayer('manual').then(() => {
        window.aplayers.push(new APlayer({
            container: document.querySelector('#ap'), preload: 'none', autoplay: false, audio: [
                {
                    name="rainymood",
                    artist="rainymood",
                    url="https://rainymood.com/audio1110/0.m4a",
                    cover="https://rainymood.com/i/badge.jpg"
                }
            ]
        }));
    });
</script>
!!!

Last Modified: August 16, 2020
Archives QR Code
QR Code for this page
Tipping QR Code
0:00