const express = require('express') const fetch = require('node-fetch') const config = require('./config.js') const server = express(); server.use((req, res, next) => { console.log(req.method, req.path) next() }) server.use((err, req, res, next) => { console.error(err.stack) res.status(500).send('Something broke! Try again!') }) const credentials = Buffer.from(`${config.user}:${config.pass}`).toString('base64') const authorization = `Basic ${credentials}` var cached_sounds = [] function headers(){ return { "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Authorization": authorization, } } function fetch_library(page, tags=""){ return fetch(`${config.baseURL}/library`, { "credentials": "include", "headers": headers(), "body": `type=file,url&dir=.&tags=${tags}&keywords=&page=${page}&action=query`, "method": "POST", }).then(response => { try { return response.json() } catch (error) { return {} } }) } async function fetch_total_pages(){ return fetch_library(1).then(data => data.total_pages) } async function fetch_page(page){ return fetch_library(page).then(data => data.items) } async function enqueue(id){ fetch(`${config.baseURL}/post`, { "credentials": "include", "headers": headers(), "body": `add_item_next=${id}`, "method": "POST", }) } function set_volume(value){ fetch(`${config.baseURL}/post`, { "credentials": "include", "headers": headers(), "body": `action=volume_set_value&new_volume=${value}`, "method": "POST", }) } async function playlist(){ let info_res = await fetch(`${config.baseURL}/post`, { "credentials": "include", "headers": headers(), "method": "POST", }) let info_json = await info_res.json() let playlist_res = await fetch(`${config.baseURL}/playlist`, { "credentials": "include", "headers": headers(), "method": "GET", }) let playlist_json = await playlist_res.json() info_json.items = playlist_json.items return info_json } async function get_all_sounds(){ let sounds = [] total_pages = await fetch_total_pages() let i = 1 while(i <= total_pages){ let items = await fetch_page(i) items.forEach(item => { let tags = item.tags.map( i => {return i[0]} ) if(item.type =="File"){ let parts = item.path.split("-", 2) let name = item.path if(parts.length > 1){ name = parts[1] } let parts2 = name.split("/", 2) if(parts2.length > 1){ name = parts2[1] } // NOTE: tags is index here to unpack the list it comes in... // [ [tag1, tag2] ] sounds.push({ "id": item.id, "name": name, "path": item.path, "tags": tags, "type": "file", }) } else if (item.type == "URL") { sounds.push({ "id": item.id, "name": item.title, "type": "url", "tags": tags, }) } }) i++ } cached_sounds = sounds return sounds } async function organize_sounds(){ let sounds = {} config.names.forEach(name => { sounds[name] = [] }) let other = [] let tags = {} all_sounds = await get_all_sounds() all_sounds.forEach(item => { if (item.tags){ item.tags.forEach(tag => { if(!tags.hasOwnProperty(tag)){ tags[tag] = [] } tags[tag].push(item) }) } let matched = false Object.keys(sounds).forEach(name => { if(item.type == "file"){ path = item.path.split("-")[0] if(path.toLowerCase().indexOf(name) != -1){ sounds[name].push(item) matched = true } } }) if(!matched){ other.push(item) } }) sounds["other"] = other return {"sounds": sounds, "tags": tags} } server.get('/', async (req, res) => { var html = `

Now playling

` try { let soundObj = await organize_sounds() let sounds = soundObj["sounds"] let tags = soundObj["tags"] Object.keys(sounds).forEach(title => { html += `

${title.toUpperCase()}

` sounds[title].forEach(item => { let tags = "" if(item.tags){ tags = `
${item.tags.join(", ")}
` } try { html += `
${item.name}
${tags}
\n` } catch (error) { console.log(error) } }) html += `
` }) html += `

Tags

` Object.keys(tags).forEach(tagName => { let idsForTag = tags[tagName].map( item => {return item.id}) let idsString = idsForTag.join("', '") html += `
Add all '${tagName}'
\n` }) html += `
` html += "" res.send(html); } catch (error){ console.log(error) } }) server.get('/random', async (req, res, next) => { let all_sounds = cached_sounds let filtered_sounds = all_sounds.filter(item => { return item.type == "file" && !item.path.startsWith("uploads/") }) let rand_sound = filtered_sounds[Math.floor(Math.random() * filtered_sounds.length)] await enqueue(rand_sound.id) res.send("ok") }) server.get('/playlist', async (req, res, next) => { try { let playlist_items = await playlist() res.send(playlist_items) } catch (error) { console.error("problem getting current status") console.error(error) res.send({items: [], }) } }) server.get('/main.js', async (req, res, next) => { res.sendFile(__dirname + "/main.js") }) server.get('/delete/:id', async (req, res, next) => { fetch(`${config.baseURL}/post`, { "credentials": "include", "headers": headers(), "body": `delete_music=${req.params.id}`, "method": "POST", }) res.send("ok") }) server.get('/volume/:val', async (req, res, next) => { set_volume(req.params.val) res.send("ok") }) server.get('/:id', async (req, res, next) => { await enqueue(req.params.id) res.send("ok") }) console.log("listening...") server.listen(config.port)