/* Copyright 2023 0xf8.dev@proton.me This file is part of Galerie Galerie is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Galerie is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Galerie. If not, see . */ import { gzipSync, gunzipSync } from "zlib"; let apiUrl: string = `${location.protocol}//${location.hostname}:8856/`; class Favorites { private data: string[] = []; constructor() { console.log("Loading favorites"); this.data = JSON.parse(localStorage.getItem("settings.favorites")) || []; this.sync(); } public async sync(): Promise { localStorage.setItem("settings.favorites", JSON.stringify(this.data)); } public async clear(): Promise { this.data = []; this.sync(); } public async pop(): Promise { let item: any = this.data.pop(); this.sync(); return item; } public async push(toadd): Promise { this.data.push(toadd); this.sync(); } public async delete(d): Promise { this.data = this.data.filter((v) => { return v != d }); this.sync(); } public async at(d): Promise { return this.data.at(d); } public async contains(d): Promise { return this.data.includes(d); } public async shuffle(): Promise { let data: string[] = this.data; for (let i = 0; i < await this.data.length; i++) { data.sort(() => { return Math.random() - 0.5 }); } return data; } } class Blacklist { private data: string[] = []; constructor() { console.log("Loading blacklist"); this.data = JSON.parse(localStorage.getItem("settings.blacklist")) || []; this.sync(); } public async sync(): Promise { localStorage.setItem("settings.blacklist", JSON.stringify(this.data)); } public async clear(): Promise { this.data = []; this.sync(); } public async pop(): Promise { let item: any = this.data.pop(); this.sync(); return item; } public async push(toadd): Promise { this.data.push(toadd); this.sync(); } public async delete(d): Promise { this.data = this.data.filter((v) => { return v != d }); this.sync(); } public async at(d): Promise { return this.data.at(d); } public async contains(d): Promise { return this.data.includes(d); } } class Cache { private cache: string[]; private checksum: string; last: string[]; constructor() {} async load(): Promise { console.log("Loading cache"); if (localStorage.getItem("cache")) this.cache = JSON.parse(gunzipSync(Buffer.from(localStorage.getItem("cache"), "base64")).toString()); else this.cache = []; this.checksum = localStorage.getItem("cache.checksum"); if (!this.cache || !this.checksum) { await this.sync(); } else if (!await this.validate()) { await this.sync(); } } async sync(): Promise { console.log("Syncing cache"); try { let sync = await fetch(apiUrl + "sync", { body: JSON.stringify({ action: "fullUpdate", checksum: this.checksum }), method: "POST", }); let data = await sync.json(); if (!sync.ok) throw Error(sync.statusText); console.log(data); if (!data.valid) { this.checksum = data.checksum, this.cache = data.files; } await this.update(); } catch (e) { throw e; } } private async update(): Promise { localStorage.setItem("cache", gzipSync(JSON.stringify(this.cache)).toString("base64")); localStorage.setItem("cache.checksum", this.checksum); } private async validate(): Promise { try { let sync = await fetch(apiUrl + "sync", { body: JSON.stringify({ action: "validateChecksum", checksum: localStorage.getItem("cache.checksum") }), method: "POST", }); if (!sync.ok) throw Error(sync.statusText); return (await sync.json()).valid; } catch(e) { throw e; } } public async at(d): Promise { return this.cache.at(d); } public async order(): Promise { let data: string[] = this.cache; if (JSON.parse(localStorage.getItem("config")).deterministic) { data = this.cache.sort((a, b) => a.localeCompare(b)); } else { for (let i = 0; i < await this.length(); i++) { data.sort(() => { return Math.random() - 0.5 }); } } this.last = data; return data; } public async length(): Promise { return this.cache.length; } } class Config { private data = {}; private defaultConfig = { "ignoreBlacklist": false, "onlyFavorites": false, "deterministic": false } constructor() { console.log("Loading config"); if (!localStorage.getItem("config")) localStorage.setItem("config", JSON.stringify(this.defaultConfig)); this.data = JSON.parse(localStorage.getItem("config")); this.verify(); this.sync(); } private verify() { for (let k in this.defaultConfig) if (!this.get(k)) this.data[k] = this.defaultConfig[k]; } public sync() { localStorage.setItem("config", JSON.stringify(this.data)); } public set(vr, vl) { this.data[vr] = vl; } public get(vr) { return this.data[vr]; } public keys() { return Object.keys(this.data); } } export default class Settings { favorites: Favorites; blacklist: Blacklist; cache: Cache; config: Config; constructor() { this.favorites = new Favorites(); this.blacklist = new Blacklist(); this.cache = new Cache(); this.config = new Config(); } } export { apiUrl };