hiss/old.src/view/player.js
2025-02-04 14:21:03 -07:00

226 lines
4.9 KiB
JavaScript

const view = window.view ??= {}
const app = window.app ??= {}
import * as mode from "./panels.js"
import * as queue from "./queue.js"
import * as entry from "../entry.js"
export const states = {
EMPTY: 0,
PLAYING: 1,
PAUSED: 2
}
export const Init = () => {
app.player = {
currentTime: 0
}
}
export const View = async () => {
view.player = {
cover: document.getElementById('track-cover'),
title: document.getElementById('track-title'),
artist: document.getElementById('track-artist'),
timestamp: document.getElementById('timestamp'),
trackLength: document.getElementById('track-length'),
progress: document.getElementById('playback-progress')
}
if(app.player.current) {
Switch(await Load(app.player.current, app.player.currentTime), app.player.current)
}
}
export const Open = () => {
mode.Display('player')
}
export const TogglePausePlay = () => {
if(State() === states.PLAYING) {
Pause()
} else {
Play()
}
}
export const OnKeydown = (event) => {
switch(event.key) {
case 'ArrowUp':
navigator.volumeManager?.requestUp()
break
case 'ArrowDown':
navigator.volumeManager?.requestDown()
break
case ' ':
case 'Enter':
if(State() === states.PLAYING) {
Pause()
} else {
Play()
}
break
case ']':
case 'SoftRight':
Next()
break
default:
return true
}
}
export const Load = async (eTrack, fromTime) => {
let f = await device.Open(eTrack.handle)
let u = URL.createObjectURL(f)
// if(fromTime) {
// u = new URL(u)
// u.hash = '#t=' + fromTime
// }
let a = new Audio(u)
if(fromTime) {
a.currentTime = fromTime
}
return a
}
export const Switch = (aTrack, eTrack) => {
if(State() === states.PLAYING) {
view.playback.pause()
}
view.playback = aTrack
app.player.current = eTrack
attach()
Render()
}
export const attach = () => {
let a = view.playback
a.addEventListener('playing', onStart)
a.addEventListener('timeupdate', onTimeUpdate)
a.addEventListener('ended', onEnded)
storeTime()
}
export const onStart = () => {
storeTime()
renderDuration()
onTimeUpdate()
}
export const onTimeUpdate = () => {
let s = parseInt(view.playback.currentTime)
if(s > app.player.currentTime) {
storeTime()
renderTimestamp()
}
renderProgress()
}
export const storeTime = () => {
app.player.currentTime = view.playback ?
parseInt(view.playback.currentTime) :
0
}
export const formatTime = currentTime => {
let minutes = Math.floor(currentTime / 60).toString()
let seconds = Math.floor(currentTime % 60).toString()
return minutes.padStart(2, '0') + ':' + seconds.padStart(2, '0')
}
export const onEnded = () => {
view.playback = null
Next()
}
/* Rendering */
export const Render = async () => {
marqueeableText(view.player.title, app.player.current.name)
marqueeableText(view.player.artist, app.player.current.artist)
renderCover()
renderTimestamp()
renderDuration()
}
export const marqueeableText = (eElement, sName) => {
while(eElement.firstChild) {
eElement.lastChild.remove()
}
eElement.classList = []
let s = textContainer(eElement, sName)
if(s.offsetWidth > eElement.offsetWidth) {
eElement.classList = [ 'marquee' ]
textContainer(eElement, sName)
}
}
export const textContainer = (eElement, sText) => {
let s = document.createElement('span')
s.innerText = sText
eElement.appendChild(s)
return s
}
export const renderProgress = () => {
let t = view.playback.currentTime / view.playback.duration
t = parseInt(t * 100)
view.player.progress.style.strokeDasharray = `${t}, ${100 - t}`
}
export const renderTimestamp = (iTimestamp = app.player.currentTime) => {
view.player.timestamp.innerText = formatTime(iTimestamp)
}
export const renderDuration = (iDuration = view.playback.duration) => {
view.player.trackLength.innerText = formatTime(iDuration)
}
export const renderCover = async () => {
view.player.cover.src = app.player.current.coverId ?
URL.createObjectURL(await entry.GetCover(app.player.current)):
''
}
/* Actions */
export const Play = async () => {
if(view.playback) {
view.playback.play()
return
}
await Next()
}
export const Next = async () => {
let e = queue.Shift()
if(e) {
Switch(await Load(e), e)
view.playback.play()
}
}
export const Pause = () => {
view.playback.pause()
}
export const State = () => {
if(view.playback == null) {
return states.EMPTY
} else {
return view.playback.paused ? states.PAUSED : states.PLAYING
}
}