APlayer & MetingJS Integration#
Overview#
Butterfly embeds APlayer (a web audio player) via MetingJS, a wrapper that translates HTML data-* attributes into API calls against streaming music platforms (NetEase, Tencent, Kugou, etc.). The theme ships APlayer v1.10.1 and MetingJS v1.1.6 (from the butterfly-extsrc package) as optional built-in dependencies β no separate Hexo plugin is required.
Key entry points:
- Template:
layout/includes/third-party/aplayer.pug - Injection gate:
layout/includes/additional-js.pug - Default config:
scripts/common/default_config.js - Asset version pins:
plugins.yml
Enabling the Integration#
The feature is gated by aplayerInject in _config.yml :
aplayerInject:
enable: false # master switch (off by default)
per_page: true # inject scripts on every page
aplayer.pug is only included when enable: true and at least one of :
per_page: true- PJAX is globally enabled (
theme.pjax.enable) - The current page sets
aplayer: truein its front-matter
hexo-tag-aplayerconflict: If thehexo-tag-aplayerHexo plugin is installed, setasset_inject: falsein Hexo's root_config.ymlto prevent double-injecting APlayer/MetingJS assets.
Asset Loading#
aplayer.pug injects three assets in order: CSS β APlayer JS β MetingJS.
| Asset key | Package | File | Version |
|---|---|---|---|
aplayer_css | aplayer | dist/APlayer.min.css | 1.10.1 |
aplayer_js | aplayer | dist/APlayer.min.js | 1.10.1 |
meting_js | butterfly-extsrc | metingjs/dist/Meting.min.js | 1.1.6 |
The CSS link uses media="print" + onload="this.media='all'" for non-render-blocking load . CDN source and custom URLs for all three assets can be overridden under CDN.option (keys: aplayer_css, aplayer_js, meting_js).
MetingJS version note: The bundled version is v1.1.6 (not v2.x) to preserve compatibility with
hexo-tag-aplayer.
Placing a Player#
Global sticky player via inject.bottom#
Insert the APlayer HTML div into inject.bottom:
inject:
bottom:
- <div class="aplayer no-destroy" data-id="60198" data-server="netease"
data-type="playlist" data-fixed="true" data-autoplay="true"></div>
Raw HTML with data-* attributes is sufficient β hexo-tag-aplayer is not needed.
MetingJS data attributes#
| Attribute | Required | Notes |
|---|---|---|
data-id | β | Song / playlist / album ID or search keyword |
data-server | β | netease, tencent, kugou, xiami, baidu |
data-type | β | song, playlist, album, search, artist |
data-fixed | β | true = sticky bottom player |
data-mini | β | true = mini mode |
data-autoplay | β | default false |
data-theme | β | accent color, default #2980b9 |
data-mutex | β | default true; pauses other players on play |
data-volume | β | 0β1, default 0.7 |
data-loop | β | all / one / none, default all |
data-order | β | list / random, default list |
data-preload | β | none / metadata / auto, default auto |
Per-page player via front-matter#
To scope APlayer injection to a single post without enabling per_page site-wide, add to the post's front-matter:
aplayer: true
Then write the <div class="aplayer" ...> inline in the Markdown body. The injection gate checks page.aplayer as a third path .
PJAX Lifecycle Hooks#
When PJAX is enabled, aplayer.pug registers two hooks via btf.addGlobalFn:
| Hook | Registered function | Effect |
|---|---|---|
pjaxSend | destroyAplayer | Destroys all non-fixed APlayer instances before navigation |
pjaxComplete | runMetingJS | Re-runs loadMeting() after the new page loads |
destroyAplayer iterates window.aplayers and skips any instance where options.fixed === true . A global sticky player with data-fixed="true" therefore survives page transitions uninterrupted. The no-destroy CSS class seen in tutorials is a naming convention only β the real guard is the fixed APlayer option.