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

127 lines
2.7 KiB
JavaScript

const app = window.app ??= {}
const view = window.view ??= {}
import * as device from 'device'
import Store from 'store'
// TODO: decouple from app.browser and add loading bar
export let covers
export const Start = async () => {
covers = await Store.Open('cover', 'data')
}
export const Init = async () => {
view.loadingStatus = document.getElementById('loading-status')
app.trackCount = 0
app.index = await Entries()
}
export const Entries = async (hHandle, eParent) => {
let dirE = await device.Entries(hHandle)
let out = []
for(let [ n, h ] of dirE) {
let e = await Create(n, h, eParent)
if(e != undefined) {
out.push(e)
displayTrackFound(e)
}
}
return out
}
export const displayTrackFound = (entry) => {
app.trackCount++
view.loadingStatus.innerText = `${entry.handle.name}\n(${app.trackCount})`
}
export const trackFiletypes = [
'.mp3',
'.ogg',
'.wav',
'.flac'
]
export const Create = async (sName, hHandle, eParent) => {
let e = {
handle: hHandle
}
if(eParent) {
e.parent = eParent
}
switch(hHandle.kind) {
case 'directory':
e.entries = await Entries(hHandle, e)
e.name = sName
break
case 'file':
let ext = sName.slice(sName.lastIndexOf('.'))
if(trackFiletypes.includes(ext)) {
await Track(e)
} else {
return
}
}
e.order = e.trackNumber ?? 0
return e
}
const Track = async e => {
let md = await Metadata(e)
e.album = md.album
e.name = md.title
e.artist = md.artist ?? "Unknown Artist"
e.trackNumber = md.track ? parseInt(md.track) : Infinity
e.lyrics = md.lyrics?.lyrics && new Map([ [ 0, md.lyrics?.lyrics ] ])
e.coverId = md.picture && await IndexCover(md.picture)
}
export const IndexCover = async ({ format, data }) => {
let id = format + '-' + data.length
// TODO: don't get, just check if has
let c = await covers.Get(id)
.catch(err => {})
if(c == null) {
c = new Blob([ new Uint8Array(data) ], { type: format })
await covers.Set(id, c)
}
return id
}
export const GetCover = (eTrack) => {
return covers.Get(eTrack.coverId)
}
const Metadata = async e => {
let d = await device.Open(e.handle).then(mediaTags)
.catch(e => console.error(e))
if(!d) {
return /((?<track>\d+)\s+)?((?<artist>.+)-\s*)?\s*(?<title>.+)\s*\.\w+/
.exec(e.handle.name)
.groups
} else {
return d.tags
}
}
const mediaTags = blob => new Promise((resolve, reject) => {
jsmediatags.read(blob, {
onSuccess(tags) {
resolve(tags)
},
onError(err) {
reject(err)
}
})
})