webrtc/public/music.js

165 lines
5.9 KiB
JavaScript
Raw Normal View History

2023-10-02 22:24:38 +08:00
import { Span, Button, List, ListItem } from './weigets.js'
2023-09-28 15:20:02 +08:00
export default class MusicList {
2023-10-02 05:30:20 +08:00
constructor({ list = [], EventListeners = {}, onplay, onstop, onadd, onremove, onlike, onunlike, onban, onload }) {
this.event = { onplay, onstop, onadd, onremove, onlike, onunlike, onban, onload }
2023-09-28 15:20:02 +08:00
this.ul = List({})
2023-09-30 20:20:57 +08:00
this.ul.classList.add('music-list')
2023-09-29 21:21:26 +08:00
this.EventListeners = EventListeners
2023-09-29 17:31:37 +08:00
this.list = []
2023-09-29 21:21:26 +08:00
list.forEach(item => this.add(item)) // 列表逐一添加
document.body.appendChild(this.ul) // 元素加入页面
2023-09-28 15:20:02 +08:00
// 添加音乐播放器
this.audio = new Audio()
this.audio.addEventListener('ended', () => {
this.next()
})
2023-09-28 17:59:23 +08:00
//this.audio.addEventListener('timeupdate', () => {
// console.log(this.audio.currentTime)
//})
2023-09-29 21:21:26 +08:00
// 本地添加音乐按钮
2023-09-28 15:20:02 +08:00
const input = document.createElement('input')
input.type = 'file'
input.multiple = true
input.accept = 'audio/*'
input.onchange = event => {
for (const file of event.target.files) {
2023-09-28 18:15:12 +08:00
const id = 'music' + Date.now()
2023-09-28 15:20:02 +08:00
const { name, size, type } = file
const reader = new FileReader()
reader.onload = async event => {
const arrayBuffer = event.target.result
2023-10-02 05:30:20 +08:00
this.add({ id, name, size, type, arrayBuffer }) // 添加到列表(默认并不存储)
this.like({ id, name, size, type, arrayBuffer }) // 本地缓存的必要条件是喜欢
2023-09-28 15:20:02 +08:00
}
reader.readAsArrayBuffer(file)
}
}
2023-10-01 20:09:28 +08:00
// 写入 css 样式到 head
2023-10-01 03:57:01 +08:00
const style = document.createElement('style')
style.innerText = `
2023-10-02 21:59:43 +08:00
ul.music-list > li > span {
2023-10-01 03:57:01 +08:00
cursor: pointer;
}
2023-10-02 23:09:53 +08:00
ul.music-list > li.play > span {
2023-10-02 06:44:37 +08:00
color: #02be08;
}
2023-10-01 19:59:22 +08:00
ul.music-list > li.cache::marker {
color: #02be08;
font-size: 1em;
contentx: '⚡';
}
ul.music-list > li.disable {
color: #999999;
}
2023-10-01 03:57:01 +08:00
ul.music-list > li > button {
margin-left: 10px;
border: none;
2023-10-02 07:07:33 +08:00
border-radius: 1em;
2023-10-01 03:57:01 +08:00
cursor: pointer;
2023-10-02 22:08:12 +08:00
user-select: none;
2023-10-02 07:07:33 +08:00
font-size: .5rem;
padding: 0 .5rem;
color: #555555;
2023-10-01 03:57:01 +08:00
}
ul.music-list > li > button:hover {
background-color: #ccc;
}
`
document.head.appendChild(style)
2023-09-28 15:20:02 +08:00
document.body.appendChild(input)
}
2023-09-29 21:21:26 +08:00
add(item) {
2023-10-02 00:53:17 +08:00
// 如果ID已存在则不添加
if (this.list.find(i => i.id === item.id)) {
return
}
2023-10-01 03:20:16 +08:00
// 将字节转换为可读的单位
const bytesToSize = bytes => {
if (bytes === 0) return '0 B'
const k = 1024
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
const i = Math.floor(Math.log(bytes) / Math.log(k))
return (bytes / Math.pow(k, i)).toFixed(2) + ' ' + sizes[i]
}
2023-09-29 21:21:26 +08:00
this.list.push(item)
this.ul.appendChild(ListItem({
2023-09-28 15:20:02 +08:00
id: item.id,
2023-10-01 19:59:22 +08:00
classList: item.arrayBuffer ? ['cache'] : [],
2023-09-28 15:20:02 +08:00
children: [
2023-10-02 22:24:38 +08:00
Span({
textContent: `${item.name} - ${bytesToSize(item.size)}`,
2023-10-02 21:59:43 +08:00
onclick: event => {
event.stopPropagation()
2023-10-02 23:09:53 +08:00
const li = event.target.parentElement // ListItem
const ul = li.parentElement // List
const list = Array.from(ul.children) // ListItems
list.forEach(li => li.classList.remove('play'))
if (!this.audio.paused && this.playing === item) {
li.classList.remove('play')
2023-10-02 21:59:43 +08:00
this.stop(item)
} else {
2023-10-02 23:09:53 +08:00
li.classList.add('play')
2023-10-02 21:59:43 +08:00
this.play(item)
}
}
}),
2023-09-28 15:20:02 +08:00
Button({
2023-10-02 22:24:38 +08:00
textContent: item.arrayBuffer ? '移除' : '缓存',
2023-09-28 15:20:02 +08:00
onclick: event => {
event.stopPropagation()
2023-10-02 06:30:20 +08:00
if (item.arrayBuffer) {
2023-10-02 22:24:38 +08:00
event.target.textContent = '缓存'
2023-10-02 06:30:20 +08:00
this.unlike(item)
} else {
2023-10-02 22:24:38 +08:00
event.target.textContent = '移除'
2023-10-02 06:30:20 +08:00
this.ul.querySelector(`#${item.id}`).classList.add('cache')
this.like(item)
}
2023-09-29 18:36:05 +08:00
}
2023-09-28 15:20:02 +08:00
})
]
2023-09-29 21:21:26 +08:00
}))
2023-10-02 00:30:47 +08:00
this.event.onadd(item, this.list)
2023-09-29 17:31:37 +08:00
}
2023-10-02 00:30:47 +08:00
async remove(item) {
2023-10-01 11:28:35 +08:00
this.ul.querySelector(`#${item.id}`)?.remove()
if (!this.audio.paused) this.stop() // 停止播放
2023-10-02 00:30:47 +08:00
this.event.onremove(item)
2023-09-28 17:59:23 +08:00
}
2023-09-30 00:13:30 +08:00
async load(item) {
2023-10-02 00:30:47 +08:00
await this.event.onload(item)
2023-09-30 00:13:30 +08:00
}
2023-09-29 20:20:00 +08:00
async play(item) {
if (!item.arrayBuffer) {
2023-09-30 00:13:30 +08:00
await this.load(item)
2023-09-29 20:20:00 +08:00
}
2023-10-02 00:30:47 +08:00
this.playing = item
2023-09-28 17:59:23 +08:00
this.audio.src = URL.createObjectURL(new Blob([item.arrayBuffer], { type: item.type }))
this.audio.play()
2023-10-02 00:30:47 +08:00
this.event.onplay(item)
2023-09-28 17:59:23 +08:00
}
2023-10-02 00:30:47 +08:00
async stop() {
2023-09-28 17:59:23 +08:00
this.audio.pause()
this.audio.src = ''
2023-10-02 00:30:47 +08:00
this.event.onstop(this.playing)
2023-10-02 06:30:20 +08:00
this.playing = null
2023-09-28 15:20:02 +08:00
}
2023-10-02 00:30:47 +08:00
async like(item) {
2023-09-29 18:36:05 +08:00
if (!item.arrayBuffer) {
2023-10-02 00:30:47 +08:00
await this.load(item)
2023-09-29 18:36:05 +08:00
}
2023-10-02 05:38:44 +08:00
this.event.onlike(item, this.list)
2023-10-02 00:30:47 +08:00
}
2023-10-02 05:30:20 +08:00
async unlike(item) {
2023-10-02 06:33:11 +08:00
this.remove(item)
2023-10-02 05:38:44 +08:00
this.event.onunlike(item, this.list)
2023-10-02 05:30:20 +08:00
}
2023-10-02 00:30:47 +08:00
async ban(item) {
this.event.onban(item)
2023-09-29 18:36:05 +08:00
}
2023-09-28 15:20:02 +08:00
next() { }
prev() { }
}