import TracksTable from "./tracks_table.mjs" import IntegrityManager from "./integrity_manager.mjs" import { updateObjectFromJoinedKey } from "./utils.mjs" import { loadMetadata, SeriesMetadata } from "./metadata.mjs" export default class Editor { constructor() { const params = new URLSearchParams(window.location.search) this.filename = params.get("f") window.addEventListener("keydown", e => { if (e.key === "s" && e.ctrlKey) { e.preventDefault() this.save() } }) this.tables = { audio: new TracksTable(this, "audio", "audio-tracks", "audio_tracks"), subtitle: new TracksTable(this, "subtitle", "subtitle-tracks", "subtitle_tracks") } this.metadata = null this.data = {} this.dirty = false this.integrityMgr = new IntegrityManager(this) document.getElementById("check-integrity").addEventListener("click", () => this.checkIntegrity()) document.getElementById("improve-all").addEventListener("click", () => this.improveAllNames()) document.getElementById("save").addEventListener("click", () => this.save()) document.getElementById("reload").addEventListener("click", () => window.location.reload()) document.getElementById("toggle-notifs").addEventListener("click", () => this.toggleNotifications()) document.getElementById("close-notifs").addEventListener("click", () => this.closeNotifications()) document.getElementById("prev-episode").addEventListener("click", () => this.prevEpisode()) document.getElementById("next-episode").addEventListener("click", () => this.nextEpisode()) this.titleInput = document.getElementById("title") this.titleInput.addEventListener("change", () => { this.data.title = this.titleInput.value this.setDirty() }) this.setup() } setup() { document.getElementById("filename").innerText = this.filename this.fetchData() } fetchData() { fetch(`/api/file/${this.filename}`).then(res => { if (res.ok) { return res.json() } return null }).then(res => { if (res !== null) { this.metadata = loadMetadata(res) this.displayData() } }) } displayData() { const seriesToolbar = document.getElementById("series-toolbar") if (this.metadata instanceof SeriesMetadata) { seriesToolbar.classList.add("show") const cur = this.metadata.episodeIdx + 1 const tot = this.metadata.episodes.length const epMeta = this.metadata.getCurrentEpisode() const season = epMeta.season const episode = epMeta.episode seriesToolbar.querySelector("#cur-episode").innerText = `S${season}E${episode} (${cur} / ${tot})` } else { seriesToolbar.classList.remove("show") } this.data = this.metadata.getData() this.titleInput.value = this.data.title this.tables.audio.loadTracks(this.data.audio_tracks) this.tables.subtitle.loadTracks(this.data.subtitle_tracks) } save() { fetch(`/api/file/${this.filename}`, { method: "POST", body: JSON.stringify(this.metadata.data), headers: { "Content-Type": "application/json" } }).then(res => { if (res.ok) { this.dirty = false document.getElementById("unsaved").classList.remove("show") this.notify("Saved successfully !", "success") } else { this.notify(`Error ${res.status}: ${res.statusText}`, "error", 10000) } }) } setDirty() { this.dirty = true document.getElementById("unsaved").classList.add("show") } editTrack(listKey, trackIdx, key, value) { updateObjectFromJoinedKey(this.data[listKey][trackIdx], key, value) this.setDirty() } notify(text, type, duration=5000) { const list = document.getElementById("notifs") const hist = document.getElementById("notifs-hist").querySelector(".list") const notif = document.createElement("div") notif.classList.add("notif") notif.dataset.type = type notif.innerText = text list.appendChild(notif) setTimeout(() => notif.remove(), duration) notif.addEventListener("click", () => notif.remove()) hist.prepend(notif.cloneNode(true)) } checkIntegrity() { if (this.integrityMgr.checkIntegrity()) { this.notify("No integrity error detected !", "success") } } improveAllNames() { this.integrityMgr.improveAllNames() this.notify("Improved all names !", "success") } toggleNotifications() { const hist = document.getElementById("notifs-hist") if (hist.classList.contains("show")) { this.closeNotifications() } else { this.openNotifications() } } openNotifications() { const hist = document.getElementById("notifs-hist") hist.classList.add("show") } closeNotifications() { const hist = document.getElementById("notifs-hist") hist.classList.remove("show") } prevEpisode() { if (this.metadata instanceof SeriesMetadata) { if (this.metadata.prev()) { this.displayData() } } } nextEpisode() { if (this.metadata instanceof SeriesMetadata) { if (this.metadata.next()) { this.displayData() } } } }