127 lines
2.7 KiB
JavaScript
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)
|
|
}
|
|
})
|
|
}) |