├── .babelrc ├── .editorconfig ├── .gitignore ├── .npmignore ├── AUTHORS ├── LICENSE ├── README.md ├── common ├── constant.es └── util.es ├── docs └── README-zh_cn.md ├── gulpfile.babel.js ├── index.deprecated.es ├── index.es ├── lib ├── config.es ├── tag │ ├── base.es │ ├── player.es │ ├── playerList.es │ ├── playerLyric.es │ └── playerMeting.es └── view.es └── package.json /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | 'presets': ['es2015'] 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.es] 4 | indent_style = space 5 | indent_size = 2 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | *.js 4 | !gulpfile.babel.js 5 | package-lock.json 6 | .idea 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.es 2 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Original Author & Maintainer 2 | ---------------------------- 3 | grzhan (envy518@gmail.com) 4 | 5 | Contributors 6 | ------------ 7 | DualWield(xuli@shnow.cn) 8 | Yann Rocq (yann@rocq.net) 9 | Myer921 (Myer@morz.org) 10 | dixyes 11 | 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2016 grzhan 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hexo-tag-aplayer 2 | 3 |   4 | 5 | Embed APlayer([https://github.com/DIYgod/APlayer](https://github.com/DIYgod/APlayer)) in Hexo posts/pages. 6 | 7 | [中文文档](https://github.com/MoePlayer/hexo-tag-aplayer/blob/master/docs/README-zh_cn.md) 8 | 9 | 10 | 11 | 12 | 13 | - [Installation](#installation) 14 | - [Dependency](#dependency) 15 | - [Usage](#usage) 16 | - [Option](#option) 17 | - [With lyrics](#with-lyrics) 18 | - [With playlist](#with-playlist) 19 | - [MeingJS support (new in 3.0)](#meingjs-support-new-in-30) 20 | - [PJAX compatible](#pjax-compatible) 21 | - [Customization (new in 3.0)](#customization-new-in-30) 22 | - [Troubleshoot](#troubleshoot) 23 | - [Space within arguments](#space-within-arguments) 24 | - [Duplicate APlayer.JS loading](#duplicate-aplayerjs-loading) 25 | - [LICENSE](#license) 26 | 27 | 28 | 29 | 30 | 31 | 32 |  33 | 34 | 35 | ## Installation 36 | 37 | npm install --save hexo-tag-aplayer 38 | ## Dependency 39 | 40 | + APlayer.js >= 1.10.0 41 | + Meting.js >= 1.2.0 42 | 43 | ## Usage 44 | 45 | {% aplayer title author url [picture_url, narrow, autoplay, width:xxx, lrc:xxx] %} 46 | 47 | ### Option 48 | 49 | + `title` : music title 50 | + `author`: music author 51 | + `url`: music file url 52 | + `picture_url`: optional, music picture url 53 | + `narrow`: optional, narrow style 54 | + `autoplay`: optional, autoplay music, not supported by mobile browsers 55 | + `width:xxx`: optional, prefix `width:`, player's width (default: 100%) 56 | + `lrc:xxx`: optional, prefix `lrc:`, LRC file url 57 | 58 | With [post asset folders](https://hexo.io/docs/asset-folders.html#Tag-Plugins-For-Relative-Path-Referencing) enabled, you can easily place your image, music and LRC file into asset folder, and reference them like: 59 | 60 | {% aplayer "Caffeine" "Jeff Williams" "caffeine.mp3" "picture.jpg" "lrc:caffeine.txt" %} 61 | 62 | ### With lyrics 63 | 64 | Besides 'lrc' option, you can use `aplayerlrc` which has end tag to show lyrics. 65 | 66 | {% aplayerlrc "title" "author" "url" "autoplay" %} 67 | [00:00.00]lrc here 68 | {% endaplayerlrc %} 69 | 70 | ### With playlist 71 | 72 | {% aplayerlist %} 73 | { 74 | "narrow": false, // Optional, narrow style 75 | "autoplay": true, // Optional, autoplay song(s), not supported by mobile browsers 76 | "mode": "random", // Optional, play mode, can be `random` `single` `circulation`(loop) `order`(no loop), default: `circulation` 77 | "showlrc": 3, // Optional, show lrc, can be 1, 2, 3 78 | "mutex": true, // Optional, pause other players when this player playing 79 | "theme": "#e6d0b2", // Optional, theme color, default: #b7daff 80 | "preload": "metadata", // Optional, the way to load music, can be 'none' 'metadata' 'auto', default: 'auto' 81 | "listmaxheight": "513px", // Optional, max height of play list 82 | "music": [ 83 | { 84 | "title": "CoCo", 85 | "author": "Jeff Williams", 86 | "url": "caffeine.mp3", 87 | "pic": "caffeine.jpeg", 88 | "lrc": "caffeine.txt" 89 | }, 90 | { 91 | "title": "アイロニ", 92 | "author": "鹿乃", 93 | "url": "irony.mp3", 94 | "pic": "irony.jpg" 95 | } 96 | ] 97 | } 98 | {% endaplayerlist %} 99 | 100 | ### MeingJS support (new in 3.0) 101 | 102 | When you use MetingJS, your blog can play musics from Tencent, Netease, Xiami, Kugou, Baidu and more. 103 | 104 | See [metowolf/MetingJS](https://github.com/metowolf/MetingJS) and [metowolf/Meting](https://github.com/metowolf/Meting) in detail. 105 | 106 | If you want to use MetingJS in `hexo-tag-aplayer`, you need enable it in `_config.yml` 107 | 108 | ```yaml 109 | aplayer: 110 | meting: true 111 | ``` 112 | 113 | Now you can use `{% meting ...%}` in your post: 114 | 115 | ``` 116 | 117 | {% meting "60198" "netease" "playlist" %} 118 | 119 | 120 | {% meting "60198" "netease" "playlist" "autoplay" "mutex:false" "listmaxheight:340px" "preload:none" "theme:#ad7a86"%} 121 | ``` 122 | 123 | The `{% meting %}` options are shown below: 124 | 125 | | Option | Default | Description | 126 | | ------------- | ------------ | ------------------------------------------------------------ | 127 | | id | **required** | song id / playlist id / album id / search keyword | 128 | | server | **required** | Music platform: `netease`, `tencent`, `kugou`, `xiami`, `baidu` | 129 | | type | **required** | `song`, `playlist`, `album`, `search`, `artist` | 130 | | fixed | `false` | Enable fixed mode | 131 | | mini | `false` | Enable mini mode | 132 | | loop | `all` | Player loop play, values: 'all', 'one', 'none' | 133 | | order | `list` | Player play order, values: 'list', 'random' | 134 | | volume | 0.7 | Default volume, notice that player will remember user setting, default volume will not work after user set volume themselves | 135 | | lrctype | 0 | Lyric type | 136 | | listfolded | `false` | Indicate whether list should folded at first | 137 | | autoplay | `false` | Autoplay song(s), not supported by mobile browsers | 138 | | mutex | `true` | Pause other players when this player playing | 139 | | listmaxheight | `340px` | Max height of play list | 140 | | preload | `auto` | The way to load music, can be `none`, `metadata`, `auto` | 141 | | storagename | `metingjs` | LocalStorage key that store player setting | 142 | | theme | `#ad7a86` | Theme color | 143 | 144 | Read section [customization](#customization-new-in-30) to learn how to configure self-host meting api server in `hexo-tag-aplayer` and other configuration. 145 | 146 | ### PJAX compatible 147 | 148 | You need destroy APlayer instances manually when you use PJAX. 149 | 150 | ```js 151 | $(document).on('pjax:start', function () { 152 | if (window.aplayers) { 153 | for (let i = 0; i < window.aplayers.length; i++) { 154 | window.aplayers[i].destroy(); 155 | } 156 | window.aplayers = []; 157 | } 158 | }); 159 | ``` 160 | 161 | ## Customization (new in 3.0) 162 | 163 | You can configure `hexo-tag-aplayer` in `_config.yml`: 164 | 165 | ```yaml 166 | aplayer: 167 | script_dir: some/place # Script asset path in public directory, default: 'assets/js' 168 | style_dir: some/place # Style asset path in public directory, default: 'assets/css' 169 | cdn: http://xxx/aplayer.min.js # External APlayer.js url (CDN) 170 | style_cdn: http://xxx/aplayer.min.css # External APlayer.css url (CDN) 171 | meting: true # Meting support, default: false 172 | meting_api: http://xxx/api.php # Meting api url 173 | meting_cdn: http://xxx/Meing.min.js # External Meting.js url (CDN) 174 | asset_inject: true # Auto asset injection, default: true 175 | externalLink: http://xxx/aplayer.min.js # Deprecated, use 'cdn' instead 176 | ``` 177 | 178 | ## Troubleshoot 179 | 180 | ### Space within arguments 181 | 182 | Hexo has an [issue](https://github.com/hexojs/hexo/issues/1455) that cannot use space within tag arguments. 183 | 184 | If you encounter this problem, **install the latest (beta) version, and wrap the arguments within a string literal, for example:** 185 | 186 | ``` 187 | {% aplayer "Caffeine" "Jeff Williams" "caffeine.mp3" "autoplay" "width:70%" "lrc:caffeine.txt" %} 188 | ``` 189 | 190 | ### Duplicate APlayer.JS loading 191 | 192 | The plugin hooks filter `after_render:html` , and it would inject `APlayer.js` and `Meting.js` in `
`: 193 | 194 | ```html 195 | 196 | 197 | ... 198 | 199 | 200 | 201 | ... 202 | 203 | ``` 204 | 205 | However, `after_render:html` is not fired in some cases : 206 | 207 | + [Does not work with hexo-renderer-jade](https://github.com/hexojs/hexo-inject/issues/1) 208 | + `after_render:html` seems not to get emitted in default settings of hexo server module (`hexo server`), it means you have to use static serving mode( `hexo server -s`) instead. 209 | 210 | In such cases, the plugin would hook`after_post_render` as a fallback, which has a possibility to cause duplicate asset loadings. 211 | 212 | If you want to solve this issue definitely, you can disable this auto-injection feature in `_config.yml` and insert the scripts by yourself: 213 | 214 | ```yaml 215 | aplayer: 216 | asset_inject: false 217 | ``` 218 | 219 | ## LICENSE 220 | 221 | MIT 222 | -------------------------------------------------------------------------------- /common/constant.es: -------------------------------------------------------------------------------- 1 | export const APLAYER_TAG_MARKER = `aplayer-tag-marker` 2 | export const APLAYER_SCRIPT_MARKER = `aplayer-script-marker` 3 | export const APLAYER_SECONDARY_SCRIPT_MARKER = `aplayer-secondary-script-marker` 4 | export const APLAYER_STYLE_MARKER = `aplayer-style-marker` 5 | export const APLAYER_SECONDARY_STYLE_MARKER = `aplayer-secondary-style-marker` 6 | export const METING_TAG_MARKER = `meting-tag-marker` 7 | export const METING_SCRIPT_MARKER = `meting-script-marker` 8 | export const METING_SECONDARY_SCRIPT_MARKER = `meting-secondary-script-marker` 9 | 10 | export const PLAYER_TAG_OPTION = { 11 | title: '', author: '', url: '', pic: '', 12 | narrow: false, autoplay: false, width: '', 13 | lrcOption: false, lrcPath: '' 14 | } 15 | 16 | export const METING_TAG_OPTION = { 17 | id: '', server: '', type: '', mode: 'circulation', 18 | autoplay: false, mutex: true, listmaxheight: '340px', 19 | preload: 'auto', theme: '#ad7a86' 20 | } -------------------------------------------------------------------------------- /common/util.es: -------------------------------------------------------------------------------- 1 | const escapeRegExp = (str) => { 2 | return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1") 3 | } 4 | 5 | export const generateRandomString = function(length) { 6 | const ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' 7 | return Array.apply(null, {length}).map(() => ALPHABET.charAt(Math.floor(Math.random() * ALPHABET.length))).join('') 8 | } 9 | 10 | export const throwError = (message) => { 11 | throw new Error(`[hexo-tag-aplayer] ${message}`) 12 | } 13 | 14 | export const clone = (object) => { 15 | return JSON.parse(JSON.stringify(object)) 16 | } 17 | 18 | export const extractOptionValue = (pair) => { 19 | return pair.slice(pair.indexOf(':') + 1) 20 | } 21 | 22 | export const removeAll = (target, find) => { 23 | return target.replace(new RegExp(escapeRegExp(find), 'g'), '') 24 | } -------------------------------------------------------------------------------- /docs/README-zh_cn.md: -------------------------------------------------------------------------------- 1 | # hexo-tag-aplayer 2 | 3 |   4 | 5 | [APlayer](https://github.com/MoePlayer/APlayer) 播放器的 Hexo 标签插件(现已支持 [MetingJS](https://github.com/metowolf/MetingJS))。 6 | 7 | 8 | 9 | 10 | 11 | - [安装](#%E5%AE%89%E8%A3%85) 12 | - [依赖](#%E4%BE%9D%E8%B5%96) 13 | - [使用](#%E4%BD%BF%E7%94%A8) 14 | - [标签参数](#%E6%A0%87%E7%AD%BE%E5%8F%82%E6%95%B0) 15 | - [歌词标签](#%E6%AD%8C%E8%AF%8D%E6%A0%87%E7%AD%BE) 16 | - [播放列表](#%E6%92%AD%E6%94%BE%E5%88%97%E8%A1%A8) 17 | - [MeingJS 支持 (3.0 新功能)](#meingjs-%E6%94%AF%E6%8C%81-30-%E6%96%B0%E5%8A%9F%E8%83%BD) 18 | - [PJAX 兼容](#pjax-%E5%85%BC%E5%AE%B9) 19 | - [自定义配置(3.0 新功能)](#%E8%87%AA%E5%AE%9A%E4%B9%89%E9%85%8D%E7%BD%AE%EF%BC%8830-%E6%96%B0%E5%8A%9F%E8%83%BD%EF%BC%89) 20 | - [故障排除](#%E6%95%85%E9%9A%9C%E6%8E%92%E9%99%A4) 21 | - [标签参数空格问题](#%E6%A0%87%E7%AD%BE%E5%8F%82%E6%95%B0%E7%A9%BA%E6%A0%BC%E9%97%AE%E9%A2%98) 22 | - [重复载入 Aplayer.js 资源脚本问题](#%E9%87%8D%E5%A4%8D%E8%BD%BD%E5%85%A5-aplayerjs-%E8%B5%84%E6%BA%90%E8%84%9A%E6%9C%AC%E9%97%AE%E9%A2%98) 23 | - [LICENSE](#license) 24 | 25 | 26 | 27 | 28 | 29 |  30 | 31 | ## 安装 32 | 33 | ``` 34 | npm install --save hexo-tag-aplayer 35 | ``` 36 | 37 | ## 依赖 38 | 39 | + APlayer.js > 1.8.0 40 | + Meting.js > 1.1.1 41 | 42 | ## 使用 43 | 44 | ``` 45 | {% aplayer title author url [picture_url, narrow, autoplay, width:xxx, lrc:xxx] %} 46 | ``` 47 | 48 | ### 标签参数 49 | 50 | - `title` : 曲目标题 51 | - `author`: 曲目作者 52 | - `url`: 音乐文件 URL 地址 53 | - `picture_url`: (可选) 音乐对应的图片地址 54 | - `narrow`: (可选)播放器袖珍风格 55 | - `autoplay`: (可选) 自动播放,移动端浏览器暂时不支持此功能 56 | - `width:xxx`: (可选) 播放器宽度 (默认: 100%) 57 | - `lrc:xxx`: (可选)歌词文件 URL 地址 58 | 59 | 当开启 Hexo 的 [文章资源文件夹](https://hexo.io/zh-cn/docs/asset-folders.html#%E6%96%87%E7%AB%A0%E8%B5%84%E6%BA%90%E6%96%87%E4%BB%B6%E5%A4%B9) 功能时,可以将图片、音乐文件、歌词文件放入与文章对应的资源文件夹中,然后直接引用: 60 | 61 | ``` 62 | {% aplayer "Caffeine" "Jeff Williams" "caffeine.mp3" "picture.jpg" "lrc:caffeine.txt" %} 63 | ``` 64 | 65 | ### 歌词标签 66 | 67 | 除了使用标签 `lrc` 选项来设定歌词,你也可以直接使用 `aplayerlrc` 标签来直接插入歌词文本在博客中: 68 | 69 | ``` 70 | {% aplayerlrc "title" "author" "url" "autoplay" %} 71 | [00:00.00]lrc here 72 | {% endaplayerlrc %} 73 | ``` 74 | 75 | ### 播放列表 76 | 77 | ``` 78 | {% aplayerlist %} 79 | { 80 | "narrow": false, // (可选)播放器袖珍风格 81 | "autoplay": true, // (可选) 自动播放,移动端浏览器暂时不支持此功能 82 | "mode": "random", // (可选)曲目循环类型,有 'random'(随机播放), 'single' (单曲播放), 'circulation' (循环播放), 'order' (列表播放), 默认:'circulation' 83 | "showlrc": 3, // (可选)歌词显示配置项,可选项有:1,2,3 84 | "mutex": true, // (可选)该选项开启时,如果同页面有其他 aplayer 播放,该播放器会暂停 85 | "theme": "#e6d0b2", // (可选)播放器风格色彩设置,默认:#b7daff 86 | "preload": "metadata", // (可选)音乐文件预载入模式,可选项: 'none' 'metadata' 'auto', 默认: 'auto' 87 | "listmaxheight": "513px", // (可选) 该播放列表的最大长度 88 | "music": [ 89 | { 90 | "title": "CoCo", 91 | "author": "Jeff Williams", 92 | "url": "caffeine.mp3", 93 | "pic": "caffeine.jpeg", 94 | "lrc": "caffeine.txt" 95 | }, 96 | { 97 | "title": "アイロニ", 98 | "author": "鹿乃", 99 | "url": "irony.mp3", 100 | "pic": "irony.jpg" 101 | } 102 | ] 103 | } 104 | {% endaplayerlist %} 105 | ``` 106 | 107 | ### MeingJS 支持 (3.0 新功能) 108 | 109 | [MetingJS](https://github.com/metowolf/MetingJS) 是基于[Meting API](https://github.com/metowolf/Meting) 的 APlayer 衍生播放器,引入 MetingJS 后,播放器将支持对于 QQ音乐、网易云音乐、虾米、酷狗、百度等平台的音乐播放。 110 | 111 | 如果想在本插件中使用 MetingJS,请在 Hexo 配置文件 `_config.yml` 中设置: 112 | 113 | ```yaml 114 | aplayer: 115 | meting: true 116 | ``` 117 | 118 | 接着就可以通过 `{% meting ...%}` 在文章中使用 MetingJS 播放器了: 119 | 120 | ``` 121 | 122 | {% meting "60198" "netease" "playlist" %} 123 | 124 | 125 | {% meting "60198" "netease" "playlist" "autoplay" "mutex:false" "listmaxheight:340px" "preload:none" "theme:#ad7a86"%} 126 | ``` 127 | 128 | 有关 `{% meting %}` 的选项列表如下: 129 | 130 | | 选项 | 默认值 | 描述 | 131 | | ------------- | ---------- | ----------------------------------------------------------- | 132 | | id | **必须值** | 歌曲 id / 播放列表 id / 相册 id / 搜索关键字 | 133 | | server | **必须值** | 音乐平台: `netease`, `tencent`, `kugou`, `xiami`, `baidu` | 134 | | type | **必须值** | `song`, `playlist`, `album`, `search`, `artist` | 135 | | fixed | `false` | 开启固定模式 | 136 | | mini | `false` | 开启迷你模式 | 137 | | loop | `all` | 列表循环模式:`all`, `one`,`none` | 138 | | order | `list` | 列表播放模式: `list`, `random` | 139 | | volume | 0.7 | 播放器音量 | 140 | | lrctype | 0 | 歌词格式类型 | 141 | | listfolded | `false` | 指定音乐播放列表是否折叠 | 142 | | storagename | `metingjs` | LocalStorage 中存储播放器设定的键名 | 143 | | autoplay | `true` | 自动播放,移动端浏览器暂时不支持此功能 | 144 | | mutex | `true` | 该选项开启时,如果同页面有其他 aplayer 播放,该播放器会暂停 | 145 | | listmaxheight | `340px` | 播放列表的最大长度 | 146 | | preload | `auto` | 音乐文件预载入模式,可选项: `none`, `metadata`, `auto` | 147 | | theme | `#ad7a86` | 播放器风格色彩设置 | 148 | 149 | 关于如何设置自建的 Meting API 服务器地址,以及其他 MetingJS 配置,请参考章节[自定义配置](#%E8%87%AA%E5%AE%9A%E4%B9%89%E9%85%8D%E7%BD%AE30-%E6%96%B0%E5%8A%9F%E8%83%BD) 150 | 151 | ### PJAX 兼容 152 | 153 | 若在 Hexo 中使用了 PJAX,可能需要自己手动清理 APlayer 全局实例: 154 | 155 | ```js 156 | $(document).on('pjax:start', function () { 157 | if (window.aplayers) { 158 | for (let i = 0; i < window.aplayers.length; i++) { 159 | window.aplayers[i].destroy(); 160 | } 161 | window.aplayers = []; 162 | } 163 | }); 164 | ``` 165 | 166 | ## 自定义配置(3.0 新功能) 167 | 168 | 现在你可以在 Hexo 配置文件 `_config.yml` 中配置本插件: 169 | 170 | ```yaml 171 | aplayer: 172 | script_dir: some/place # Public 目录下脚本目录路径,默认: 'assets/js' 173 | style_dir: some/place # Public 目录下样式目录路径,默认: 'assets/css' 174 | cdn: http://xxx/aplayer.min.js # 引用 APlayer.js 外部 CDN 地址 (默认不开启) 175 | style_cdn: http://xxx/aplayer.min.css # 引用 APlayer.css 外部 CDN 地址 (默认不开启) 176 | meting: true # MetingJS 支持 177 | meting_api: http://xxx/api.php # 自定义 Meting API 地址 178 | meting_cdn: http://xxx/Meing.min.js # 引用 Meting.js 外部 CDN 地址 (默认不开启) 179 | asset_inject: true # 自动插入 Aplayer.js 与 Meting.js 资源脚本, 默认开启 180 | externalLink: http://xxx/aplayer.min.js # 老版本参数,功能与参数 cdn 相同 181 | ``` 182 | 183 | ## 故障排除 184 | 185 | ### 标签参数空格问题 186 | 187 | 在 Hexo 标签中,用户可能无法直接在标签参数中[加入空格](https://github.com/hexojs/hexo/issues/1455) 188 | 189 | 如果遇到这类问题,请直接将参数用双引号括起来使用,如下所示: 190 | 191 | ``` 192 | {% aplayer "Caffeine" "Jeff Williams" "caffeine.mp3" "autoplay" "width:70%" "lrc:caffeine.txt" %} 193 | ``` 194 | 195 | ### 重复载入 Aplayer.js 资源脚本问题 196 | 197 | 本插件通过 `after_render:html`过滤器 , 将 `APlayer.js` 和 `Meting.js` 插入到使用了本插件标签 的 HTML 文件中: 198 | 199 | ```html 200 | 201 | 202 | ... 203 | 204 | 205 | 206 | ... 207 | 208 | ``` 209 | 210 | 但是 `after_render:html` 在一些情形下可能无法被正常触发: 211 | 212 | - [Does not work with hexo-renderer-jade](https://github.com/hexojs/hexo-inject/issues/1) 213 | - `after_render:html` 似乎在 Hexo 服务器模式默认配置中无法被调用 (`hexo server`), 遇到这种情况用户可能需要使用 `hexo-server` 的静态文件解析模式 ( `hexo server -s`) . 214 | 215 | 如果在博客生成过程中,插件发现 `after_render:html` 没有被调用,那么插件将会通过 `after_post_render` 过滤器来植入脚本。但是使用 `after_post_render` 会有重复载入 `APlayer.js` 的情况(例如当一个页面中存在多篇博客时),以及一些非文章页面将无法使用本插件。 216 | 217 | 如果想完全解决这个问题,用户可能需要自己在主题文件中手动加入 `Aplayer.js` 与 `Meting.js`,同时关闭插件的自动脚本插入功能: 218 | 219 | ```yaml 220 | aplayer: 221 | asset_inject: false 222 | ``` 223 | 224 | ## LICENSE 225 | 226 | MIT -------------------------------------------------------------------------------- /gulpfile.babel.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import gulp from 'gulp'; 4 | import babel from 'gulp-babel'; 5 | import rename from 'gulp-rename'; 6 | import clean from 'gulp-clean'; 7 | import watch from 'gulp-watch'; 8 | import plumber from 'gulp-plumber'; 9 | 10 | const LOCAL_ENV_PATH = process.env.HEXO_TAG_APLAYER_LOCAL_PATH; 11 | const sources = ['index.es', 'lib/**/*.es', 'common/**/*.es']; 12 | const resetExt = (path) => { 13 | path.extname = '.js'; 14 | console.log(JSON.stringify(path)) 15 | }; 16 | 17 | gulp.task('default', ['build']); 18 | 19 | gulp.task('build', () => { 20 | return gulp.src(sources, {base: '.'}) 21 | .pipe(babel({ 22 | 'presets': ['es2015'] 23 | })) 24 | .pipe(rename(resetExt)) 25 | .pipe(gulp.dest('.')); 26 | }); 27 | 28 | gulp.task('local-test', () => { 29 | return gulp.src(sources, {base: '.'}) 30 | .pipe(babel({ 31 | 'presets': ['es2015'] 32 | })) 33 | .pipe(rename(resetExt)) 34 | .pipe(gulp.dest(LOCAL_ENV_PATH)); 35 | }); 36 | 37 | gulp.task('clean', () => { 38 | const builds = sources.map((s) => s.replace('es', 'js')); 39 | return gulp.src(builds, {read: false}) 40 | .pipe(clean()); 41 | }); 42 | 43 | gulp.task('watch', () => { 44 | return watch(sources, () => { 45 | return gulp.src(sources, {base: '.'}) 46 | .pipe(watch(sources)) 47 | .pipe(plumber(err => console.log(err.stack))) 48 | .pipe(babel({ 49 | 'presets': ['es2015'] 50 | })) 51 | .pipe(plumber.stop()) 52 | .pipe(rename(resetExt)) 53 | .pipe(gulp.dest(LOCAL_ENV_PATH)); 54 | }); 55 | }); -------------------------------------------------------------------------------- /index.deprecated.es: -------------------------------------------------------------------------------- 1 | /** 2 | * hexo-tag-aplayer 3 | * https://github.com/grzhan/hexo-tag-aplayer 4 | * Copyright (c) 2016, grzhan 5 | * Licensed under the MIT license. 6 | * 7 | * Syntax: 8 | * {% aplayer title author url [picture_url, narrow, autoplay] %} 9 | */ 10 | require('babel-polyfill'); 11 | let counter = 0; 12 | const fs = require('hexo-fs'), 13 | util = require('hexo-util'), 14 | path = require('path'), 15 | urllib = require('url'), 16 | srcDir = path.dirname(require.resolve('aplayer')), 17 | scriptDir = path.join('assets', 'js/'), 18 | aplayerScript = 'APlayer.min.js', 19 | registers = [ 20 | [aplayerScript, scriptDir + aplayerScript, path.join(srcDir, aplayerScript)] 21 | ]; 22 | 23 | const preProcessUrl = (id, url) => { 24 | if (url.startsWith('https://') || url.startsWith('http://') || url.startsWith('/')) { 25 | return url; 26 | } 27 | const PostAsset = hexo.model('PostAsset') 28 | const asset = PostAsset.findOne({post: id, slug: url}); 29 | if (!asset) throw new Error(`Specified music file not found ${url}`); 30 | return urllib.resolve(hexo.config.root, asset.path); 31 | }; 32 | 33 | registers.forEach((register) => { 34 | const [regName, path, srcPath] = register; 35 | hexo.extend.generator.register(regName, () => { 36 | return { 37 | path, 38 | config() { 39 | return fs.createReadStream(srcPath); 40 | } 41 | }; 42 | }); 43 | }); 44 | 45 | const generateAPlayerUrl = () => { 46 | const aplayerConfig = hexo.config.aplayer || {}; 47 | if (aplayerConfig.externalLink) { 48 | return aplayerConfig.externalLink; 49 | } else { 50 | const root = hexo.config.root ? hexo.config.root : '/'; 51 | return path.join(root, '/', scriptDir, aplayerScript); 52 | } 53 | }; 54 | 55 | hexo.extend.filter.register('after_post_render', (data) => { 56 | data.content = 57 | util.htmlTag('script', {src: generateAPlayerUrl()}, ' ') + 58 | data.content; 59 | return data; 60 | }); 61 | 62 | // {% aplayer title author url [picture_url, narrow, autoplay] %} 63 | hexo.extend.tag.register('aplayer', function(args) { 64 | let [title, author, url] = args, lrcPath = '', 65 | narrow = false, autoplay = false, lrcOpt = false, width = '', 66 | pic = args[3] && args[3] !== 'narrow' && args[3] !== 'autoplay' 67 | && !args[3].includes('lrc:') && !args[3].includes('width:') ? preProcessUrl(this._id, args[3]) : '', 68 | id = 'aplayer' + (counter++), raw = '', content = ''; 69 | url = preProcessUrl(this._id, url); 70 | // Parse optional arguments 71 | if (args.length > 3) { 72 | let options = args.slice(3); 73 | narrow = options.includes('narrow'); 74 | autoplay = options.includes('autoplay'); 75 | for (let i = 0; i < options.length; i++) { 76 | let option = options[i]; 77 | lrcOpt = option.indexOf('lrc:') == 0 ? true : lrcOpt; 78 | lrcPath = option.indexOf('lrc:') == 0 ? option.slice(option.indexOf(':') + 1) : lrcPath; 79 | width = option.indexOf('width:') == 0 ? option + ';' : width; 80 | } 81 | } 82 | width = narrow ? '' : width; 83 | raw = `${content}`; 91 | } 92 | } 93 | raw += 94 | `
${content}135 |
${content}61 |
${this.lyrics}43 |