diff options
Diffstat (limited to 'includes/editor.js')
-rw-r--r-- | includes/editor.js | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/includes/editor.js b/includes/editor.js new file mode 100644 index 0000000..df0baf3 --- /dev/null +++ b/includes/editor.js @@ -0,0 +1,193 @@ +const prompts = require('prompts'); +const songs = require('../assets/content/songs.json'); +const albums = require('../assets/content/albums.json'); +const fs = require("fs"); +const path = require("path"); +const chalk = require("chalk"); +const Fuse = require("fuse.js"); + +function reload() { + for (let songID of Object.keys(songs)) { + if (fs.existsSync("/opt/mist")) { + if (!fs.existsSync("/opt/mist/flac/" + songID + ".flac") || !fs.existsSync("/opt/mist/aac/" + songID + ".m4a") || !fs.existsSync("/opt/mist/jpeg/" + songID + ".jpg")) { + delete songs[songID]; + } + } else { + if (!fs.existsSync("../assets/content/" + songID + ".flac") || !fs.existsSync("../assets/content/" + songID + ".m4a") || !fs.existsSync("../assets/content/" + songID + ".jpg")) { + delete songs[songID]; + } + } + } + + let idList = [...Object.keys(songs), ...Object.keys(albums)]; + + if (fs.existsSync("/opt/mist")) { + for (let file of fs.readdirSync("/opt/mist/flac")) { + if (fs.lstatSync("/opt/mist/flac/" + file).isFile()) { + let id = path.basename(file, path.extname(file)); + + if (!idList.includes(id) && !file.endsWith(".json")) { + fs.unlinkSync("/opt/mist/flac/" + file); + if (fs.existsSync("../assets/content/" + file)) fs.unlinkSync("../assets/content/" + file); + } else { + if (!fs.existsSync("../assets/content/" + file)) fs.symlinkSync("/opt/mist/flac/" + file, "../assets/content/" + file); + } + } + } + + for (let file of fs.readdirSync("/opt/mist/aac")) { + if (fs.lstatSync("/opt/mist/aac/" + file).isFile()) { + let id = path.basename(file, path.extname(file)); + + if (!idList.includes(id) && !file.endsWith(".json")) { + fs.unlinkSync("/opt/mist/aac/" + file); + if (fs.existsSync("../assets/content/" + file)) fs.unlinkSync("../assets/content/" + file); + } else { + if (!fs.existsSync("../assets/content/" + file)) fs.symlinkSync("/opt/mist/aac/" + file, "../assets/content/" + file); + } + } + } + + for (let file of fs.readdirSync("/opt/mist/jpeg")) { + if (fs.lstatSync("/opt/mist/jpeg/" + file).isFile()) { + let id = path.basename(file, path.extname(file)); + + if (!idList.includes(id) && !file.endsWith(".json")) { + fs.unlinkSync("/opt/mist/jpeg/" + file); + if (fs.existsSync("../assets/content/" + file)) fs.unlinkSync("../assets/content/" + file); + } else { + if (!fs.existsSync("../assets/content/" + file)) fs.symlinkSync("/opt/mist/jpeg/" + file, "../assets/content/" + file); + } + } + } + } else { + for (let file of fs.readdirSync("../assets/content")) { + if (fs.lstatSync("../assets/content/" + file).isFile()) { + let id = path.basename(file, path.extname(file)); + + if (!idList.includes(id) && !file.endsWith(".json")) { + fs.unlinkSync("../assets/content/" + file); + } + } + } + } + + for (let albumID of Object.keys(albums)) { + let album = albums[albumID]; + album["tracks"] = [...new Set(album["tracks"])].sort((a, b) => { + return songs[a]['track'] - songs[b]['track']; + }); + } + + fs.writeFileSync("../assets/content/songs.json", JSON.stringify(songs)); + fs.writeFileSync("../assets/content/albums.json", JSON.stringify(albums)); +} + +reload(); + +console.log(chalk.bold("Mist metadata editor") + "\n"); + +const fuse = new Fuse([...Object.entries(songs).map(i => { + j = i[1]; + j['_type'] = "song"; + j['_id'] = i[0]; + return j; +}), ...Object.entries(albums).map(i => { + j = i[1]; + j['_type'] = "album"; + j['_id'] = i[0]; + return j; +})], { + keys: ['title', 'artist'] +}); + +async function main() { + console.clear(); + const response = await prompts({ + type: 'text', + name: 'search', + message: 'Enter the name of a song or album:' + }); + + if (!response['search']) { + return; + } + + let query = response['search']; + let results = fuse.search(query); + let items = []; + + for (let result of results) { + items.push({ + title: chalk.cyan(result.item._type === "song" ? "Song: " : "Album: ") + result.item.artist + " - " + result.item.title, + value: result.item._type + ":" + result.item._id + }) + } + + const select = await prompts({ + type: 'select', + name: 'choice', + message: 'Select a song or album in the list.', + choices: items + }); + + if (!select['choice']) { + return; + } + + await item(select['choice']); +} + +async function item(meta) { + console.clear(); + let id = meta.split(":")[1]; + let type = meta.split(":")[0]; + let item; + + if (type === "song") item = songs[id]; + if (type === "album") item = albums[id]; + + let options = [ + { title: "ID: " + id, value: "", disabled: true }, + { title: chalk.gray("Back"), value: "back" }, + ]; + + options.push({ title: chalk.red("Delete"), value: "delete" }); + + const select = await prompts({ + type: 'select', + name: 'choice', + message: chalk.cyan(type === "song" ? "Song: " : "Album: ") + item.artist + " - " + item.title, + choices: options + }); + + if (!select['choice']) { + return; + } + + if (select['choice'] === "back") { + main(); + return; + } + + if (select['choice'] === "delete") { + let confirm = await prompts({ + type: 'confirm', + name: 'confirm', + message: 'Are you sure you want to delete this ' + type + '? This is permanent and will affect users.' + }); + + if (typeof confirm['confirm'] !== "boolean") { + return; + } else { + if (confirm['confirm']) { + // TODO: Delete + main(); + } else { + + } + } + } +} + +main();
\ No newline at end of file |