Compare commits
No commits in common. "master" and "1.5.4" have entirely different histories.
|
|
@ -1,3 +0,0 @@
|
||||||
dist
|
|
||||||
demo
|
|
||||||
docs
|
|
||||||
56
.eslintrc
|
|
@ -1,56 +0,0 @@
|
||||||
{
|
|
||||||
"extends": ["eslint:recommended", "plugin:prettier/recommended"],
|
|
||||||
"plugins": ["prettier"],
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 2018,
|
|
||||||
"sourceType": "module"
|
|
||||||
},
|
|
||||||
"env": {
|
|
||||||
"es6": true,
|
|
||||||
"browser": true,
|
|
||||||
"node": true,
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"block-scoped-var": 1,
|
|
||||||
"curly": 1,
|
|
||||||
"eqeqeq": 1,
|
|
||||||
"no-global-assign": 1,
|
|
||||||
"no-implicit-globals": 1,
|
|
||||||
"no-labels": 1,
|
|
||||||
"no-multi-str": 1,
|
|
||||||
"comma-spacing": 1,
|
|
||||||
"comma-style": 1,
|
|
||||||
"func-call-spacing": 1,
|
|
||||||
"keyword-spacing": 1,
|
|
||||||
"linebreak-style": 1,
|
|
||||||
"no-multiple-empty-lines": 1,
|
|
||||||
"space-infix-ops": 1,
|
|
||||||
"arrow-spacing": 1,
|
|
||||||
"no-var": 1,
|
|
||||||
"prefer-const": 1,
|
|
||||||
"no-unsafe-negation": 1,
|
|
||||||
"array-callback-return": 1,
|
|
||||||
"dot-notation": 1,
|
|
||||||
"no-eval": 1,
|
|
||||||
"no-extend-native": 1,
|
|
||||||
"no-extra-label": 1,
|
|
||||||
"semi": 1,
|
|
||||||
"space-before-blocks": 1,
|
|
||||||
"space-in-parens": 1,
|
|
||||||
"space-unary-ops": 1,
|
|
||||||
"spaced-comment": 1,
|
|
||||||
"arrow-body-style": 1,
|
|
||||||
"arrow-parens": 1,
|
|
||||||
"no-restricted-imports": 1,
|
|
||||||
"no-duplicate-imports": 1,
|
|
||||||
"no-useless-computed-key": 1,
|
|
||||||
"no-useless-rename": 1,
|
|
||||||
"rest-spread-spacing": 1,
|
|
||||||
"no-trailing-spaces": 1,
|
|
||||||
"no-control-regex": 0,
|
|
||||||
"prettier/prettier": 0,
|
|
||||||
"no-await-in-loop": 1,
|
|
||||||
"require-atomic-updates": 0,
|
|
||||||
"no-prototype-builtins": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
中文用户请注意:请尽量用**英文**描述你的 issue,这样能够让尽可能多的人帮到你。
|
|
||||||
|
|
||||||
If you want to report a bug, please provide the following information:
|
|
||||||
|
|
||||||
- The steps to reproduce.
|
|
||||||
- A minimal demo of the problem via https://jsfiddle.net or http://codepen.io/pen if possible.
|
|
||||||
- Which versions of APlayer, and which browser / OS are affected by this issue?
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
dist
|
|
||||||
demo
|
|
||||||
docs
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"printWidth": 233,
|
|
||||||
"tabWidth": 4,
|
|
||||||
"singleQuote": true,
|
|
||||||
"trailingComma": "es5",
|
|
||||||
"arrowParens": "always"
|
|
||||||
}
|
|
||||||
11
.travis.yml
|
|
@ -1,12 +1,3 @@
|
||||||
language: node_js
|
language: node_js
|
||||||
|
|
||||||
node_js:
|
node_js:
|
||||||
- lts/*
|
- "4.0"
|
||||||
|
|
||||||
script:
|
|
||||||
- npm run build
|
|
||||||
|
|
||||||
cache:
|
|
||||||
yarn: true
|
|
||||||
directories:
|
|
||||||
- node_modules
|
|
||||||
22
LICENSE
|
|
@ -1,6 +1,8 @@
|
||||||
The MIT License (MIT)
|
The Star And Thank Author License (SATA)
|
||||||
|
|
||||||
Copyright (c) DIYgod <diy.d.god@gmail.com> (https://www.anotherhome.net/)
|
Copyright (c) 2016 DIYgod(i@html.love)
|
||||||
|
|
||||||
|
Project Url: https://github.com/DIYgod/APlayer
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
@ -12,10 +14,24 @@ furnished to do so, subject to the following conditions:
|
||||||
The above copyright notice and this permission notice shall be included in
|
The above copyright notice and this permission notice shall be included in
|
||||||
all copies or substantial portions of the Software.
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
And wait, the most important, you shall star/+1/like the project(s) in project url
|
||||||
|
section above first, and then thank the author(s) in Copyright section.
|
||||||
|
|
||||||
|
Here are some suggested ways:
|
||||||
|
|
||||||
|
- Email the authors a thank-you letter, and make friends with him/her/them.
|
||||||
|
- Report bugs or issues.
|
||||||
|
- Tell friends what a wonderful project this is.
|
||||||
|
- And, sure, you can just express thanks in your mind without telling the world.
|
||||||
|
|
||||||
|
Contributors of this project by forking have the option to add his/her name and
|
||||||
|
forked project url at copyright and project url sections, but shall not delete
|
||||||
|
or modify anything else in these two sections.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
291
README.md
|
|
@ -1,115 +1,222 @@
|
||||||
<p align="center">
|
# APlayer
|
||||||
<img src="https://i.imgur.com/LnPvZvO.png" alt="ADPlayer" width="100">
|
|
||||||
</p>
|
|
||||||
<h1 align="center">APlayer</h1>
|
|
||||||
|
|
||||||
> Wow, such a lovely HTML5 music player
|
|
||||||
|
|
||||||
[](https://www.npmjs.com/package/aplayer)
|
[](https://www.npmjs.com/package/aplayer)
|
||||||
[](https://github.com/MoePlayer/APlayer/blob/master/LICENSE)
|
[](https://github.com/DIYgod/APlayer/blob/master/LICENSE)
|
||||||
|
[](https://david-dm.org/DIYgod/APlayer#info=devDependencies)
|
||||||
[](https://www.npmjs.com/package/aplayer)
|
[](https://www.npmjs.com/package/aplayer)
|
||||||
[](https://github.com/MoePlayer/APlayer/tree/master/dist)
|
[](https://travis-ci.org/DIYgod/APlayer)
|
||||||
[](https://travis-ci.org/MoePlayer/APlayer)
|
[](https://gitter.im/diygod233/aplayer)
|
||||||
[](https://david-dm.org/MoePlayer/APlayer#info=devDependencies)
|
[](https://www.anotherhome.net/)
|
||||||
[](https://github.com/MoePlayer/APlayer#donate)
|
|
||||||
|
> Wow, such a beautiful html5 music player
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
|
|
||||||
|
[Demo](http://aplayer.js.org)
|
||||||
|
|
||||||
|
Screenshot
|
||||||

|

|
||||||
|
|
||||||
APlayer is a lovely HTML5 music player.
|
## Install
|
||||||
|
|
||||||
**APlayer supports:**
|
```
|
||||||
|
$ npm install aplayer --save
|
||||||
|
```
|
||||||
|
|
||||||
- Media formats - MP4 H.264 (AAC or MP3) - WAVE PCM - Ogg Theora Vorbis
|
## CDN
|
||||||
- Features - Playlist - Lyrics
|
|
||||||
|
|
||||||
Using APlayer on your project? [Let me know!](https://github.com/MoePlayer/APlayer/issues/79)
|
[cdnjs](https://cdnjs.com/libraries/aplayer)
|
||||||
|
|
||||||
**[Docs](https://aplayer.js.org)**
|
## Usage
|
||||||
|
|
||||||
**[中文文档](https://aplayer.js.org/#/zh-Hans/)**
|
### HTML
|
||||||
|
|
||||||
## Join the Discussion
|
```HTML
|
||||||
|
<div id="player1" class="aplayer"></div>
|
||||||
|
<!-- ... -->
|
||||||
|
<script src="APlayer.min.js"></script>
|
||||||
|
```
|
||||||
|
|
||||||
- [Telegram Group](https://t.me/adplayer)
|
### JS
|
||||||
- [QQ Group](https://shang.qq.com/wpa/qunwpa?idkey=bf22213ae0028a82e5adf3f286dfd4f01e0997dc9f1dcd8e831a0a85e799be17): 415835947
|
|
||||||
|
```JS
|
||||||
|
var ap = new APlayer(option);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Options
|
||||||
|
|
||||||
|
```JS
|
||||||
|
var option = {
|
||||||
|
element: document.getElementById('player1'), // Optional, player element
|
||||||
|
narrow: false, // Optional, narrow style
|
||||||
|
autoplay: true, // Optional, autoplay song(s), not supported by mobile browsers
|
||||||
|
showlrc: 0, // Optional, show lrc, can be 0, 1, 2, see: ###With lrc
|
||||||
|
mutex: true, // Optional, pause other players when this player playing
|
||||||
|
theme: '#e6d0b2', // Optional, theme color, default: #b7daff
|
||||||
|
mode: 'random', // Optional, play mode, can be `random` `single` `circulation`(loop) `order`(no loop), default: `circulation`
|
||||||
|
preload: 'metadata', // Optional, the way to load music, can be 'none' 'metadata' 'auto', default: 'auto'
|
||||||
|
listmaxheight: '513px', // Optional, max height of play list
|
||||||
|
music: { // Required, music info, see: ###With playlist
|
||||||
|
title: 'Preparation', // Required, music title
|
||||||
|
author: 'Hans Zimmer/Richard Harvey', // Required, music author
|
||||||
|
url: 'http://7xifn9.com1.z0.glb.clouddn.com/Preparation.mp3', // Required, music url
|
||||||
|
pic: 'http://7xifn9.com1.z0.glb.clouddn.com/Preparation.jpg', // Optional, music picture
|
||||||
|
lrc: '[00:00.00]lrc here\n[00:01.00]aplayer' // Optional, lrc, see: ###With lrc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### API
|
||||||
|
|
||||||
|
+ `ap.play()` // Resume play
|
||||||
|
+ `ap.play(time)` // Set currentTime
|
||||||
|
+ `ap.pause()` // Pause
|
||||||
|
+ `ap.toggle()` // Toggle between play and pause
|
||||||
|
+ `ap.volume(percentage)` // Set volume
|
||||||
|
+ `ap.on(event, handler)` // Event binding
|
||||||
|
+ `ap.setMusic(index)` // Switch music
|
||||||
|
+ `ap.lrc` // Lrc time and text
|
||||||
|
+ `ap.playIndex` // Current playing index
|
||||||
|
+ `ap.audio` // Return native video, most [native api](http://www.w3schools.com/tags/ref_av_dom.asp) are supported
|
||||||
|
+ `dp.audio.currentTime` // Returns the current playback position
|
||||||
|
+ Most [native api](http://www.w3schools.com/tags/ref_av_dom.asp)
|
||||||
|
|
||||||
|
#### Event binding
|
||||||
|
|
||||||
|
`ap.on(event, handler)`
|
||||||
|
|
||||||
|
`event`:
|
||||||
|
+ `play`: Triggered when APlayer start play
|
||||||
|
+ `pause`: Triggered when APlayer paused
|
||||||
|
+ `canplay`: Triggered when enough data is available that APlayer can be played
|
||||||
|
+ `playing`: Triggered periodically when APlayer is playing
|
||||||
|
+ `ended`: Triggered when APlayer ended
|
||||||
|
+ `error`: Triggered when an error occurs
|
||||||
|
|
||||||
|
#### Work with module bundler
|
||||||
|
|
||||||
|
```js
|
||||||
|
var APlayer = require('APlayer');
|
||||||
|
var ap = new APlayer({
|
||||||
|
// ...
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### With lrc
|
||||||
|
|
||||||
|
Show lrc, you can put LRC in JS or HTML as you like.
|
||||||
|
|
||||||
|
#### LRC format:
|
||||||
|
|
||||||
|
Support multiple time tag, support three decimal second
|
||||||
|
|
||||||
|
```
|
||||||
|
[mm:ss.xx]lyric
|
||||||
|
[mm:ss.xxx]lyric
|
||||||
|
[mm:ss.xx][mm:ss.xx][mm:ss.xx]lyric
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
#### LRC in JS:
|
||||||
|
|
||||||
|
JS:
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
showlrc: 1,
|
||||||
|
music: {
|
||||||
|
lrc: '[00:00.00]lrc here\n[00:01.00]aplayer' // lrc here, separate lines with \n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### LRC in HTML:
|
||||||
|
|
||||||
|
JS:
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
showlrc: 2
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
HTML:
|
||||||
|
|
||||||
|
```HTML
|
||||||
|
<div id="player1" class="aplayer">
|
||||||
|
<pre class="aplayer-lrc-content">
|
||||||
|
[00:00.00]平凡之路 - 朴树
|
||||||
|
[00:04.01]作词:韩寒 朴树
|
||||||
|
[00:08.02]作曲:朴树 编曲:朴树
|
||||||
|
[00:12.02]徘徊着的 在路上的
|
||||||
|
[00:17.37]你要走吗
|
||||||
|
[00:23.20]易碎的 骄傲着
|
||||||
|
<!-- ... -->
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### LRC in lrc file or API:
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
showlrc: 3,
|
||||||
|
music: {
|
||||||
|
lrc: 'path/to/music.lrc'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### With playlist
|
||||||
|
|
||||||
|
Show multiple music.
|
||||||
|
|
||||||
|
#### JS:
|
||||||
|
|
||||||
|
Option:
|
||||||
|
|
||||||
|
```JS
|
||||||
|
music: [
|
||||||
|
{
|
||||||
|
title: '',
|
||||||
|
author: '',
|
||||||
|
url: '',
|
||||||
|
pic: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '',
|
||||||
|
author: '',
|
||||||
|
url: '',
|
||||||
|
pic: ''
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run in development
|
||||||
|
|
||||||
|
```
|
||||||
|
$ npm install
|
||||||
|
$ npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## Make a release
|
||||||
|
|
||||||
|
```
|
||||||
|
$ npm install
|
||||||
|
$ npm run build
|
||||||
|
```
|
||||||
|
|
||||||
## Related Projects
|
## Related Projects
|
||||||
|
|
||||||
### Plugins
|
- [APlayer-Typecho-Plugin](https://github.com/zgq354/APlayer-Typecho-Plugin)
|
||||||
|
|
||||||
- [APlayer-Typecho-Plugin](https://github.com/zgq354/APlayer-Typecho-Plugin): Typecho
|
- [hexo-tag-aplayer](https://github.com/grzhan/hexo-tag-aplayer)
|
||||||
- [hexo-tag-aplayer](https://github.com/grzhan/hexo-tag-aplayer): Hexo
|
|
||||||
- [Hermit-X(APlayer for WordPress)](https://github.com/liwanglin12/Hermit-X): WordPress
|
|
||||||
- [APlayerHandle](https://github.com/kn007/APlayerHandle): WordPress
|
|
||||||
- [APlayer_for_Z-BlogPHP](https://github.com/fghrsh/APlayer_for_Z-BlogPHP): Z-BlogPHP
|
|
||||||
- [react-aplayer](https://github.com/sabrinaluo/react-aplayer): React
|
|
||||||
- [Vue-APlayer](https://github.com/SevenOutman/vue-aplayer): Vue
|
|
||||||
- [vue-aplayer](https://github.com/MoeFE/vue-aplayer): Vue
|
|
||||||
- [php-aplayer](https://github.com/Daryl-L/php-aplayer): PHP
|
|
||||||
- [aplayer-hugo-module](https://github.com/Runzelee/aplayer-hugo-module): Hugo
|
|
||||||
|
|
||||||
### Tooling
|
- [163music-APlayer-you-get-docker](https://github.com/YUX-IO/163music-APlayer-you-get-docker)
|
||||||
|
|
||||||
- [APlayer-Controler](https://github.com/Mashiro-Sorata/APlayer-Controler): controling tool
|
- [Hermit-X(APlayer for WordPress)](https://github.com/liwanglin12/Hermit-X)
|
||||||
- [MetingJS](https://github.com/metowolf/MetingJS): work with Meting music API
|
|
||||||
- Feel free to submit yours in [`Let me know!`](https://github.com/MoePlayer/APlayer/issues/79)
|
|
||||||
|
|
||||||
## Who use APlayer?
|
## LICENSE
|
||||||
|
|
||||||
- [bilibili](https://www.bilibili.com/): 国内知名的视频弹幕网站
|
[The Star And Thank Author License (SATA)](https://github.com/DIYgod/APlayer/blob/master/LICENSE)
|
||||||
- [黑客派](https://hacpai.com/): 程序员和设计师的聚集地,一个活跃的小众社区
|
|
||||||
- [浙江大学 CC98 论坛](https://zh.wikipedia.org/wiki/CC98%E8%AE%BA%E5%9D%9B): 浙江大学校网内规模最大的论坛,中国各大学中较活跃的 BBS 之一
|
|
||||||
- [Jelly Rue](http://jellyrue.com/): Jelly Rue, an indie pop-rock band from Tartu.
|
|
||||||
- [Opus](http://www.opusopus.co/): An artist-exploration data visualization application
|
|
||||||
- [站长之家](http://www.chinaz.com/15year/index.html): 针对中文站点提供资讯、技术、资源、服务
|
|
||||||
- [LLSupport](https://www.lovelivesupport.com/): This site provides a lot of information about LoveLive
|
|
||||||
- [歌词千寻](https://www.lrcgc.com/diy): 每日更新的 LRC 歌词网站
|
|
||||||
- [iSearch](http://i.oppsu.cn): 一个提供 iTunes 搜索,试听,高清专辑封面获取,查看最新音乐动态等综合性平台
|
|
||||||
- [LRC 歌词编辑器](https://github.com/MoeFE/Lyric): 一款非常实用的在线 LRC 歌词编辑器
|
|
||||||
- [Аэростатика](https://aerostatica.ru/)
|
|
||||||
- [HealthDig](https://healthdig.co): 每天只需两分钟的重点新闻资讯
|
|
||||||
- Feel free to submit yours in [`Let me know!`](https://github.com/MoePlayer/APlayer/issues/79)
|
|
||||||
|
|
||||||
## Current Premium Sponsors
|
|
||||||
|
|
||||||
### Special Sponsors
|
|
||||||
|
|
||||||
<a href="https://www.dogecloud.com/?ref=dplayer" target="_blank">
|
|
||||||
<img width="222px" src="https://player.dogecloud.com/img/logo_with_product3.png">
|
|
||||||
</a>
|
|
||||||
|
|
||||||
## Contributors
|
|
||||||
|
|
||||||
This project exists thanks to all the people who contribute.
|
|
||||||
|
|
||||||
<a href="https://github.com/MoePlayer/APlayer/graphs/contributors"><img src="https://opencollective.com/APlayer/contributors.svg?width=890" /></a>
|
|
||||||
|
|
||||||
## Donate
|
|
||||||
|
|
||||||
APlayer is an MIT licensed open source project and completely free to use. However, the amount of effort needed to maintain and develop new features for the project is not sustainable without proper financial backing.
|
|
||||||
|
|
||||||
You can support APlayer via donations.
|
|
||||||
|
|
||||||
### Recurring Donation
|
|
||||||
|
|
||||||
- Become a Sponser on [GitHub](https://github.com/sponsors/DIYgod)
|
|
||||||
- Become a Sponser on [Patreon](https://www.patreon.com/DIYgod)
|
|
||||||
- Become a Sponser on [爱发电](https://afdian.net/@diygod)
|
|
||||||
- Contact us directly: i@diygod.me
|
|
||||||
|
|
||||||
### One-time Donation
|
|
||||||
|
|
||||||
We accept donations via the following ways:
|
|
||||||
|
|
||||||
- [WeChat Pay](https://diygod.me/images/wx.jpg)
|
|
||||||
- [Alipay](https://diygod.me/images/zfb.jpg)
|
|
||||||
- [Paypal](https://www.paypal.me/DIYgod)
|
|
||||||
|
|
||||||
## Author
|
|
||||||
|
|
||||||
**APlayer** © [DIYgod](https://github.com/DIYgod), Released under the [MIT](./LICENSE) License.<br>
|
|
||||||
Authored and maintained by DIYgod with help from contributors ([list](https://github.com/DIYgod/APlayer/contributors)).
|
|
||||||
|
|
||||||
> [Blog](https://diygod.me) · GitHub [@DIYgod](https://github.com/DIYgod) · Twitter [@DIYgod](https://twitter.com/DIYgod) · Telegram Channel [@awesomeDIYgod](https://t.me/awesomeDIYgod)
|
|
||||||
255
demo/demo.js
|
|
@ -1,17 +1,18 @@
|
||||||
const ap1 = new APlayer({
|
var ap1 = new APlayer({
|
||||||
element: document.getElementById('player1'),
|
element: document.getElementById('player1'),
|
||||||
mini: false,
|
narrow: false,
|
||||||
autoplay: false,
|
autoplay: true,
|
||||||
lrcType: false,
|
showlrc: false,
|
||||||
mutex: true,
|
mutex: true,
|
||||||
|
theme: '#e6d0b2',
|
||||||
preload: 'metadata',
|
preload: 'metadata',
|
||||||
audio: [{
|
mode: 'circulation',
|
||||||
name: '光るなら',
|
music: {
|
||||||
artist: 'Goose house',
|
title: 'Preparation',
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3',
|
author: 'Hans Zimmer/Richard Harvey',
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg',
|
url: 'http://devtest.qiniudn.com/Preparation.mp3',
|
||||||
theme: '#ebd0c2'
|
pic: 'http://devtest.qiniudn.com/Preparation.jpg'
|
||||||
}]
|
}
|
||||||
});
|
});
|
||||||
ap1.on('play', function () {
|
ap1.on('play', function () {
|
||||||
console.log('play');
|
console.log('play');
|
||||||
|
|
@ -35,181 +36,99 @@ ap1.on('error', function () {
|
||||||
console.log('error');
|
console.log('error');
|
||||||
});
|
});
|
||||||
|
|
||||||
const ap2 = new APlayer({
|
var ap2 = new APlayer({
|
||||||
element: document.getElementById('player2'),
|
element: document.getElementById('player2'),
|
||||||
mini: true,
|
narrow: true,
|
||||||
autoplay: false,
|
autoplay: false,
|
||||||
lrcType: false,
|
showlrc: false,
|
||||||
mutex: true,
|
mutex: true,
|
||||||
audio: [{
|
theme: '#e6d0b2',
|
||||||
name: '光るなら',
|
mode: 'circulation',
|
||||||
artist: 'Goose house',
|
music: {
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3',
|
title: 'Preparation',
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg',
|
author: 'Hans Zimmer/Richard Harvey',
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.lrc',
|
url: 'http://devtest.qiniudn.com/Preparation.mp3',
|
||||||
theme: '#ebd0c2'
|
pic: 'http://devtest.qiniudn.com/Preparation.jpg'
|
||||||
}]
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const ap3 = new APlayer({
|
var ap3 = new APlayer({
|
||||||
element: document.getElementById('player3'),
|
element: document.getElementById('player3'),
|
||||||
mini: false,
|
narrow: false,
|
||||||
autoplay: false,
|
autoplay: false,
|
||||||
lrcType: 3,
|
showlrc: 3,
|
||||||
mutex: true,
|
mutex: true,
|
||||||
audio: [{
|
theme: '#615754',
|
||||||
name: '光るなら',
|
mode: 'circulation',
|
||||||
artist: 'Goose house',
|
music: {
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3',
|
title: '回レ!雪月花',
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg',
|
author: '小倉唯',
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.lrc',
|
url: 'http://devtest.qiniudn.com/回レ!雪月花.mp3',
|
||||||
theme: '#ebd0c2'
|
pic: 'http://devtest.qiniudn.com/回レ!雪月花.jpg',
|
||||||
}]
|
lrc: "回レ!雪月花.lrc"
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const ap4 = new APlayer({
|
var ap4 = new APlayer({
|
||||||
element: document.getElementById('player4'),
|
element: document.getElementById('player4'),
|
||||||
mini: false,
|
narrow: false,
|
||||||
autoplay: false,
|
autoplay: false,
|
||||||
lrcType: false,
|
showlrc: false,
|
||||||
mutex: true,
|
mutex: true,
|
||||||
theme: '#ad7a86',
|
theme: '#ad7a86',
|
||||||
order: 'random',
|
mode: 'random',
|
||||||
audio: [{
|
music: [
|
||||||
name: '光るなら',
|
{
|
||||||
artist: 'Goose house',
|
title: 'あっちゅ~ま青春!',
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3',
|
author: '七森中☆ごらく部',
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg',
|
url: 'http://devtest.qiniudn.com/あっちゅ~ま青春!.mp3',
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.lrc',
|
pic: 'http://devtest.qiniudn.com/あっちゅ~ま青春!.jpg'
|
||||||
theme: '#ebd0c2'
|
},
|
||||||
}, {
|
{
|
||||||
name: 'トリカゴ',
|
title: 'secret base~君がくれたもの~',
|
||||||
artist: 'XX:me',
|
author: '茅野愛衣',
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.mp3',
|
url: 'http://devtest.qiniudn.com/secret base~.mp3',
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.jpg',
|
pic: 'http://devtest.qiniudn.com/secret base~.jpg'
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.lrc',
|
},
|
||||||
theme: '#46718b'
|
{
|
||||||
}, {
|
title: '回レ!雪月花',
|
||||||
name: '前前前世',
|
author: '小倉唯',
|
||||||
artist: 'RADWIMPS',
|
url: 'http://devtest.qiniudn.com/回レ!雪月花.mp3',
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.mp3',
|
pic: 'http://devtest.qiniudn.com/回レ!雪月花.jpg'
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.jpg',
|
}
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.lrc',
|
]
|
||||||
theme: '#505d6b'
|
|
||||||
}, {
|
|
||||||
name: '光るなら(HLS)',
|
|
||||||
artist: 'Goose house',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hls/hikarunara.m3u8',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg',
|
|
||||||
theme: '#ebd0c2',
|
|
||||||
type: 'hls'
|
|
||||||
}]
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const ap5 = new APlayer({
|
var ap5 = new APlayer({
|
||||||
element: document.getElementById('player5'),
|
element: document.getElementById('player5'),
|
||||||
mini: false,
|
narrow: false,
|
||||||
autoplay: false,
|
autoplay: false,
|
||||||
lrcType: 3,
|
showlrc: 3,
|
||||||
mutex: true,
|
|
||||||
theme: '#e9e9e9',
|
|
||||||
listFolded: false,
|
|
||||||
listMaxHeight: 80,
|
|
||||||
audio: [{
|
|
||||||
name: '光るなら',
|
|
||||||
artist: 'Goose house',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg',
|
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.lrc',
|
|
||||||
}, {
|
|
||||||
name: 'トリカゴ',
|
|
||||||
artist: 'XX:me',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.jpg',
|
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.lrc',
|
|
||||||
}, {
|
|
||||||
name: '前前前世',
|
|
||||||
artist: 'RADWIMPS',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.jpg',
|
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.lrc',
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
const colorThief = new ColorThief();
|
|
||||||
const image = new Image();
|
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
const setTheme = (index) => {
|
|
||||||
if (!ap5.list.audios[index].theme) {
|
|
||||||
xhr.onload = function(){
|
|
||||||
let coverUrl = URL.createObjectURL(this.response);
|
|
||||||
image.onload = function(){
|
|
||||||
let color = colorThief.getColor(image);
|
|
||||||
ap5.theme(`rgb(${color[0]}, ${color[1]}, ${color[2]})`, index);
|
|
||||||
URL.revokeObjectURL(coverUrl)
|
|
||||||
};
|
|
||||||
image.src = coverUrl;
|
|
||||||
}
|
|
||||||
xhr.open('GET', ap5.list.audios[index].cover, true);
|
|
||||||
xhr.responseType = 'blob';
|
|
||||||
xhr.send();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
setTheme(ap5.list.index);
|
|
||||||
ap5.on('listswitch', (data) => {
|
|
||||||
setTheme(data.index);
|
|
||||||
});
|
|
||||||
|
|
||||||
const ap6 = new APlayer({
|
|
||||||
element: document.getElementById('player6'),
|
|
||||||
mutex: true,
|
|
||||||
audio: [{
|
|
||||||
name: '光るなら(HLS)',
|
|
||||||
artist: 'Goose house',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hls/hikarunara.m3u8',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg',
|
|
||||||
theme: '#ebd0c2',
|
|
||||||
type: 'hls'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
const ap7 = new APlayer({
|
|
||||||
element: document.getElementById('player7'),
|
|
||||||
mutex: true,
|
|
||||||
audio: [{
|
|
||||||
name: '光るなら(HLS)',
|
|
||||||
artist: 'Goose house',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hls/hikarunara.m3u8',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg',
|
|
||||||
theme: '#ebd0c2',
|
|
||||||
type: 'customHls',
|
|
||||||
}],
|
|
||||||
customAudioType: {
|
|
||||||
'customHls': function (audioElement, audio, player) {
|
|
||||||
if (Hls.isSupported()) {
|
|
||||||
const hls = new Hls();
|
|
||||||
hls.loadSource(audio.url);
|
|
||||||
hls.attachMedia(audioElement);
|
|
||||||
}
|
|
||||||
else if (audioElement.canPlayType('application/x-mpegURL') || audioElement.canPlayType('application/vnd.apple.mpegURL')) {
|
|
||||||
audioElement.src = audio.url;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
player.notice('Error: HLS is not supported.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const ap8 = new APlayer({
|
|
||||||
element: document.getElementById('player8'),
|
|
||||||
mutex: true,
|
mutex: true,
|
||||||
theme: '#ad7a86',
|
theme: '#ad7a86',
|
||||||
order: 'random',
|
mode: 'random',
|
||||||
lrcType: 3,
|
listmaxheight: '80px',
|
||||||
fixed: true,
|
music: [
|
||||||
});
|
{
|
||||||
$.ajax({
|
title: 'あっちゅ~ま青春!',
|
||||||
url: 'https://api.i-meto.com/meting/api?server=netease&type=playlist&id=35798529',
|
author: '七森中☆ごらく部',
|
||||||
success: function (list) {
|
url: 'http://devtest.qiniudn.com/あっちゅ~ま青春!.mp3',
|
||||||
ap8.list.add(JSON.parse(list));
|
pic: 'http://devtest.qiniudn.com/あっちゅ~ま青春!.jpg',
|
||||||
}
|
lrc: 'あっちゅ~ま青春!.lrc'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'secret base~君がくれたもの~',
|
||||||
|
author: '茅野愛衣',
|
||||||
|
url: 'http://devtest.qiniudn.com/secret base~.mp3',
|
||||||
|
pic: 'http://devtest.qiniudn.com/secret base~.jpg',
|
||||||
|
lrc: 'secret base~君がくれたもの~.lrc'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '回レ!雪月花',
|
||||||
|
author: '小倉唯',
|
||||||
|
url: 'http://devtest.qiniudn.com/回レ!雪月花.mp3',
|
||||||
|
pic: 'http://devtest.qiniudn.com/回レ!雪月花.jpg',
|
||||||
|
lrc: '回レ!雪月花.lrc'
|
||||||
|
}
|
||||||
|
]
|
||||||
});
|
});
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
max-width: 32rem;
|
max-width: 32rem;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
margin-bottom: 150px;
|
margin-bottom: 50px;
|
||||||
}
|
}
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 54px;
|
font-size: 54px;
|
||||||
|
|
@ -43,67 +43,26 @@
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/vconsole/dist/vconsole.min.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/hls.js/dist/hls.min.js"></script>
|
|
||||||
<script src="APlayer.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/color-thief-don@2.0.2/src/color-thief.js"></script>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<a href="https://github.com/DIYgod/APlayer" target="_blank" class="github-corner"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#151513; color:#fff; position: absolute; top: 0; border: 0; right: 0;"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>APlayer</h1>
|
<h1>APlayer</h1>
|
||||||
<h2>Wow, such a beautiful html5 music player</h2>
|
<h2>Wow, such a beautiful html5 music player</h2>
|
||||||
<p>Made by <a href="https://www.anotherhome.net/" target="_blank">DIYgod</a>. Available on <a href="https://github.com/DIYgod/APlayer" target="_blank">GitHub</a>. Licensed MIT.</p>
|
<p>Made by <a href="https://www.anotherhome.net/" target="_blank">DIYgod</a>. Available on <a href="https://github.com/DIYgod/APlayer" target="_blank">GitHub</a>. Licensed MIT.</p>
|
||||||
<hr>
|
<hr>
|
||||||
<h3>Normal</h3>
|
<h3>Normal</h3>
|
||||||
<div id="player1"></div>
|
<div id="player1" class="aplayer"></div>
|
||||||
<p></p>
|
|
||||||
<button onclick="ap1.play()">ap.play()</button>
|
|
||||||
<button onclick="ap1.seek(100)">ap.seek(100)</button>
|
|
||||||
<button onclick="ap1.pause()">ap.pause()</button>
|
|
||||||
<button onclick="ap1.toggle()">ap.toggle()</button>
|
|
||||||
<button onclick="ap1.volume(0.1)">ap.volume(0.1)</button>
|
|
||||||
<button onclick="ap1.addAudio([
|
|
||||||
{
|
|
||||||
name: 'あっちゅ~ま青春!',
|
|
||||||
artist: '七森中☆ごらく部',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yuruyuri.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yuruyuri.jpg'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'secret base~君がくれたもの~',
|
|
||||||
artist: '茅野愛衣',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/secretbase.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/secretbase.jpg'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '回レ!雪月花',
|
|
||||||
artist: '小倉唯',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/snowmoonflowers.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/snowmoonflowers.jpg'
|
|
||||||
}
|
|
||||||
])">ap.addAudio(...)</button>
|
|
||||||
<button onclick="ap1.destroy()">ap.destroy()</button>
|
|
||||||
<h3>With playlist</h3>
|
|
||||||
<div id="player4" class="aplayer"></div>
|
|
||||||
<p></p>
|
|
||||||
<button onclick="ap4.switchAudio(2)">ap.switchAudio(2)</button>
|
|
||||||
<h3>With lyrics</h3>
|
<h3>With lyrics</h3>
|
||||||
<div id="player3" class="aplayer"></div>
|
<div id="player3" class="aplayer"></div>
|
||||||
|
<h3>With playlist</h3>
|
||||||
|
<div id="player4" class="aplayer"></div>
|
||||||
<h3>With playlist and lyrics</h3>
|
<h3>With playlist and lyrics</h3>
|
||||||
<div id="player5" class="aplayer"></div>
|
<div id="player5" class="aplayer"></div>
|
||||||
<h3>Narrow</h3>
|
<h3>Narrow</h3>
|
||||||
<div id="player2" class="aplayer"></div>
|
<div id="player2" class="aplayer"></div>
|
||||||
<h3>HLS</h3>
|
|
||||||
<div id="player6" class="aplayer"></div>
|
|
||||||
<div id="player7" class="aplayer"></div>
|
|
||||||
<div id="player8" class="aplayer"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script src="../dist/APlayer.min.js"></script>
|
||||||
if (/mobile/i.test(window.navigator.userAgent)) {
|
|
||||||
new VConsole();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/jquery"></script>
|
|
||||||
<script src="demo.js"></script>
|
<script src="demo.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
[00:00.230]君と夏の終わり 将来の夢(与你在夏末约定 将来的梦想)
|
||||||
|
[00:04.170]大きな希望 忘れない(远大的希望 不要忘记了)
|
||||||
|
[00:07.170]10年後の8月(我相信 十年後的八月)
|
||||||
|
[00:09.700]また出会えるのを 信じて(我们还能再相遇)
|
||||||
|
[00:14.360]最高の思い出を…(共划美好的回忆)
|
||||||
|
[00:39.960]出会いは ふっとした 瞬間 帰り道の交差点で(相识 是那麼不经意的瞬间 我在回家途中的十字路口)
|
||||||
|
[00:47.050]声をかけてくれたね 「一緒に帰ろう」(听见你的一声〞一起回家吧〞)
|
||||||
|
[00:54.310]僕は 照れくさそうに カバンで顔を隠しながら(我当时有点尴尬 还拿书包遮著脸)
|
||||||
|
[01:01.470]本当は とても とても 嬉しかったよ(其实我 心里好高兴 真的好高兴)
|
||||||
|
[01:08.590]あぁ 花火が夜空 きれいに咲いて ちょっとセツナク(啊!烟火在夜空中 灿烂盛开 几许伤感)
|
||||||
|
[01:15.770]あぁ 風が時間とともに 流れる(啊!风随着时光流逝)
|
||||||
|
[01:22.580]嬉しくって 楽しくって 冒険も いろいろしたね(满心欢喜地 兴致冲冲地 我们四处探险)
|
||||||
|
[01:29.760]二人の 秘密の 基地の中(就在我们的 秘密基地中)
|
||||||
|
[01:36.740]君と夏の終わり 将来の夢 大きな希望 忘れない(与你在夏末约定 将来的梦想 远大的希望 不要忘记了)
|
||||||
|
[01:43.920]10年後の8月 また出会えるのを 信じて(我相信 十年後的八月 我们还能再相遇)
|
||||||
|
[01:51.010]君が最後まで 心から 「ありがとう」叫んでいたこと(我知道 一直到最後)
|
||||||
|
[01:56.930]知っていたよ(你仍在心底呼喊著〞谢谢你〞)
|
||||||
|
[01:58.200]涙をこらえて 笑顔でさようなら せつないよね(强忍著泪水 笑著说再见 无限感叹涌现)
|
||||||
|
[02:05.420]最高の思い出を…(那一段最美好的回忆…)
|
||||||
|
[02:13.070]あぁ 夏休みも あと少しで 終っちゃうから(啊!暑假就快要过完了)
|
||||||
|
[02:20.310]あぁ 太陽と月 仲良くして(啊!太阳和月亮 默契十足)
|
||||||
|
[02:27.080]悲しくって 寂しくって 喧嘩も いろいろしたね(想到令人悲伤 或许有些寂寥 我们也多有争吵)
|
||||||
|
[02:34.160]二人の 秘密の 基地の中(就在我们的 秘密基地中)
|
||||||
|
[02:41.140]君が最後まで 心から 「ありがとう」叫んでいたこと(我知道 一直到最後)
|
||||||
|
[02:47.000]知っていたよ(你仍在心底呼喊著〞谢谢你)
|
||||||
|
[02:48.340]涙をこらえて 笑顔でさようなら せつないよね(强忍著泪水 笑著说再见 无限感叹涌现)
|
||||||
|
[02:55.630]最高の思い出を…(那一段最美好的回忆)
|
||||||
|
[03:03.320]突然の 転校で どうしようもなく(你突然要转学 你我都可奈何)
|
||||||
|
[03:24.190]手紙 書くよ 電話もするよ 忘れないでね 僕のことを(我会写信给你 也会打电话给你 千万不要忘记我)
|
||||||
|
[03:31.420]いつまでも 二人の 基地の中(永远别忘记 那段在秘密基地中的日子)
|
||||||
|
[03:38.520]君と夏の終わり ずっと話して(与你在夏末 聊了这麼多)
|
||||||
|
[03:42.530]夕日を見てから星を眺め(从黄昏到繁星点点)
|
||||||
|
[03:45.670]君の頬を 流れた涙は ずっと忘れない(流过你双颊的泪水 我永远不会忘记)
|
||||||
|
[03:52.820]君が最後まで 大きく手を振ってくれたこと(直到最後 你紧紧握住我的手 这感觉也将长在我心中)
|
||||||
|
[03:58.540]きっと忘れない(於是就这样)
|
||||||
|
[03:59.930]だから こうして 夢の中で ずっと永遠に…(让我们在梦中相会吧 永远的…)
|
||||||
|
[04:07.110]君と夏の終わり 将来の夢 大きな希望 忘れない(与你在夏末约定 将来的梦想 远大的希望 不要忘记了)
|
||||||
|
[04:14.270]10年後の8月 また出会えるのを 信じて(我相信 十年後的八月 我们还能再相遇)
|
||||||
|
[04:21.400]君が最後まで 心から 「ありがとう」叫んでいたこと(我知道 一直到最後)
|
||||||
|
[04:27.260]知っていたよ(你仍在心底呼喊著〞谢谢你〞)
|
||||||
|
[04:28.640]涙をこらえて 笑顔でさようなら せつないよね(强忍著泪水 笑著说再见 无限感叹涌现)
|
||||||
|
[04:35.910]最高の思い出を…(那一段最美好的回忆…)
|
||||||
|
[04:43.160]最高の思い出を…(那一段最美好的回忆…)
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
[ti:あっちゅ~ま青春!]
|
||||||
|
[ar:七森中☆ごらく部]
|
||||||
|
[al:あっちゅ~ま青春!]
|
||||||
|
[00:00.76]青春オーライ 青春オーエス 青春謳歌 はりきって行くぞ(青春 All right 青春 Oh Hisse 青春讴歌 鼓足干劲上吧!)
|
||||||
|
[00:05.96]青春ドンマイ 青春ファイト 青春最高(青春 Don't Mind 青春 Fight 青春最棒了!)
|
||||||
|
[00:09.67]Yeah!! Yeah!! Yeah!! Yeah!!
|
||||||
|
[00:12.21]青春はじめよう 1・2・さん☆ハイ!(让青春起步吧! 1·2·三☆OK!)
|
||||||
|
[00:14.78]ひとまず走るぞ 1・2・さん☆ハイ!(不管如何先跑起来吧! 1·2·三☆OK!)
|
||||||
|
[00:17.32]みんなが笑顔で 1・2・さん☆ハイ!(大家都露出笑脸! 1·2·三☆OK!)
|
||||||
|
[00:19.95]これが青春だ 1・2・さん☆ハイ!(这就是青春! 1·2·三☆OK!)
|
||||||
|
[00:22.71]春! 桜もちを食べよう 夏! かき氷で決まり(春天! 来吃樱叶饼吧 夏天! 就决定是刨冰啦)
|
||||||
|
[00:27.89]秋! 焼きいもを頬張り 冬! 雪でまたかき氷(秋天! 把烤白薯大口塞进嘴里 冬天! 在雪里面又是刨冰)
|
||||||
|
[00:32.57]もういっちょ☆(再来☆)
|
||||||
|
[00:33.16]春! 教室を間違えて 夏! 宿題を忘れて(春天! 进错了教室 夏天! 把作业忘掉了)
|
||||||
|
[00:38.37]秋! マラソンでビリケツ 冬! こたつに長期滞在(秋天! 马拉松最后一名 冬天! 长期居住在暖炉里)
|
||||||
|
[00:43.61]1年365日 ときどき366日(一年中的365天 有时候是366天)
|
||||||
|
[00:48.69]色々あるけど 全力!全開! 全身全霊! 楽しもうよ よーよよよよ(虽然会发生很多事情,但是一起尽力尽兴!全心全意!享受每一天吧!吧~吧吧吧吧)
|
||||||
|
[00:55.23]「えんじょい!えんじょい!じょじょじょじょじょい!」(「享受吧!享受吧! 吧吧吧吧吧!」)
|
||||||
|
[00:57.83]あっちゅ~ま青春! まぶし~いよ青春!(转瞬即逝的青春! 灿烂无比的青春!)
|
||||||
|
[01:03.17]眠気さよなら ココロの瞳をぱっちりあけよう(向困意说拜拜 把心灵的眼睛睁得大大的吧)
|
||||||
|
[01:08.42]あっちゅ~ま青春! 猛スピード青春!(转瞬即逝的青春! 飞速前进的青春!)
|
||||||
|
[01:13.64]まばたきしてちゃ おいしいところ見逃しちゃうよ 注意!(要是乱眨眼睛的话 就会把美味的时光错过了的啦! 要注意哦!)
|
||||||
|
[01:18.87]青春オーライ 青春オーエス 青春謳歌 はりきって行くぞ(青春 All right 青春 Oh Hisse 青春讴歌 鼓足干劲上吧!)
|
||||||
|
[01:24.17]青春ドンマイ 青春ファイト 青春最高(青春 Don't Mind(别在意) 青春 Fight(奋斗) 青春最棒了!)
|
||||||
|
[01:27.85]Yeah!! Yeah!! Yeah!! Yeah!!
|
||||||
|
[01:30.44]朝! ニワトリに追いかけられ 昼! まさかのテスト0点(早上!被鸡到处追着跑 中午! 考试没想到竟然零分!)
|
||||||
|
[01:35.72]放課後! みんなに励まされて 夜! 今日は寝て忘れましょう(放学后! 大家给我加油 晚上!今天就睡觉把烦恼忘掉吧!)
|
||||||
|
[01:40.35]次の日~っ☆(第二天~☆)
|
||||||
|
[01:40.84]朝! ぎりぎり社長出勤 昼! 給食をおかわり(早上!差点就迟到了 中午!食堂的饭再来一份)
|
||||||
|
[01:46.10]放課後! 部室でダラダララ~ 夜! 長電話止まらない(放学后! 在部团教室懒散度过 晚上! 煲电话粥停不下来)
|
||||||
|
[01:51.32]1日いつでも24時間 巻くこと押すことどちらもできない(一天永远都是24小时 既不会提前也不会延后)
|
||||||
|
[01:56.52]やりたいことなら貪欲強欲 別腹パッパラやり尽そうよ よーよよよよ(如果是想做的事情的话 就要贪婪地去追求 开启第二个胃 去把所有想干的事情都做了吧!)
|
||||||
|
[02:02.95]「わっしょい!わっしょい!しょしょしょしょしょい!」(「欧耶! 欧耶! 耶耶耶耶耶!」)
|
||||||
|
[02:05.58]あっちゅ~ま青春! 楽し~いよ青春!(转瞬即逝的青春! 快乐无比的青春!)
|
||||||
|
[02:11.06]春に始まり春に向かってく 思い出つくろう(开始在春天的青春 为了这个春天 一起创造回忆吧)
|
||||||
|
[02:16.23]あっちゅ~ま青春! 青い春だ青春!(转瞬即逝的青春! 青色的春天就是……青春!)
|
||||||
|
[02:21.40]ブルーなキモチ みんなといるとカラフルになる 不思議!(那些忧郁的心情 只要和大家在一起就会变得色彩缤纷 真是不可思议!)
|
||||||
|
[02:26.82]青春オーライ 青春オーエス 青春謳歌 はりきって行くぞ(青春 All right 青春 Oh Hisse 青春讴歌 鼓足干劲上吧!)
|
||||||
|
[02:31.99]青春ドンマイ 青春ファイト 青春最高(青春 Don't Mind 青春 Fight 青春最棒了!)
|
||||||
|
[02:35.68]Yeah!! Yeah!! Yeah!! Yeah!!
|
||||||
|
[02:47.61]あっちゅ~ま青春! まぶし~いよ青春!(转瞬即逝的青春! 灿烂无比的青春!)
|
||||||
|
[02:52.67]眠気さよなら ココロの瞳をぱっちりあけよう(向困意说拜拜 把心灵的眼睛睁得大大的吧)
|
||||||
|
[02:58.01]あっちゅ~ま青春! 猛スピード青春!(转瞬即逝的青春! 飞速前进的青春!)
|
||||||
|
[03:03.22]まばたきしてちゃ おいしいところ見逃しちゃうよ 注意!(要是乱眨眼睛的话 就会把美味的时光错过了的啦! 要注意哦!)
|
||||||
|
[03:08.56]あっちゅ~ま青春! にぎや~かな青春!(转瞬即逝的青春! 热热闹闹的青春!)
|
||||||
|
[03:13.68]今が青春 感じられた日はステキな日だよ(现在就是能感受到青春的 最棒的日子哦)
|
||||||
|
[03:18.86]あっちゅ~ま青春! 二度と来ない青春!(转瞬即逝的青春! 一去不复返的青春!)
|
||||||
|
[03:24.07]気付けばいつも私の青春 キミがいるんだ キ・セ・キ(回过神来 在我的青春中都有你在身边 真・是・奇・迹)
|
||||||
|
[03:29.41]青春オーライ 青春オーエス 青春謳歌 はりきって行くぞ(青春 All right 青春 Oh Hisse 青春讴歌 鼓足干劲上吧!)
|
||||||
|
[03:34.56]青春ドンマイ 青春ファイト 青春最高(青春 Don't Mind 青春 Fight 青春最棒了!)
|
||||||
|
[03:38.23]Yeah!! Yeah!! Yeah!! Yeah!!
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
[by:京兆万年]
|
||||||
|
[ti:回レ!雪月花 小紫ver.]
|
||||||
|
[ar:小倉唯]
|
||||||
|
[lr:ヒゲドライバー]
|
||||||
|
[co:ヒゲドライバー]
|
||||||
|
[ag:ヒゲドライバー]
|
||||||
|
[00:00.00]せ〜の いちにっさんはい!(预~备 一 二 三 嗨!)
|
||||||
|
[00:04.68]ほい! いよーーーーっ ぽん!(嘿 咿哟 嘭)
|
||||||
|
[00:07.66]ハッハッハッハッハッハッハィヤ(哈 哈 哈 哈 哈 哈 嗨呀)
|
||||||
|
[00:11.12]ハッハッハッハッハッハッ う~(哈 哈 哈 哈 哈 哈 呜~)
|
||||||
|
[00:13.36]さぁさぁさぁ(来 来 来)
|
||||||
|
[00:14.08]これよりご覧いただきますは(接下来诸位将欣赏到的是)
|
||||||
|
[00:15.65]カブキ者たちの栄枯盛衰(歌舞伎演员们的荣辱盛衰)
|
||||||
|
[00:17.14]時代常に日進月歩(时代总是在日新月异)
|
||||||
|
[00:18.24]聞いてってよ老若男女(且听我一一道来 男女老少)
|
||||||
|
[00:20.14]一見は勧善懲悪(乍一看是惩恶扬善)
|
||||||
|
[00:21.49]悪者どもを一刀両断(将坏人们一刀两断)
|
||||||
|
[00:22.85]「でもホンドにそれだけで楽しいの?」(“但是你真的会因此而觉得扬眉吐气吗?”)
|
||||||
|
[00:25.63]もうなんだって蒟蒻問答(无论问什么 都是牛头马嘴)
|
||||||
|
[00:27.58]ハッハッハッハッハッハッハィヤ(哈哈哈哈哈哈 咿呀)
|
||||||
|
[00:30.57]ハッハッハッハッ(哈哈哈哈)
|
||||||
|
[00:31.97]いよーーーーっ ぽん!(咿哟 嘭)
|
||||||
|
[00:33.61]どこからともなく現れて(自何处出现委实难料)
|
||||||
|
[00:34.96]すぐどこかへ行っちゃって神出鬼沒(眼又遁隐他处总是神出鬼没)
|
||||||
|
[00:36.35]チャンスを待ったら一日千秋(若是静候机会 便是一日千秋)
|
||||||
|
[00:38.03]追いかければ東奔西走(追上前去的话又要东奔西走)
|
||||||
|
[00:39.68]時代常に千変万化(时代总是千变万化)
|
||||||
|
[00:40.95]人の心は複雑怪奇(世人之心复杂怪奇)
|
||||||
|
[00:42.31]「でも本気でそんなこ言ってんの?」(“但是说着这些话的你岂不也是难免戏谑?”)
|
||||||
|
[00:45.02]もうどうにも満身創痍(也罢 无论怎样都将满身疮痍)
|
||||||
|
[00:46.98]嗚呼、巡り巡って夜の町(呜呼 绕来绕去相会在这夜色下的街)
|
||||||
|
[00:53.27]キミは合図出し踊りだす((由)你发出信号 (让)我们一同起舞转)
|
||||||
|
[00:58.12]はぁ~(哈呜~)
|
||||||
|
[00:58.88]回レ回レ回レ回レ回レ回レ回レ回レ回レ!(旋转吧旋转吧旋转吧旋转吧旋转吧旋转吧旋转吧旋转吧旋转吧!)
|
||||||
|
[01:02.12]華麗に花弁 散らすように(在散落的美丽花瓣中)
|
||||||
|
[01:04.97]回レ回レ回レ回レ回レ回レ回レ回レ回レ!(旋转吧旋转吧旋转吧旋转吧旋转吧旋转吧旋转吧旋转吧旋转吧!)
|
||||||
|
[01:08.13]髪も振り乱して(头发凌乱又怎样?)
|
||||||
|
[01:10.23]一昨日、昨日、今日と、明日と、明後日と(前日、昨日、今日、明日、后日)
|
||||||
|
[01:14.13]この宴は続く(这场宴会亦不息)
|
||||||
|
[01:16.31]踊レ、歌エ、一心不乱に回レ!(舞动吧 歌唱吧 一心不乱的旋转吧于)
|
||||||
|
[01:20.19]今宵は雪月花(今夜的雪月花)
|
||||||
|
[01:25.43]ほい! いよーーーーっ ぽん!(哈~!~哟ーーーー~嘣~!)
|
||||||
|
[01:29.14]ハッハッハッハッハッハッハィヤ(哈 哈 哈 哈 哈 哈 嗨呀)
|
||||||
|
[01:32.16]ハッハッハッハッハッハッ う~(哈 哈 哈 哈 哈 哈 呜)
|
||||||
|
[01:34.39]ねぇねぇねぇ(呐~呐~呐~)
|
||||||
|
[01:35.12]この世に平安訪れるの?(平安已经访问此世了吗?)
|
||||||
|
[01:36.50]のべつ幕無し丁丁発止(不会闭幕的丁当争斗)
|
||||||
|
[01:38.09]兵ども千客万来(官兵们接踵而来)
|
||||||
|
[01:39.50]ひしめき合群雄割拠(相互吵吵嚷嚷群雄割据)
|
||||||
|
[01:41.00]伸るか反るか一攫千金(成败在于敢否一举千金)
|
||||||
|
[01:42.47]気が付いたら絶体絶命(回过头来却已穷途末路)
|
||||||
|
[01:43.50]「でも本音のとこ、どうなってんの?」(「不过真心的所在、到底是什么样呢?」)
|
||||||
|
[01:46.62]もうまったく奇想天外(真是的总这么异想天开)
|
||||||
|
[01:48.51]嗚呼、辿り辿って夜の町(呜呼、追溯于夜晚小镇上)
|
||||||
|
[01:54.83]迷い一つなく踊りだす(心无杂念的就此起舞吧)
|
||||||
|
[01:59.68]はぁ~(哈阿~)
|
||||||
|
[02:00.44]回レ回レ回レ回レ回レ 回レ回レ回レ回レ!(转啊转啊转啊转啊转啊转啊转啊转啊转啊!)
|
||||||
|
[02:03.64]華麗に花弁 散らすように(犹如花瓣华丽的散落一般)
|
||||||
|
[02:06.49]回レ回レ回レ回レ回レ 回レ回レ回レ回レ!(转啊转啊转啊转啊转啊转啊转啊转啊转啊!)
|
||||||
|
[02:09.66]髪も振り乱して(长发也随风飘散)
|
||||||
|
[02:11.72]一昨日、昨日、今日と、明日と、明後日と(无论前天、昨天、还是今天、明天、与后天)
|
||||||
|
[02:15.63]この宴は続く(这宴会还会持续)
|
||||||
|
[02:17.67]踊レ、歌エ、一心不乱に回レ!(跳吧、唱吧、一心一意的转吧!)
|
||||||
|
[02:21.60]今宵は雪月花(因为今宵乃是雪月花)
|
||||||
|
[02:36.74]ハッハッハッハッハッハッハィヤ(哈 哈 哈 哈 哈 哈 嗨呀)
|
||||||
|
[02:39.72]ハッハッハッハッハッハッ さぁさぁさぁ(哈 哈 哈 哈 哈 哈 来~来~来~)
|
||||||
|
[02:42.45]ハッハッハッハッハッハッハィヤ(哈 哈 哈 哈 哈 哈 嗨呀)
|
||||||
|
[02:45.49]ハッハッハッハッハッハッ(哈 哈 哈 哈 哈 哈)
|
||||||
|
[02:47.66]花で一つ、鳥で二つ(花就是一、鸟就是二)
|
||||||
|
[02:51.31]手打ち鳴らす(拍着手轻声唱)
|
||||||
|
[02:54.12]風で三つ、嗚呼、月出て四つ(风就是三、呜呼、月出就有四)
|
||||||
|
[02:58.76]鳴らす鳴らす……(轻声唱轻轻唱……)
|
||||||
|
[03:00.09]花で一つ、鳥で二つ(花就是一、鸟就是二)
|
||||||
|
[03:03.34]手打ち鳴らす(拍着手轻声唱)
|
||||||
|
[03:06.25]風で三つ、嗚呼、月出て四つ(风就是三、呜呼、月出就有四)
|
||||||
|
[03:10.78]鳴らす鳴らす……(轻轻唱轻声唱……)
|
||||||
|
[03:13.28]今は(在此)
|
||||||
|
[03:15.35]回レ回レ回レ回レ回レ 回レ回レ回レ回レ!(转啊转啊转啊转啊转啊转啊转啊转啊转啊!)
|
||||||
|
[03:18.63]華麗に花弁 散らすように(犹如花瓣华丽的散落一般)
|
||||||
|
[03:21.35]回レ回レ回レ回レ回レ 回レ回レ回レ回レ!(转啊转啊转啊转啊转啊转啊转啊转啊转啊!)
|
||||||
|
[03:24.60]髪も振り乱して(长发也随风飘散)
|
||||||
|
[03:26.72]一昨日、昨日、今日と、明日と、明後日と(无论前天、昨天、还是今天、明天、与后天)
|
||||||
|
[03:30.67]この宴は続く(这宴会不会结束)
|
||||||
|
[03:32.75]踊レ、歌エ、一心不乱に回レ!(跳吧、唱吧、一心一意的转吧!)
|
||||||
|
[03:36.63]今宵は何曜日か?(今宵是星期几呢?)
|
||||||
|
[03:39.02]水木金?(三四五?)
|
||||||
|
[03:40.56]土日月火?(六七一二?)
|
||||||
|
[03:44.11]ハッハッハッハッハッハッハィヤ(哈 哈 哈 哈 哈 哈 嗨呀)
|
||||||
|
[03:47.00]ハッハッハッハッ(哈 哈 哈 哈 哈 哈)
|
||||||
|
[03:48.57]いよーーーーっ ぽん!(~哟ーーーー~嘣~!)
|
||||||
|
[03:50.43]-終わり-(-End-)
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
aplayer.js.org
|
|
||||||
589
docs/README.md
|
|
@ -1,589 +0,0 @@
|
||||||
---
|
|
||||||
search: english
|
|
||||||
---
|
|
||||||
|
|
||||||
# APlayer
|
|
||||||
|
|
||||||
🍭 Wow, such a beautiful HTML5 music player
|
|
||||||
|
|
||||||
## Special Sponsors
|
|
||||||
|
|
||||||
<a href="https://www.dogecloud.com/?ref=dplayer" target="_blank">
|
|
||||||
<img width="222px" src="https://player.dogecloud.com/img/logo_with_product3.png">
|
|
||||||
</a>
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
Using npm:
|
|
||||||
|
|
||||||
```
|
|
||||||
npm install aplayer --save
|
|
||||||
```
|
|
||||||
|
|
||||||
Using Yarn:
|
|
||||||
|
|
||||||
```
|
|
||||||
yarn add aplayer
|
|
||||||
```
|
|
||||||
|
|
||||||
## Quick Start
|
|
||||||
|
|
||||||
<div class="aplayer-wrap">
|
|
||||||
<div id="aplayer2"><button class="docute-button load">Click to load player</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
```html
|
|
||||||
<link rel="stylesheet" href="APlayer.min.css">
|
|
||||||
<div id="aplayer"></div>
|
|
||||||
<script src="APlayer.min.js"></script>
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
const ap = new APlayer({
|
|
||||||
container: document.getElementById('aplayer'),
|
|
||||||
audio: [{
|
|
||||||
name: 'name',
|
|
||||||
artist: 'artist',
|
|
||||||
url: 'url.mp3',
|
|
||||||
cover: 'cover.jpg'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
Work with module bundler:
|
|
||||||
|
|
||||||
```js
|
|
||||||
import 'aplayer/dist/APlayer.min.css';
|
|
||||||
import APlayer from 'aplayer';
|
|
||||||
|
|
||||||
const ap = new APlayer(options);
|
|
||||||
```
|
|
||||||
|
|
||||||
## Options
|
|
||||||
|
|
||||||
Name | Default | Description
|
|
||||||
----|-------|----
|
|
||||||
container | document.querySelector('.aplayer') | player container
|
|
||||||
fixed | false | enable fixed mode, [see more details](https://aplayer.js.org/#/home?id=fixed-mode)
|
|
||||||
mini | false | enable mini mode, [see more details](https://aplayer.js.org/#/home?id=mini-mode)
|
|
||||||
autoplay | false | audio autoplay
|
|
||||||
theme | '#b7daff' | main color
|
|
||||||
loop | 'all' | player loop play, values: 'all', 'one', 'none'
|
|
||||||
order | 'list' | player play order, values: 'list', 'random'
|
|
||||||
preload | 'auto' | values: 'none', 'metadata', 'auto'
|
|
||||||
volume | 0.7 | default volume, notice that player will remember user setting, default volume will not work after user set volume themselves
|
|
||||||
audio | - | audio info, should be an object or object array
|
|
||||||
audio.name | - | audio name
|
|
||||||
audio.artist | - | audio artist
|
|
||||||
audio.url | - | audio url
|
|
||||||
audio.cover | - | audio cover
|
|
||||||
audio.lrc | - | [see more details](https://aplayer.js.org/#/home?id=lrc)
|
|
||||||
audio.theme | - | main color when switching to this audio, it has priority over the above theme
|
|
||||||
audio.type | 'auto' | values: 'auto', 'hls', 'normal' or other custom type, [see more details](https://aplayer.js.org/#/home?id=mse-support)
|
|
||||||
customAudioType | - | [see more details](https://aplayer.js.org/#/home?id=mse-support)
|
|
||||||
mutex | true | prevent to play multiple player at the same time, pause other players when this player start play
|
|
||||||
lrcType | 0 | [see more details](https://aplayer.js.org/#/home?id=lrc)
|
|
||||||
listFolded | false | indicate whether list should folded at first
|
|
||||||
listMaxHeight | - | list max height
|
|
||||||
storageName | 'aplayer-setting' | localStorage key that store player setting
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
<div class="aplayer-wrap">
|
|
||||||
<div id="aplayer3"><button class="docute-button load">Click to load player</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
```js
|
|
||||||
const ap = new APlayer({
|
|
||||||
container: document.getElementById('player'),
|
|
||||||
mini: false,
|
|
||||||
autoplay: false,
|
|
||||||
theme: '#FADFA3',
|
|
||||||
loop: 'all',
|
|
||||||
order: 'random',
|
|
||||||
preload: 'auto',
|
|
||||||
volume: 0.7,
|
|
||||||
mutex: true,
|
|
||||||
listFolded: false,
|
|
||||||
listMaxHeight: 90,
|
|
||||||
lrcType: 3,
|
|
||||||
audio: [
|
|
||||||
{
|
|
||||||
name: 'name1',
|
|
||||||
artist: 'artist1',
|
|
||||||
url: 'url1.mp3',
|
|
||||||
cover: 'cover1.jpg',
|
|
||||||
lrc: 'lrc1.lrc',
|
|
||||||
theme: '#ebd0c2'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'name2',
|
|
||||||
artist: 'artist2',
|
|
||||||
url: 'url2.mp3',
|
|
||||||
cover: 'cover2.jpg',
|
|
||||||
lrc: 'lrc2.lrc',
|
|
||||||
theme: '#46718b'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
+ `APlayer.version`: static property, return the version of APlayer
|
|
||||||
|
|
||||||
+ `ap.play()`: play audio
|
|
||||||
|
|
||||||
+ `ap.pause()`: pause audio
|
|
||||||
|
|
||||||
+ `ap.seek(time: number)`: seek to specified time, the unit of time is second
|
|
||||||
|
|
||||||
```js
|
|
||||||
ap.seek(100);
|
|
||||||
```
|
|
||||||
|
|
||||||
+ `ap.toggle()`: toggle between play and pause
|
|
||||||
|
|
||||||
+ `ap.on(event: string, handler: function)`: bind audio and player events, [see more details](https://aplayer.js.org/#/home?id=event-binding)
|
|
||||||
|
|
||||||
+ `ap.volume(percentage: number, nostorage: boolean)`: set audio volume
|
|
||||||
|
|
||||||
```js
|
|
||||||
ap.volume(0.1, true);
|
|
||||||
```
|
|
||||||
|
|
||||||
+ `ap.theme(color: string, index: number)`: set player theme, the default of index is current audio index
|
|
||||||
|
|
||||||
```js
|
|
||||||
ap.theme('#000', 0);
|
|
||||||
```
|
|
||||||
|
|
||||||
+ `ap.setMode(mode: string)`: set player mode, the value of mode should be 'mini' or 'normal'
|
|
||||||
|
|
||||||
+ `ap.mode`: return current player mode, 'mini' or 'normal'
|
|
||||||
|
|
||||||
+ `ap.notice(text: string, time: number, opacity: number)`: show message, the unit of time is millisecond, the default of time is 2000, the default of opacity is 0.8, setting time to 0 can disable notice autohide.
|
|
||||||
|
|
||||||
```js
|
|
||||||
ap.notice('Amazing player', 2000, 0.8);
|
|
||||||
```
|
|
||||||
|
|
||||||
+ `ap.skipBack()`: skip to previous audio
|
|
||||||
|
|
||||||
+ `ap.skipForward()`: skip to next audio
|
|
||||||
|
|
||||||
+ `ap.destroy()`: destroy player
|
|
||||||
|
|
||||||
+ `ap.lrc`
|
|
||||||
|
|
||||||
+ `ap.lrc.show()`: show lrc
|
|
||||||
|
|
||||||
+ `ap.lrc.hide()`: hide lrc
|
|
||||||
|
|
||||||
+ `ap.lrc.toggle()`: toggle lrc between show and hide
|
|
||||||
|
|
||||||
+ `ap.list`
|
|
||||||
|
|
||||||
+ `ap.list.show()`: show list
|
|
||||||
|
|
||||||
+ `ap.list.hide()`: hide list
|
|
||||||
|
|
||||||
+ `ap.list.toggle()`: toggle list between show and hide
|
|
||||||
|
|
||||||
+ `ap.list.add(audios: array | object)`: add new audios to the list
|
|
||||||
|
|
||||||
```js
|
|
||||||
ap.list.add([{
|
|
||||||
name: 'name',
|
|
||||||
artist: 'artist',
|
|
||||||
url: 'url.mp3',
|
|
||||||
cover: 'cover.jpg',
|
|
||||||
lrc: 'lrc.lrc',
|
|
||||||
theme: '#ebd0c2'
|
|
||||||
}]);
|
|
||||||
```
|
|
||||||
|
|
||||||
+ `ap.list.remove(index: number)`: remove an audio from the list
|
|
||||||
|
|
||||||
```js
|
|
||||||
ap.list.remove(1);
|
|
||||||
```
|
|
||||||
|
|
||||||
+ `ap.list.switch()`: switch to an audio in the list
|
|
||||||
|
|
||||||
```js
|
|
||||||
ap.list.switch(1);
|
|
||||||
```
|
|
||||||
|
|
||||||
+ `ap.list.clear()`: remove all audios from the list
|
|
||||||
|
|
||||||
+ `ap.audio`: native audio
|
|
||||||
|
|
||||||
+ `ap.audio.currentTime`: returns the current playback position
|
|
||||||
|
|
||||||
+ `ap.audio.duration`: returns audio total time
|
|
||||||
|
|
||||||
+ `ap.audio.paused`: returns whether the audio paused
|
|
||||||
|
|
||||||
+ most [native api](http://www.w3schools.com/tags/ref_av_dom.asp) are supported
|
|
||||||
|
|
||||||
## Event binding
|
|
||||||
|
|
||||||
`ap.on(event, handler)`
|
|
||||||
|
|
||||||
```js
|
|
||||||
ap.on('ended', function () {
|
|
||||||
console.log('player ended');
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
Audio events
|
|
||||||
|
|
||||||
- abort
|
|
||||||
- canplay
|
|
||||||
- canplaythrough
|
|
||||||
- durationchange
|
|
||||||
- emptied
|
|
||||||
- ended
|
|
||||||
- error
|
|
||||||
- loadeddata
|
|
||||||
- loadedmetadata
|
|
||||||
- loadstart
|
|
||||||
- mozaudioavailable
|
|
||||||
- pause
|
|
||||||
- play
|
|
||||||
- playing
|
|
||||||
- progress
|
|
||||||
- ratechange
|
|
||||||
- seeked
|
|
||||||
- seeking
|
|
||||||
- stalled
|
|
||||||
- suspend
|
|
||||||
- timeupdate
|
|
||||||
- volumechange
|
|
||||||
- waiting
|
|
||||||
|
|
||||||
Player events
|
|
||||||
|
|
||||||
- listshow
|
|
||||||
- listhide
|
|
||||||
- listadd
|
|
||||||
- listremove
|
|
||||||
- listswitch
|
|
||||||
- listclear
|
|
||||||
- noticeshow
|
|
||||||
- noticehide
|
|
||||||
- destroy
|
|
||||||
- lrcshow
|
|
||||||
- lrchide
|
|
||||||
|
|
||||||
## LRC
|
|
||||||
|
|
||||||
We have three ways to pass LRC to APlayer, indicate the way to pass LRC by option `lrcType`, then put lrc to option `audio.lrc` or HTML.
|
|
||||||
|
|
||||||
<div class="aplayer-wrap">
|
|
||||||
<div id="aplayer4"><button class="docute-button load">Click to load player</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
### LRC file
|
|
||||||
|
|
||||||
The first way, put LRC to a LRC file, LRC file will be loaded when this audio start to play.
|
|
||||||
|
|
||||||
```js
|
|
||||||
const ap = new APlayer({
|
|
||||||
container: document.getElementById('aplayer'),
|
|
||||||
lrcType: 3,
|
|
||||||
audio: {
|
|
||||||
name: 'name',
|
|
||||||
artist: 'artist',
|
|
||||||
url: 'demo.mp3',
|
|
||||||
cover: 'demo.jpg',
|
|
||||||
lrc: 'lrc.lrc'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### LRC string in JS
|
|
||||||
|
|
||||||
The second way, put LRC to a JS string.
|
|
||||||
|
|
||||||
```js
|
|
||||||
const ap = new APlayer({
|
|
||||||
container: document.getElementById('aplayer'),
|
|
||||||
lrcType: 1,
|
|
||||||
audio: {
|
|
||||||
name: 'name',
|
|
||||||
artist: 'artist',
|
|
||||||
url: 'demo.mp3',
|
|
||||||
cover: 'demo.jpg',
|
|
||||||
lrc: '[00:00.00]APlayer\n[00:04.01]is\n[00:08.02]amazing'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### LRC in HTML
|
|
||||||
|
|
||||||
The third way, put LRC to HTML.
|
|
||||||
|
|
||||||
```html
|
|
||||||
<link rel="stylesheet" href="APlayer.min.css">
|
|
||||||
<div id="player">
|
|
||||||
<pre class="aplayer-lrc-content">
|
|
||||||
[00:00.00]APlayer audio1
|
|
||||||
[00:04.01]is
|
|
||||||
[00:08.02]amazing
|
|
||||||
<!-- ... -->
|
|
||||||
</pre>
|
|
||||||
<pre class="aplayer-lrc-content">
|
|
||||||
[00:00.00]APlayer audio2
|
|
||||||
[00:04.01]is
|
|
||||||
[00:08.02]amazing
|
|
||||||
<!-- ... -->
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
<script src="APlayer.min.js"></script>
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
const ap = new APlayer({
|
|
||||||
container: document.getElementById('aplayer'),
|
|
||||||
lrcType: 2,
|
|
||||||
audio: [[
|
|
||||||
{
|
|
||||||
name: 'name1',
|
|
||||||
artist: 'artist1',
|
|
||||||
url: 'url1.mp3',
|
|
||||||
cover: 'cover1.jpg'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'name2',
|
|
||||||
artist: 'artist2',
|
|
||||||
url: 'url2.mp3',
|
|
||||||
cover: 'cover2.jpg'
|
|
||||||
}
|
|
||||||
]]
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### LRC format
|
|
||||||
|
|
||||||
The following LRC format are supported:
|
|
||||||
|
|
||||||
`[mm:ss]APlayer`
|
|
||||||
|
|
||||||
`[mm:ss.xx]is`
|
|
||||||
|
|
||||||
`[mm:ss.xxx]amazing`
|
|
||||||
|
|
||||||
`[mm:ss.xx][mm:ss.xx]APlayer`
|
|
||||||
|
|
||||||
`[mm:ss.xx]<mm:ss.xx>is`
|
|
||||||
|
|
||||||
`[mm:ss.xx]amazing[mm:ss.xx]APlayer`
|
|
||||||
|
|
||||||
## Playlist
|
|
||||||
|
|
||||||
APlayer will show a playlist when it has more than one audio, option `listFolded` indicates whether list should folded at first, and option `listMaxHeight` indicates list max height.
|
|
||||||
|
|
||||||
<div class="aplayer-wrap">
|
|
||||||
<div id="aplayer5"><button class="docute-button load">Click to load player</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
```js
|
|
||||||
const ap = new APlayer({
|
|
||||||
container: document.getElementById('player'),
|
|
||||||
listFolded: false,
|
|
||||||
listMaxHeight: 90,
|
|
||||||
lrcType: 3,
|
|
||||||
audio: [
|
|
||||||
{
|
|
||||||
name: 'name1',
|
|
||||||
artist: 'artist1',
|
|
||||||
url: 'url1.mp3',
|
|
||||||
cover: 'cover1.jpg',
|
|
||||||
lrc: 'lrc1.lrc',
|
|
||||||
theme: '#ebd0c2'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'name2',
|
|
||||||
artist: 'artist2',
|
|
||||||
url: 'url2.mp3',
|
|
||||||
cover: 'cover2.jpg',
|
|
||||||
lrc: 'lrc2.lrc',
|
|
||||||
theme: '#46718b'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## Fixed mode
|
|
||||||
|
|
||||||
APlayer can be fixed to page bottom via fixed mode, fixed mode is a very different mode, enjoy it!
|
|
||||||
|
|
||||||
<div class="aplayer-wrap">
|
|
||||||
<div id="aplayer9"><button class="docute-button load">Click to load player</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
```js
|
|
||||||
const ap = new APlayer({
|
|
||||||
container: document.getElementById('player'),
|
|
||||||
fixed: true,
|
|
||||||
audio: [{
|
|
||||||
name: 'name',
|
|
||||||
artist: 'artist',
|
|
||||||
url: 'url.mp3',
|
|
||||||
cover: 'cover.jpg',
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## Mini mode
|
|
||||||
|
|
||||||
If you don't have enough space for normal player, mini mode might be your choice.
|
|
||||||
|
|
||||||
Please note that mini mode is conflicted with fixed mode.
|
|
||||||
|
|
||||||
<div class="aplayer-wrap">
|
|
||||||
<div id="aplayer6"><button class="docute-button load">Click to load player</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
```js
|
|
||||||
const ap = new APlayer({
|
|
||||||
container: document.getElementById('player'),
|
|
||||||
mini: true,
|
|
||||||
audio: [{
|
|
||||||
name: 'name',
|
|
||||||
artist: 'artist',
|
|
||||||
url: 'url.mp3',
|
|
||||||
cover: 'cover.jpg',
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## MSE support
|
|
||||||
|
|
||||||
### HLS
|
|
||||||
|
|
||||||
It requires the library [hls.js](https://github.com/video-dev/hls.js) and it should be loaded before `APlayer.min.js`.
|
|
||||||
|
|
||||||
<div class="aplayer-wrap">
|
|
||||||
<div id="aplayer7"><button class="docute-button load">Click to load player</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
```html
|
|
||||||
<link rel="stylesheet" href="APlayer.min.css">
|
|
||||||
<div id="aplayer"></div>
|
|
||||||
<script src="hls.min.js"></script>
|
|
||||||
<script src="APlayer.min.js"></script>
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
const ap = new APlayer({
|
|
||||||
container: document.getElementById('aplayer'),
|
|
||||||
audio: [{
|
|
||||||
name: 'HLS',
|
|
||||||
artist: 'artist',
|
|
||||||
url: 'url.m3u8',
|
|
||||||
cover: 'cover.jpg',
|
|
||||||
type: 'hls'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
// another way, use customType
|
|
||||||
const ap = new APlayer({
|
|
||||||
container: document.getElementById('aplayer'),
|
|
||||||
audio: [{
|
|
||||||
name: 'HLS',
|
|
||||||
artist: 'artist',
|
|
||||||
url: 'url.m3u8',
|
|
||||||
cover: 'cover.jpg',
|
|
||||||
type: 'customHls'
|
|
||||||
}],
|
|
||||||
customAudioType: {
|
|
||||||
'customHls': function (audioElement, audio, player) {
|
|
||||||
if (Hls.isSupported()) {
|
|
||||||
const hls = new Hls();
|
|
||||||
hls.loadSource(audio.url);
|
|
||||||
hls.attachMedia(audioElement);
|
|
||||||
}
|
|
||||||
else if (audioElement.canPlayType('application/x-mpegURL') || audioElement.canPlayType('application/vnd.apple.mpegURL')) {
|
|
||||||
audioElement.src = audio.url;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
player.notice('Error: HLS is not supported.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## Self-adapting theme according to cover
|
|
||||||
|
|
||||||
It requires the library [color-thief](https://github.com/lokesh/color-thief/blob/master/src/color-thief.js).
|
|
||||||
|
|
||||||
<div class="aplayer-wrap">
|
|
||||||
<div id="aplayer8"><button class="docute-button load">Click to load player</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
```html
|
|
||||||
<link rel="stylesheet" href="APlayer.min.css">
|
|
||||||
<div id="aplayer"></div>
|
|
||||||
<script src="APlayer.min.js"></script>
|
|
||||||
<script src="color-thief.js"></script>
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
const ap = new APlayer({
|
|
||||||
container: document.getElementById('aplayer'),
|
|
||||||
theme: '#e9e9e9',
|
|
||||||
audio: [{
|
|
||||||
name: 'name1',
|
|
||||||
artist: 'artist1',
|
|
||||||
url: 'url1.mp3',
|
|
||||||
cover: 'cover1.jpg'
|
|
||||||
}, {
|
|
||||||
name: 'name2',
|
|
||||||
artist: 'artist2',
|
|
||||||
url: 'url2.mp3',
|
|
||||||
cover: 'cover2.jpg'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
|
|
||||||
const colorThief = new ColorThief();
|
|
||||||
const image = new Image();
|
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
const setTheme = (index) => {
|
|
||||||
if (!ap.list.audios[index].theme) {
|
|
||||||
xhr.onload = function(){
|
|
||||||
let coverUrl = URL.createObjectURL(this.response);
|
|
||||||
image.onload = function(){
|
|
||||||
let color = colorThief.getColor(image);
|
|
||||||
ap.theme(`rgb(${color[0]}, ${color[1]}, ${color[2]})`, index);
|
|
||||||
URL.revokeObjectURL(coverUrl)
|
|
||||||
};
|
|
||||||
image.src = coverUrl;
|
|
||||||
}
|
|
||||||
xhr.open('GET', ap.list.audios[index].cover, true);
|
|
||||||
xhr.responseType = 'blob';
|
|
||||||
xhr.send();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
setTheme(ap.list.index);
|
|
||||||
ap.on('listswitch', (index) => {
|
|
||||||
setTheme(index);
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## CDN
|
|
||||||
|
|
||||||
- [jsDelivr](https://www.jsdelivr.com/package/npm/aplayer)
|
|
||||||
- [cdnjs](https://cdnjs.com/libraries/aplayer)
|
|
||||||
- [unpkg](https://unpkg.com/aplayer/)
|
|
||||||
|
|
||||||
## FAQ
|
|
||||||
|
|
||||||
### Why can't player autoplay in some mobile browsers?
|
|
||||||
|
|
||||||
Most mobile browsers forbid audio autoplay, you wont be able to achieve it without hacks.
|
|
||||||
352
docs/config.js
|
|
@ -1,352 +0,0 @@
|
||||||
const langs = [
|
|
||||||
{ title: 'English', path: '/home', matchPath: /^\/(home|ecosystem|support)/ },
|
|
||||||
{ title: '简体中文', path: '/zh-Hans/', matchPath: /^\/zh-Hans/ },
|
|
||||||
];
|
|
||||||
|
|
||||||
docute.init({
|
|
||||||
landing: 'landing.html',
|
|
||||||
title: 'APlayer',
|
|
||||||
repo: 'DIYgod/APlayer',
|
|
||||||
twitter: 'DIYgod',
|
|
||||||
'edit-link': 'https://github.com/MoePlayer/APlayer/tree/master/docs',
|
|
||||||
nav: {
|
|
||||||
default: [
|
|
||||||
{
|
|
||||||
title: 'Home', path: '/home'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Ecosystem', path: '/ecosystem'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Support APlayer', path: '/support'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Languages', type: 'dropdown', items: langs
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'zh-Hans': [
|
|
||||||
{
|
|
||||||
title: '首页', path: '/zh-Hans/'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '生态', path: '/zh-Hans/ecosystem'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '支持 APlayer', path: '/zh-Hans/support'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '选择语言', type: 'dropdown', items: langs
|
|
||||||
}
|
|
||||||
],
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
docsearch({
|
|
||||||
apiKey: '',
|
|
||||||
indexName: 'aplayer',
|
|
||||||
tags: ['english', 'zh-Hans'],
|
|
||||||
url: 'https://aplayer.js.org'
|
|
||||||
}),
|
|
||||||
evanyou(),
|
|
||||||
player(),
|
|
||||||
insertUmamiJS('8c8b314e-99d9-4ac4-bee9-0e9826bb2b1c', 'https://umami.diygod.dev/script.js')
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
function insertUmamiJS(id, url) {
|
|
||||||
var script = document.createElement('script');
|
|
||||||
script.setAttribute("data-website-id",id);
|
|
||||||
script.src = url;
|
|
||||||
script.async = true;
|
|
||||||
document.head.appendChild(script);
|
|
||||||
}
|
|
||||||
|
|
||||||
function player () {
|
|
||||||
return function (context) {
|
|
||||||
context.event.on('landing:updated', function () {
|
|
||||||
console.log('landing:updated');
|
|
||||||
clearPlayer();
|
|
||||||
aplayer0();
|
|
||||||
aplayer1();
|
|
||||||
});
|
|
||||||
context.event.on('content:updated', function () {
|
|
||||||
console.log('content:updated');
|
|
||||||
clearPlayer();
|
|
||||||
for (let i = 0; i < document.querySelectorAll('.load').length; i++) {
|
|
||||||
document.querySelectorAll('.load')[i].addEventListener('click', function () {
|
|
||||||
window[this.parentElement.id] && window[this.parentElement.id]();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearPlayer () {
|
|
||||||
for (let i = 0; i < 10; i++) {
|
|
||||||
if (window['ap' + i]) {
|
|
||||||
window['ap' + i].destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function aplayer1 () {
|
|
||||||
window.ap1 = new APlayer({
|
|
||||||
container: document.getElementById('aplayer1'),
|
|
||||||
theme: '#F57F17',
|
|
||||||
lrcType: 3,
|
|
||||||
audio: [{
|
|
||||||
name: '光るなら',
|
|
||||||
artist: 'Goose house',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg',
|
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.lrc',
|
|
||||||
theme: '#ebd0c2'
|
|
||||||
}, {
|
|
||||||
name: 'トリカゴ',
|
|
||||||
artist: 'XX:me',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.jpg',
|
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.lrc',
|
|
||||||
theme: '#46718b'
|
|
||||||
}, {
|
|
||||||
name: '前前前世',
|
|
||||||
artist: 'RADWIMPS',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.jpg',
|
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.lrc',
|
|
||||||
theme: '#505d6b'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function aplayer0 () {
|
|
||||||
window.ap0 = new APlayer({
|
|
||||||
container: document.getElementById('aplayer0'),
|
|
||||||
fixed: true,
|
|
||||||
lrcType: 3,
|
|
||||||
audio: [{
|
|
||||||
name: '前前前世',
|
|
||||||
artist: 'RADWIMPS',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.jpg',
|
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.lrc',
|
|
||||||
theme: '#505d6b'
|
|
||||||
}, {
|
|
||||||
name: 'トリカゴ',
|
|
||||||
artist: 'XX:me',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.jpg',
|
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.lrc',
|
|
||||||
theme: '#46718b'
|
|
||||||
}, {
|
|
||||||
name: '光るなら',
|
|
||||||
artist: 'Goose house',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg',
|
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.lrc',
|
|
||||||
theme: '#ebd0c2'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function aplayer2 () {
|
|
||||||
window.ap2 = new APlayer({
|
|
||||||
container: document.getElementById('aplayer2'),
|
|
||||||
audio: [{
|
|
||||||
name: '光るなら',
|
|
||||||
artist: 'Goose house',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg',
|
|
||||||
theme: '#ebd0c2'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function aplayer3 () {
|
|
||||||
window.ap3 = new APlayer({
|
|
||||||
container: document.getElementById('aplayer3'),
|
|
||||||
mini: false,
|
|
||||||
autoplay: false,
|
|
||||||
loop: 'all',
|
|
||||||
order: 'random',
|
|
||||||
preload: 'auto',
|
|
||||||
volume: 0.7,
|
|
||||||
mutex: true,
|
|
||||||
listFolded: false,
|
|
||||||
listMaxHeight: 90,
|
|
||||||
lrcType: 3,
|
|
||||||
audio: [{
|
|
||||||
name: '光るなら',
|
|
||||||
artist: 'Goose house',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg',
|
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.lrc',
|
|
||||||
theme: '#ebd0c2'
|
|
||||||
}, {
|
|
||||||
name: 'トリカゴ',
|
|
||||||
artist: 'XX:me',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.jpg',
|
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.lrc',
|
|
||||||
theme: '#46718b'
|
|
||||||
}, {
|
|
||||||
name: '前前前世',
|
|
||||||
artist: 'RADWIMPS',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.jpg',
|
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.lrc',
|
|
||||||
theme: '#505d6b'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function aplayer4 () {
|
|
||||||
window.ap4 = new APlayer({
|
|
||||||
container: document.getElementById('aplayer4'),
|
|
||||||
lrcType: 3,
|
|
||||||
audio: [{
|
|
||||||
name: '光るなら',
|
|
||||||
artist: 'Goose house',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg',
|
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.lrc',
|
|
||||||
theme: '#ebd0c2'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function aplayer5 () {
|
|
||||||
window.ap5 = new APlayer({
|
|
||||||
container: document.getElementById('aplayer5'),
|
|
||||||
lrcType: 3,
|
|
||||||
audio: [{
|
|
||||||
name: '光るなら',
|
|
||||||
artist: 'Goose house',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg',
|
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.lrc',
|
|
||||||
theme: '#ebd0c2'
|
|
||||||
}, {
|
|
||||||
name: 'トリカゴ',
|
|
||||||
artist: 'XX:me',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.jpg',
|
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.lrc',
|
|
||||||
theme: '#46718b'
|
|
||||||
}, {
|
|
||||||
name: '前前前世',
|
|
||||||
artist: 'RADWIMPS',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.jpg',
|
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.lrc',
|
|
||||||
theme: '#505d6b'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function aplayer6 () {
|
|
||||||
window.ap6 = new APlayer({
|
|
||||||
container: document.getElementById('aplayer6'),
|
|
||||||
mini: true,
|
|
||||||
audio: [{
|
|
||||||
name: '光るなら',
|
|
||||||
artist: 'Goose house',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg',
|
|
||||||
theme: '#ebd0c2'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function aplayer7 () {
|
|
||||||
window.ap7 = new APlayer({
|
|
||||||
container: document.getElementById('aplayer7'),
|
|
||||||
audio: [{
|
|
||||||
name: '光るなら(HLS)',
|
|
||||||
artist: 'Goose house',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hls/hikarunara.m3u8',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg',
|
|
||||||
theme: '#ebd0c2',
|
|
||||||
type: 'hls'
|
|
||||||
}, {
|
|
||||||
name: '光るなら',
|
|
||||||
artist: 'Goose house',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg',
|
|
||||||
theme: '#ebd0c2'
|
|
||||||
}, {
|
|
||||||
name: 'トリカゴ',
|
|
||||||
artist: 'XX:me',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.jpg',
|
|
||||||
theme: '#46718b'
|
|
||||||
}, {
|
|
||||||
name: '前前前世',
|
|
||||||
artist: 'RADWIMPS',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.jpg',
|
|
||||||
theme: '#505d6b'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function aplayer8 () {
|
|
||||||
window.ap8 = new APlayer({
|
|
||||||
container: document.getElementById('aplayer8'),
|
|
||||||
theme: '#e9e9e9',
|
|
||||||
audio: [{
|
|
||||||
name: '光るなら',
|
|
||||||
artist: 'Goose house',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg',
|
|
||||||
}, {
|
|
||||||
name: 'トリカゴ',
|
|
||||||
artist: 'XX:me',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.jpg',
|
|
||||||
}, {
|
|
||||||
name: '前前前世',
|
|
||||||
artist: 'RADWIMPS',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.jpg',
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
|
|
||||||
const colorThief = new ColorThief();
|
|
||||||
window.ap8.on('switchaudio', function (index) {
|
|
||||||
if (!window.ap8.options.audio[index].theme) {
|
|
||||||
colorThief.getColorAsync(window.ap8.options.audio[index].cover, function (color) {
|
|
||||||
window.ap8.theme(`rgb(${color[0]}, ${color[1]}, ${color[2]})`, index);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function aplayer9 () {
|
|
||||||
window.ap9 = new APlayer({
|
|
||||||
container: document.getElementById('aplayer9'),
|
|
||||||
fixed: true,
|
|
||||||
lrcType: 3,
|
|
||||||
audio: [{
|
|
||||||
name: '光るなら',
|
|
||||||
artist: 'Goose house',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.jpg',
|
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/hikarunara.lrc',
|
|
||||||
theme: '#ebd0c2'
|
|
||||||
}, {
|
|
||||||
name: 'トリカゴ',
|
|
||||||
artist: 'XX:me',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.jpg',
|
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/darling.lrc',
|
|
||||||
theme: '#46718b'
|
|
||||||
}, {
|
|
||||||
name: '前前前世',
|
|
||||||
artist: 'RADWIMPS',
|
|
||||||
url: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.mp3',
|
|
||||||
cover: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.jpg',
|
|
||||||
lrc: 'https://cn-south-17-aplayer-46154810.oss.dogecdn.com/yourname.lrc',
|
|
||||||
theme: '#505d6b'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
---
|
|
||||||
search: english
|
|
||||||
---
|
|
||||||
|
|
||||||
# Ecosystem
|
|
||||||
|
|
||||||
Let's make APlayer better, feel free to submit yours in [`Let me know!`](https://github.com/MoePlayer/APlayer/issues/79)
|
|
||||||
|
|
||||||
## Help
|
|
||||||
|
|
||||||
### Joining the Discussion
|
|
||||||
|
|
||||||
- [Telegram Group](https://t.me/adplayer)
|
|
||||||
- [QQ Group](https://shang.qq.com/wpa/qunwpa?idkey=bf22213ae0028a82e5adf3f286dfd4f01e0997dc9f1dcd8e831a0a85e799be17): 415835947
|
|
||||||
|
|
||||||
### Creating issue
|
|
||||||
|
|
||||||
- [MoePlayer/APlayer/issues](https://github.com/MoePlayer/APlayer/issues)
|
|
||||||
|
|
||||||
## Related Projects
|
|
||||||
|
|
||||||
### Plugins
|
|
||||||
|
|
||||||
- [APlayer-Typecho-Plugin](https://github.com/zgq354/APlayer-Typecho-Plugin): Typecho
|
|
||||||
- [hexo-tag-aplayer](https://github.com/grzhan/hexo-tag-aplayer): Hexo
|
|
||||||
- [Hermit-X(APlayer for WordPress)](https://github.com/liwanglin12/Hermit-X): WordPress
|
|
||||||
- [APlayerHandle](https://github.com/kn007/APlayerHandle): WordPress
|
|
||||||
- [APlayer_for_Z-BlogPHP](https://github.com/fghrsh/APlayer_for_Z-BlogPHP): Z-BlogPHP
|
|
||||||
- [react-aplayer](https://github.com/sabrinaluo/react-aplayer): React
|
|
||||||
- [Vue-APlayer](https://github.com/SevenOutman/vue-aplayer): Vue
|
|
||||||
- [vue-aplayer](https://github.com/MoeFE/vue-aplayer): Vue
|
|
||||||
- [php-aplayer](https://github.com/Daryl-L/php-aplayer): PHP
|
|
||||||
- [aplayer-hugo-module](https://github.com/Runzelee/aplayer-hugo-module): Hugo
|
|
||||||
|
|
||||||
### Tooling
|
|
||||||
|
|
||||||
- [APlayer-Controler](https://github.com/Mashiro-Sorata/APlayer-Controler): controling tool
|
|
||||||
- [MetingJS](https://github.com/metowolf/MetingJS): work with Meting music API
|
|
||||||
|
|
||||||
## Who use APlayer?
|
|
||||||
|
|
||||||
- [bilibili](https://www.bilibili.com/): 国内知名的视频弹幕网站
|
|
||||||
- [黑客派](https://hacpai.com/): 程序员和设计师的聚集地,一个活跃的小众社区
|
|
||||||
- [浙江大学CC98论坛](https://zh.wikipedia.org/wiki/CC98%E8%AE%BA%E5%9D%9B): 浙江大学校网内规模最大的论坛,中国各大学中较活跃的BBS之一
|
|
||||||
- [Jelly Rue](http://jellyrue.com/): Jelly Rue, an indie pop-rock band from Tartu.
|
|
||||||
- [Opus](http://www.opusopus.co/): An artist-exploration data visualization application
|
|
||||||
- [站长之家](http://www.chinaz.com/15year/index.html): 针对中文站点提供资讯、技术、资源、服务
|
|
||||||
- [LLSupport](https://www.lovelivesupport.com/): This site provides a lot of information about LoveLive
|
|
||||||
- [歌词千寻](https://www.lrcgc.com/diy): 每日更新的LRC歌词网站
|
|
||||||
- [iSearch](http://i.oppsu.cn): 一个提供 iTunes 搜索,试听,高清专辑封面获取,查看最新音乐动态等综合性平台
|
|
||||||
- [LRC歌词编辑器](https://github.com/MoeFE/Lyric): 一款非常实用的在线LRC歌词编辑器
|
|
||||||
- [Аэростатика](https://aerostatica.ru/)
|
|
||||||
- [HealthDig](https://healthdig.co): 每天只需两分钟的重点新闻资讯
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
|
|
||||||
<title>APlayer</title>
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docute@3.4.12/dist/docute.css">
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docute@3.4.12/dist/theme-github.css" />
|
|
||||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-48084758-8"></script>
|
|
||||||
<script>
|
|
||||||
window.dataLayer = window.dataLayer || [];
|
|
||||||
function gtag() { dataLayer.push(arguments); }
|
|
||||||
gtag('js', new Date());
|
|
||||||
|
|
||||||
gtag('config', 'UA-48084758-8');
|
|
||||||
</script>
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/aplayer@1.10.0/dist/APlayer.min.css">
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/hls.js/dist/hls.min.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/aplayer@1.10.0/dist/APlayer.min.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/color-thief-don@2.0.2/src/color-thief.js"></script>
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
text-rendering: auto;
|
|
||||||
}
|
|
||||||
#evanyou-canvas {
|
|
||||||
z-index: -1 !important;
|
|
||||||
}
|
|
||||||
.aplayer-wrap {
|
|
||||||
max-width: 700px;
|
|
||||||
margin: 20px 0;
|
|
||||||
}
|
|
||||||
.sidebar-toggle {
|
|
||||||
z-index: 90;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<!-- don't remove this part start -->
|
|
||||||
<div id="app"></div>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/docute@3.4.12/plugins/docsearch.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/docute-evanyou/dist/evanyou.min.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/docute@3.4.12/dist/docute.js"></script>
|
|
||||||
<script src="./config.js"></script>
|
|
||||||
<!-- livereload script placeholder -->
|
|
||||||
<!-- don't remove this part end -->
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,84 +0,0 @@
|
||||||
<h1>APlayer</h1>
|
|
||||||
|
|
||||||
<h3>🍭 Wow, such a beautiful HTML5 music player.</h3>
|
|
||||||
|
|
||||||
<div class="aplayer-wrap">
|
|
||||||
<div id="aplayer1"></div>
|
|
||||||
</div>
|
|
||||||
<div id="aplayer0"></div>
|
|
||||||
|
|
||||||
<div class="landing-buttons">
|
|
||||||
<a class="landing-button" target="_blank" href="https://github.com/MoePlayer/APlayer">
|
|
||||||
GitHub
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a class="landing-button" router-link="/home">
|
|
||||||
Docs
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
h1 {
|
|
||||||
margin: 0;
|
|
||||||
margin-top: -50px;
|
|
||||||
font-weight: normal;
|
|
||||||
font-size: 40px;
|
|
||||||
letter-spacing: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin-top: 20px;
|
|
||||||
color: #999;
|
|
||||||
font-weight: normal;
|
|
||||||
letter-spacing: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.landing {
|
|
||||||
padding: 10px;
|
|
||||||
display: -webkit-box;
|
|
||||||
display: -ms-flexbox;
|
|
||||||
display: flex;
|
|
||||||
-webkit-box-align: center;
|
|
||||||
-ms-flex-align: center;
|
|
||||||
align-items: center;
|
|
||||||
-webkit-box-pack: center;
|
|
||||||
-ms-flex-pack: center;
|
|
||||||
justify-content: center;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
-webkit-box-direction: normal;
|
|
||||||
-ms-flex-direction: column;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.features {
|
|
||||||
margin-top: 20px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 1.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.landing-button {
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
border-radius: 33px;
|
|
||||||
padding: 10px 30px;
|
|
||||||
background-color: white;
|
|
||||||
display: inline-block;
|
|
||||||
margin-right: 20px;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.landing-button:hover {
|
|
||||||
border-color: #42b983;
|
|
||||||
color: #42b983;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-wrap {
|
|
||||||
width: 600px;
|
|
||||||
max-width: 100%;
|
|
||||||
margin: 20px 0 40px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
---
|
|
||||||
search: english
|
|
||||||
---
|
|
||||||
|
|
||||||
# Sponsor APlayer Development
|
|
||||||
|
|
||||||
APlayer is an MIT licensed open source project and completely free to use. However, the amount of effort needed to maintain and develop new features for the project is not sustainable without proper financial backing.
|
|
||||||
|
|
||||||
If you run a business and are using APlayer in a revenue-generating product, it makes business sense to sponsor APlayer development: it ensures the project that your product relies on stays healthy and actively maintained.
|
|
||||||
|
|
||||||
If you are an individual user and have enjoyed the productivity of using APlayer, consider donating as a sign of appreciation - like buying me coffee once in a while :)
|
|
||||||
|
|
||||||
You can support APlayer via donations.
|
|
||||||
|
|
||||||
### Recurring Donation
|
|
||||||
|
|
||||||
- Become a Sponser on [GitHub](https://github.com/sponsors/DIYgod)
|
|
||||||
- Become a Sponser on [Patreon](https://www.patreon.com/DIYgod)
|
|
||||||
- Become a Sponser on [爱发电](https://afdian.net/@diygod)
|
|
||||||
- Contact us directly: i@diygod.me
|
|
||||||
|
|
||||||
### One-time Donation
|
|
||||||
|
|
||||||
We accept donations via the following ways:
|
|
||||||
|
|
||||||
- [WeChat Pay](https://diygod.me/images/wx.jpg)
|
|
||||||
- [Alipay](https://diygod.me/images/zfb.jpg)
|
|
||||||
- [Paypal](https://www.paypal.me/DIYgod)
|
|
||||||
|
|
||||||
## Current Premium Sponsors
|
|
||||||
|
|
||||||
### Special Sponsors
|
|
||||||
|
|
||||||
<a href="https://www.dogecloud.com/?ref=dplayer" target="_blank">
|
|
||||||
<img width="222px" src="https://player.dogecloud.com/img/logo_with_product3.png">
|
|
||||||
</a>
|
|
||||||
|
|
||||||
## APlayer contributors
|
|
||||||
|
|
||||||
This project exists thanks to all the people who contribute.
|
|
||||||
|
|
||||||
<a href="https://github.com/MoePlayer/APlayer/graphs/contributors"><img src="https://opencollective.com/APlayer/contributors.svg?width=890" /></a>
|
|
||||||
|
|
@ -1,589 +0,0 @@
|
||||||
---
|
|
||||||
nav: zh-Hans
|
|
||||||
search: zh-Hans
|
|
||||||
---
|
|
||||||
|
|
||||||
# APlayer
|
|
||||||
|
|
||||||
🍭 Wow, such a beautiful HTML5 music player
|
|
||||||
|
|
||||||
## 特别赞助商
|
|
||||||
|
|
||||||
<a href="https://www.dogecloud.com/?ref=dplayer" target="_blank">
|
|
||||||
<img width="222px" src="https://player.dogecloud.com/img/logo_with_product3.png">
|
|
||||||
</a>
|
|
||||||
|
|
||||||
## 安装
|
|
||||||
|
|
||||||
使用 npm:
|
|
||||||
|
|
||||||
```
|
|
||||||
npm install aplayer --save
|
|
||||||
```
|
|
||||||
|
|
||||||
使用 Yarn:
|
|
||||||
|
|
||||||
```
|
|
||||||
yarn add aplayer
|
|
||||||
```
|
|
||||||
|
|
||||||
## 入门
|
|
||||||
|
|
||||||
<div class="aplayer-wrap">
|
|
||||||
<div id="aplayer2"><button class="docute-button load">点击加载播放器</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
```html
|
|
||||||
<link rel="stylesheet" href="APlayer.min.css">
|
|
||||||
<div id="aplayer"></div>
|
|
||||||
<script src="APlayer.min.js"></script>
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
const ap = new APlayer({
|
|
||||||
container: document.getElementById('aplayer'),
|
|
||||||
audio: [{
|
|
||||||
name: 'name',
|
|
||||||
artist: 'artist',
|
|
||||||
url: 'url.mp3',
|
|
||||||
cover: 'cover.jpg'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
使用模块管理器:
|
|
||||||
|
|
||||||
```js
|
|
||||||
import 'APlayer/dist/APlayer.min.css';
|
|
||||||
import APlayer from 'APlayer';
|
|
||||||
|
|
||||||
const ap = new APlayer(options);
|
|
||||||
```
|
|
||||||
|
|
||||||
## 参数
|
|
||||||
|
|
||||||
名称 | 默认值 | 描述
|
|
||||||
----|-------|----
|
|
||||||
container | document.querySelector('.aplayer') | 播放器容器元素
|
|
||||||
fixed | false | 开启吸底模式, [详情](https://aplayer.js.org/#/home?id=fixed-mode)
|
|
||||||
mini | false | 开启迷你模式, [详情](https://aplayer.js.org/#/home?id=mini-mode)
|
|
||||||
autoplay | false | 音频自动播放
|
|
||||||
theme | '#b7daff' | 主题色
|
|
||||||
loop | 'all' | 音频循环播放, 可选值: 'all', 'one', 'none'
|
|
||||||
order | 'list' | 音频循环顺序, 可选值: 'list', 'random'
|
|
||||||
preload | 'auto' | 预加载,可选值: 'none', 'metadata', 'auto'
|
|
||||||
volume | 0.7 | 默认音量,请注意播放器会记忆用户设置,用户手动设置音量后默认音量即失效
|
|
||||||
audio | - | 音频信息, 应该是一个对象或对象数组
|
|
||||||
audio.name | - | 音频名称
|
|
||||||
audio.artist | - | 音频艺术家
|
|
||||||
audio.url | - | 音频链接
|
|
||||||
audio.cover | - | 音频封面
|
|
||||||
audio.lrc | - | [详情](https://aplayer.js.org/#/home?id=lrc)
|
|
||||||
audio.theme | - | 切换到此音频时的主题色,比上面的 theme 优先级高
|
|
||||||
audio.type | 'auto' | 可选值: 'auto', 'hls', 'normal' 或其他自定义类型, [详情](https://aplayer.js.org/#/home?id=mse-support)
|
|
||||||
customAudioType | - | 自定义类型,[详情](https://aplayer.js.org/#/home?id=mse-support)
|
|
||||||
mutex | true | 互斥,阻止多个播放器同时播放,当前播放器播放时暂停其他播放器
|
|
||||||
lrcType | 0 | [详情](https://aplayer.js.org/#/home?id=lrc)
|
|
||||||
listFolded | false | 列表默认折叠
|
|
||||||
listMaxHeight | - | 列表最大高度
|
|
||||||
storageName | 'aplayer-setting' | 存储播放器设置的 localStorage key
|
|
||||||
|
|
||||||
例如:
|
|
||||||
|
|
||||||
<div class="aplayer-wrap">
|
|
||||||
<div id="aplayer3"><button class="docute-button load">点击加载播放器</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
```js
|
|
||||||
const ap = new APlayer({
|
|
||||||
container: document.getElementById('player'),
|
|
||||||
mini: false,
|
|
||||||
autoplay: false,
|
|
||||||
theme: '#FADFA3',
|
|
||||||
loop: 'all',
|
|
||||||
order: 'random',
|
|
||||||
preload: 'auto',
|
|
||||||
volume: 0.7,
|
|
||||||
mutex: true,
|
|
||||||
listFolded: false,
|
|
||||||
listMaxHeight: 90,
|
|
||||||
lrcType: 3,
|
|
||||||
audio: [
|
|
||||||
{
|
|
||||||
name: 'name1',
|
|
||||||
artist: 'artist1',
|
|
||||||
url: 'url1.mp3',
|
|
||||||
cover: 'cover1.jpg',
|
|
||||||
lrc: 'lrc1.lrc',
|
|
||||||
theme: '#ebd0c2'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'name2',
|
|
||||||
artist: 'artist2',
|
|
||||||
url: 'url2.mp3',
|
|
||||||
cover: 'cover2.jpg',
|
|
||||||
lrc: 'lrc2.lrc',
|
|
||||||
theme: '#46718b'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## API
|
|
||||||
|
|
||||||
+ `APlayer.version`: 静态属性, 返回 APlayer 的版本号
|
|
||||||
|
|
||||||
+ `ap.play()`: 播放音频
|
|
||||||
|
|
||||||
+ `ap.pause()`: 暂停音频
|
|
||||||
|
|
||||||
+ `ap.seek(time: number)`: 跳转到特定时间,时间的单位为秒
|
|
||||||
|
|
||||||
```js
|
|
||||||
ap.seek(100);
|
|
||||||
```
|
|
||||||
|
|
||||||
+ `ap.toggle()`: 切换播放和暂停
|
|
||||||
|
|
||||||
+ `ap.on(event: string, handler: function)`: 绑定音频和播放器事件,[详情](https://aplayer.js.org/#/home?id=event-binding)
|
|
||||||
|
|
||||||
+ `ap.volume(percentage: number, nostorage: boolean)`: 设置音频音量
|
|
||||||
|
|
||||||
```js
|
|
||||||
ap.volume(0.1, true);
|
|
||||||
```
|
|
||||||
|
|
||||||
+ `ap.theme(color: string, index: number)`: 设置播放器主题色, index 默认为当前音频的 index
|
|
||||||
|
|
||||||
```js
|
|
||||||
ap.theme('#000', 0);
|
|
||||||
```
|
|
||||||
|
|
||||||
+ `ap.setMode(mode: string)`: 设置播放器模式,mode 取值应为 'mini' 或 'normal'
|
|
||||||
|
|
||||||
+ `ap.mode`: 返回播放器当前模式,'mini' 或 'normal'
|
|
||||||
|
|
||||||
+ `ap.notice(text: string, time: number, opacity: number)`: 显示通知,时间的单位为毫秒,默认时间 2000 毫秒,默认透明度 0.8,设置时间为 0 可以取消通知自动隐藏
|
|
||||||
|
|
||||||
```js
|
|
||||||
ap.notice('Amazing player', 2000, 0.8);
|
|
||||||
```
|
|
||||||
|
|
||||||
+ `ap.skipBack()`: 切换到上一首音频
|
|
||||||
|
|
||||||
+ `ap.skipForward()`: 切换到下一首音频
|
|
||||||
|
|
||||||
+ `ap.destroy()`: 销毁播放器
|
|
||||||
|
|
||||||
+ `ap.lrc`
|
|
||||||
|
|
||||||
+ `ap.lrc.show()`: 显示歌词
|
|
||||||
|
|
||||||
+ `ap.lrc.hide()`: 隐藏歌词
|
|
||||||
|
|
||||||
+ `ap.lrc.toggle()`: 显示/隐藏歌词
|
|
||||||
|
|
||||||
+ `ap.list`
|
|
||||||
|
|
||||||
+ `ap.list.show()`: 显示播放列表
|
|
||||||
|
|
||||||
+ `ap.list.hide()`: 隐藏播放列表
|
|
||||||
|
|
||||||
+ `ap.list.toggle()`: 显示/隐藏播放列表
|
|
||||||
|
|
||||||
+ `ap.list.add(audios: array | object)`: 添加一个或几个新音频到播放列表
|
|
||||||
|
|
||||||
```js
|
|
||||||
ap.list.add([{
|
|
||||||
name: 'name',
|
|
||||||
artist: 'artist',
|
|
||||||
url: 'url.mp3',
|
|
||||||
cover: 'cover.jpg',
|
|
||||||
lrc: 'lrc.lrc',
|
|
||||||
theme: '#ebd0c2'
|
|
||||||
}]);
|
|
||||||
```
|
|
||||||
|
|
||||||
+ `ap.list.remove(index: number)`: 移除播放列表中的一个音频
|
|
||||||
|
|
||||||
```js
|
|
||||||
ap.list.remove(1);
|
|
||||||
```
|
|
||||||
|
|
||||||
+ `ap.list.switch()`: 切换到播放列表里的其他音频
|
|
||||||
|
|
||||||
```js
|
|
||||||
ap.list.switch(1);
|
|
||||||
```
|
|
||||||
|
|
||||||
+ `ap.list.clear()`: 清空播放列表
|
|
||||||
|
|
||||||
+ `ap.audio`: 原生 audio
|
|
||||||
|
|
||||||
+ `ap.audio.currentTime`: 返回音频当前播放时间
|
|
||||||
|
|
||||||
+ `ap.audio.duration`: 返回音频总时间
|
|
||||||
|
|
||||||
+ `ap.audio.paused`: 返回音频是否暂停
|
|
||||||
|
|
||||||
+ 支持大多数[原生audio接口](http://www.w3schools.com/tags/ref_av_dom.asp)
|
|
||||||
|
|
||||||
## 事件绑定
|
|
||||||
|
|
||||||
`ap.on(event, handler)`
|
|
||||||
|
|
||||||
```js
|
|
||||||
ap.on('ended', function () {
|
|
||||||
console.log('player ended');
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
音频事件
|
|
||||||
|
|
||||||
- abort
|
|
||||||
- canplay
|
|
||||||
- canplaythrough
|
|
||||||
- durationchange
|
|
||||||
- emptied
|
|
||||||
- ended
|
|
||||||
- error
|
|
||||||
- loadeddata
|
|
||||||
- loadedmetadata
|
|
||||||
- loadstart
|
|
||||||
- mozaudioavailable
|
|
||||||
- pause
|
|
||||||
- play
|
|
||||||
- playing
|
|
||||||
- progress
|
|
||||||
- ratechange
|
|
||||||
- seeked
|
|
||||||
- seeking
|
|
||||||
- stalled
|
|
||||||
- suspend
|
|
||||||
- timeupdate
|
|
||||||
- volumechange
|
|
||||||
- waiting
|
|
||||||
|
|
||||||
播放器事件
|
|
||||||
|
|
||||||
- listshow
|
|
||||||
- listhide
|
|
||||||
- listadd
|
|
||||||
- listremove
|
|
||||||
- listswitch
|
|
||||||
- listclear
|
|
||||||
- noticeshow
|
|
||||||
- noticehide
|
|
||||||
- destroy
|
|
||||||
- lrcshow
|
|
||||||
- lrchide
|
|
||||||
|
|
||||||
## 歌词
|
|
||||||
|
|
||||||
我们有三种方式来给 APlayer 传递歌词,使用 `lrcType` 参数指明使用哪种方式,然后把歌词放到 `audio.lrc` 参数或者 HTML 里。
|
|
||||||
|
|
||||||
<div class="aplayer-wrap">
|
|
||||||
<div id="aplayer4"><button class="docute-button load">点击加载播放器</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
### LRC 文件方式
|
|
||||||
|
|
||||||
第一种方式,把歌词放到 LRC 文件里,音频播放时会加载对应的 LRC 文件。
|
|
||||||
|
|
||||||
```js
|
|
||||||
const ap = new APlayer({
|
|
||||||
container: document.getElementById('aplayer'),
|
|
||||||
lrcType: 3,
|
|
||||||
audio: {
|
|
||||||
name: 'name',
|
|
||||||
artist: 'artist',
|
|
||||||
url: 'demo.mp3',
|
|
||||||
cover: 'demo.jpg',
|
|
||||||
lrc: 'lrc.lrc'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### JS 字符串方式
|
|
||||||
|
|
||||||
第二种方式,把歌词放到 JS 字符串里面。
|
|
||||||
|
|
||||||
```js
|
|
||||||
const ap = new APlayer({
|
|
||||||
container: document.getElementById('aplayer'),
|
|
||||||
lrcType: 1,
|
|
||||||
audio: {
|
|
||||||
name: 'name',
|
|
||||||
artist: 'artist',
|
|
||||||
url: 'demo.mp3',
|
|
||||||
cover: 'demo.jpg',
|
|
||||||
lrc: '[00:00.00]APlayer\n[00:04.01]is\n[00:08.02]amazing'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### HTML 方式
|
|
||||||
|
|
||||||
第三种方式,把歌词放到 HTML 里面。
|
|
||||||
|
|
||||||
```html
|
|
||||||
<link rel="stylesheet" href="APlayer.min.css">
|
|
||||||
<div id="player">
|
|
||||||
<pre class="aplayer-lrc-content">
|
|
||||||
[00:00.00]APlayer audio1
|
|
||||||
[00:04.01]is
|
|
||||||
[00:08.02]amazing
|
|
||||||
<!-- ... -->
|
|
||||||
</pre>
|
|
||||||
<pre class="aplayer-lrc-content">
|
|
||||||
[00:00.00]APlayer audio2
|
|
||||||
[00:04.01]is
|
|
||||||
[00:08.02]amazing
|
|
||||||
<!-- ... -->
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
<script src="APlayer.min.js"></script>
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
const ap = new APlayer({
|
|
||||||
container: document.getElementById('aplayer'),
|
|
||||||
lrcType: 2,
|
|
||||||
audio: [[
|
|
||||||
{
|
|
||||||
name: 'name1',
|
|
||||||
artist: 'artist1',
|
|
||||||
url: 'url1.mp3',
|
|
||||||
cover: 'cover1.jpg'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'name2',
|
|
||||||
artist: 'artist2',
|
|
||||||
url: 'url2.mp3',
|
|
||||||
cover: 'cover2.jpg'
|
|
||||||
}
|
|
||||||
]]
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### 歌词格式
|
|
||||||
|
|
||||||
支持下面格式的歌词:
|
|
||||||
|
|
||||||
`[mm:ss]APlayer`
|
|
||||||
|
|
||||||
`[mm:ss.xx]is`
|
|
||||||
|
|
||||||
`[mm:ss.xxx]amazing`
|
|
||||||
|
|
||||||
`[mm:ss.xx][mm:ss.xx]APlayer`
|
|
||||||
|
|
||||||
`[mm:ss.xx]<mm:ss.xx>is`
|
|
||||||
|
|
||||||
`[mm:ss.xx]amazing[mm:ss.xx]APlayer`
|
|
||||||
|
|
||||||
## 播放列表
|
|
||||||
|
|
||||||
当有多个音频时会 APlayer 会展示一个播放列表,`listFolded` 参数指明列表是否默认折叠,`listMaxHeight` 参数指明列表最大高度。
|
|
||||||
|
|
||||||
<div class="aplayer-wrap">
|
|
||||||
<div id="aplayer5"><button class="docute-button load">点击加载播放器</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
```js
|
|
||||||
const ap = new APlayer({
|
|
||||||
container: document.getElementById('player'),
|
|
||||||
listFolded: false,
|
|
||||||
listMaxHeight: 90,
|
|
||||||
lrcType: 3,
|
|
||||||
audio: [
|
|
||||||
{
|
|
||||||
name: 'name1',
|
|
||||||
artist: 'artist1',
|
|
||||||
url: 'url1.mp3',
|
|
||||||
cover: 'cover1.jpg',
|
|
||||||
lrc: 'lrc1.lrc',
|
|
||||||
theme: '#ebd0c2'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'name2',
|
|
||||||
artist: 'artist2',
|
|
||||||
url: 'url2.mp3',
|
|
||||||
cover: 'cover2.jpg',
|
|
||||||
lrc: 'lrc2.lrc',
|
|
||||||
theme: '#46718b'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
```
|
|
||||||
## 吸底模式
|
|
||||||
|
|
||||||
APlayer 可以通过吸底模式固定在页面底部,这种模式跟普通模式有很大不同。
|
|
||||||
|
|
||||||
<div class="aplayer-wrap">
|
|
||||||
<div id="aplayer9"><button class="docute-button load">点击加载播放器</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
```js
|
|
||||||
const ap = new APlayer({
|
|
||||||
container: document.getElementById('player'),
|
|
||||||
fixed: true,
|
|
||||||
audio: [{
|
|
||||||
name: 'name',
|
|
||||||
artist: 'artist',
|
|
||||||
url: 'url.mp3',
|
|
||||||
cover: 'cover.jpg',
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## 迷你模式
|
|
||||||
|
|
||||||
如果你没有足够空间来放置正常模式的播放器,那么你可以考虑使用迷你模式。
|
|
||||||
|
|
||||||
请注意迷你模式与吸底模式冲突。
|
|
||||||
|
|
||||||
<div class="aplayer-wrap">
|
|
||||||
<div id="aplayer6"><button class="docute-button load">点击加载播放器</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
```js
|
|
||||||
const ap = new APlayer({
|
|
||||||
container: document.getElementById('player'),
|
|
||||||
mini: true,
|
|
||||||
audio: [{
|
|
||||||
name: 'name',
|
|
||||||
artist: 'artist',
|
|
||||||
url: 'url.mp3',
|
|
||||||
cover: 'cover.jpg',
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## MSE 支持
|
|
||||||
|
|
||||||
### HLS
|
|
||||||
|
|
||||||
需要在 `APlayer.min.js` 前面加载 [hls.js](https://github.com/video-dev/hls.js)。
|
|
||||||
|
|
||||||
<div class="aplayer-wrap">
|
|
||||||
<div id="aplayer7"><button class="docute-button load">点击加载播放器</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
```html
|
|
||||||
<link rel="stylesheet" href="APlayer.min.css">
|
|
||||||
<div id="aplayer"></div>
|
|
||||||
<script src="hls.min.js"></script>
|
|
||||||
<script src="APlayer.min.js"></script>
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
const ap = new APlayer({
|
|
||||||
container: document.getElementById('aplayer'),
|
|
||||||
audio: [{
|
|
||||||
name: 'HLS',
|
|
||||||
artist: 'artist',
|
|
||||||
url: 'url.m3u8',
|
|
||||||
cover: 'cover.jpg',
|
|
||||||
type: 'hls'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
// 另一种方式,使用 customAudioType
|
|
||||||
const ap = new APlayer({
|
|
||||||
container: document.getElementById('aplayer'),
|
|
||||||
audio: [{
|
|
||||||
name: 'HLS',
|
|
||||||
artist: 'artist',
|
|
||||||
url: 'url.m3u8',
|
|
||||||
cover: 'cover.jpg',
|
|
||||||
type: 'customHls'
|
|
||||||
}],
|
|
||||||
customAudioType: {
|
|
||||||
'customHls': function (audioElement, audio, player) {
|
|
||||||
if (Hls.isSupported()) {
|
|
||||||
const hls = new Hls();
|
|
||||||
hls.loadSource(audio.url);
|
|
||||||
hls.attachMedia(audioElement);
|
|
||||||
}
|
|
||||||
else if (audioElement.canPlayType('application/x-mpegURL') || audioElement.canPlayType('application/vnd.apple.mpegURL')) {
|
|
||||||
audioElement.src = audio.url;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
player.notice('Error: HLS is not supported.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## 根据封面自适应主题色
|
|
||||||
|
|
||||||
需要额外加载 [color-thief.js](https://github.com/lokesh/color-thief/blob/master/src/color-thief.js)
|
|
||||||
|
|
||||||
<div class="aplayer-wrap">
|
|
||||||
<div id="aplayer8"><button class="docute-button load">点击加载播放器</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
```html
|
|
||||||
<link rel="stylesheet" href="APlayer.min.css">
|
|
||||||
<div id="aplayer"></div>
|
|
||||||
<script src="APlayer.min.js"></script>
|
|
||||||
<script src="color-thief.js"></script>
|
|
||||||
```
|
|
||||||
|
|
||||||
```js
|
|
||||||
const ap = new APlayer({
|
|
||||||
container: document.getElementById('aplayer'),
|
|
||||||
theme: '#e9e9e9',
|
|
||||||
audio: [{
|
|
||||||
name: 'name1',
|
|
||||||
artist: 'artist1',
|
|
||||||
url: 'url1.mp3',
|
|
||||||
cover: 'cover1.jpg'
|
|
||||||
}, {
|
|
||||||
name: 'name2',
|
|
||||||
artist: 'artist2',
|
|
||||||
url: 'url2.mp3',
|
|
||||||
cover: 'cover2.jpg'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
|
|
||||||
const colorThief = new ColorThief();
|
|
||||||
const image = new Image();
|
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
const setTheme = (index) => {
|
|
||||||
if (!ap.list.audios[index].theme) {
|
|
||||||
xhr.onload = function(){
|
|
||||||
let coverUrl = URL.createObjectURL(this.response);
|
|
||||||
image.onload = function(){
|
|
||||||
let color = colorThief.getColor(image);
|
|
||||||
ap.theme(`rgb(${color[0]}, ${color[1]}, ${color[2]})`, index);
|
|
||||||
URL.revokeObjectURL(coverUrl)
|
|
||||||
};
|
|
||||||
image.src = coverUrl;
|
|
||||||
}
|
|
||||||
xhr.open('GET', ap.list.audios[index].cover, true);
|
|
||||||
xhr.responseType = 'blob';
|
|
||||||
xhr.send();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
setTheme(ap.list.index);
|
|
||||||
ap.on('listswitch', (index) => {
|
|
||||||
setTheme(index);
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## CDN
|
|
||||||
|
|
||||||
- [jsDelivr](https://www.jsdelivr.com/package/npm/aplayer)
|
|
||||||
- [cdnjs](https://cdnjs.com/libraries/aplayer)
|
|
||||||
- [unpkg](https://unpkg.com/aplayer/)
|
|
||||||
|
|
||||||
## 常见问题
|
|
||||||
|
|
||||||
### 为什么播放器不能在手机上自动播放?
|
|
||||||
|
|
||||||
大多数移动端浏览器禁止了音频自动播放。
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
---
|
|
||||||
nav: zh-Hans
|
|
||||||
search: zh-Hans
|
|
||||||
---
|
|
||||||
|
|
||||||
# 生态
|
|
||||||
|
|
||||||
让 APlayer 变得更好,请随意在 [`Let me know!`](https://github.com/MoePlayer/APlayer/issues/79) 提交你的项目和产品
|
|
||||||
|
|
||||||
## 帮助
|
|
||||||
|
|
||||||
### 参与讨论
|
|
||||||
|
|
||||||
- [Telegram 群](https://t.me/adplayer)
|
|
||||||
- [QQ 群](https://shang.qq.com/wpa/qunwpa?idkey=bf22213ae0028a82e5adf3f286dfd4f01e0997dc9f1dcd8e831a0a85e799be17): 415835947
|
|
||||||
|
|
||||||
### 提交 issue
|
|
||||||
|
|
||||||
- [MoePlayer/APlayer/issues](https://github.com/MoePlayer/APlayer/issues)
|
|
||||||
|
|
||||||
## 相关项目
|
|
||||||
|
|
||||||
### 插件
|
|
||||||
|
|
||||||
- [APlayer-Typecho-Plugin](https://github.com/zgq354/APlayer-Typecho-Plugin): Typecho
|
|
||||||
- [hexo-tag-aplayer](https://github.com/grzhan/hexo-tag-aplayer): Hexo
|
|
||||||
- [Hermit-X(APlayer for WordPress)](https://github.com/liwanglin12/Hermit-X): WordPress
|
|
||||||
- [APlayerHandle](https://github.com/kn007/APlayerHandle): WordPress
|
|
||||||
- [APlayer_for_Z-BlogPHP](https://github.com/fghrsh/APlayer_for_Z-BlogPHP): Z-BlogPHP
|
|
||||||
- [react-aplayer](https://github.com/sabrinaluo/react-aplayer): React
|
|
||||||
- [Vue-APlayer](https://github.com/SevenOutman/vue-aplayer): Vue
|
|
||||||
- [vue-aplayer](https://github.com/MoeFE/vue-aplayer): Vue
|
|
||||||
- [php-aplayer](https://github.com/Daryl-L/php-aplayer): PHP
|
|
||||||
|
|
||||||
### 工具
|
|
||||||
|
|
||||||
- [APlayer-Controler](https://github.com/Mashiro-Sorata/APlayer-Controler): controling tool
|
|
||||||
- [MetingJS](https://github.com/metowolf/MetingJS): work with Meting music API
|
|
||||||
|
|
||||||
## 谁在用 APlayer?
|
|
||||||
|
|
||||||
- [bilibili](https://www.bilibili.com/): 国内知名的视频弹幕网站
|
|
||||||
- [黑客派](https://hacpai.com/): 程序员和设计师的聚集地,一个活跃的小众社区
|
|
||||||
- [浙江大学CC98论坛](https://zh.wikipedia.org/wiki/CC98%E8%AE%BA%E5%9D%9B): 浙江大学校网内规模最大的论坛,中国各大学中较活跃的BBS之一
|
|
||||||
- [Jelly Rue](http://jellyrue.com/): Jelly Rue, an indie pop-rock band from Tartu.
|
|
||||||
- [Opus](http://www.opusopus.co/): An artist-exploration data visualization application
|
|
||||||
- [站长之家](http://www.chinaz.com/15year/index.html): 针对中文站点提供资讯、技术、资源、服务
|
|
||||||
- [LLSupport](https://www.lovelivesupport.com/): This site provides a lot of information about LoveLive
|
|
||||||
- [歌词千寻](https://www.lrcgc.com/diy): 每日更新的LRC歌词网站
|
|
||||||
- [iSearch](http://i.oppsu.cn): 一个提供 iTunes 搜索,试听,高清专辑封面获取,查看最新音乐动态等综合性平台
|
|
||||||
- [LRC歌词编辑器](https://github.com/MoeFE/Lyric): 一款非常实用的在线LRC歌词编辑器
|
|
||||||
- [Аэростатика](https://aerostatica.ru/)
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
---
|
|
||||||
nav: zh-Hans
|
|
||||||
search: zh-Hans
|
|
||||||
---
|
|
||||||
|
|
||||||
# 赞助 APlayer 的研发
|
|
||||||
|
|
||||||
APlayer 是采用 MIT 许可的开源项目,使用完全免费。 但是随着项目规模的增长,也需要有相应的资金支持才能持续项目的维护的开发。
|
|
||||||
|
|
||||||
如果你是企业经营者并且将 APlayer 用在商业产品中,那么赞助 APlayer 有商业上的益处:可以让你的产品所依赖的框架保持健康并得到积极的维护。
|
|
||||||
|
|
||||||
如果你是个人开发者并且享受 APlayer 带来的高开发效率,可以用捐助来表示你的谢意 —— 比如偶尔给我买杯咖啡 :)
|
|
||||||
|
|
||||||
你可以通过下列的方法来赞助 APlayer 的开发.
|
|
||||||
|
|
||||||
## 周期性赞助
|
|
||||||
|
|
||||||
- 通过 [GitHub](https://github.com/sponsors/DIYgod) 赞助
|
|
||||||
- 通过 [Patreon](https://www.patreon.com/DIYgod) 赞助
|
|
||||||
- 通过 [爱发电](https://afdian.net/@diygod) 赞助
|
|
||||||
- 给我们发邮件联系赞助事宜: <i@diygod.me>
|
|
||||||
|
|
||||||
## 一次性赞助
|
|
||||||
|
|
||||||
我们通过以下方式接受赞助:
|
|
||||||
|
|
||||||
- [微信支付](https://diygod.me/images/wx.jpg)
|
|
||||||
- [支付宝](https://diygod.me/images/zfb.jpg)
|
|
||||||
- [Paypal](https://www.paypal.me/DIYgod)
|
|
||||||
|
|
||||||
## 当前的顶级赞助商
|
|
||||||
|
|
||||||
### 特别赞助商
|
|
||||||
|
|
||||||
<a href="https://www.dogecloud.com/?ref=dplayer" target="_blank">
|
|
||||||
<img width="222px" src="https://player.dogecloud.com/img/logo_with_product3.png">
|
|
||||||
</a>
|
|
||||||
|
|
||||||
## APlayer 贡献者
|
|
||||||
|
|
||||||
感谢所有贡献者。
|
|
||||||
|
|
||||||
<a href="https://github.com/MoePlayer/APlayer/graphs/contributors"><img src="https://opencollective.com/APlayer/contributors.svg?width=890" /></a>
|
|
||||||
116
package.json
|
|
@ -1,80 +1,40 @@
|
||||||
{
|
{
|
||||||
"name": "aplayer",
|
"name": "aplayer",
|
||||||
"version": "1.10.1",
|
"version": "1.5.4",
|
||||||
"description": "Wow, such a beautiful html5 music player",
|
"description": "Wow, such a beautiful html5 music player",
|
||||||
"main": "dist/APlayer.min.js",
|
"main": "dist/APlayer.min.js",
|
||||||
"style": "dist/APlayer.min.css",
|
"scripts": {
|
||||||
"scripts": {
|
"test": "webpack",
|
||||||
"start": "npm run dev",
|
"start": "webpack-dev-server --hot --progress --inline --host 0.0.0.0"
|
||||||
"build": "cross-env NODE_ENV=production webpack --config webpack/prod.config.js --progress --display-error-details --colors",
|
},
|
||||||
"dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack/dev.config.js --watch --colors",
|
"repository": {
|
||||||
"test": "eslint src webpack",
|
"type": "git",
|
||||||
"format": "eslint \"**/*.js\" --fix && prettier \"**/*.{js,json,md}\" --write",
|
"url": "git+https://github.com/DIYgod/APlayer.git"
|
||||||
"format:staged": "eslint \"**/*.js\" --fix && pretty-quick --staged --verbose --pattern \"**/*.{js,json,md}\"",
|
},
|
||||||
"format:check": "eslint \"**/*.js\" && prettier-check \"**/*.{js,json,md}\""
|
"keywords": [
|
||||||
},
|
"player",
|
||||||
"files": [
|
"music",
|
||||||
"dist"
|
"html5"
|
||||||
],
|
],
|
||||||
"repository": {
|
"author": "DIYgod",
|
||||||
"url": "git+https://github.com/DIYgod/APlayer.git",
|
"license": "SATA",
|
||||||
"type": "git"
|
"bugs": {
|
||||||
},
|
"url": "https://github.com/DIYgod/APlayer/issues"
|
||||||
"keywords": [
|
},
|
||||||
"player",
|
"homepage": "https://github.com/DIYgod/APlayer#readme",
|
||||||
"music",
|
"devDependencies": {
|
||||||
"html5"
|
"autoprefixer": "^6.4.0",
|
||||||
],
|
"babel-loader": "^6.2.4",
|
||||||
"gitHooks": {
|
"babel-preset-es2015": "^6.13.2",
|
||||||
"pre-commit": "npm run format:staged"
|
"css-loader": "^0.25.0",
|
||||||
},
|
"exports-loader": "^0.6.3",
|
||||||
"author": "DIYgod",
|
"file-loader": "^0.9.0",
|
||||||
"license": "MIT",
|
"node-sass": "^3.8.0",
|
||||||
"bugs": {
|
"postcss-loader": "^0.13.0",
|
||||||
"url": "https://github.com/DIYgod/APlayer/issues"
|
"sass-loader": "^4.0.0",
|
||||||
},
|
"style-loader": "^0.13.1",
|
||||||
"homepage": "https://github.com/DIYgod/APlayer#readme",
|
"url-loader": "^0.5.7",
|
||||||
"devDependencies": {
|
"webpack": "^1.13.1",
|
||||||
"@babel/core": "^7.6.0",
|
"webpack-dev-server": "^1.14.1"
|
||||||
"@babel/preset-env": "^7.4.5",
|
}
|
||||||
"@vuepress/plugin-back-to-top": "1.7.1",
|
|
||||||
"@vuepress/plugin-google-analytics": "1.7.1",
|
|
||||||
"@vuepress/plugin-pwa": "1.7.1",
|
|
||||||
"art-template": "4.13.2",
|
|
||||||
"art-template-loader": "1.4.3",
|
|
||||||
"autoprefixer": "^9.6.1",
|
|
||||||
"babel-loader": "^8.0.6",
|
|
||||||
"cross-env": "^7.0.0",
|
|
||||||
"css-loader": "^5.0.0",
|
|
||||||
"cssnano": "^4.1.10",
|
|
||||||
"eslint": "^7.0.0",
|
|
||||||
"eslint-config-prettier": "^6.3.0",
|
|
||||||
"eslint-loader": "^4.0.0",
|
|
||||||
"eslint-plugin-prettier": "^3.1.1",
|
|
||||||
"exports-loader": "^1.0.0",
|
|
||||||
"file-loader": "^6.0.0",
|
|
||||||
"git-revision-webpack-plugin": "^3.0.3",
|
|
||||||
"mini-css-extract-plugin": "1.3.0",
|
|
||||||
"node-sass": "^5.0.0",
|
|
||||||
"postcss-loader": "^3.0.0",
|
|
||||||
"prettier": "^2.0.1",
|
|
||||||
"prettier-check": "^2.0.0",
|
|
||||||
"pretty-quick": "^3.0.0",
|
|
||||||
"sass-loader": "^10.0.0",
|
|
||||||
"strip-loader": "^0.1.2",
|
|
||||||
"style-loader": "^2.0.0",
|
|
||||||
"svg-inline-loader": "0.8.2",
|
|
||||||
"template-string-optimize-loader": "^3.0.0",
|
|
||||||
"url-loader": "^4.0.0",
|
|
||||||
"vuepress": "1.7.1",
|
|
||||||
"webpack": "^4.40.2",
|
|
||||||
"webpack-cli": "3.3.12",
|
|
||||||
"webpack-dev-server": "^3.8.1",
|
|
||||||
"yorkie": "^2.0.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"balloon-css": "^1.0.3",
|
|
||||||
"promise-polyfill": "8.2.0",
|
|
||||||
"smoothscroll": "0.4.0"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,782 @@
|
||||||
|
console.log("\n %c APlayer 1.5.4 %c http://aplayer.js.org \n\n","color: #fadfa3; background: #030307; padding:5px 0;","background: #fadfa3; padding:5px 0;");
|
||||||
|
|
||||||
|
require('./APlayer.scss');
|
||||||
|
|
||||||
|
let instances = [];
|
||||||
|
|
||||||
|
class APlayer {
|
||||||
|
/**
|
||||||
|
* APlayer constructor function
|
||||||
|
*
|
||||||
|
* @param {Object} option - See README
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
constructor(option) {
|
||||||
|
const svg = {
|
||||||
|
'play': ['0 0 16 31', 'M15.552 15.168q0.448 0.32 0.448 0.832 0 0.448-0.448 0.768l-13.696 8.512q-0.768 0.512-1.312 0.192t-0.544-1.28v-16.448q0-0.96 0.544-1.28t1.312 0.192z'],
|
||||||
|
'pause': ['0 0 17 32', 'M14.080 4.8q2.88 0 2.88 2.048v18.24q0 2.112-2.88 2.112t-2.88-2.112v-18.24q0-2.048 2.88-2.048zM2.88 4.8q2.88 0 2.88 2.048v18.24q0 2.112-2.88 2.112t-2.88-2.112v-18.24q0-2.048 2.88-2.048z'],
|
||||||
|
'volume-up': ['0 0 28 32', 'M13.728 6.272v19.456q0 0.448-0.352 0.8t-0.8 0.32-0.8-0.32l-5.952-5.952h-4.672q-0.48 0-0.8-0.352t-0.352-0.8v-6.848q0-0.48 0.352-0.8t0.8-0.352h4.672l5.952-5.952q0.32-0.32 0.8-0.32t0.8 0.32 0.352 0.8zM20.576 16q0 1.344-0.768 2.528t-2.016 1.664q-0.16 0.096-0.448 0.096-0.448 0-0.8-0.32t-0.32-0.832q0-0.384 0.192-0.64t0.544-0.448 0.608-0.384 0.512-0.64 0.192-1.024-0.192-1.024-0.512-0.64-0.608-0.384-0.544-0.448-0.192-0.64q0-0.48 0.32-0.832t0.8-0.32q0.288 0 0.448 0.096 1.248 0.48 2.016 1.664t0.768 2.528zM25.152 16q0 2.72-1.536 5.056t-4 3.36q-0.256 0.096-0.448 0.096-0.48 0-0.832-0.352t-0.32-0.8q0-0.704 0.672-1.056 1.024-0.512 1.376-0.8 1.312-0.96 2.048-2.4t0.736-3.104-0.736-3.104-2.048-2.4q-0.352-0.288-1.376-0.8-0.672-0.352-0.672-1.056 0-0.448 0.32-0.8t0.8-0.352q0.224 0 0.48 0.096 2.496 1.056 4 3.36t1.536 5.056zM29.728 16q0 4.096-2.272 7.552t-6.048 5.056q-0.224 0.096-0.448 0.096-0.48 0-0.832-0.352t-0.32-0.8q0-0.64 0.704-1.056 0.128-0.064 0.384-0.192t0.416-0.192q0.8-0.448 1.44-0.896 2.208-1.632 3.456-4.064t1.216-5.152-1.216-5.152-3.456-4.064q-0.64-0.448-1.44-0.896-0.128-0.096-0.416-0.192t-0.384-0.192q-0.704-0.416-0.704-1.056 0-0.448 0.32-0.8t0.832-0.352q0.224 0 0.448 0.096 3.776 1.632 6.048 5.056t2.272 7.552z'],
|
||||||
|
'volume-down': ['0 0 28 32', 'M13.728 6.272v19.456q0 0.448-0.352 0.8t-0.8 0.32-0.8-0.32l-5.952-5.952h-4.672q-0.48 0-0.8-0.352t-0.352-0.8v-6.848q0-0.48 0.352-0.8t0.8-0.352h4.672l5.952-5.952q0.32-0.32 0.8-0.32t0.8 0.32 0.352 0.8zM20.576 16q0 1.344-0.768 2.528t-2.016 1.664q-0.16 0.096-0.448 0.096-0.448 0-0.8-0.32t-0.32-0.832q0-0.384 0.192-0.64t0.544-0.448 0.608-0.384 0.512-0.64 0.192-1.024-0.192-1.024-0.512-0.64-0.608-0.384-0.544-0.448-0.192-0.64q0-0.48 0.32-0.832t0.8-0.32q0.288 0 0.448 0.096 1.248 0.48 2.016 1.664t0.768 2.528z'],
|
||||||
|
'volume-off': ['0 0 28 32', 'M13.728 6.272v19.456q0 0.448-0.352 0.8t-0.8 0.32-0.8-0.32l-5.952-5.952h-4.672q-0.48 0-0.8-0.352t-0.352-0.8v-6.848q0-0.48 0.352-0.8t0.8-0.352h4.672l5.952-5.952q0.32-0.32 0.8-0.32t0.8 0.32 0.352 0.8z'],
|
||||||
|
'circulation': ['0 0 29 32', 'M25.6 9.92q1.344 0 2.272 0.928t0.928 2.272v9.28q0 1.28-0.928 2.24t-2.272 0.96h-22.4q-1.28 0-2.24-0.96t-0.96-2.24v-9.28q0-1.344 0.96-2.272t2.24-0.928h8v-3.52l6.4 5.76-6.4 5.76v-3.52h-6.72v6.72h19.84v-6.72h-4.8v-4.48h6.080z'],
|
||||||
|
'random': ['0 0 33 31', 'M29.867 9.356l-5.003 5.003c-0.094 0.094-0.235 0.141-0.36 0.141-0.266 0-0.5-0.219-0.5-0.5v-3.002h-4.002c-2.079 0-3.064 1.423-3.94 3.111-0.453 0.875-0.844 1.782-1.219 2.673-1.735 4.033-3.768 8.223-8.849 8.223h-3.502c-0.281 0-0.5-0.219-0.5-0.5v-3.002c0-0.281 0.219-0.5 0.5-0.5h3.502c2.079 0 3.064-1.423 3.94-3.111 0.453-0.875 0.844-1.782 1.219-2.673 1.735-4.033 3.768-8.223 8.849-8.223h4.002v-3.002c0-0.281 0.219-0.5 0.5-0.5 0.141 0 0.266 0.063 0.375 0.156l4.987 4.987c0.094 0.094 0.141 0.235 0.141 0.36s-0.047 0.266-0.141 0.36zM10.262 14.781c-0.907-1.892-1.907-3.783-4.268-3.783h-3.502c-0.281 0-0.5-0.219-0.5-0.5v-3.002c0-0.281 0.219-0.5 0.5-0.5h3.502c2.783 0 4.831 1.298 6.41 3.518-0.876 1.344-1.517 2.798-2.142 4.268zM29.867 23.363l-5.003 5.003c-0.094 0.094-0.235 0.141-0.36 0.141-0.266 0-0.5-0.235-0.5-0.5v-3.002c-4.643 0-7.504 0.547-10.396-3.518 0.86-1.344 1.501-2.798 2.126-4.268 0.907 1.892 1.907 3.783 4.268 3.783h4.002v-3.002c0-0.281 0.219-0.5 0.5-0.5 0.141 0 0.266 0.063 0.375 0.156l4.987 4.987c0.094 0.094 0.141 0.235 0.141 0.36s-0.047 0.266-0.141 0.36z'],
|
||||||
|
'order': ['0 0 32 32', 'M0.622 18.334h19.54v7.55l11.052-9.412-11.052-9.413v7.549h-19.54v3.725z'],
|
||||||
|
'single': ['0 0 34 32', 'M16 0c-8.837 0-16 7.163-16 16s7.163 16 16 16c8.837 0 16-7.163 16-16s-7.163-16-16-16zM16 29.5c-7.456 0-13.5-6.044-13.5-13.5s6.044-13.5 13.5-13.5 13.5 6.044 13.5 13.5-6.044 13.5-13.5 13.5zM15.606 12.578h-3.856v-1.563h1.207c0.429 0 0.839-0.076 1.219-0.225 0.386-0.148 0.715-0.353 0.987-0.612 0.272-0.263 0.495-0.578 0.659-0.952 0.171-0.369 0.253-0.781 0.253-1.227h1.675v16h-2.144v-11.422z'],
|
||||||
|
'menu': ['0 0 22 32', 'M20.8 14.4q0.704 0 1.152 0.48t0.448 1.12-0.48 1.12-1.12 0.48h-19.2q-0.64 0-1.12-0.48t-0.48-1.12 0.448-1.12 1.152-0.48h19.2zM1.6 11.2q-0.64 0-1.12-0.48t-0.48-1.12 0.448-1.12 1.152-0.48h19.2q0.704 0 1.152 0.48t0.448 1.12-0.48 1.12-1.12 0.48h-19.2zM20.8 20.8q0.704 0 1.152 0.48t0.448 1.12-0.48 1.12-1.12 0.48h-19.2q-0.64 0-1.12-0.48t-0.48-1.12 0.448-1.12 1.152-0.48h19.2z']
|
||||||
|
};
|
||||||
|
this.getSVG = (type) => {
|
||||||
|
return `
|
||||||
|
<svg xmlns:xlink="http://www.w3.org/1999/xlink" height="100%" version="1.1" viewBox="${svg[type][0]}" width="100%">
|
||||||
|
<use xlink:href="#aplayer-${type}"></use>
|
||||||
|
<path class="aplayer-fill" d="${svg[type][1]}" id="aplayer-${type}"></path>
|
||||||
|
</svg>
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.isMobile = /mobile/i.test(window.navigator.userAgent);
|
||||||
|
// compatibility: some mobile browsers don't suppose autoplay
|
||||||
|
if (this.isMobile) {
|
||||||
|
option.autoplay = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// default options
|
||||||
|
const defaultOption = {
|
||||||
|
element: document.getElementsByClassName('aplayer')[0],
|
||||||
|
narrow: false,
|
||||||
|
autoplay: false,
|
||||||
|
mutex: true,
|
||||||
|
showlrc: 0,
|
||||||
|
theme: '#b7daff',
|
||||||
|
mode: 'circulation'
|
||||||
|
};
|
||||||
|
for (let defaultKey in defaultOption) {
|
||||||
|
if (defaultOption.hasOwnProperty(defaultKey) && !option.hasOwnProperty(defaultKey)) {
|
||||||
|
option[defaultKey] = defaultOption[defaultKey];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// multiple music
|
||||||
|
this.playIndex = Object.prototype.toString.call(option.music) === '[object Array]' ? 0 : -1;
|
||||||
|
|
||||||
|
this.option = option;
|
||||||
|
this.audios = [];
|
||||||
|
this.mode = option.mode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse second to 00:00 format. 00:00:00 if audio is over an hour long.
|
||||||
|
*
|
||||||
|
* @param {Number} second
|
||||||
|
* @return {String} 00:00 format. 00:00:00 if over an hour long.
|
||||||
|
*/
|
||||||
|
this.secondToTime = (second) => {
|
||||||
|
const add0 = (num) => {
|
||||||
|
return num < 10 ? '0' + num : '' + num;
|
||||||
|
};
|
||||||
|
const min = parseInt(second / 60);
|
||||||
|
const sec = parseInt(second - min * 60);
|
||||||
|
const hours = parseInt(min / 60);
|
||||||
|
const minAdjust = parseInt((second / 60) - (60 * parseInt((second / 60) / 60)));
|
||||||
|
return second >= 3600 ? add0(hours) + ':' + add0(minAdjust) + ':' + add0(sec) : add0(min) + ':' + add0(sec);
|
||||||
|
};
|
||||||
|
|
||||||
|
// save lrc
|
||||||
|
this.element = this.option.element;
|
||||||
|
if (this.option.showlrc === 2 || this.option.showlrc === true) {
|
||||||
|
this.savelrc = [];
|
||||||
|
for (let i = 0; i < this.element.getElementsByClassName('aplayer-lrc-content').length; i++) {
|
||||||
|
this.savelrc.push(this.element.getElementsByClassName('aplayer-lrc-content')[i].innerHTML);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.lrcs = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update progress bar, including loading progress bar and play progress bar
|
||||||
|
*
|
||||||
|
* @param {String} type - Point out which bar it is, should be played loaded or volume
|
||||||
|
* @param {Number} percentage
|
||||||
|
* @param {String} direction - Point out the direction of this bar, Should be height or width
|
||||||
|
*/
|
||||||
|
this.updateBar = (type, percentage, direction) => {
|
||||||
|
percentage = percentage > 0 ? percentage : 0;
|
||||||
|
percentage = percentage < 1 ? percentage : 1;
|
||||||
|
bar[type + 'Bar'].style[direction] = percentage * 100 + '%';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update lrc
|
||||||
|
*
|
||||||
|
* @param {Number} currentTime
|
||||||
|
*/
|
||||||
|
this.updateLrc = (currentTime = this.audio.currentTime) => {
|
||||||
|
if (this.lrcIndex > this.lrc.length - 1 || currentTime < this.lrc[this.lrcIndex][0] || (!this.lrc[this.lrcIndex + 1] || currentTime >= this.lrc[this.lrcIndex + 1][0])) {
|
||||||
|
for (let i = 0; i < this.lrc.length; i++) {
|
||||||
|
if (currentTime >= this.lrc[i][0] && (!this.lrc[i + 1] || currentTime < this.lrc[i + 1][0])) {
|
||||||
|
this.lrcIndex = i;
|
||||||
|
this.lrcContents.style.transform = `translateY(${-this.lrcIndex * 16}px)`;
|
||||||
|
this.lrcContents.style.webkitTransform = `translateY(${-this.lrcIndex * 16}px)`;
|
||||||
|
this.lrcContents.getElementsByClassName('aplayer-lrc-current')[0].classList.remove('aplayer-lrc-current');
|
||||||
|
this.lrcContents.getElementsByTagName('p')[i].classList.add('aplayer-lrc-current');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// define APlayer events
|
||||||
|
const eventTypes = ['play', 'pause', 'canplay', 'playing', 'ended', 'error'];
|
||||||
|
this.event = {};
|
||||||
|
for (let i = 0; i < eventTypes.length; i++) {
|
||||||
|
this.event[eventTypes[i]] = [];
|
||||||
|
}
|
||||||
|
this.trigger = (type) => {
|
||||||
|
for (let i = 0; i < this.event[type].length; i++) {
|
||||||
|
this.event[type][i]();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.multiple = this.playIndex > -1;
|
||||||
|
this.music = this.multiple ? this.option.music[this.playIndex] : this.option.music;
|
||||||
|
|
||||||
|
// add class aplayer-withlrc
|
||||||
|
if (this.option.showlrc) {
|
||||||
|
this.element.classList.add('aplayer-withlrc');
|
||||||
|
}
|
||||||
|
if (this.option.music.length > 1) {
|
||||||
|
this.element.classList.add('aplayer-list');
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill in HTML
|
||||||
|
let eleHTML = `
|
||||||
|
<div class="aplayer-pic" ${(this.music.pic ? (`style="background-image: url('${this.music.pic}');"`) : ``)}>
|
||||||
|
<div class="aplayer-button aplayer-play">
|
||||||
|
<button class="aplayer-icon aplayer-icon-play">`
|
||||||
|
+ this.getSVG('play')
|
||||||
|
+ ` </button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="aplayer-info">
|
||||||
|
<div class="aplayer-music">
|
||||||
|
<span class="aplayer-title"></span>
|
||||||
|
<span class="aplayer-author"></span>
|
||||||
|
</div>
|
||||||
|
<div class="aplayer-lrc">
|
||||||
|
<div class="aplayer-lrc-contents" style="transform: translateY(0); -webkit-transform: translateY(0);"></div>
|
||||||
|
</div>
|
||||||
|
<div class="aplayer-controller">
|
||||||
|
<div class="aplayer-bar-wrap">
|
||||||
|
<div class="aplayer-bar">
|
||||||
|
<div class="aplayer-loaded" style="width: 0"></div>
|
||||||
|
<div class="aplayer-played" style="width: 0; background: ${this.option.theme};">
|
||||||
|
<span class="aplayer-thumb" style="border: 1px solid ${this.option.theme};"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="aplayer-time">
|
||||||
|
<span class="aplayer-time-inner">
|
||||||
|
- <span class="aplayer-ptime">00:00</span> / <span class="aplayer-dtime">00:00</span>
|
||||||
|
</span>
|
||||||
|
<div class="aplayer-volume-wrap">
|
||||||
|
<button class="aplayer-icon aplayer-icon-volume-down" ${this.isMobile ? 'style="display: none;"' : ''}>`
|
||||||
|
+ this.getSVG('volume-down')
|
||||||
|
+ ` </button>
|
||||||
|
<div class="aplayer-volume-bar-wrap">
|
||||||
|
<div class="aplayer-volume-bar">
|
||||||
|
<div class="aplayer-volume" style="height: 80%; background: ${this.option.theme};"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="aplayer-icon aplayer-icon-mode">`
|
||||||
|
+ this.getSVG(this.mode)
|
||||||
|
+ ` </button>
|
||||||
|
${(this.multiple ? `<button class="aplayer-icon aplayer-icon-menu">`
|
||||||
|
+ this.getSVG('menu')
|
||||||
|
+ ` </button>` : ``)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
if (this.multiple) {
|
||||||
|
eleHTML += `
|
||||||
|
<div class="aplayer-list" ${this.option.listmaxheight ? `style="max-height: ${this.option.listmaxheight}` : ``}">
|
||||||
|
<ol>`;
|
||||||
|
for (let i = 0; i < this.option.music.length; i++) {
|
||||||
|
eleHTML += `
|
||||||
|
<li>
|
||||||
|
<span class="aplayer-list-cur" style="background: ${this.option.theme};"></span>
|
||||||
|
<span class="aplayer-list-index">${(i + 1)}</span>
|
||||||
|
<span class="aplayer-list-title">${this.option.music[i].title}</span>
|
||||||
|
<span class="aplayer-list-author">${this.option.music[i].author}</span>
|
||||||
|
</li>`
|
||||||
|
}
|
||||||
|
eleHTML += `
|
||||||
|
</ol>
|
||||||
|
</div>`
|
||||||
|
}
|
||||||
|
this.element.innerHTML = eleHTML;
|
||||||
|
|
||||||
|
// hide mode button in arrow container
|
||||||
|
if (this.element.offsetWidth < 300) {
|
||||||
|
this.element.getElementsByClassName('aplayer-icon-mode')[0].style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ptime = this.element.getElementsByClassName('aplayer-ptime')[0];
|
||||||
|
|
||||||
|
if (this.element.getElementsByClassName('aplayer-info')[0].offsetWidth < 200) {
|
||||||
|
this.element.getElementsByClassName('aplayer-time')[0].classList.add('aplayer-time-narrow');
|
||||||
|
}
|
||||||
|
// fix the width of aplayer bar
|
||||||
|
let bar = {};
|
||||||
|
bar.barWrap = this.element.getElementsByClassName('aplayer-bar-wrap')[0];
|
||||||
|
|
||||||
|
// switch to narrow style
|
||||||
|
if (this.option.narrow) {
|
||||||
|
this.element.classList.add('aplayer-narrow');
|
||||||
|
}
|
||||||
|
|
||||||
|
// play and pause button
|
||||||
|
this.button = this.element.getElementsByClassName('aplayer-button')[0];
|
||||||
|
this.button.addEventListener('click', (e) => {
|
||||||
|
if (this.button.classList.contains('aplayer-play')) {
|
||||||
|
this.play();
|
||||||
|
}
|
||||||
|
else if (this.button.classList.contains('aplayer-pause')) {
|
||||||
|
this.pause();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// click music list: change music
|
||||||
|
if (this.multiple) {
|
||||||
|
const listItem = this.element.getElementsByClassName('aplayer-list')[0].getElementsByTagName('li');
|
||||||
|
for (let i = 0; i < this.option.music.length; i++) {
|
||||||
|
listItem[i].addEventListener('click', () => {
|
||||||
|
const musicIndex = parseInt(listItem[i].getElementsByClassName('aplayer-list-index')[0].innerHTML) - 1;
|
||||||
|
if (musicIndex !== this.playIndex) {
|
||||||
|
this.setMusic(musicIndex);
|
||||||
|
this.play();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.toggle();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// control play progress
|
||||||
|
bar.playedBar = this.element.getElementsByClassName('aplayer-played')[0];
|
||||||
|
bar.loadedBar = this.element.getElementsByClassName('aplayer-loaded')[0];
|
||||||
|
const thumb = this.element.getElementsByClassName('aplayer-thumb')[0];
|
||||||
|
let barWidth;
|
||||||
|
bar.barWrap.addEventListener('click', (event) => {
|
||||||
|
const e = event || window.event;
|
||||||
|
barWidth = bar.barWrap.clientWidth;
|
||||||
|
const percentage = (e.clientX - getElementViewLeft(bar.barWrap)) / barWidth;
|
||||||
|
this.updateBar('played', percentage, 'width');
|
||||||
|
this.element.getElementsByClassName('aplayer-ptime')[0].innerHTML = this.secondToTime(percentage * this.audio.duration);
|
||||||
|
this.audio.currentTime = parseFloat(bar.playedBar.style.width) / 100 * this.audio.duration;
|
||||||
|
});
|
||||||
|
|
||||||
|
thumb.addEventListener('mouseover', () => {
|
||||||
|
thumb.style.background = this.option.theme;
|
||||||
|
});
|
||||||
|
thumb.addEventListener('mouseout', () => {
|
||||||
|
thumb.style.background = '#fff';
|
||||||
|
});
|
||||||
|
|
||||||
|
const thumbMove = (event) => {
|
||||||
|
const e = event || window.event;
|
||||||
|
let percentage = (e.clientX - getElementViewLeft(bar.barWrap)) / barWidth;
|
||||||
|
percentage = percentage > 0 ? percentage : 0;
|
||||||
|
percentage = percentage < 1 ? percentage : 1;
|
||||||
|
this.updateBar('played', percentage, 'width');
|
||||||
|
if (this.option.showlrc) {
|
||||||
|
this.updateLrc(parseFloat(bar.playedBar.style.width) / 100 * this.audio.duration);
|
||||||
|
}
|
||||||
|
this.element.getElementsByClassName('aplayer-ptime')[0].innerHTML = this.secondToTime(percentage * this.audio.duration);
|
||||||
|
};
|
||||||
|
|
||||||
|
const thumbUp = () => {
|
||||||
|
document.removeEventListener('mouseup', thumbUp);
|
||||||
|
document.removeEventListener('mousemove', thumbMove);
|
||||||
|
this.audio.currentTime = parseFloat(bar.playedBar.style.width) / 100 * this.audio.duration;
|
||||||
|
this.playedTime = setInterval(() => {
|
||||||
|
this.updateBar('played', this.audio.currentTime / this.audio.duration, 'width');
|
||||||
|
if (this.option.showlrc) {
|
||||||
|
this.updateLrc();
|
||||||
|
}
|
||||||
|
this.element.getElementsByClassName('aplayer-ptime')[0].innerHTML = this.secondToTime(this.audio.currentTime);
|
||||||
|
this.trigger('playing');
|
||||||
|
}, 100);
|
||||||
|
};
|
||||||
|
|
||||||
|
thumb.addEventListener('mousedown', () => {
|
||||||
|
barWidth = bar.barWrap.clientWidth;
|
||||||
|
clearInterval(this.playedTime);
|
||||||
|
document.addEventListener('mousemove', thumbMove);
|
||||||
|
document.addEventListener('mouseup', thumbUp);
|
||||||
|
});
|
||||||
|
|
||||||
|
// control volume
|
||||||
|
bar.volumeBar = this.element.getElementsByClassName('aplayer-volume')[0];
|
||||||
|
const volumeBarWrap = this.element.getElementsByClassName('aplayer-volume-bar')[0];
|
||||||
|
this.volumeicon = this.element.getElementsByClassName('aplayer-time')[0].getElementsByTagName('button')[0];
|
||||||
|
const barHeight = 35;
|
||||||
|
this.element.getElementsByClassName('aplayer-volume-bar-wrap')[0].addEventListener('click', (event) => {
|
||||||
|
const e = event || window.event;
|
||||||
|
let percentage = (barHeight - e.clientY + getElementViewTop(volumeBarWrap)) / barHeight;
|
||||||
|
percentage = percentage > 0 ? percentage : 0;
|
||||||
|
percentage = percentage < 1 ? percentage : 1;
|
||||||
|
this.volume(percentage);
|
||||||
|
});
|
||||||
|
this.volumeicon.addEventListener('click', () => {
|
||||||
|
if (this.audio.muted) {
|
||||||
|
this.audio.muted = false;
|
||||||
|
this.volumeicon.className = this.audio.volume === 1 ? 'aplayer-icon aplayer-icon-volume-up' : 'aplayer-icon aplayer-icon-volume-down';
|
||||||
|
if (this.audio.volume === 1) {
|
||||||
|
this.volumeicon.className = 'aplayer-icon aplayer-icon-volume-up';
|
||||||
|
this.volumeicon.innerHTML = this.getSVG('volume-up');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.volumeicon.className = 'aplayer-icon aplayer-icon-volume-down';
|
||||||
|
this.volumeicon.innerHTML = this.getSVG('volume-down');
|
||||||
|
}
|
||||||
|
this.updateBar('volume', this.audio.volume, 'height');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.audio.muted = true;
|
||||||
|
this.volumeicon.className = 'aplayer-icon aplayer-icon-volume-off';
|
||||||
|
this.volumeicon.innerHTML = this.getSVG('volume-off');
|
||||||
|
this.updateBar('volume', 0, 'height');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// get element's view position
|
||||||
|
function getElementViewLeft(element) {
|
||||||
|
let actualLeft = element.offsetLeft;
|
||||||
|
let current = element.offsetParent;
|
||||||
|
let elementScrollLeft;
|
||||||
|
while (current !== null) {
|
||||||
|
actualLeft += current.offsetLeft;
|
||||||
|
current = current.offsetParent;
|
||||||
|
}
|
||||||
|
elementScrollLeft = document.body.scrollLeft + document.documentElement.scrollLeft;
|
||||||
|
return actualLeft - elementScrollLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getElementViewTop(element) {
|
||||||
|
let actualTop = element.offsetTop;
|
||||||
|
let current = element.offsetParent;
|
||||||
|
let elementScrollTop;
|
||||||
|
while (current !== null) {
|
||||||
|
actualTop += current.offsetTop;
|
||||||
|
current = current.offsetParent;
|
||||||
|
}
|
||||||
|
elementScrollTop = document.body.scrollTop + document.documentElement.scrollTop;
|
||||||
|
return actualTop - elementScrollTop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mode control
|
||||||
|
const modeEle = this.element.getElementsByClassName('aplayer-icon-mode')[0];
|
||||||
|
modeEle.addEventListener('click', () => {
|
||||||
|
if (this.mode === 'random') {
|
||||||
|
this.mode = 'single';
|
||||||
|
}
|
||||||
|
else if (this.mode === 'single') {
|
||||||
|
this.mode = 'order';
|
||||||
|
}
|
||||||
|
else if (this.mode === 'order') {
|
||||||
|
this.mode = 'circulation';
|
||||||
|
}
|
||||||
|
else if (this.mode === 'circulation') {
|
||||||
|
this.mode = 'random';
|
||||||
|
}
|
||||||
|
modeEle.innerHTML = this.getSVG(this.mode);
|
||||||
|
this.audio.loop = !(this.multiple || this.mode === 'order');
|
||||||
|
});
|
||||||
|
|
||||||
|
// toggle menu control
|
||||||
|
if (this.multiple) {
|
||||||
|
const list = this.element.getElementsByClassName('aplayer-list')[0];
|
||||||
|
list.style.height = list.offsetHeight + 'px';
|
||||||
|
this.element.getElementsByClassName('aplayer-icon-menu')[0].addEventListener('click', () => {
|
||||||
|
if (!list.classList.contains('aplayer-list-hide')) {
|
||||||
|
list.classList.add('aplayer-list-hide');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
list.classList.remove('aplayer-list-hide');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.mode === 'random') {
|
||||||
|
let random = parseInt(Math.random() * this.option.music.length);
|
||||||
|
this.setMusic(random);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.setMusic(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
instances.push(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set music
|
||||||
|
*/
|
||||||
|
setMusic(index) {
|
||||||
|
// get this.music
|
||||||
|
if (this.multiple && typeof(index) !== 'undefined') {
|
||||||
|
this.playIndex = index;
|
||||||
|
}
|
||||||
|
const indexMusic = this.playIndex;
|
||||||
|
this.music = this.multiple ? this.option.music[indexMusic] : this.option.music;
|
||||||
|
|
||||||
|
// set html
|
||||||
|
if (this.music.pic) {
|
||||||
|
this.element.getElementsByClassName('aplayer-pic')[0].style.backgroundImage = `url('${this.music.pic}')`;
|
||||||
|
}
|
||||||
|
this.element.getElementsByClassName('aplayer-title')[0].innerHTML = this.music.title;
|
||||||
|
this.element.getElementsByClassName('aplayer-author')[0].innerHTML = ` - ${this.music.author}`;
|
||||||
|
if (this.multiple) {
|
||||||
|
if (this.element.getElementsByClassName('aplayer-list-light')[0]) {
|
||||||
|
this.element.getElementsByClassName('aplayer-list-light')[0].classList.remove('aplayer-list-light');
|
||||||
|
}
|
||||||
|
this.element.getElementsByClassName('aplayer-list')[0].getElementsByTagName('li')[indexMusic].classList.add('aplayer-list-light');
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the previous audio object
|
||||||
|
if (this.audio) {
|
||||||
|
this.pause();
|
||||||
|
this.audio.currentTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.multiple) {
|
||||||
|
this.element.getElementsByClassName('aplayer-list')[0].scrollTop = indexMusic * 33;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get this audio object
|
||||||
|
if ((this.multiple && !this.audios[indexMusic]) || this.playIndex === -1) {
|
||||||
|
this.audio = document.createElement("audio");
|
||||||
|
this.audio.src = this.music.url;
|
||||||
|
this.audio.preload = this.option.preload ? this.option.preload : 'auto';
|
||||||
|
|
||||||
|
// show audio time: the metadata has loaded or changed
|
||||||
|
this.audio.addEventListener('durationchange', () => {
|
||||||
|
if (this.audio.duration !== 1) { // compatibility: Android browsers will output 1 at first
|
||||||
|
this.element.getElementsByClassName('aplayer-dtime')[0].innerHTML = this.secondToTime(this.audio.duration);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// show audio loaded bar: to inform interested parties of progress downloading the media
|
||||||
|
this.audio.addEventListener('progress', () => {
|
||||||
|
const percentage = this.audio.buffered.length ? this.audio.buffered.end(this.audio.buffered.length - 1) / this.audio.duration : 0;
|
||||||
|
this.updateBar('loaded', percentage, 'width');
|
||||||
|
});
|
||||||
|
|
||||||
|
// audio download error: an error occurs
|
||||||
|
this.audio.addEventListener('error', () => {
|
||||||
|
this.element.getElementsByClassName('aplayer-author')[0].innerHTML = ` - Error happens ╥﹏╥`;
|
||||||
|
this.trigger('pause');
|
||||||
|
});
|
||||||
|
|
||||||
|
// audio can play: enough data is available that the media can be played
|
||||||
|
this.audio.addEventListener('canplay', () => {
|
||||||
|
this.trigger('canplay');
|
||||||
|
});
|
||||||
|
|
||||||
|
// multiple music play
|
||||||
|
this.ended = false;
|
||||||
|
if (this.multiple) {
|
||||||
|
this.audio.addEventListener('ended', () => {
|
||||||
|
if (this.isMobile) {
|
||||||
|
this.ended = true;
|
||||||
|
this.pause();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.audio.currentTime !== 0) {
|
||||||
|
if (this.mode === 'random') {
|
||||||
|
let random = parseInt(Math.random() * this.option.music.length);
|
||||||
|
if (random === this.playIndex) {
|
||||||
|
random++;
|
||||||
|
random = random % this.option.music.length;
|
||||||
|
}
|
||||||
|
this.setMusic(random);
|
||||||
|
}
|
||||||
|
else if (this.mode === 'single') {
|
||||||
|
this.setMusic(this.playIndex);
|
||||||
|
}
|
||||||
|
else if (this.mode === 'order') {
|
||||||
|
if (this.playIndex < this.option.music.length - 1) {
|
||||||
|
this.setMusic(++this.playIndex);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.ended = true;
|
||||||
|
this.pause();
|
||||||
|
this.trigger('ended');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (this.mode === 'circulation') {
|
||||||
|
if (this.playIndex < this.option.music.length - 1) {
|
||||||
|
this.setMusic(++this.playIndex);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.setMusic(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.audio.addEventListener('ended', () => {
|
||||||
|
if (this.mode === 'order') {
|
||||||
|
this.ended = true;
|
||||||
|
this.pause();
|
||||||
|
this.trigger('ended');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// control volume
|
||||||
|
this.audio.volume = parseInt(this.element.getElementsByClassName('aplayer-volume')[0].style.height) / 100;
|
||||||
|
|
||||||
|
// loop
|
||||||
|
this.audio.loop = !(this.multiple || this.mode === 'order');
|
||||||
|
|
||||||
|
if (this.multiple) {
|
||||||
|
this.audios[indexMusic] = this.audio;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.audio = this.audios[indexMusic];
|
||||||
|
this.audio.volume = parseInt(this.element.getElementsByClassName('aplayer-volume')[0].style.height) / 100;
|
||||||
|
this.audio.currentTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse lrc, suppose multiple time tag
|
||||||
|
*
|
||||||
|
* @param {String} lrc_s - Format:
|
||||||
|
* [mm:ss.xx]lyric
|
||||||
|
* [mm:ss.xxx]lyric
|
||||||
|
* [mm:ss.xx][mm:ss.xx][mm:ss.xx]lyric
|
||||||
|
*
|
||||||
|
* @return {String} [[time, text], [time, text], [time, text], ...]
|
||||||
|
*/
|
||||||
|
const parseLrc = (lrc_s) => {
|
||||||
|
const lyric = lrc_s.split('\n');
|
||||||
|
let lrc = [];
|
||||||
|
const lyricLen = lyric.length;
|
||||||
|
for (let i = 0; i < lyricLen; i++) {
|
||||||
|
// match lrc time
|
||||||
|
const lrcTimes = lyric[i].match(/\[(\d{2}):(\d{2})\.(\d{2,3})]/g);
|
||||||
|
// match lrc text
|
||||||
|
const lrcText = lyric[i].replace(/\[(\d{2}):(\d{2})\.(\d{2,3})]/g, '').replace(/^\s+|\s+$/g, '');
|
||||||
|
|
||||||
|
if (lrcTimes != null) {
|
||||||
|
// handle multiple time tag
|
||||||
|
const timeLen = lrcTimes.length;
|
||||||
|
for (let j = 0; j < timeLen; j++) {
|
||||||
|
const oneTime = /\[(\d{2}):(\d{2})\.(\d{2,3})]/.exec(lrcTimes[j]);
|
||||||
|
const lrcTime = (oneTime[1]) * 60 + parseInt(oneTime[2]) + parseInt(oneTime[3]) / ((oneTime[3] + '').length === 2 ? 100 : 1000);
|
||||||
|
lrc.push([lrcTime, lrcText]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// sort by time
|
||||||
|
lrc.sort((a, b) => a[0] - b[0]);
|
||||||
|
return lrc;
|
||||||
|
};
|
||||||
|
|
||||||
|
// fill in lrc
|
||||||
|
if (this.option.showlrc) {
|
||||||
|
const index = this.multiple ? indexMusic : 0;
|
||||||
|
|
||||||
|
if (!this.lrcs[index]) {
|
||||||
|
let lrcs = '';
|
||||||
|
if (this.option.showlrc === 1) {
|
||||||
|
if (this.multiple) {
|
||||||
|
lrcs = this.option.music[index].lrc;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lrcs = this.option.music.lrc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (this.option.showlrc === 2 || this.option.showlrc === true) {
|
||||||
|
lrcs = this.savelrc[index];
|
||||||
|
}
|
||||||
|
else if (this.option.showlrc === 3) {
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
xhr.onreadystatechange = () => {
|
||||||
|
if (xhr.readyState === 4) {
|
||||||
|
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
|
||||||
|
lrcs = xhr.responseText;
|
||||||
|
this.lrcs[index] = parseLrc(lrcs);
|
||||||
|
this.lrc = this.lrcs[index];
|
||||||
|
let lrcHTML = '';
|
||||||
|
this.lrcContents = this.element.getElementsByClassName('aplayer-lrc-contents')[0];
|
||||||
|
for (let i = 0; i < this.lrc.length; i++) {
|
||||||
|
lrcHTML += `<p>${this.lrc[i][1]}</p>`;
|
||||||
|
}
|
||||||
|
this.lrcContents.innerHTML = lrcHTML;
|
||||||
|
if (!this.lrcIndex) {
|
||||||
|
this.lrcIndex = 0;
|
||||||
|
}
|
||||||
|
this.lrcContents.getElementsByTagName('p')[0].classList.add('aplayer-lrc-current');
|
||||||
|
this.lrcContents.style.transform = 'translateY(0px)';
|
||||||
|
this.lrcContents.style.webkitTransform = 'translateY(0px)';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log('Request was unsuccessful: ' + xhr.status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let apiurl;
|
||||||
|
if (this.multiple) {
|
||||||
|
apiurl = this.option.music[index].lrc;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
apiurl = this.option.music.lrc;
|
||||||
|
}
|
||||||
|
xhr.open('get', apiurl, true);
|
||||||
|
xhr.send(null);
|
||||||
|
}
|
||||||
|
if (lrcs) {
|
||||||
|
this.lrcs[index] = parseLrc(lrcs);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.lrcs[index] = [['00:00', 'Loading']];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lrc = this.lrcs[index];
|
||||||
|
let lrcHTML = '';
|
||||||
|
this.lrcContents = this.element.getElementsByClassName('aplayer-lrc-contents')[0];
|
||||||
|
for (let i = 0; i < this.lrc.length; i++) {
|
||||||
|
lrcHTML += `<p>${this.lrc[i][1]}</p>`;
|
||||||
|
}
|
||||||
|
this.lrcContents.innerHTML = lrcHTML;
|
||||||
|
if (!this.lrcIndex) {
|
||||||
|
this.lrcIndex = 0;
|
||||||
|
}
|
||||||
|
this.lrcContents.getElementsByTagName('p')[0].classList.add('aplayer-lrc-current');
|
||||||
|
this.lrcContents.style.transform = 'translateY(0px)';
|
||||||
|
this.lrcContents.style.webkitTransform = 'translateY(0px)';
|
||||||
|
}
|
||||||
|
|
||||||
|
// set duration time
|
||||||
|
if (this.audio.duration !== 1) { // compatibility: Android browsers will output 1 at first
|
||||||
|
this.element.getElementsByClassName('aplayer-dtime')[0].innerHTML = this.audio.duration ? this.secondToTime(this.audio.duration) : '00:00';
|
||||||
|
}
|
||||||
|
|
||||||
|
// autoplay
|
||||||
|
if (this.option.autoplay && !this.isMobile) {
|
||||||
|
this.play();
|
||||||
|
}
|
||||||
|
this.option.autoplay = true; // autoplay next music
|
||||||
|
|
||||||
|
if (this.isMobile) {
|
||||||
|
this.pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Play music
|
||||||
|
*/
|
||||||
|
play(time) {
|
||||||
|
if (Object.prototype.toString.call(time) === '[object Number]') {
|
||||||
|
this.audio.currentTime = time;
|
||||||
|
}
|
||||||
|
if (this.audio.paused) {
|
||||||
|
this.button.classList.remove('aplayer-play');
|
||||||
|
this.button.classList.add('aplayer-pause');
|
||||||
|
this.button.innerHTML = '';
|
||||||
|
setTimeout(() => {
|
||||||
|
this.button.innerHTML = `
|
||||||
|
<button class="aplayer-icon aplayer-icon-pause">`
|
||||||
|
+ this.getSVG('pause')
|
||||||
|
+ ` </button>`;
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
// pause other players (Thanks @Aprikyblue)
|
||||||
|
if (this.option.mutex) {
|
||||||
|
for (let i = 0; i < instances.length; i++) {
|
||||||
|
if (this != instances[i]) {
|
||||||
|
instances[i].pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.audio.play();
|
||||||
|
if (this.playedTime) {
|
||||||
|
clearInterval(this.playedTime);
|
||||||
|
}
|
||||||
|
this.playedTime = setInterval(() => {
|
||||||
|
this.updateBar('played', this.audio.currentTime / this.audio.duration, 'width');
|
||||||
|
if (this.option.showlrc) {
|
||||||
|
this.updateLrc();
|
||||||
|
}
|
||||||
|
this.ptime.innerHTML = this.secondToTime(this.audio.currentTime);
|
||||||
|
this.trigger('playing');
|
||||||
|
}, 100);
|
||||||
|
this.trigger('play');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pause music
|
||||||
|
*/
|
||||||
|
pause() {
|
||||||
|
if (!this.audio.paused || this.ended) {
|
||||||
|
this.ended = false;
|
||||||
|
this.button.classList.remove('aplayer-pause');
|
||||||
|
this.button.classList.add('aplayer-play');
|
||||||
|
this.button.innerHTML = '';
|
||||||
|
setTimeout(() => {
|
||||||
|
this.button.innerHTML = `
|
||||||
|
<button class="aplayer-icon aplayer-icon-play">`
|
||||||
|
+ this.getSVG('play')
|
||||||
|
+ ` </button>`;
|
||||||
|
}, 100);
|
||||||
|
this.audio.pause();
|
||||||
|
clearInterval(this.playedTime);
|
||||||
|
this.trigger('pause');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set volume
|
||||||
|
*/
|
||||||
|
volume(percentage) {
|
||||||
|
this.updateBar('volume', percentage, 'height');
|
||||||
|
this.audio.volume = percentage;
|
||||||
|
if (this.audio.muted) {
|
||||||
|
this.audio.muted = false;
|
||||||
|
}
|
||||||
|
if (percentage === 1) {
|
||||||
|
this.volumeicon.className = 'aplayer-icon aplayer-icon-volume-up';
|
||||||
|
this.volumeicon.innerHTML = this.getSVG('volume-up');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.volumeicon.className = 'aplayer-icon aplayer-icon-volume-down';
|
||||||
|
this.volumeicon.innerHTML = this.getSVG('volume-down');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* attach event
|
||||||
|
*/
|
||||||
|
on(name, func) {
|
||||||
|
if (typeof func === 'function') {
|
||||||
|
this.event[name].push(func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* toggle between play and pause
|
||||||
|
*/
|
||||||
|
toggle() {
|
||||||
|
if (this.audio.paused) {
|
||||||
|
this.play();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = APlayer;
|
||||||
|
|
@ -2,213 +2,57 @@ $aplayer-height: 66px;
|
||||||
$lrc-height: 30px;
|
$lrc-height: 30px;
|
||||||
$aplayer-height-lrc: $aplayer-height + $lrc-height - 6;
|
$aplayer-height-lrc: $aplayer-height + $lrc-height - 6;
|
||||||
|
|
||||||
.aplayer {
|
.aplayer-narrow {
|
||||||
background: #fff;
|
width: $aplayer-height;
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
.aplayer-info {
|
||||||
margin: 5px;
|
display: none;
|
||||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.07), 0 1px 5px 0 rgba(0, 0, 0, 0.1);
|
|
||||||
border-radius: 2px;
|
|
||||||
overflow: hidden;
|
|
||||||
user-select: none;
|
|
||||||
line-height: initial;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
* {
|
|
||||||
box-sizing: content-box;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
svg {
|
.aplayer-withlrc {
|
||||||
width: 100%;
|
&.aplayer-narrow {
|
||||||
height: 100%;
|
width: $aplayer-height-lrc;
|
||||||
|
|
||||||
path,
|
|
||||||
circle {
|
|
||||||
fill: #fff;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
&.aplayer {
|
||||||
&.aplayer-withlist {
|
|
||||||
.aplayer-info {
|
|
||||||
border-bottom: 1px solid #e9e9e9;
|
|
||||||
}
|
|
||||||
.aplayer-list {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.aplayer-info .aplayer-controller .aplayer-time .aplayer-icon.aplayer-icon-menu {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
.aplayer-icon-order {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.aplayer-withlrc {
|
|
||||||
.aplayer-pic {
|
.aplayer-pic {
|
||||||
height: $aplayer-height-lrc;
|
height: $aplayer-height-lrc;
|
||||||
width: $aplayer-height-lrc;
|
width: $aplayer-height-lrc;
|
||||||
}
|
}
|
||||||
|
|
||||||
.aplayer-info {
|
.aplayer-info {
|
||||||
margin-left: $aplayer-height-lrc;
|
margin-left: $aplayer-height-lrc;
|
||||||
height: $aplayer-height-lrc;
|
height: $aplayer-height-lrc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aplayer-lrc {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aplayer-info {
|
||||||
padding: 10px 7px 0 7px;
|
padding: 10px 7px 0 7px;
|
||||||
}
|
}
|
||||||
.aplayer-lrc {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.aplayer-narrow {
|
.aplayer-list {
|
||||||
width: $aplayer-height;
|
&.aplayer {
|
||||||
|
|
||||||
.aplayer-info {
|
.aplayer-info {
|
||||||
display: none;
|
border-bottom: 1px solid #e9e9e9;
|
||||||
}
|
|
||||||
.aplayer-list {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.aplayer-pic,
|
|
||||||
.aplayer-body {
|
|
||||||
height: $aplayer-height;
|
|
||||||
width: $aplayer-height;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.aplayer-fixed {
|
.aplayer {
|
||||||
position: fixed;
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
bottom: 0;
|
margin: 5px;
|
||||||
left: 0;
|
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 3px 1px -2px rgba(0, 0, 0, .2), 0 1px 5px 0 rgba(0, 0, 0, .12);
|
||||||
right: 0;
|
border-radius: 2px;
|
||||||
margin: 0;
|
overflow: hidden;
|
||||||
z-index: 99;
|
user-select: none;
|
||||||
overflow: visible;
|
line-height: initial;
|
||||||
max-width: 400px;
|
|
||||||
box-shadow: none;
|
|
||||||
|
|
||||||
.aplayer-list {
|
* {
|
||||||
margin-bottom: 65px;
|
box-sizing: content-box;
|
||||||
border: 1px solid #eee;
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-body {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
margin: 0;
|
|
||||||
z-index: 99;
|
|
||||||
background: #fff;
|
|
||||||
padding-right: 18px;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
max-width: 400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-lrc {
|
|
||||||
display: block;
|
|
||||||
position: fixed;
|
|
||||||
bottom: 10px;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
margin: 0;
|
|
||||||
z-index: 98;
|
|
||||||
pointer-events: none;
|
|
||||||
text-shadow: -1px -1px 0 #fff;
|
|
||||||
|
|
||||||
&:before,
|
|
||||||
&:after {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-info {
|
|
||||||
transform: scaleX(1);
|
|
||||||
transform-origin: 0 0;
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
border-bottom: none;
|
|
||||||
border-top: 1px solid #e9e9e9;
|
|
||||||
|
|
||||||
.aplayer-music {
|
|
||||||
width: calc(100% - 105px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-miniswitcher {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.aplayer-narrow {
|
|
||||||
.aplayer-info {
|
|
||||||
display: block;
|
|
||||||
transform: scaleX(0);
|
|
||||||
}
|
|
||||||
.aplayer-body {
|
|
||||||
width: $aplayer-height !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-miniswitcher .aplayer-icon {
|
|
||||||
transform: rotateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-icon-back,
|
|
||||||
.aplayer-icon-play,
|
|
||||||
.aplayer-icon-forward,
|
|
||||||
.aplayer-icon-lrc {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-icon-back,
|
|
||||||
.aplayer-icon-play,
|
|
||||||
.aplayer-icon-forward,
|
|
||||||
.aplayer-icon-menu {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 27px;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-icon-back {
|
|
||||||
right: 75px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-icon-play {
|
|
||||||
right: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-icon-forward {
|
|
||||||
right: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-icon-menu {
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.aplayer-mobile {
|
|
||||||
.aplayer-icon-volume-down {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.aplayer-arrow {
|
|
||||||
.aplayer-icon-order,
|
|
||||||
.aplayer-icon-loop {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.aplayer-loading {
|
|
||||||
.aplayer-info .aplayer-controller .aplayer-loading-icon {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-played .aplayer-thumb {
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-body {
|
|
||||||
position: relative;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.aplayer-icon {
|
.aplayer-icon {
|
||||||
|
|
@ -221,33 +65,12 @@ $aplayer-height-lrc: $aplayer-height + $lrc-height - 6;
|
||||||
opacity: .8;
|
opacity: .8;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
font-size: 12px;
|
|
||||||
margin: 0;
|
|
||||||
display: inline-block;
|
|
||||||
|
|
||||||
path {
|
.aplayer-fill {
|
||||||
transition: all .2s ease-in-out;
|
transition: all .2s ease-in-out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.aplayer-icon-order,
|
|
||||||
.aplayer-icon-back,
|
|
||||||
.aplayer-icon-play,
|
|
||||||
.aplayer-icon-forward,
|
|
||||||
.aplayer-icon-lrc {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-icon-lrc-inactivity {
|
|
||||||
svg {
|
|
||||||
opacity: 0.4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-icon-forward {
|
|
||||||
transform: rotate(180deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-lrc-content {
|
.aplayer-lrc-content {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
@ -257,25 +80,24 @@ $aplayer-height-lrc: $aplayer-height + $lrc-height - 6;
|
||||||
float: left;
|
float: left;
|
||||||
height: $aplayer-height;
|
height: $aplayer-height;
|
||||||
width: $aplayer-height;
|
width: $aplayer-height;
|
||||||
background-size: cover;
|
background-image: url(./default.jpg);
|
||||||
background-position: center;
|
background-size: 100%;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:hover .aplayer-button {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-button {
|
.aplayer-button {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
|
cursor: pointer;
|
||||||
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
|
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
|
||||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
|
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
|
||||||
background: rgba(0, 0, 0, 0.2);
|
background: rgba(0, 0, 0, 0.2);
|
||||||
transition: all 0.1s ease;
|
transition: all 0.1s ease;
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
path {
|
.aplayer-fill {
|
||||||
fill: #fff;
|
fill: #fff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -291,7 +113,7 @@ $aplayer-height-lrc: $aplayer-height + $lrc-height - 6;
|
||||||
bottom: 50%;
|
bottom: 50%;
|
||||||
right: 50%;
|
right: 50%;
|
||||||
margin: 0 -15px -15px 0;
|
margin: 0 -15px -15px 0;
|
||||||
svg {
|
.aplayer-icon-play {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 3px;
|
top: 3px;
|
||||||
left: 4px;
|
left: 4px;
|
||||||
|
|
@ -306,7 +128,7 @@ $aplayer-height-lrc: $aplayer-height + $lrc-height - 6;
|
||||||
border: 2px solid #fff;
|
border: 2px solid #fff;
|
||||||
bottom: 4px;
|
bottom: 4px;
|
||||||
right: 4px;
|
right: 4px;
|
||||||
svg {
|
.aplayer-icon-pause {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 2px;
|
top: 2px;
|
||||||
left: 2px;
|
left: 2px;
|
||||||
|
|
@ -326,11 +148,10 @@ $aplayer-height-lrc: $aplayer-height + $lrc-height - 6;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
margin: 0 0 13px 5px;
|
margin-bottom: 13px;
|
||||||
user-select: text;
|
user-select: text;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
padding-bottom: 2px;
|
padding-bottom: 2px;
|
||||||
height: 20px;
|
|
||||||
|
|
||||||
.aplayer-title {
|
.aplayer-title {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|
@ -352,12 +173,6 @@ $aplayer-height-lrc: $aplayer-height + $lrc-height - 6;
|
||||||
cursor: pointer !important;
|
cursor: pointer !important;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.aplayer-bar .aplayer-played .aplayer-thumb {
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-bar {
|
.aplayer-bar {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 2px;
|
height: 2px;
|
||||||
|
|
@ -387,12 +202,11 @@ $aplayer-height-lrc: $aplayer-height + $lrc-height - 6;
|
||||||
right: 5px;
|
right: 5px;
|
||||||
margin-top: -4px;
|
margin-top: -4px;
|
||||||
margin-right: -10px;
|
margin-right: -10px;
|
||||||
height: 10px;
|
height: 8px;
|
||||||
width: 10px;
|
width: 8px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
cursor: pointer;
|
background: #fff;
|
||||||
transition: all .3s ease-in-out;
|
cursor: pointer !important;
|
||||||
transform: scale(0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -401,7 +215,7 @@ $aplayer-height-lrc: $aplayer-height + $lrc-height - 6;
|
||||||
.aplayer-time {
|
.aplayer-time {
|
||||||
position: relative;
|
position: relative;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 4px;
|
bottom: 3px;
|
||||||
height: 17px;
|
height: 17px;
|
||||||
color: #999;
|
color: #999;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
|
|
@ -415,23 +229,19 @@ $aplayer-height-lrc: $aplayer-height + $lrc-height - 6;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
|
|
||||||
path {
|
.aplayer-fill {
|
||||||
fill: #666;
|
fill: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.aplayer-icon-loop {
|
&.aplayer-icon-mode {
|
||||||
margin-right: 2px;
|
margin-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
path {
|
.aplayer-fill {
|
||||||
fill: #000;
|
fill: #000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.aplayer-icon-menu {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.aplayer-time-narrow {
|
&.aplayer-time-narrow {
|
||||||
|
|
@ -452,22 +262,17 @@ $aplayer-height-lrc: $aplayer-height + $lrc-height - 6;
|
||||||
cursor: pointer !important;
|
cursor: pointer !important;
|
||||||
|
|
||||||
&:hover .aplayer-volume-bar-wrap {
|
&:hover .aplayer-volume-bar-wrap {
|
||||||
height: 40px;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.aplayer-volume-bar-wrap {
|
.aplayer-volume-bar-wrap {
|
||||||
|
display: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 15px;
|
bottom: 15px;
|
||||||
right: -3px;
|
right: -3px;
|
||||||
width: 25px;
|
width: 25px;
|
||||||
height: 0;
|
height: 40px;
|
||||||
z-index: 99;
|
z-index: 99;
|
||||||
overflow: hidden;
|
|
||||||
transition: all .2s ease-in-out;
|
|
||||||
|
|
||||||
&.aplayer-volume-bar-wrap-active {
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-volume-bar {
|
.aplayer-volume-bar {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
@ -476,8 +281,6 @@ $aplayer-height-lrc: $aplayer-height + $lrc-height - 6;
|
||||||
width: 5px;
|
width: 5px;
|
||||||
height: 35px;
|
height: 35px;
|
||||||
background: #aaa;
|
background: #aaa;
|
||||||
border-radius: 2.5px;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
.aplayer-volume {
|
.aplayer-volume {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
@ -489,15 +292,6 @@ $aplayer-height-lrc: $aplayer-height + $lrc-height - 6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.aplayer-loading-icon {
|
|
||||||
display: none;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
position: absolute;
|
|
||||||
animation: rotate 1s linear infinite;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -505,6 +299,7 @@ $aplayer-height-lrc: $aplayer-height + $lrc-height - 6;
|
||||||
display: none;
|
display: none;
|
||||||
position: relative;
|
position: relative;
|
||||||
height: $lrc-height;
|
height: $lrc-height;
|
||||||
|
background: #fff;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin: -10px 0 7px;
|
margin: -10px 0 7px;
|
||||||
|
|
@ -552,16 +347,9 @@ $aplayer-height-lrc: $aplayer-height + $lrc-height - 6;
|
||||||
|
|
||||||
&.aplayer-lrc-current {
|
&.aplayer-lrc-current {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
overflow: visible;
|
|
||||||
height: initial !important;
|
|
||||||
min-height: 16px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.aplayer-lrc-hide {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-lrc-contents {
|
.aplayer-lrc-contents {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
transition: all 0.5s ease-out;
|
transition: all 0.5s ease-out;
|
||||||
|
|
@ -574,117 +362,75 @@ $aplayer-height-lrc: $aplayer-height + $lrc-height - 6;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
transition: all 0.5s ease;
|
transition: all 0.5s ease;
|
||||||
will-change: height;
|
will-change: height;
|
||||||
display: none;
|
|
||||||
overflow: hidden;
|
|
||||||
list-style-type: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
overflow-y: auto;
|
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
&.aplayer-list-hide {
|
||||||
width: 5px;
|
height: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
&::-webkit-scrollbar-thumb {
|
&::-webkit-scrollbar{
|
||||||
|
width: 5px;
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-track{
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
&::-webkit-scrollbar-thumb{
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
}
|
}
|
||||||
|
&::-webkit-scrollbar-thumb:hover{
|
||||||
&::-webkit-scrollbar-thumb:hover {
|
|
||||||
background-color: #ccc;
|
background-color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
li {
|
ol {
|
||||||
position: relative;
|
list-style-type: none;
|
||||||
height: 32px;
|
|
||||||
line-height: 32px;
|
|
||||||
padding: 0 15px;
|
|
||||||
font-size: 12px;
|
|
||||||
border-top: 1px solid #e9e9e9;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
overflow: hidden;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
&:first-child {
|
li {
|
||||||
border-top: none;
|
position: relative;
|
||||||
}
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
padding: 0 15px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-top: 1px solid #e9e9e9;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
&:hover {
|
&:first-child {
|
||||||
background: #efefef;
|
border-top: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.aplayer-list-light {
|
&:hover {
|
||||||
background: #e9e9e9;
|
background: #efefef;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.aplayer-list-light {
|
||||||
|
background: #e9e9e9;
|
||||||
|
|
||||||
|
.aplayer-list-cur {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.aplayer-list-cur {
|
.aplayer-list-cur {
|
||||||
display: inline-block;
|
display: none;
|
||||||
|
width: 3px;
|
||||||
|
height: 22px;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 5px;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
.aplayer-list-index {
|
||||||
|
color: #666;
|
||||||
.aplayer-list-cur {
|
margin-right: 12px;
|
||||||
display: none;
|
cursor: pointer;
|
||||||
width: 3px;
|
}
|
||||||
height: 22px;
|
.aplayer-list-author {
|
||||||
position: absolute;
|
color: #666;
|
||||||
left: 0;
|
float: right;
|
||||||
top: 5px;
|
cursor: pointer;
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.aplayer-list-index {
|
|
||||||
color: #666;
|
|
||||||
margin-right: 12px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.aplayer-list-author {
|
|
||||||
color: #666;
|
|
||||||
float: right;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-notice {
|
|
||||||
opacity: 0;
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
font-size: 12px;
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 5px 10px;
|
|
||||||
transition: all .3s ease-in-out;
|
|
||||||
overflow: hidden;
|
|
||||||
color: #fff;
|
|
||||||
pointer-events: none;
|
|
||||||
background-color: #f4f4f5;
|
|
||||||
color: #909399;
|
|
||||||
}
|
|
||||||
|
|
||||||
.aplayer-miniswitcher {
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
height: 100%;
|
|
||||||
background: #e6e6e6;
|
|
||||||
width: 18px;
|
|
||||||
border-radius: 0 2px 2px 0;
|
|
||||||
|
|
||||||
.aplayer-icon {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
transform: rotateY(180deg);
|
|
||||||
transition: all 0.3s ease;
|
|
||||||
|
|
||||||
path {
|
|
||||||
fill: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
path {
|
|
||||||
fill: #000;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -694,13 +440,4 @@ $aplayer-height-lrc: $aplayer-height + $lrc-height - 6;
|
||||||
@keyframes aplayer-roll {
|
@keyframes aplayer-roll {
|
||||||
0%{left:0}
|
0%{left:0}
|
||||||
100%{left: -100%}
|
100%{left: -100%}
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes rotate {
|
|
||||||
0% {
|
|
||||||
transform: rotate(0)
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: rotate(360deg)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 32 32">
|
|
||||||
<path d="M4 16c0-6.6 5.4-12 12-12s12 5.4 12 12c0 1.2-0.8 2-2 2s-2-0.8-2-2c0-4.4-3.6-8-8-8s-8 3.6-8 8 3.6 8 8 8c1.2 0 2 0.8 2 2s-0.8 2-2 2c-6.6 0-12-5.4-12-12z"></path>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 253 B |
|
|
@ -1,3 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 29 32">
|
|
||||||
<path d="M9.333 9.333h13.333v4l5.333-5.333-5.333-5.333v4h-16v8h2.667v-5.333zM22.667 22.667h-13.333v-4l-5.333 5.333 5.333 5.333v-4h16v-8h-2.667v5.333z"></path>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 244 B |
|
|
@ -1,3 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 29 32">
|
|
||||||
<path d="M2.667 7.027l1.707-1.693 22.293 22.293-1.693 1.707-4-4h-11.64v4l-5.333-5.333 5.333-5.333v4h8.973l-8.973-8.973v0.973h-2.667v-3.64l-4-4zM22.667 17.333h2.667v5.573l-2.667-2.667v-2.907zM22.667 6.667v-4l5.333 5.333-5.333 5.333v-4h-10.907l-2.667-2.667h13.573z"></path>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 357 B |
|
|
@ -1,3 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 33 32">
|
|
||||||
<path d="M9.333 9.333h13.333v4l5.333-5.333-5.333-5.333v4h-16v8h2.667v-5.333zM22.667 22.667h-13.333v-4l-5.333 5.333 5.333 5.333v-4h16v-8h-2.667v5.333zM17.333 20v-8h-1.333l-2.667 1.333v1.333h2v5.333h2z"></path>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 294 B |
|
|
@ -1,3 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 32 32">
|
|
||||||
<path d="M26.667 5.333h-21.333c-0 0-0.001 0-0.001 0-1.472 0-2.666 1.194-2.666 2.666 0 0 0 0.001 0 0.001v-0 16c0 0 0 0.001 0 0.001 0 1.472 1.194 2.666 2.666 2.666 0 0 0.001 0 0.001 0h21.333c0 0 0.001 0 0.001 0 1.472 0 2.666-1.194 2.666-2.666 0-0 0-0.001 0-0.001v0-16c0-0 0-0.001 0-0.001 0-1.472-1.194-2.666-2.666-2.666-0 0-0.001 0-0.001 0h0zM5.333 16h5.333v2.667h-5.333v-2.667zM18.667 24h-13.333v-2.667h13.333v2.667zM26.667 24h-5.333v-2.667h5.333v2.667zM26.667 18.667h-13.333v-2.667h13.333v2.667z"></path>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 590 B |
|
|
@ -1,3 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 22 32">
|
|
||||||
<path d="M20.8 14.4q0.704 0 1.152 0.48t0.448 1.12-0.48 1.12-1.12 0.48h-19.2q-0.64 0-1.12-0.48t-0.48-1.12 0.448-1.12 1.152-0.48h19.2zM1.6 11.2q-0.64 0-1.12-0.48t-0.48-1.12 0.448-1.12 1.152-0.48h19.2q0.704 0 1.152 0.48t0.448 1.12-0.48 1.12-1.12 0.48h-19.2zM20.8 20.8q0.704 0 1.152 0.48t0.448 1.12-0.48 1.12-1.12 0.48h-19.2q-0.64 0-1.12-0.48t-0.48-1.12 0.448-1.12 1.152-0.48h19.2z"></path>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 472 B |
|
|
@ -1,3 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 32 32">
|
|
||||||
<path d="M0.622 18.334h19.54v7.55l11.052-9.412-11.052-9.413v7.549h-19.54v3.725z"></path>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 174 B |
|
|
@ -1,3 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 32 32">
|
|
||||||
<path d="M22.667 4l7 6-7 6 7 6-7 6v-4h-3.653l-3.76-3.76 2.827-2.827 2.587 2.587h2v-8h-2l-12 12h-6v-4h4.347l12-12h3.653v-4zM2.667 8h6l3.76 3.76-2.827 2.827-2.587-2.587h-4.347v-4z"></path>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 272 B |
|
|
@ -1,3 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 17 32">
|
|
||||||
<path d="M14.080 4.8q2.88 0 2.88 2.048v18.24q0 2.112-2.88 2.112t-2.88-2.112v-18.24q0-2.048 2.88-2.048zM2.88 4.8q2.88 0 2.88 2.048v18.24q0 2.112-2.88 2.112t-2.88-2.112v-18.24q0-2.048 2.88-2.048z"></path>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 288 B |
|
|
@ -1,3 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 16 31">
|
|
||||||
<path d="M15.552 15.168q0.448 0.32 0.448 0.832 0 0.448-0.448 0.768l-13.696 8.512q-0.768 0.512-1.312 0.192t-0.544-1.28v-16.448q0-0.96 0.544-1.28t1.312 0.192z"></path>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 251 B |
|
|
@ -1,3 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 32 32">
|
|
||||||
<path d="M22 16l-10.105-10.6-1.895 1.987 8.211 8.613-8.211 8.612 1.895 1.988 8.211-8.613z"></path>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 184 B |
|
|
@ -1,3 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 32 32">
|
|
||||||
<path d="M25.468 6.947c-0.326-0.172-0.724-0.151-1.030 0.057l-6.438 4.38v-3.553c0-0.371-0.205-0.71-0.532-0.884-0.326-0.172-0.724-0.151-1.030 0.057l-12 8.164c-0.274 0.186-0.438 0.496-0.438 0.827s0.164 0.641 0.438 0.827l12 8.168c0.169 0.115 0.365 0.174 0.562 0.174 0.16 0 0.321-0.038 0.468-0.116 0.327-0.173 0.532-0.514 0.532-0.884v-3.556l6.438 4.382c0.169 0.115 0.365 0.174 0.562 0.174 0.16 0 0.321-0.038 0.468-0.116 0.327-0.173 0.532-0.514 0.532-0.884v-16.333c0-0.371-0.205-0.71-0.532-0.884z"></path>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 585 B |
|
|
@ -1,3 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 28 32">
|
|
||||||
<path d="M13.728 6.272v19.456q0 0.448-0.352 0.8t-0.8 0.32-0.8-0.32l-5.952-5.952h-4.672q-0.48 0-0.8-0.352t-0.352-0.8v-6.848q0-0.48 0.352-0.8t0.8-0.352h4.672l5.952-5.952q0.32-0.32 0.8-0.32t0.8 0.32 0.352 0.8zM20.576 16q0 1.344-0.768 2.528t-2.016 1.664q-0.16 0.096-0.448 0.096-0.448 0-0.8-0.32t-0.32-0.832q0-0.384 0.192-0.64t0.544-0.448 0.608-0.384 0.512-0.64 0.192-1.024-0.192-1.024-0.512-0.64-0.608-0.384-0.544-0.448-0.192-0.64q0-0.48 0.32-0.832t0.8-0.32q0.288 0 0.448 0.096 1.248 0.48 2.016 1.664t0.768 2.528z"></path>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 604 B |
|
|
@ -1,3 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 28 32">
|
|
||||||
<path d="M13.728 6.272v19.456q0 0.448-0.352 0.8t-0.8 0.32-0.8-0.32l-5.952-5.952h-4.672q-0.48 0-0.8-0.352t-0.352-0.8v-6.848q0-0.48 0.352-0.8t0.8-0.352h4.672l5.952-5.952q0.32-0.32 0.8-0.32t0.8 0.32 0.352 0.8z"></path>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 301 B |
|
|
@ -1,3 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 28 32">
|
|
||||||
<path d="M13.728 6.272v19.456q0 0.448-0.352 0.8t-0.8 0.32-0.8-0.32l-5.952-5.952h-4.672q-0.48 0-0.8-0.352t-0.352-0.8v-6.848q0-0.48 0.352-0.8t0.8-0.352h4.672l5.952-5.952q0.32-0.32 0.8-0.32t0.8 0.32 0.352 0.8zM20.576 16q0 1.344-0.768 2.528t-2.016 1.664q-0.16 0.096-0.448 0.096-0.448 0-0.8-0.32t-0.32-0.832q0-0.384 0.192-0.64t0.544-0.448 0.608-0.384 0.512-0.64 0.192-1.024-0.192-1.024-0.512-0.64-0.608-0.384-0.544-0.448-0.192-0.64q0-0.48 0.32-0.832t0.8-0.32q0.288 0 0.448 0.096 1.248 0.48 2.016 1.664t0.768 2.528zM25.152 16q0 2.72-1.536 5.056t-4 3.36q-0.256 0.096-0.448 0.096-0.48 0-0.832-0.352t-0.32-0.8q0-0.704 0.672-1.056 1.024-0.512 1.376-0.8 1.312-0.96 2.048-2.4t0.736-3.104-0.736-3.104-2.048-2.4q-0.352-0.288-1.376-0.8-0.672-0.352-0.672-1.056 0-0.448 0.32-0.8t0.8-0.352q0.224 0 0.48 0.096 2.496 1.056 4 3.36t1.536 5.056zM29.728 16q0 4.096-2.272 7.552t-6.048 5.056q-0.224 0.096-0.448 0.096-0.48 0-0.832-0.352t-0.32-0.8q0-0.64 0.704-1.056 0.128-0.064 0.384-0.192t0.416-0.192q0.8-0.448 1.44-0.896 2.208-1.632 3.456-4.064t1.216-5.152-1.216-5.152-3.456-4.064q-0.64-0.448-1.44-0.896-0.128-0.096-0.416-0.192t-0.384-0.192q-0.704-0.416-0.704-1.056 0-0.448 0.32-0.8t0.832-0.352q0.224 0 0.448 0.096 3.776 1.632 6.048 5.056t2.272 7.552z"></path>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
|
@ -1,27 +0,0 @@
|
||||||
class Bar {
|
|
||||||
constructor(template) {
|
|
||||||
this.elements = {};
|
|
||||||
this.elements.volume = template.volume;
|
|
||||||
this.elements.played = template.played;
|
|
||||||
this.elements.loaded = template.loaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update progress
|
|
||||||
*
|
|
||||||
* @param {String} type - Point out which bar it is
|
|
||||||
* @param {Number} percentage
|
|
||||||
* @param {String} direction - Point out the direction of this bar, Should be height or width
|
|
||||||
*/
|
|
||||||
set(type, percentage, direction) {
|
|
||||||
percentage = Math.max(percentage, 0);
|
|
||||||
percentage = Math.min(percentage, 1);
|
|
||||||
this.elements[type].style[direction] = percentage * 100 + '%';
|
|
||||||
}
|
|
||||||
|
|
||||||
get(type, direction) {
|
|
||||||
return parseFloat(this.elements[type].style[direction]) / 100;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Bar;
|
|
||||||
|
|
@ -1,164 +0,0 @@
|
||||||
import utils from './utils';
|
|
||||||
import Icons from './icons';
|
|
||||||
|
|
||||||
class Controller {
|
|
||||||
constructor(player) {
|
|
||||||
this.player = player;
|
|
||||||
|
|
||||||
this.initPlayButton();
|
|
||||||
this.initPlayBar();
|
|
||||||
this.initOrderButton();
|
|
||||||
this.initLoopButton();
|
|
||||||
this.initMenuButton();
|
|
||||||
if (!utils.isMobile) {
|
|
||||||
this.initVolumeButton();
|
|
||||||
}
|
|
||||||
this.initMiniSwitcher();
|
|
||||||
this.initSkipButton();
|
|
||||||
this.initLrcButton();
|
|
||||||
}
|
|
||||||
|
|
||||||
initPlayButton() {
|
|
||||||
this.player.template.pic.addEventListener('click', () => {
|
|
||||||
this.player.toggle();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
initPlayBar() {
|
|
||||||
const thumbMove = (e) => {
|
|
||||||
let percentage = ((e.clientX || e.changedTouches[0].clientX) - this.player.template.barWrap.getBoundingClientRect().left) / this.player.template.barWrap.clientWidth;
|
|
||||||
percentage = Math.max(percentage, 0);
|
|
||||||
percentage = Math.min(percentage, 1);
|
|
||||||
this.player.bar.set('played', percentage, 'width');
|
|
||||||
this.player.lrc && this.player.lrc.update(percentage * this.player.duration);
|
|
||||||
this.player.template.ptime.innerHTML = utils.secondToTime(percentage * this.player.duration);
|
|
||||||
};
|
|
||||||
|
|
||||||
const thumbUp = (e) => {
|
|
||||||
document.removeEventListener(utils.nameMap.dragEnd, thumbUp);
|
|
||||||
document.removeEventListener(utils.nameMap.dragMove, thumbMove);
|
|
||||||
let percentage = ((e.clientX || e.changedTouches[0].clientX) - this.player.template.barWrap.getBoundingClientRect().left) / this.player.template.barWrap.clientWidth;
|
|
||||||
percentage = Math.max(percentage, 0);
|
|
||||||
percentage = Math.min(percentage, 1);
|
|
||||||
this.player.bar.set('played', percentage, 'width');
|
|
||||||
this.player.seek(percentage * this.player.duration);
|
|
||||||
this.player.disableTimeupdate = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.player.template.barWrap.addEventListener(utils.nameMap.dragStart, () => {
|
|
||||||
this.player.disableTimeupdate = true;
|
|
||||||
document.addEventListener(utils.nameMap.dragMove, thumbMove);
|
|
||||||
document.addEventListener(utils.nameMap.dragEnd, thumbUp);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
initVolumeButton() {
|
|
||||||
this.player.template.volumeButton.addEventListener('click', () => {
|
|
||||||
if (this.player.audio.muted) {
|
|
||||||
this.player.volume(this.player.audio.volume, true);
|
|
||||||
} else {
|
|
||||||
this.player.audio.muted = true;
|
|
||||||
this.player.switchVolumeIcon();
|
|
||||||
this.player.bar.set('volume', 0, 'height');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const thumbMove = (e) => {
|
|
||||||
let percentage = 1 - ((e.clientY || e.changedTouches[0].clientY) - this.player.template.volumeBar.getBoundingClientRect().top) / this.player.template.volumeBar.clientHeight;
|
|
||||||
percentage = Math.max(percentage, 0);
|
|
||||||
percentage = Math.min(percentage, 1);
|
|
||||||
this.player.volume(percentage);
|
|
||||||
};
|
|
||||||
|
|
||||||
const thumbUp = (e) => {
|
|
||||||
this.player.template.volumeBarWrap.classList.remove('aplayer-volume-bar-wrap-active');
|
|
||||||
document.removeEventListener(utils.nameMap.dragEnd, thumbUp);
|
|
||||||
document.removeEventListener(utils.nameMap.dragMove, thumbMove);
|
|
||||||
let percentage = 1 - ((e.clientY || e.changedTouches[0].clientY) - this.player.template.volumeBar.getBoundingClientRect().top) / this.player.template.volumeBar.clientHeight;
|
|
||||||
percentage = Math.max(percentage, 0);
|
|
||||||
percentage = Math.min(percentage, 1);
|
|
||||||
this.player.volume(percentage);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.player.template.volumeBarWrap.addEventListener(utils.nameMap.dragStart, () => {
|
|
||||||
this.player.template.volumeBarWrap.classList.add('aplayer-volume-bar-wrap-active');
|
|
||||||
document.addEventListener(utils.nameMap.dragMove, thumbMove);
|
|
||||||
document.addEventListener(utils.nameMap.dragEnd, thumbUp);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
initOrderButton() {
|
|
||||||
this.player.template.order.addEventListener('click', () => {
|
|
||||||
if (this.player.options.order === 'list') {
|
|
||||||
this.player.options.order = 'random';
|
|
||||||
this.player.template.order.innerHTML = Icons.orderRandom;
|
|
||||||
} else if (this.player.options.order === 'random') {
|
|
||||||
this.player.options.order = 'list';
|
|
||||||
this.player.template.order.innerHTML = Icons.orderList;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
initLoopButton() {
|
|
||||||
this.player.template.loop.addEventListener('click', () => {
|
|
||||||
if (this.player.list.audios.length > 1) {
|
|
||||||
if (this.player.options.loop === 'one') {
|
|
||||||
this.player.options.loop = 'none';
|
|
||||||
this.player.template.loop.innerHTML = Icons.loopNone;
|
|
||||||
} else if (this.player.options.loop === 'none') {
|
|
||||||
this.player.options.loop = 'all';
|
|
||||||
this.player.template.loop.innerHTML = Icons.loopAll;
|
|
||||||
} else if (this.player.options.loop === 'all') {
|
|
||||||
this.player.options.loop = 'one';
|
|
||||||
this.player.template.loop.innerHTML = Icons.loopOne;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (this.player.options.loop === 'one' || this.player.options.loop === 'all') {
|
|
||||||
this.player.options.loop = 'none';
|
|
||||||
this.player.template.loop.innerHTML = Icons.loopNone;
|
|
||||||
} else if (this.player.options.loop === 'none') {
|
|
||||||
this.player.options.loop = 'all';
|
|
||||||
this.player.template.loop.innerHTML = Icons.loopAll;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
initMenuButton() {
|
|
||||||
this.player.template.menu.addEventListener('click', () => {
|
|
||||||
this.player.list.toggle();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
initMiniSwitcher() {
|
|
||||||
this.player.template.miniSwitcher.addEventListener('click', () => {
|
|
||||||
this.player.setMode(this.player.mode === 'mini' ? 'normal' : 'mini');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
initSkipButton() {
|
|
||||||
this.player.template.skipBackButton.addEventListener('click', () => {
|
|
||||||
this.player.skipBack();
|
|
||||||
});
|
|
||||||
this.player.template.skipForwardButton.addEventListener('click', () => {
|
|
||||||
this.player.skipForward();
|
|
||||||
});
|
|
||||||
this.player.template.skipPlayButton.addEventListener('click', () => {
|
|
||||||
this.player.toggle();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
initLrcButton() {
|
|
||||||
this.player.template.lrcButton.addEventListener('click', () => {
|
|
||||||
if (this.player.template.lrcButton.classList.contains('aplayer-icon-lrc-inactivity')) {
|
|
||||||
this.player.template.lrcButton.classList.remove('aplayer-icon-lrc-inactivity');
|
|
||||||
this.player.lrc && this.player.lrc.show();
|
|
||||||
} else {
|
|
||||||
this.player.template.lrcButton.classList.add('aplayer-icon-lrc-inactivity');
|
|
||||||
this.player.lrc && this.player.lrc.hide();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Controller;
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
class Events {
|
|
||||||
constructor() {
|
|
||||||
this.events = {};
|
|
||||||
|
|
||||||
this.audioEvents = [
|
|
||||||
'abort',
|
|
||||||
'canplay',
|
|
||||||
'canplaythrough',
|
|
||||||
'durationchange',
|
|
||||||
'emptied',
|
|
||||||
'ended',
|
|
||||||
'error',
|
|
||||||
'loadeddata',
|
|
||||||
'loadedmetadata',
|
|
||||||
'loadstart',
|
|
||||||
'mozaudioavailable',
|
|
||||||
'pause',
|
|
||||||
'play',
|
|
||||||
'playing',
|
|
||||||
'progress',
|
|
||||||
'ratechange',
|
|
||||||
'seeked',
|
|
||||||
'seeking',
|
|
||||||
'stalled',
|
|
||||||
'suspend',
|
|
||||||
'timeupdate',
|
|
||||||
'volumechange',
|
|
||||||
'waiting',
|
|
||||||
];
|
|
||||||
this.playerEvents = ['destroy', 'listshow', 'listhide', 'listadd', 'listremove', 'listswitch', 'listclear', 'noticeshow', 'noticehide', 'lrcshow', 'lrchide'];
|
|
||||||
}
|
|
||||||
|
|
||||||
on(name, callback) {
|
|
||||||
if (this.type(name) && typeof callback === 'function') {
|
|
||||||
if (!this.events[name]) {
|
|
||||||
this.events[name] = [];
|
|
||||||
}
|
|
||||||
this.events[name].push(callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trigger(name, data) {
|
|
||||||
if (this.events[name] && this.events[name].length) {
|
|
||||||
for (let i = 0; i < this.events[name].length; i++) {
|
|
||||||
this.events[name][i](data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type(name) {
|
|
||||||
if (this.playerEvents.indexOf(name) !== -1) {
|
|
||||||
return 'player';
|
|
||||||
} else if (this.audioEvents.indexOf(name) !== -1) {
|
|
||||||
return 'audio';
|
|
||||||
}
|
|
||||||
|
|
||||||
console.error(`Unknown event name: ${name}`);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Events;
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
import play from '../assets/play.svg';
|
|
||||||
import pause from '../assets/pause.svg';
|
|
||||||
import volumeUp from '../assets/volume-up.svg';
|
|
||||||
import volumeDown from '../assets/volume-down.svg';
|
|
||||||
import volumeOff from '../assets/volume-off.svg';
|
|
||||||
import orderRandom from '../assets/order-random.svg';
|
|
||||||
import orderList from '../assets/order-list.svg';
|
|
||||||
import menu from '../assets/menu.svg';
|
|
||||||
import loopAll from '../assets/loop-all.svg';
|
|
||||||
import loopOne from '../assets/loop-one.svg';
|
|
||||||
import loopNone from '../assets/loop-none.svg';
|
|
||||||
import loading from '../assets/loading.svg';
|
|
||||||
import right from '../assets/right.svg';
|
|
||||||
import skip from '../assets/skip.svg';
|
|
||||||
import lrc from '../assets/lrc.svg';
|
|
||||||
|
|
||||||
const Icons = {
|
|
||||||
play: play,
|
|
||||||
pause: pause,
|
|
||||||
volumeUp: volumeUp,
|
|
||||||
volumeDown: volumeDown,
|
|
||||||
volumeOff: volumeOff,
|
|
||||||
orderRandom: orderRandom,
|
|
||||||
orderList: orderList,
|
|
||||||
menu: menu,
|
|
||||||
loopAll: loopAll,
|
|
||||||
loopOne: loopOne,
|
|
||||||
loopNone: loopNone,
|
|
||||||
loading: loading,
|
|
||||||
right: right,
|
|
||||||
skip: skip,
|
|
||||||
lrc: lrc,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Icons;
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
import '../css/index.scss';
|
|
||||||
import APlayer from './player';
|
|
||||||
|
|
||||||
/* global APLAYER_VERSION GIT_HASH */
|
|
||||||
console.log(`${'\n'} %c APlayer v${APLAYER_VERSION} ${GIT_HASH} %c http://aplayer.js.org ${'\n'}`, 'color: #fadfa3; background: #030307; padding:5px 0;', 'background: #fadfa3; padding:5px 0;');
|
|
||||||
|
|
||||||
export default APlayer;
|
|
||||||
195
src/js/list.js
|
|
@ -1,195 +0,0 @@
|
||||||
import tplListItem from '../template/list-item.art';
|
|
||||||
import utils from './utils';
|
|
||||||
import smoothScroll from 'smoothscroll';
|
|
||||||
|
|
||||||
class List {
|
|
||||||
constructor(player) {
|
|
||||||
this.player = player;
|
|
||||||
this.index = 0;
|
|
||||||
this.audios = this.player.options.audio;
|
|
||||||
this.showing = true;
|
|
||||||
this.player.template.list.style.height = `${Math.min(this.player.template.list.scrollHeight, this.player.options.listMaxHeight)}px`;
|
|
||||||
|
|
||||||
this.bindEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
bindEvents() {
|
|
||||||
this.player.template.list.addEventListener('click', (e) => {
|
|
||||||
let target;
|
|
||||||
if (e.target.tagName.toUpperCase() === 'LI') {
|
|
||||||
target = e.target;
|
|
||||||
} else {
|
|
||||||
target = e.target.parentElement;
|
|
||||||
}
|
|
||||||
const audioIndex = parseInt(target.getElementsByClassName('aplayer-list-index')[0].innerHTML) - 1;
|
|
||||||
if (audioIndex !== this.index) {
|
|
||||||
this.switch(audioIndex);
|
|
||||||
this.player.play();
|
|
||||||
} else {
|
|
||||||
this.player.toggle();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
show() {
|
|
||||||
this.showing = true;
|
|
||||||
this.player.template.list.scrollTop = this.index * 33;
|
|
||||||
this.player.template.list.style.height = `${Math.min(this.player.template.list.scrollHeight, this.player.options.listMaxHeight)}px`;
|
|
||||||
this.player.events.trigger('listshow');
|
|
||||||
}
|
|
||||||
|
|
||||||
hide() {
|
|
||||||
this.showing = false;
|
|
||||||
this.player.template.list.style.height = `${Math.min(this.player.template.list.scrollHeight, this.player.options.listMaxHeight)}px`;
|
|
||||||
setTimeout(() => {
|
|
||||||
this.player.template.list.style.height = '0px';
|
|
||||||
this.player.events.trigger('listhide');
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
toggle() {
|
|
||||||
if (this.showing) {
|
|
||||||
this.hide();
|
|
||||||
} else {
|
|
||||||
this.show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
add(audios) {
|
|
||||||
this.player.events.trigger('listadd', {
|
|
||||||
audios: audios,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (Object.prototype.toString.call(audios) !== '[object Array]') {
|
|
||||||
audios = [audios];
|
|
||||||
}
|
|
||||||
audios.map((item) => {
|
|
||||||
item.name = item.name || item.title || 'Audio name';
|
|
||||||
item.artist = item.artist || item.author || 'Audio artist';
|
|
||||||
item.cover = item.cover || item.pic;
|
|
||||||
item.type = item.type || 'normal';
|
|
||||||
return item;
|
|
||||||
});
|
|
||||||
|
|
||||||
const wasSingle = !(this.audios.length > 1);
|
|
||||||
const wasEmpty = this.audios.length === 0;
|
|
||||||
|
|
||||||
this.player.template.list.innerHTML += tplListItem({
|
|
||||||
theme: this.player.options.theme,
|
|
||||||
audio: audios,
|
|
||||||
index: this.audios.length + 1,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.audios = this.audios.concat(audios);
|
|
||||||
|
|
||||||
if (wasSingle && this.audios.length > 1) {
|
|
||||||
this.player.container.classList.add('aplayer-withlist');
|
|
||||||
}
|
|
||||||
|
|
||||||
this.player.randomOrder = utils.randomOrder(this.audios.length);
|
|
||||||
this.player.template.listCurs = this.player.container.querySelectorAll('.aplayer-list-cur');
|
|
||||||
|
|
||||||
this.player.template.listCurs[this.audios.length - 1].style.backgroundColor = audios.theme || this.player.options.theme;
|
|
||||||
|
|
||||||
if (wasEmpty) {
|
|
||||||
if (this.player.options.order === 'random') {
|
|
||||||
this.switch(this.player.randomOrder[0]);
|
|
||||||
} else {
|
|
||||||
this.switch(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
remove(index) {
|
|
||||||
this.player.events.trigger('listremove', {
|
|
||||||
index: index,
|
|
||||||
});
|
|
||||||
if (this.audios[index]) {
|
|
||||||
if (this.audios.length > 1) {
|
|
||||||
const list = this.player.container.querySelectorAll('.aplayer-list li');
|
|
||||||
list[index].remove();
|
|
||||||
|
|
||||||
this.audios.splice(index, 1);
|
|
||||||
this.player.lrc && this.player.lrc.remove(index);
|
|
||||||
|
|
||||||
if (index === this.index) {
|
|
||||||
if (this.audios[index]) {
|
|
||||||
this.switch(index);
|
|
||||||
} else {
|
|
||||||
this.switch(index - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.index > index) {
|
|
||||||
this.index--;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = index; i < list.length; i++) {
|
|
||||||
list[i].getElementsByClassName('aplayer-list-index')[0].textContent = i;
|
|
||||||
}
|
|
||||||
if (this.audios.length === 1) {
|
|
||||||
this.player.container.classList.remove('aplayer-withlist');
|
|
||||||
}
|
|
||||||
|
|
||||||
this.player.template.listCurs = this.player.container.querySelectorAll('.aplayer-list-cur');
|
|
||||||
} else {
|
|
||||||
this.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(index) {
|
|
||||||
this.player.events.trigger('listswitch', {
|
|
||||||
index: index,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (typeof index !== 'undefined' && this.audios[index]) {
|
|
||||||
this.index = index;
|
|
||||||
|
|
||||||
const audio = this.audios[this.index];
|
|
||||||
|
|
||||||
// set html
|
|
||||||
this.player.template.pic.style.backgroundImage = audio.cover ? `url('${audio.cover}')` : '';
|
|
||||||
this.player.theme(this.audios[this.index].theme || this.player.options.theme, this.index, false);
|
|
||||||
this.player.template.title.innerHTML = audio.name;
|
|
||||||
this.player.template.author.innerHTML = audio.artist ? ' - ' + audio.artist : '';
|
|
||||||
|
|
||||||
const light = this.player.container.getElementsByClassName('aplayer-list-light')[0];
|
|
||||||
if (light) {
|
|
||||||
light.classList.remove('aplayer-list-light');
|
|
||||||
}
|
|
||||||
this.player.container.querySelectorAll('.aplayer-list li')[this.index].classList.add('aplayer-list-light');
|
|
||||||
|
|
||||||
smoothScroll(this.index * 33, 500, null, this.player.template.list);
|
|
||||||
|
|
||||||
this.player.setAudio(audio);
|
|
||||||
|
|
||||||
this.player.lrc && this.player.lrc.switch(this.index);
|
|
||||||
this.player.lrc && this.player.lrc.update(0);
|
|
||||||
|
|
||||||
// set duration time
|
|
||||||
if (this.player.duration !== 1) {
|
|
||||||
// compatibility: Android browsers will output 1 at first
|
|
||||||
this.player.template.dtime.innerHTML = utils.secondToTime(this.player.duration);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clear() {
|
|
||||||
this.player.events.trigger('listclear');
|
|
||||||
this.index = 0;
|
|
||||||
this.player.container.classList.remove('aplayer-withlist');
|
|
||||||
this.player.pause();
|
|
||||||
this.audios = [];
|
|
||||||
this.player.lrc && this.player.lrc.clear();
|
|
||||||
this.player.audio.src = '';
|
|
||||||
this.player.template.list.innerHTML = '';
|
|
||||||
this.player.template.pic.style.backgroundImage = '';
|
|
||||||
this.player.theme(this.player.options.theme, this.index, false);
|
|
||||||
this.player.template.title.innerHTML = 'No audio';
|
|
||||||
this.player.template.author.innerHTML = '';
|
|
||||||
this.player.bar.set('loaded', 0, 'width');
|
|
||||||
this.player.template.dtime.innerHTML = utils.secondToTime(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default List;
|
|
||||||
143
src/js/lrc.js
|
|
@ -1,143 +0,0 @@
|
||||||
import tplLrc from '../template/lrc.art';
|
|
||||||
|
|
||||||
class Lrc {
|
|
||||||
constructor(options) {
|
|
||||||
this.container = options.container;
|
|
||||||
this.async = options.async;
|
|
||||||
this.player = options.player;
|
|
||||||
this.parsed = [];
|
|
||||||
this.index = 0;
|
|
||||||
this.current = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
show() {
|
|
||||||
this.player.events.trigger('lrcshow');
|
|
||||||
this.player.template.lrcWrap.classList.remove('aplayer-lrc-hide');
|
|
||||||
}
|
|
||||||
|
|
||||||
hide() {
|
|
||||||
this.player.events.trigger('lrchide');
|
|
||||||
this.player.template.lrcWrap.classList.add('aplayer-lrc-hide');
|
|
||||||
}
|
|
||||||
|
|
||||||
toggle() {
|
|
||||||
if (this.player.template.lrcWrap.classList.contains('aplayer-lrc-hide')) {
|
|
||||||
this.show();
|
|
||||||
} else {
|
|
||||||
this.hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
update(currentTime = this.player.audio.currentTime) {
|
|
||||||
if (this.index > this.current.length - 1 || currentTime < this.current[this.index][0] || (!this.current[this.index + 1] || currentTime >= this.current[this.index + 1][0])) {
|
|
||||||
for (let i = 0; i < this.current.length; i++) {
|
|
||||||
if (currentTime >= this.current[i][0] && (!this.current[i + 1] || currentTime < this.current[i + 1][0])) {
|
|
||||||
this.index = i;
|
|
||||||
this.container.style.transform = `translateY(${-this.index * 16}px)`;
|
|
||||||
this.container.style.webkitTransform = `translateY(${-this.index * 16}px)`;
|
|
||||||
this.container.getElementsByClassName('aplayer-lrc-current')[0].classList.remove('aplayer-lrc-current');
|
|
||||||
this.container.getElementsByTagName('p')[i].classList.add('aplayer-lrc-current');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(index) {
|
|
||||||
if (!this.parsed[index]) {
|
|
||||||
if (!this.async) {
|
|
||||||
if (this.player.list.audios[index].lrc) {
|
|
||||||
this.parsed[index] = this.parse(this.player.list.audios[index].lrc);
|
|
||||||
} else {
|
|
||||||
this.parsed[index] = [['00:00', 'Not available']];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.parsed[index] = [['00:00', 'Loading']];
|
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
xhr.onreadystatechange = () => {
|
|
||||||
if (index === this.player.list.index && xhr.readyState === 4) {
|
|
||||||
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
|
|
||||||
this.parsed[index] = this.parse(xhr.responseText);
|
|
||||||
} else {
|
|
||||||
this.player.notice(`LRC file request fails: status ${xhr.status}`);
|
|
||||||
this.parsed[index] = [['00:00', 'Not available']];
|
|
||||||
}
|
|
||||||
this.container.innerHTML = tplLrc({
|
|
||||||
lyrics: this.parsed[index],
|
|
||||||
});
|
|
||||||
this.update(0);
|
|
||||||
this.current = this.parsed[index];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const apiurl = this.player.list.audios[index].lrc;
|
|
||||||
xhr.open('get', apiurl, true);
|
|
||||||
xhr.send(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.container.innerHTML = tplLrc({
|
|
||||||
lyrics: this.parsed[index],
|
|
||||||
});
|
|
||||||
this.current = this.parsed[index];
|
|
||||||
this.update(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse lrc, suppose multiple time tag
|
|
||||||
*
|
|
||||||
* @param {String} lrc_s - Format:
|
|
||||||
* [mm:ss]lyric
|
|
||||||
* [mm:ss.xx]lyric
|
|
||||||
* [mm:ss.xxx]lyric
|
|
||||||
* [mm:ss.xx][mm:ss.xx][mm:ss.xx]lyric
|
|
||||||
* [mm:ss.xx]<mm:ss.xx>lyric
|
|
||||||
*
|
|
||||||
* @return {String} [[time, text], [time, text], [time, text], ...]
|
|
||||||
*/
|
|
||||||
parse(lrc_s) {
|
|
||||||
if (lrc_s) {
|
|
||||||
lrc_s = lrc_s.replace(/([^\]^\n])\[/g, (match, p1) => p1 + '\n[');
|
|
||||||
const lyric = lrc_s.split('\n');
|
|
||||||
let lrc = [];
|
|
||||||
const lyricLen = lyric.length;
|
|
||||||
for (let i = 0; i < lyricLen; i++) {
|
|
||||||
// match lrc time
|
|
||||||
const lrcTimes = lyric[i].match(/\[(\d{2}):(\d{2})(\.(\d{2,3}))?]/g);
|
|
||||||
// match lrc text
|
|
||||||
const lrcText = lyric[i]
|
|
||||||
.replace(/.*\[(\d{2}):(\d{2})(\.(\d{2,3}))?]/g, '')
|
|
||||||
.replace(/<(\d{2}):(\d{2})(\.(\d{2,3}))?>/g, '')
|
|
||||||
.replace(/^\s+|\s+$/g, '');
|
|
||||||
|
|
||||||
if (lrcTimes) {
|
|
||||||
// handle multiple time tag
|
|
||||||
const timeLen = lrcTimes.length;
|
|
||||||
for (let j = 0; j < timeLen; j++) {
|
|
||||||
const oneTime = /\[(\d{2}):(\d{2})(\.(\d{2,3}))?]/.exec(lrcTimes[j]);
|
|
||||||
const min2sec = oneTime[1] * 60;
|
|
||||||
const sec2sec = parseInt(oneTime[2]);
|
|
||||||
const msec2sec = oneTime[4] ? parseInt(oneTime[4]) / ((oneTime[4] + '').length === 2 ? 100 : 1000) : 0;
|
|
||||||
const lrcTime = min2sec + sec2sec + msec2sec;
|
|
||||||
lrc.push([lrcTime, lrcText]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// sort by time
|
|
||||||
lrc = lrc.filter((item) => item[1]);
|
|
||||||
lrc.sort((a, b) => a[0] - b[0]);
|
|
||||||
return lrc;
|
|
||||||
} else {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
remove(index) {
|
|
||||||
this.parsed.splice(index, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
clear() {
|
|
||||||
this.parsed = [];
|
|
||||||
this.container.innerHTML = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Lrc;
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
export default (options) => {
|
|
||||||
// default options
|
|
||||||
const defaultOption = {
|
|
||||||
container: options.element || document.getElementsByClassName('aplayer')[0],
|
|
||||||
mini: options.narrow || options.fixed || false,
|
|
||||||
fixed: false,
|
|
||||||
autoplay: false,
|
|
||||||
mutex: true,
|
|
||||||
lrcType: options.showlrc || options.lrc || 0,
|
|
||||||
preload: 'metadata',
|
|
||||||
theme: '#b7daff',
|
|
||||||
loop: 'all',
|
|
||||||
order: 'list',
|
|
||||||
volume: 0.7,
|
|
||||||
listFolded: options.fixed,
|
|
||||||
listMaxHeight: options.listmaxheight || 250,
|
|
||||||
audio: options.music || [],
|
|
||||||
storageName: 'aplayer-setting',
|
|
||||||
};
|
|
||||||
for (const defaultKey in defaultOption) {
|
|
||||||
if (defaultOption.hasOwnProperty(defaultKey) && !options.hasOwnProperty(defaultKey)) {
|
|
||||||
options[defaultKey] = defaultOption[defaultKey];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
options.listMaxHeight = parseFloat(options.listMaxHeight);
|
|
||||||
|
|
||||||
if (Object.prototype.toString.call(options.audio) !== '[object Array]') {
|
|
||||||
options.audio = [options.audio];
|
|
||||||
}
|
|
||||||
|
|
||||||
options.audio.map((item) => {
|
|
||||||
item.name = item.name || item.title || 'Audio name';
|
|
||||||
item.artist = item.artist || item.author || 'Audio artist';
|
|
||||||
item.cover = item.cover || item.pic;
|
|
||||||
item.type = item.type || 'normal';
|
|
||||||
return item;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (options.audio.length <= 1 && options.loop === 'one') {
|
|
||||||
options.loop = 'all';
|
|
||||||
}
|
|
||||||
|
|
||||||
return options;
|
|
||||||
};
|
|
||||||
491
src/js/player.js
|
|
@ -1,491 +0,0 @@
|
||||||
import Promise from 'promise-polyfill';
|
|
||||||
|
|
||||||
import utils from './utils';
|
|
||||||
import Icons from './icons';
|
|
||||||
import handleOption from './options';
|
|
||||||
import Template from './template';
|
|
||||||
import Bar from './bar';
|
|
||||||
import Storage from './storage';
|
|
||||||
import Lrc from './lrc';
|
|
||||||
import Controller from './controller';
|
|
||||||
import Timer from './timer';
|
|
||||||
import Events from './events';
|
|
||||||
import List from './list';
|
|
||||||
|
|
||||||
const instances = [];
|
|
||||||
|
|
||||||
class APlayer {
|
|
||||||
/**
|
|
||||||
* APlayer constructor function
|
|
||||||
*
|
|
||||||
* @param {Object} options - See README
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
constructor(options) {
|
|
||||||
this.options = handleOption(options);
|
|
||||||
this.container = this.options.container;
|
|
||||||
this.paused = true;
|
|
||||||
this.playedPromise = Promise.resolve();
|
|
||||||
this.mode = 'normal';
|
|
||||||
|
|
||||||
this.randomOrder = utils.randomOrder(this.options.audio.length);
|
|
||||||
|
|
||||||
this.container.classList.add('aplayer');
|
|
||||||
if (this.options.lrcType && !this.options.fixed) {
|
|
||||||
this.container.classList.add('aplayer-withlrc');
|
|
||||||
}
|
|
||||||
if (this.options.audio.length > 1) {
|
|
||||||
this.container.classList.add('aplayer-withlist');
|
|
||||||
}
|
|
||||||
if (utils.isMobile) {
|
|
||||||
this.container.classList.add('aplayer-mobile');
|
|
||||||
}
|
|
||||||
this.arrow = this.container.offsetWidth <= 300;
|
|
||||||
if (this.arrow) {
|
|
||||||
this.container.classList.add('aplayer-arrow');
|
|
||||||
}
|
|
||||||
|
|
||||||
// save lrc
|
|
||||||
if (this.options.lrcType === 2 || this.options.lrcType === true) {
|
|
||||||
const lrcEle = this.container.getElementsByClassName('aplayer-lrc-content');
|
|
||||||
for (let i = 0; i < lrcEle.length; i++) {
|
|
||||||
if (this.options.audio[i]) {
|
|
||||||
this.options.audio[i].lrc = lrcEle[i].innerHTML;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.template = new Template({
|
|
||||||
container: this.container,
|
|
||||||
options: this.options,
|
|
||||||
randomOrder: this.randomOrder,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.options.fixed) {
|
|
||||||
this.container.classList.add('aplayer-fixed');
|
|
||||||
this.template.body.style.width = this.template.body.offsetWidth - 18 + 'px';
|
|
||||||
}
|
|
||||||
if (this.options.mini) {
|
|
||||||
this.setMode('mini');
|
|
||||||
this.template.info.style.display = 'block';
|
|
||||||
}
|
|
||||||
if (this.template.info.offsetWidth < 200) {
|
|
||||||
this.template.time.classList.add('aplayer-time-narrow');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.options.lrcType) {
|
|
||||||
this.lrc = new Lrc({
|
|
||||||
container: this.template.lrc,
|
|
||||||
async: this.options.lrcType === 3,
|
|
||||||
player: this,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.events = new Events();
|
|
||||||
this.storage = new Storage(this);
|
|
||||||
this.bar = new Bar(this.template);
|
|
||||||
this.controller = new Controller(this);
|
|
||||||
this.timer = new Timer(this);
|
|
||||||
this.list = new List(this);
|
|
||||||
|
|
||||||
this.initAudio();
|
|
||||||
this.bindEvents();
|
|
||||||
if (this.options.order === 'random') {
|
|
||||||
this.list.switch(this.randomOrder[0]);
|
|
||||||
} else {
|
|
||||||
this.list.switch(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// autoplay
|
|
||||||
if (this.options.autoplay) {
|
|
||||||
this.play();
|
|
||||||
}
|
|
||||||
|
|
||||||
instances.push(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
initAudio() {
|
|
||||||
this.audio = document.createElement('audio');
|
|
||||||
this.audio.preload = this.options.preload;
|
|
||||||
|
|
||||||
for (let i = 0; i < this.events.audioEvents.length; i++) {
|
|
||||||
this.audio.addEventListener(this.events.audioEvents[i], (e) => {
|
|
||||||
this.events.trigger(this.events.audioEvents[i], e);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.volume(this.storage.get('volume'), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bindEvents() {
|
|
||||||
this.on('play', () => {
|
|
||||||
if (this.paused) {
|
|
||||||
this.setUIPlaying();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.on('pause', () => {
|
|
||||||
if (!this.paused) {
|
|
||||||
this.setUIPaused();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.on('timeupdate', () => {
|
|
||||||
if (!this.disableTimeupdate) {
|
|
||||||
this.bar.set('played', this.audio.currentTime / this.duration, 'width');
|
|
||||||
this.lrc && this.lrc.update();
|
|
||||||
const currentTime = utils.secondToTime(this.audio.currentTime);
|
|
||||||
if (this.template.ptime.innerHTML !== currentTime) {
|
|
||||||
this.template.ptime.innerHTML = currentTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// show audio time: the metadata has loaded or changed
|
|
||||||
this.on('durationchange', () => {
|
|
||||||
if (this.duration !== 1) {
|
|
||||||
// compatibility: Android browsers will output 1 at first
|
|
||||||
this.template.dtime.innerHTML = utils.secondToTime(this.duration);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Can seek now
|
|
||||||
this.on('loadedmetadata', () => {
|
|
||||||
this.seek(0);
|
|
||||||
if (!this.paused) {
|
|
||||||
this.audio.play();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// show audio loaded bar: to inform interested parties of progress downloading the media
|
|
||||||
this.on('canplay', () => {
|
|
||||||
const percentage = this.audio.buffered.length ? this.audio.buffered.end(this.audio.buffered.length - 1) / this.duration : 0;
|
|
||||||
this.bar.set('loaded', percentage, 'width');
|
|
||||||
});
|
|
||||||
this.on('progress', () => {
|
|
||||||
const percentage = this.audio.buffered.length ? this.audio.buffered.end(this.audio.buffered.length - 1) / this.duration : 0;
|
|
||||||
this.bar.set('loaded', percentage, 'width');
|
|
||||||
});
|
|
||||||
|
|
||||||
// audio download error: an error occurs
|
|
||||||
let skipTime;
|
|
||||||
this.on('error', () => {
|
|
||||||
if (this.list.audios.length > 1) {
|
|
||||||
this.notice('An audio error has occurred, player will skip forward in 2 seconds.');
|
|
||||||
skipTime = setTimeout(() => {
|
|
||||||
this.skipForward();
|
|
||||||
if (!this.paused) {
|
|
||||||
this.play();
|
|
||||||
}
|
|
||||||
}, 2000);
|
|
||||||
} else if (this.list.audios.length === 1) {
|
|
||||||
this.notice('An audio error has occurred.');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.events.on('listswitch', () => {
|
|
||||||
skipTime && clearTimeout(skipTime);
|
|
||||||
});
|
|
||||||
|
|
||||||
// multiple audio play
|
|
||||||
this.on('ended', () => {
|
|
||||||
if (this.options.loop === 'none') {
|
|
||||||
if (this.options.order === 'list') {
|
|
||||||
if (this.list.index < this.list.audios.length - 1) {
|
|
||||||
this.list.switch((this.list.index + 1) % this.list.audios.length);
|
|
||||||
this.play();
|
|
||||||
} else {
|
|
||||||
this.list.switch((this.list.index + 1) % this.list.audios.length);
|
|
||||||
this.pause();
|
|
||||||
}
|
|
||||||
} else if (this.options.order === 'random') {
|
|
||||||
if (this.randomOrder.indexOf(this.list.index) < this.randomOrder.length - 1) {
|
|
||||||
this.list.switch(this.nextIndex());
|
|
||||||
this.play();
|
|
||||||
} else {
|
|
||||||
this.list.switch(this.nextIndex());
|
|
||||||
this.pause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (this.options.loop === 'one') {
|
|
||||||
this.list.switch(this.list.index);
|
|
||||||
this.play();
|
|
||||||
} else if (this.options.loop === 'all') {
|
|
||||||
this.skipForward();
|
|
||||||
this.play();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setAudio(audio) {
|
|
||||||
if (this.hls) {
|
|
||||||
this.hls.destroy();
|
|
||||||
this.hls = null;
|
|
||||||
}
|
|
||||||
let type = audio.type;
|
|
||||||
if (this.options.customAudioType && this.options.customAudioType[type]) {
|
|
||||||
if (Object.prototype.toString.call(this.options.customAudioType[type]) === '[object Function]') {
|
|
||||||
this.options.customAudioType[type](this.audio, audio, this);
|
|
||||||
} else {
|
|
||||||
console.error(`Illegal customType: ${type}`);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!type || type === 'auto') {
|
|
||||||
if (/m3u8(#|\?|$)/i.exec(audio.url)) {
|
|
||||||
type = 'hls';
|
|
||||||
} else {
|
|
||||||
type = 'normal';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (type === 'hls') {
|
|
||||||
if (window.Hls.isSupported()) {
|
|
||||||
this.hls = new window.Hls();
|
|
||||||
this.hls.loadSource(audio.url);
|
|
||||||
this.hls.attachMedia(this.audio);
|
|
||||||
} else if (this.audio.canPlayType('application/x-mpegURL') || this.audio.canPlayType('application/vnd.apple.mpegURL')) {
|
|
||||||
this.audio.src = audio.url;
|
|
||||||
} else {
|
|
||||||
this.notice('Error: HLS is not supported.');
|
|
||||||
}
|
|
||||||
} else if (type === 'normal') {
|
|
||||||
this.audio.src = audio.url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
theme(color = this.list.audios[this.list.index].theme || this.options.theme, index = this.list.index, isReset = true) {
|
|
||||||
if (isReset) {
|
|
||||||
this.list.audios[index] && (this.list.audios[index].theme = color);
|
|
||||||
}
|
|
||||||
this.template.listCurs[index] && (this.template.listCurs[index].style.backgroundColor = color);
|
|
||||||
if (index === this.list.index) {
|
|
||||||
this.template.pic.style.backgroundColor = color;
|
|
||||||
this.template.played.style.background = color;
|
|
||||||
this.template.thumb.style.background = color;
|
|
||||||
this.template.volume.style.background = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
seek(time) {
|
|
||||||
time = Math.max(time, 0);
|
|
||||||
time = Math.min(time, this.duration);
|
|
||||||
this.audio.currentTime = time;
|
|
||||||
this.bar.set('played', time / this.duration, 'width');
|
|
||||||
this.template.ptime.innerHTML = utils.secondToTime(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
get duration() {
|
|
||||||
return isNaN(this.audio.duration) ? 0 : this.audio.duration;
|
|
||||||
}
|
|
||||||
|
|
||||||
setUIPlaying() {
|
|
||||||
if (this.paused) {
|
|
||||||
this.paused = false;
|
|
||||||
this.template.button.classList.remove('aplayer-play');
|
|
||||||
this.template.button.classList.add('aplayer-pause');
|
|
||||||
this.template.button.innerHTML = '';
|
|
||||||
setTimeout(() => {
|
|
||||||
this.template.button.innerHTML = Icons.pause;
|
|
||||||
}, 100);
|
|
||||||
this.template.skipPlayButton.innerHTML = Icons.pause;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.timer.enable('loading');
|
|
||||||
|
|
||||||
if (this.options.mutex) {
|
|
||||||
for (let i = 0; i < instances.length; i++) {
|
|
||||||
if (this !== instances[i]) {
|
|
||||||
instances[i].pause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
play() {
|
|
||||||
this.setUIPlaying();
|
|
||||||
|
|
||||||
const playPromise = this.audio.play();
|
|
||||||
if (playPromise) {
|
|
||||||
playPromise.catch((e) => {
|
|
||||||
console.warn(e);
|
|
||||||
if (e.name === 'NotAllowedError') {
|
|
||||||
this.setUIPaused();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setUIPaused() {
|
|
||||||
if (!this.paused) {
|
|
||||||
this.paused = true;
|
|
||||||
|
|
||||||
this.template.button.classList.remove('aplayer-pause');
|
|
||||||
this.template.button.classList.add('aplayer-play');
|
|
||||||
this.template.button.innerHTML = '';
|
|
||||||
setTimeout(() => {
|
|
||||||
this.template.button.innerHTML = Icons.play;
|
|
||||||
}, 100);
|
|
||||||
this.template.skipPlayButton.innerHTML = Icons.play;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.container.classList.remove('aplayer-loading');
|
|
||||||
this.timer.disable('loading');
|
|
||||||
}
|
|
||||||
|
|
||||||
pause() {
|
|
||||||
this.setUIPaused();
|
|
||||||
this.audio.pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
switchVolumeIcon() {
|
|
||||||
if (this.volume() >= 0.95) {
|
|
||||||
this.template.volumeButton.innerHTML = Icons.volumeUp;
|
|
||||||
} else if (this.volume() > 0) {
|
|
||||||
this.template.volumeButton.innerHTML = Icons.volumeDown;
|
|
||||||
} else {
|
|
||||||
this.template.volumeButton.innerHTML = Icons.volumeOff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set volume
|
|
||||||
*/
|
|
||||||
volume(percentage, nostorage) {
|
|
||||||
percentage = parseFloat(percentage);
|
|
||||||
if (!isNaN(percentage)) {
|
|
||||||
percentage = Math.max(percentage, 0);
|
|
||||||
percentage = Math.min(percentage, 1);
|
|
||||||
this.bar.set('volume', percentage, 'height');
|
|
||||||
if (!nostorage) {
|
|
||||||
this.storage.set('volume', percentage);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.audio.volume = percentage;
|
|
||||||
if (this.audio.muted) {
|
|
||||||
this.audio.muted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.switchVolumeIcon();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.audio.muted ? 0 : this.audio.volume;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bind events
|
|
||||||
*/
|
|
||||||
on(name, callback) {
|
|
||||||
this.events.on(name, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* toggle between play and pause
|
|
||||||
*/
|
|
||||||
toggle() {
|
|
||||||
if (this.template.button.classList.contains('aplayer-play')) {
|
|
||||||
this.play();
|
|
||||||
} else if (this.template.button.classList.contains('aplayer-pause')) {
|
|
||||||
this.pause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// abandoned
|
|
||||||
switchAudio(index) {
|
|
||||||
this.list.switch(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
// abandoned
|
|
||||||
addAudio(audios) {
|
|
||||||
this.list.add(audios);
|
|
||||||
}
|
|
||||||
|
|
||||||
// abandoned
|
|
||||||
removeAudio(index) {
|
|
||||||
this.list.remove(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* destroy this player
|
|
||||||
*/
|
|
||||||
destroy() {
|
|
||||||
instances.splice(instances.indexOf(this), 1);
|
|
||||||
this.pause();
|
|
||||||
this.container.innerHTML = '';
|
|
||||||
this.audio.src = '';
|
|
||||||
this.timer.destroy();
|
|
||||||
this.events.trigger('destroy');
|
|
||||||
}
|
|
||||||
|
|
||||||
setMode(mode = 'normal') {
|
|
||||||
this.mode = mode;
|
|
||||||
if (mode === 'mini') {
|
|
||||||
this.container.classList.add('aplayer-narrow');
|
|
||||||
} else if (mode === 'normal') {
|
|
||||||
this.container.classList.remove('aplayer-narrow');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
notice(text, time = 2000, opacity = 0.8) {
|
|
||||||
this.template.notice.innerHTML = text;
|
|
||||||
this.template.notice.style.opacity = opacity;
|
|
||||||
if (this.noticeTime) {
|
|
||||||
clearTimeout(this.noticeTime);
|
|
||||||
}
|
|
||||||
this.events.trigger('noticeshow', {
|
|
||||||
text: text,
|
|
||||||
});
|
|
||||||
if (time) {
|
|
||||||
this.noticeTime = setTimeout(() => {
|
|
||||||
this.template.notice.style.opacity = 0;
|
|
||||||
this.events.trigger('noticehide');
|
|
||||||
}, time);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prevIndex() {
|
|
||||||
if (this.list.audios.length > 1) {
|
|
||||||
if (this.options.order === 'list') {
|
|
||||||
return this.list.index - 1 < 0 ? this.list.audios.length - 1 : this.list.index - 1;
|
|
||||||
} else if (this.options.order === 'random') {
|
|
||||||
const index = this.randomOrder.indexOf(this.list.index);
|
|
||||||
if (index === 0) {
|
|
||||||
return this.randomOrder[this.randomOrder.length - 1];
|
|
||||||
} else {
|
|
||||||
return this.randomOrder[index - 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nextIndex() {
|
|
||||||
if (this.list.audios.length > 1) {
|
|
||||||
if (this.options.order === 'list') {
|
|
||||||
return (this.list.index + 1) % this.list.audios.length;
|
|
||||||
} else if (this.options.order === 'random') {
|
|
||||||
const index = this.randomOrder.indexOf(this.list.index);
|
|
||||||
if (index === this.randomOrder.length - 1) {
|
|
||||||
return this.randomOrder[0];
|
|
||||||
} else {
|
|
||||||
return this.randomOrder[index + 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
skipBack() {
|
|
||||||
this.list.switch(this.prevIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
skipForward() {
|
|
||||||
this.list.switch(this.nextIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
static get version() {
|
|
||||||
/* global APLAYER_VERSION */
|
|
||||||
return APLAYER_VERSION;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default APlayer;
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
import utils from './utils';
|
|
||||||
|
|
||||||
class Storage {
|
|
||||||
constructor(player) {
|
|
||||||
this.storageName = player.options.storageName;
|
|
||||||
|
|
||||||
this.data = JSON.parse(utils.storage.get(this.storageName));
|
|
||||||
if (!this.data) {
|
|
||||||
this.data = {};
|
|
||||||
}
|
|
||||||
this.data.volume = this.data.volume || player.options.volume;
|
|
||||||
}
|
|
||||||
|
|
||||||
get(key) {
|
|
||||||
return this.data[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
set(key, value) {
|
|
||||||
this.data[key] = value;
|
|
||||||
utils.storage.set(this.storageName, JSON.stringify(this.data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Storage;
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
import Icons from './icons';
|
|
||||||
import tplPlayer from '../template/player.art';
|
|
||||||
|
|
||||||
class Template {
|
|
||||||
constructor(options) {
|
|
||||||
this.container = options.container;
|
|
||||||
this.options = options.options;
|
|
||||||
this.randomOrder = options.randomOrder;
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
|
||||||
let cover = '';
|
|
||||||
if (this.options.audio.length) {
|
|
||||||
if (this.options.order === 'random') {
|
|
||||||
cover = this.options.audio[this.randomOrder[0]].cover;
|
|
||||||
} else {
|
|
||||||
cover = this.options.audio[0].cover;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.container.innerHTML = tplPlayer({
|
|
||||||
options: this.options,
|
|
||||||
icons: Icons,
|
|
||||||
cover: cover,
|
|
||||||
getObject: (obj) => obj,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.lrc = this.container.querySelector('.aplayer-lrc-contents');
|
|
||||||
this.lrcWrap = this.container.querySelector('.aplayer-lrc');
|
|
||||||
this.ptime = this.container.querySelector('.aplayer-ptime');
|
|
||||||
this.info = this.container.querySelector('.aplayer-info');
|
|
||||||
this.time = this.container.querySelector('.aplayer-time');
|
|
||||||
this.barWrap = this.container.querySelector('.aplayer-bar-wrap');
|
|
||||||
this.button = this.container.querySelector('.aplayer-button');
|
|
||||||
this.body = this.container.querySelector('.aplayer-body');
|
|
||||||
this.list = this.container.querySelector('.aplayer-list');
|
|
||||||
this.listCurs = this.container.querySelectorAll('.aplayer-list-cur');
|
|
||||||
this.played = this.container.querySelector('.aplayer-played');
|
|
||||||
this.loaded = this.container.querySelector('.aplayer-loaded');
|
|
||||||
this.thumb = this.container.querySelector('.aplayer-thumb');
|
|
||||||
this.volume = this.container.querySelector('.aplayer-volume');
|
|
||||||
this.volumeBar = this.container.querySelector('.aplayer-volume-bar');
|
|
||||||
this.volumeButton = this.container.querySelector('.aplayer-time button');
|
|
||||||
this.volumeBarWrap = this.container.querySelector('.aplayer-volume-bar-wrap');
|
|
||||||
this.loop = this.container.querySelector('.aplayer-icon-loop');
|
|
||||||
this.order = this.container.querySelector('.aplayer-icon-order');
|
|
||||||
this.menu = this.container.querySelector('.aplayer-icon-menu');
|
|
||||||
this.pic = this.container.querySelector('.aplayer-pic');
|
|
||||||
this.title = this.container.querySelector('.aplayer-title');
|
|
||||||
this.author = this.container.querySelector('.aplayer-author');
|
|
||||||
this.dtime = this.container.querySelector('.aplayer-dtime');
|
|
||||||
this.notice = this.container.querySelector('.aplayer-notice');
|
|
||||||
this.miniSwitcher = this.container.querySelector('.aplayer-miniswitcher');
|
|
||||||
this.skipBackButton = this.container.querySelector('.aplayer-icon-back');
|
|
||||||
this.skipForwardButton = this.container.querySelector('.aplayer-icon-forward');
|
|
||||||
this.skipPlayButton = this.container.querySelector('.aplayer-icon-play');
|
|
||||||
this.lrcButton = this.container.querySelector('.aplayer-icon-lrc');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Template;
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
class Timer {
|
|
||||||
constructor(player) {
|
|
||||||
this.player = player;
|
|
||||||
|
|
||||||
window.requestAnimationFrame = (() =>
|
|
||||||
window.requestAnimationFrame ||
|
|
||||||
window.webkitRequestAnimationFrame ||
|
|
||||||
window.mozRequestAnimationFrame ||
|
|
||||||
window.oRequestAnimationFrame ||
|
|
||||||
window.msRequestAnimationFrame ||
|
|
||||||
function(callback) {
|
|
||||||
window.setTimeout(callback, 1000 / 60);
|
|
||||||
})();
|
|
||||||
|
|
||||||
this.types = ['loading'];
|
|
||||||
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
|
||||||
this.types.forEach((item) => {
|
|
||||||
this[`init${item}Checker`]();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
initloadingChecker() {
|
|
||||||
let lastPlayPos = 0;
|
|
||||||
let currentPlayPos = 0;
|
|
||||||
let bufferingDetected = false;
|
|
||||||
this.loadingChecker = setInterval(() => {
|
|
||||||
if (this.enableloadingChecker) {
|
|
||||||
// whether the audio is buffering
|
|
||||||
currentPlayPos = this.player.audio.currentTime;
|
|
||||||
if (!bufferingDetected && currentPlayPos === lastPlayPos && !this.player.audio.paused) {
|
|
||||||
this.player.container.classList.add('aplayer-loading');
|
|
||||||
bufferingDetected = true;
|
|
||||||
}
|
|
||||||
if (bufferingDetected && currentPlayPos > lastPlayPos && !this.player.audio.paused) {
|
|
||||||
this.player.container.classList.remove('aplayer-loading');
|
|
||||||
bufferingDetected = false;
|
|
||||||
}
|
|
||||||
lastPlayPos = currentPlayPos;
|
|
||||||
}
|
|
||||||
}, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
enable(type) {
|
|
||||||
this[`enable${type}Checker`] = true;
|
|
||||||
|
|
||||||
if (type === 'fps') {
|
|
||||||
this.initfpsChecker();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
disable(type) {
|
|
||||||
this[`enable${type}Checker`] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
destroy() {
|
|
||||||
this.types.forEach((item) => {
|
|
||||||
this[`enable${item}Checker`] = false;
|
|
||||||
this[`${item}Checker`] && clearInterval(this[`${item}Checker`]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Timer;
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
const isMobile = /mobile/i.test(window.navigator.userAgent);
|
|
||||||
|
|
||||||
const utils = {
|
|
||||||
/**
|
|
||||||
* Parse second to time string
|
|
||||||
*
|
|
||||||
* @param {Number} second
|
|
||||||
* @return {String} 00:00 or 00:00:00
|
|
||||||
*/
|
|
||||||
secondToTime: (second) => {
|
|
||||||
const add0 = (num) => (num < 10 ? '0' + num : '' + num);
|
|
||||||
const hour = Math.floor(second / 3600);
|
|
||||||
const min = Math.floor((second - hour * 3600) / 60);
|
|
||||||
const sec = Math.floor(second - hour * 3600 - min * 60);
|
|
||||||
return (hour > 0 ? [hour, min, sec] : [min, sec]).map(add0).join(':');
|
|
||||||
},
|
|
||||||
|
|
||||||
isMobile: isMobile,
|
|
||||||
|
|
||||||
storage: {
|
|
||||||
set: (key, value) => {
|
|
||||||
localStorage.setItem(key, value);
|
|
||||||
},
|
|
||||||
|
|
||||||
get: (key) => localStorage.getItem(key),
|
|
||||||
},
|
|
||||||
|
|
||||||
nameMap: {
|
|
||||||
dragStart: isMobile ? 'touchstart' : 'mousedown',
|
|
||||||
dragMove: isMobile ? 'touchmove' : 'mousemove',
|
|
||||||
dragEnd: isMobile ? 'touchend' : 'mouseup',
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* get random order, using Fisher–Yates shuffle
|
|
||||||
*/
|
|
||||||
randomOrder: (length) => {
|
|
||||||
function shuffle(arr) {
|
|
||||||
for (let i = arr.length - 1; i >= 0; i--) {
|
|
||||||
const randomIndex = Math.floor(Math.random() * (i + 1));
|
|
||||||
const itemAtIndex = arr[randomIndex];
|
|
||||||
arr[randomIndex] = arr[i];
|
|
||||||
arr[i] = itemAtIndex;
|
|
||||||
}
|
|
||||||
return arr;
|
|
||||||
}
|
|
||||||
return shuffle(
|
|
||||||
[...Array(length)].map(function(item, i) {
|
|
||||||
return i;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default utils;
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
{{each audio}}
|
|
||||||
<li>
|
|
||||||
<span class="aplayer-list-cur" style="background-color: {{ $value.theme || theme }};"></span>
|
|
||||||
<span class="aplayer-list-index">{{ $index + index }}</span>
|
|
||||||
<span class="aplayer-list-title">{{ $value.name }}</span>
|
|
||||||
<span class="aplayer-list-author">{{ $value.artist }}</span>
|
|
||||||
</li>
|
|
||||||
{{/each}}
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
{{each lyrics}}
|
|
||||||
<p{{ if $index === 0 }} class="aplayer-lrc-current"{{ /if }}>{{$value[1]}}</p>
|
|
||||||
{{/each}}
|
|
||||||
|
|
@ -1,145 +0,0 @@
|
||||||
{{ if !options.fixed }}
|
|
||||||
<div class="aplayer-body">
|
|
||||||
<div class="aplayer-pic" style="{{ if cover }}background-image: url("{{ cover }}");{{ /if }}background-color: {{ options.theme }};">
|
|
||||||
<div class="aplayer-button aplayer-play">{{@ icons.play }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="aplayer-info">
|
|
||||||
<div class="aplayer-music">
|
|
||||||
<span class="aplayer-title">No audio</span>
|
|
||||||
<span class="aplayer-author"></span>
|
|
||||||
</div>
|
|
||||||
<div class="aplayer-lrc">
|
|
||||||
<div class="aplayer-lrc-contents" style="transform: translateY(0); -webkit-transform: translateY(0);"></div>
|
|
||||||
</div>
|
|
||||||
<div class="aplayer-controller">
|
|
||||||
<div class="aplayer-bar-wrap">
|
|
||||||
<div class="aplayer-bar">
|
|
||||||
<div class="aplayer-loaded" style="width: 0"></div>
|
|
||||||
<div class="aplayer-played" style="width: 0; background: {{ options.theme }};">
|
|
||||||
<span class="aplayer-thumb" style="background: {{ options.theme }};">
|
|
||||||
<span class="aplayer-loading-icon">{{@ icons.loading }}</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="aplayer-time">
|
|
||||||
<span class="aplayer-time-inner">
|
|
||||||
<span class="aplayer-ptime">00:00</span> / <span class="aplayer-dtime">00:00</span>
|
|
||||||
</span>
|
|
||||||
<span class="aplayer-icon aplayer-icon-back">
|
|
||||||
{{@ icons.skip }}
|
|
||||||
</span>
|
|
||||||
<span class="aplayer-icon aplayer-icon-play">
|
|
||||||
{{@ icons.play }}
|
|
||||||
</span>
|
|
||||||
<span class="aplayer-icon aplayer-icon-forward">
|
|
||||||
{{@ icons.skip }}
|
|
||||||
</span>
|
|
||||||
<div class="aplayer-volume-wrap">
|
|
||||||
<button type="button" class="aplayer-icon aplayer-icon-volume-down">
|
|
||||||
{{@ icons.volumeDown }}
|
|
||||||
</button>
|
|
||||||
<div class="aplayer-volume-bar-wrap">
|
|
||||||
<div class="aplayer-volume-bar">
|
|
||||||
<div class="aplayer-volume" style="height: 80%; background: {{ options.theme }};"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button type="button" class="aplayer-icon aplayer-icon-order">
|
|
||||||
{{ if options.order === 'list' }}{{@ icons.orderList }}{{ else if options.order === 'random' }}{{@ icons.orderRandom }}{{ /if }}
|
|
||||||
</button>
|
|
||||||
<button type="button" class="aplayer-icon aplayer-icon-loop">
|
|
||||||
{{ if options.loop === 'one' }}{{@ icons.loopOne }}{{ else if options.loop === 'all' }}{{@ icons.loopAll }}{{ else if options.loop === 'none' }}{{@ icons.loopNone }}{{ /if }}
|
|
||||||
</button>
|
|
||||||
<button type="button" class="aplayer-icon aplayer-icon-menu">
|
|
||||||
{{@ icons.menu }}
|
|
||||||
</button>
|
|
||||||
<button type="button" class="aplayer-icon aplayer-icon-lrc">
|
|
||||||
{{@ icons.lrc }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="aplayer-notice"></div>
|
|
||||||
<div class="aplayer-miniswitcher"><button class="aplayer-icon">{{@ icons.right }}</button></div>
|
|
||||||
</div>
|
|
||||||
<ol class="aplayer-list{{ if options.listFolded }} aplayer-list-hide{{ /if }}">
|
|
||||||
{{ include './list-item.art' getObject({
|
|
||||||
theme: options.theme,
|
|
||||||
audio: options.audio,
|
|
||||||
index: 1
|
|
||||||
}) }}
|
|
||||||
</ol>
|
|
||||||
{{ else }}
|
|
||||||
<ol class="aplayer-list{{ if options.listFolded }} aplayer-list-hide{{ /if }}">
|
|
||||||
{{ include './list-item.art' getObject({
|
|
||||||
theme: options.theme,
|
|
||||||
audio: options.audio,
|
|
||||||
index: 1
|
|
||||||
}) }}
|
|
||||||
</ol>
|
|
||||||
<div class="aplayer-body">
|
|
||||||
<div class="aplayer-pic" style="{{ if cover }}background-image: url("{{ cover }}");{{ /if }}background-color: {{ options.theme }};">
|
|
||||||
<div class="aplayer-button aplayer-play">{{@ icons.play }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="aplayer-info" style="display: none;">
|
|
||||||
<div class="aplayer-music">
|
|
||||||
<span class="aplayer-title">No audio</span>
|
|
||||||
<span class="aplayer-author"></span>
|
|
||||||
</div>
|
|
||||||
<div class="aplayer-controller">
|
|
||||||
<div class="aplayer-bar-wrap">
|
|
||||||
<div class="aplayer-bar">
|
|
||||||
<div class="aplayer-loaded" style="width: 0"></div>
|
|
||||||
<div class="aplayer-played" style="width: 0; background: {{ options.theme }};">
|
|
||||||
<span class="aplayer-thumb" style="background: {{ options.theme }};">
|
|
||||||
<span class="aplayer-loading-icon">{{@ icons.loading }}</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="aplayer-time">
|
|
||||||
<span class="aplayer-time-inner">
|
|
||||||
<span class="aplayer-ptime">00:00</span> / <span class="aplayer-dtime">00:00</span>
|
|
||||||
</span>
|
|
||||||
<span class="aplayer-icon aplayer-icon-back">
|
|
||||||
{{@ icons.skip }}
|
|
||||||
</span>
|
|
||||||
<span class="aplayer-icon aplayer-icon-play">
|
|
||||||
{{@ icons.play }}
|
|
||||||
</span>
|
|
||||||
<span class="aplayer-icon aplayer-icon-forward">
|
|
||||||
{{@ icons.skip }}
|
|
||||||
</span>
|
|
||||||
<div class="aplayer-volume-wrap">
|
|
||||||
<button type="button" class="aplayer-icon aplayer-icon-volume-down">
|
|
||||||
{{@ icons.volumeDown }}
|
|
||||||
</button>
|
|
||||||
<div class="aplayer-volume-bar-wrap">
|
|
||||||
<div class="aplayer-volume-bar">
|
|
||||||
<div class="aplayer-volume" style="height: 80%; background: {{ options.theme }};"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button type="button" class="aplayer-icon aplayer-icon-order">
|
|
||||||
{{ if options.order === 'list' }}{{@ icons.orderList }}{{ else if options.order === 'random' }}{{@ icons.orderRandom }}{{ /if }}
|
|
||||||
</button>
|
|
||||||
<button type="button" class="aplayer-icon aplayer-icon-loop">
|
|
||||||
{{ if options.loop === 'one' }}{{@ icons.loopOne }}{{ else if options.loop === 'all' }}{{@ icons.loopAll }}{{ else if options.loop === 'none' }}{{@ icons.loopNone }}{{ /if }}
|
|
||||||
</button>
|
|
||||||
<button type="button" class="aplayer-icon aplayer-icon-menu">
|
|
||||||
{{@ icons.menu }}
|
|
||||||
</button>
|
|
||||||
<button type="button" class="aplayer-icon aplayer-icon-lrc">
|
|
||||||
{{@ icons.lrc }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="aplayer-notice"></div>
|
|
||||||
<div class="aplayer-miniswitcher"><button class="aplayer-icon">{{@ icons.right }}</button></div>
|
|
||||||
</div>
|
|
||||||
<div class="aplayer-lrc">
|
|
||||||
<div class="aplayer-lrc-contents" style="transform: translateY(0); -webkit-transform: translateY(0);"></div>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
6
tea.yaml
|
|
@ -1,6 +0,0 @@
|
||||||
# https://tea.xyz/what-is-this-file
|
|
||||||
---
|
|
||||||
version: 1.0.0
|
|
||||||
codeOwners:
|
|
||||||
- '0x185bfcef7b37010e2511309048a130f477f54fBf'
|
|
||||||
quorum: 1
|
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
var webpack = require('webpack');
|
||||||
|
var path = require('path');
|
||||||
|
var autoprefixer = require('autoprefixer');
|
||||||
|
|
||||||
|
var ROOT_PATH = path.resolve(__dirname);
|
||||||
|
var APP_PATH = path.resolve(ROOT_PATH, 'src');
|
||||||
|
var BUILD_PATH = path.resolve(ROOT_PATH, 'dist');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
devtool: 'source-map',
|
||||||
|
|
||||||
|
entry: './src/APlayer.js',
|
||||||
|
|
||||||
|
output: {
|
||||||
|
path: BUILD_PATH,
|
||||||
|
filename: 'APlayer.min.js',
|
||||||
|
library: 'APlayer',
|
||||||
|
libraryTarget: 'umd',
|
||||||
|
umdNamedDefine: true
|
||||||
|
},
|
||||||
|
|
||||||
|
devServer: {
|
||||||
|
publicPath: "/dist/",
|
||||||
|
},
|
||||||
|
|
||||||
|
module: {
|
||||||
|
loaders: [
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
loader: 'babel',
|
||||||
|
include: APP_PATH,
|
||||||
|
query: {
|
||||||
|
presets: ['es2015']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.scss$/,
|
||||||
|
loaders: ['style', 'css', 'postcss', 'sass'],
|
||||||
|
include: APP_PATH
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(png|jpg)$/,
|
||||||
|
loader: 'url?limit=40000'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
plugins: [
|
||||||
|
new webpack.optimize.UglifyJsPlugin({
|
||||||
|
compress: {
|
||||||
|
warnings: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
],
|
||||||
|
|
||||||
|
postcss: [
|
||||||
|
autoprefixer({
|
||||||
|
browsers: ['last 15 versions', '> 1%', 'ie 8', 'ie 7']
|
||||||
|
})
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
@ -1,115 +0,0 @@
|
||||||
const path = require('path');
|
|
||||||
const webpack = require('webpack');
|
|
||||||
const GitRevisionPlugin = require('git-revision-webpack-plugin');
|
|
||||||
const gitRevisionPlugin = new GitRevisionPlugin();
|
|
||||||
const autoprefixer = require('autoprefixer');
|
|
||||||
const cssnano = require('cssnano');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
mode: 'development',
|
|
||||||
|
|
||||||
devtool: 'cheap-module-source-map',
|
|
||||||
|
|
||||||
entry: {
|
|
||||||
APlayer: './src/js/index.js',
|
|
||||||
},
|
|
||||||
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, '..', 'dist'),
|
|
||||||
filename: '[name].js',
|
|
||||||
library: '[name]',
|
|
||||||
libraryTarget: 'umd',
|
|
||||||
libraryExport: 'default',
|
|
||||||
umdNamedDefine: true,
|
|
||||||
publicPath: '/',
|
|
||||||
},
|
|
||||||
|
|
||||||
resolve: {
|
|
||||||
modules: ['node_modules'],
|
|
||||||
extensions: ['.js', '.scss'],
|
|
||||||
},
|
|
||||||
|
|
||||||
module: {
|
|
||||||
strictExportPresence: true,
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.js$/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: 'babel-loader',
|
|
||||||
options: {
|
|
||||||
cacheDirectory: true,
|
|
||||||
presets: ['@babel/preset-env'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.scss$/,
|
|
||||||
use: [
|
|
||||||
'style-loader',
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {
|
|
||||||
importLoaders: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'postcss-loader',
|
|
||||||
options: {
|
|
||||||
plugins: [autoprefixer, cssnano],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'sass-loader',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(png|jpg)$/,
|
|
||||||
loader: 'url-loader',
|
|
||||||
options: {
|
|
||||||
limit: 40000,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.svg$/,
|
|
||||||
loader: 'svg-inline-loader',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.art$/,
|
|
||||||
loader: 'art-template-loader',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
|
|
||||||
devServer: {
|
|
||||||
compress: true,
|
|
||||||
contentBase: path.resolve(__dirname, '..', 'demo'),
|
|
||||||
clientLogLevel: 'none',
|
|
||||||
quiet: false,
|
|
||||||
open: true,
|
|
||||||
historyApiFallback: {
|
|
||||||
disableDotRule: true,
|
|
||||||
},
|
|
||||||
watchOptions: {
|
|
||||||
ignored: /node_modules/,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
plugins: [
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
APLAYER_VERSION: `"${require('../package.json').version}"`,
|
|
||||||
GIT_HASH: JSON.stringify(gitRevisionPlugin.version()),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
|
|
||||||
node: {
|
|
||||||
dgram: 'empty',
|
|
||||||
fs: 'empty',
|
|
||||||
net: 'empty',
|
|
||||||
tls: 'empty',
|
|
||||||
},
|
|
||||||
|
|
||||||
performance: {
|
|
||||||
hints: false,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
||||||
const path = require('path');
|
|
||||||
const webpack = require('webpack');
|
|
||||||
const GitRevisionPlugin = require('git-revision-webpack-plugin');
|
|
||||||
const gitRevisionPlugin = new GitRevisionPlugin();
|
|
||||||
const autoprefixer = require('autoprefixer');
|
|
||||||
const cssnano = require('cssnano');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
mode: 'production',
|
|
||||||
|
|
||||||
bail: true,
|
|
||||||
|
|
||||||
devtool: 'source-map',
|
|
||||||
|
|
||||||
entry: {
|
|
||||||
APlayer: './src/js/index.js',
|
|
||||||
},
|
|
||||||
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, '..', 'dist'),
|
|
||||||
filename: '[name].min.js',
|
|
||||||
library: '[name]',
|
|
||||||
libraryTarget: 'umd',
|
|
||||||
libraryExport: 'default',
|
|
||||||
umdNamedDefine: true,
|
|
||||||
publicPath: '/',
|
|
||||||
},
|
|
||||||
|
|
||||||
resolve: {
|
|
||||||
modules: ['node_modules'],
|
|
||||||
extensions: ['.js', '.scss'],
|
|
||||||
},
|
|
||||||
|
|
||||||
module: {
|
|
||||||
strictExportPresence: true,
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.js$/,
|
|
||||||
use: [
|
|
||||||
'template-string-optimize-loader',
|
|
||||||
{
|
|
||||||
loader: 'babel-loader',
|
|
||||||
options: {
|
|
||||||
cacheDirectory: true,
|
|
||||||
presets: ['@babel/preset-env'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.scss$/,
|
|
||||||
use: [
|
|
||||||
'style-loader',
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {
|
|
||||||
importLoaders: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'postcss-loader',
|
|
||||||
options: {
|
|
||||||
plugins: [autoprefixer, cssnano],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'sass-loader',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.(png|jpg)$/,
|
|
||||||
loader: 'url-loader',
|
|
||||||
options: {
|
|
||||||
limit: 40000,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.svg$/,
|
|
||||||
loader: 'svg-inline-loader',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.art$/,
|
|
||||||
loader: 'art-template-loader',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
|
|
||||||
plugins: [
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
APLAYER_VERSION: `"${require('../package.json').version}"`,
|
|
||||||
GIT_HASH: JSON.stringify(gitRevisionPlugin.version()),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
|
|
||||||
node: {
|
|
||||||
dgram: 'empty',
|
|
||||||
fs: 'empty',
|
|
||||||
net: 'empty',
|
|
||||||
tls: 'empty',
|
|
||||||
},
|
|
||||||
};
|
|
||||||