summaryrefslogtreecommitdiff
path: root/includes/editor.js
diff options
context:
space:
mode:
Diffstat (limited to 'includes/editor.js')
-rw-r--r--includes/editor.js193
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