diff --git a/demo/demo.js b/demo/demo.js index 9b5e189..81e6488 100644 --- a/demo/demo.js +++ b/demo/demo.js @@ -96,6 +96,13 @@ const ap4 = new APlayer({ cover: 'https://moeplayer.b0.upaiyun.com/aplayer/yourname.jpg', lrc: 'https://moeplayer.b0.upaiyun.com/aplayer/yourname.lrc', theme: '#505d6b' + }, { + name: '光るなら(HLS)', + artist: 'Goose house', + url: 'https://moeplayer.b0.upaiyun.com/aplayer/hls/hikarunara.m3u8', + cover: 'https://moeplayer.b0.upaiyun.com/aplayer/hikarunara.jpg', + theme: '#ebd0c2', + type: 'hls' }] }); @@ -135,4 +142,44 @@ ap5.on('switchaudio', (index) => { ap5.theme(`rgb(${color[0]}, ${color[1]}, ${color[2]})`, index); }); } +}); + +const ap6 = new APlayer({ + element: document.getElementById('player6'), + mutex: true, + audio: [{ + name: '光るなら(HLS)', + artist: 'Goose house', + url: 'https://moeplayer.b0.upaiyun.com/aplayer/hls/hikarunara.m3u8', + cover: 'https://moeplayer.b0.upaiyun.com/aplayer/hikarunara.jpg', + theme: '#ebd0c2', + type: 'hls' + }] +}); +const ap7 = new APlayer({ + element: document.getElementById('player7'), + mutex: true, + audio: [{ + name: '光るなら(HLS)', + artist: 'Goose house', + url: 'https://moeplayer.b0.upaiyun.com/aplayer/hls/hikarunara.m3u8', + cover: 'https://moeplayer.b0.upaiyun.com/aplayer/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.'); + } + } + } }); \ No newline at end of file diff --git a/demo/index.html b/demo/index.html index a9c7368..51683ab 100644 --- a/demo/index.html +++ b/demo/index.html @@ -43,8 +43,9 @@ font-size: 18px; } - - + + +
@@ -91,6 +92,9 @@

Narrow

+

HLS

+
+
diff --git a/docs/README.md b/docs/README.md index c8e95a2..a2b4331 100644 --- a/docs/README.md +++ b/docs/README.md @@ -81,6 +81,8 @@ 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 @@ -411,12 +413,71 @@ const ap = new APlayer({ }); ``` +## 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`. + +
+
+
+ +```html + +
+ + +``` + +```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).
-
+
```html diff --git a/docs/config.js b/docs/config.js index ddf6d62..d44371d 100644 --- a/docs/config.js +++ b/docs/config.js @@ -219,7 +219,39 @@ function aplayer6 () { function aplayer7 () { window.ap7 = new APlayer({ - container: document.getElementById('aplayer7'), + container: document.getElementById('player7'), + audio: [{ + name: '光るなら(HLS)', + artist: 'Goose house', + url: 'https://moeplayer.b0.upaiyun.com/aplayer/hls/hikarunara.m3u8', + cover: 'https://moeplayer.b0.upaiyun.com/aplayer/hikarunara.jpg', + theme: '#ebd0c2', + type: 'hls' + }, { + name: '光るなら', + artist: 'Goose house', + url: 'https://moeplayer.b0.upaiyun.com/aplayer/hikarunara.mp3', + cover: 'https://moeplayer.b0.upaiyun.com/aplayer/hikarunara.jpg', + theme: '#ebd0c2' + }, { + name: 'トリカゴ', + artist: 'XX:me', + url: 'https://moeplayer.b0.upaiyun.com/aplayer/darling.mp3', + cover: 'https://moeplayer.b0.upaiyun.com/aplayer/darling.jpg', + theme: '#46718b' + }, { + name: '前前前世', + artist: 'RADWIMPS', + url: 'https://moeplayer.b0.upaiyun.com/aplayer/yourname.mp3', + cover: 'https://moeplayer.b0.upaiyun.com/aplayer/yourname.jpg', + theme: '#505d6b' + }] + }); +} + +function aplayer8 () { + window.ap8 = new APlayer({ + container: document.getElementById('aplayer8'), theme: '#e9e9e9', audio: [{ name: '光るなら', @@ -240,10 +272,10 @@ function aplayer7 () { }); const colorThief = new ColorThief(); - window.ap7.on('switchaudio', function (index) { - if (!window.ap7.options.audio[index].theme) { - colorThief.getColorAsync(window.ap7.options.audio[index].cover, function (color) { - window.ap7.theme(`rgb(${color[0]}, ${color[1]}, ${color[2]})`, index); + 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); }); } }); diff --git a/docs/zh-Hans/README.md b/docs/zh-Hans/README.md index da02e9f..b136505 100644 --- a/docs/zh-Hans/README.md +++ b/docs/zh-Hans/README.md @@ -82,6 +82,8 @@ 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 | 列表默认折叠 @@ -412,12 +414,71 @@ const ap = new APlayer({ }); ``` +## MSE 支持 + +### HLS + +需要在 `APlayer.min.js` 前面加载 [hls.js](https://github.com/video-dev/hls.js)。 + +
+
+
+ +```html + +
+ + +``` + +```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)
-
+
```html diff --git a/src/js/options.js b/src/js/options.js index 70779d6..6d3920b 100644 --- a/src/js/options.js +++ b/src/js/options.js @@ -30,6 +30,7 @@ export default (options) => { item.name = item.name || item.title; item.artist = item.artist || item.author; item.cover = item.cover || item.pic; + item.type = item.type || 'normal'; return item; }); diff --git a/src/js/player.js b/src/js/player.js index 055a5b3..cf905ed 100644 --- a/src/js/player.js +++ b/src/js/player.js @@ -200,16 +200,17 @@ class APlayer { this.playIndex = index; } + const audio = this.options.audio[this.playIndex]; // set html - if (this.options.audio[this.playIndex].cover) { - this.template.pic.style.backgroundImage = `url('${this.options.audio[this.playIndex].cover}')`; + if (audio.cover) { + this.template.pic.style.backgroundImage = `url('${audio.cover}')`; } else { this.template.pic.style.backgroundImage = ''; } this.theme(); - this.template.title.innerHTML = this.options.audio[this.playIndex].name; - this.template.author.innerHTML = this.options.audio[this.playIndex].artist ? ' - ' + this.options.audio[this.playIndex].artist : ''; + this.template.title.innerHTML = audio.name; + this.template.author.innerHTML = audio.artist ? ' - ' + audio.artist : ''; const light = this.container.getElementsByClassName('aplayer-list-light')[0]; if (light) { light.classList.remove('aplayer-list-light'); @@ -218,7 +219,47 @@ class APlayer { this.template.list.scrollTop = this.playIndex * 33; - this.audio.src = this.options.audio[this.playIndex].url; + // mse + 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 (Hls.isSupported()) { + this.hls = new 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; + } + } + this.seek(0); let playPromise;