diff --git a/directory/.env b/directory/.env index f0a27de..a9de916 100644 --- a/directory/.env +++ b/directory/.env @@ -1,4 +1,2 @@ VITE_APP_TITLE=AKLive2D -VITE_VERSION=0.5.9 -VITE_APP_VOICE_URL=jp/CN_037.ogg -VITE_SHOWCASE_VERSION=3.3.13 \ No newline at end of file +VITE_APP_VOICE_URL=jp/CN_037.ogg \ No newline at end of file diff --git a/directory/Version b/directory/Version index 89235c0..12697f7 100644 --- a/directory/Version +++ b/directory/Version @@ -1 +1 @@ -0.5.9 \ No newline at end of file +0.5.12 \ No newline at end of file diff --git a/directory/src/context/useConfigContext.jsx b/directory/src/context/useConfigContext.jsx index f94a880..542870b 100644 --- a/directory/src/context/useConfigContext.jsx +++ b/directory/src/context/useConfigContext.jsx @@ -1,29 +1,91 @@ -import { createContext, useState, useEffect } from "react" -import db from "@/db" +import { createContext, useState, useEffect, useCallback } from "react" +import db, { invalidateCache } from "@/db" + +const versionCompare = (v1, v2) => { + const v1Arr = v1.split(".") + const v2Arr = v2.split(".") + for (let i = 0; i < v1Arr.length; i++) { + if (v1Arr[i] > v2Arr[i]) { + return 1 + } else if (v1Arr[i] < v2Arr[i]) { + return -1 + } + } + return 0 +} + +const invalidateRules = (local, version) => { + if (local === undefined) { + // no local version + return true + } + if (version === undefined) { + // no remote version + return false + } + return versionCompare(local, version) < 0 +} export const ConfigContext = createContext() export function ConfigProvider(props) { const [config, setConfig] = useState([]) const [operators, setOperators] = useState([]) + const [version, setVersion] = useState({}) - useEffect(() => { + const fetchConfig = (version) => { fetch("/_assets/directory.json").then(res => res.json()).then(data => { setConfig(data) db.config.put({ key: "config", value: data }) - let operatorsList = [] - data.operators.forEach((item) => { - operatorsList = [...operatorsList, ...item] - }) - setOperators(operatorsList) + resolveOperators(data) + db.config.put({ key: "version", value: version }) }) + } + + const resolveOperators = useCallback((data) => { + let operatorsList = [] + data.operators.forEach((item) => { + operatorsList = [...operatorsList, ...item] + }) + setOperators(operatorsList) + }, []) + + useEffect(() => { fetch("/_assets/version.json").then(res => res.json()).then(data => { - db.config.put({ key: "version", value: data }) + db.config.get({ key: "version" }).then((local) => { + if (local === undefined || invalidateRules(local.value.directory, data.directory) || invalidateRules(local.value.showcase, data.showcase)) { + invalidateCache() + fetchConfig(data) + } else { + db.config.get({ key: "config" }).then((local) => { + if (local) { + setConfig(local.value) + resolveOperators(local.value) + } else { + fetchConfig(data) + } + }) + } + }) + setVersion(data) }) + /* + local.directory | version.directory | action + --------------- | ----------------- | ------ + 1.0.0 | 1.0.0 | use cache + 1.0.0 | 1.0.1 | invalidate cache + 1.0.1 | 1.0.0 | impossible + + local.showcase | version.showcase | action + -------------- | ---------------- | ------ + 1.0.0 | 1.0.0 | use cache + 1.0.0 | 1.0.1 | invalidate cache + 1.0.1 | 1.0.0 | use cache + */ }, []) return ( - + {props.children} ) diff --git a/directory/src/db/index.js b/directory/src/db/index.js index 915d0c7..6edf713 100644 --- a/directory/src/db/index.js +++ b/directory/src/db/index.js @@ -7,4 +7,10 @@ db.version(2).stores({ config: '++key, value', }); +export function invalidateCache() { + db.image.clear(); + db.voice.clear(); + db.config.clear(); +} + export default db; \ No newline at end of file diff --git a/directory/src/routes/path/home.jsx b/directory/src/routes/path/home.jsx index 0a221a8..70fd5e2 100644 --- a/directory/src/routes/path/home.jsx +++ b/directory/src/routes/path/home.jsx @@ -87,15 +87,15 @@ export default function Home() { const loadVoice = (link) => { if (!voiceOn) return db.voice.get({ key: link }).then((v) => { - if (v === undefined) { + if (v) { + playVoice(v.blob) + } else { fetch(`/${link}/assets/voice/${import.meta.env.VITE_APP_VOICE_URL}`) .then(res => res.blob()) .then(blob => { db.voice.put({ key: link, blob: blob }) playVoice(blob) }) - } else { - playVoice(v.blob) } }) } @@ -162,15 +162,15 @@ function ImageElement({ item, language }) { useEffect(() => { db.image.get({ key: item.link }).then((v) => { - if (v === undefined) { + if (v) { + setBlobUrl(URL.createObjectURL(v.blob)) + } else { fetch(`/${item.link}/assets/${item.fallback_name.replace("#", "%23")}_portrait.png`) .then(res => res.blob()) .then(blob => { db.image.put({ key: item.link, blob: blob }) setBlobUrl(URL.createObjectURL(blob)) }) - } else { - setBlobUrl(URL.createObjectURL(v.blob)) } }) }, [item.link]) diff --git a/directory/src/routes/root.jsx b/directory/src/routes/root.jsx index a92f314..cea5dc7 100644 --- a/directory/src/routes/root.jsx +++ b/directory/src/routes/root.jsx @@ -12,6 +12,7 @@ import { } from "react-router-dom"; import './root.css' import routes from '@/routes' +import { ConfigContext } from '@/context/useConfigContext'; import { HeaderContext } from '@/context/useHeaderContext'; import { LanguageContext } from '@/context/useLanguageContext'; import Dropdown from '@/component/dropdown'; @@ -34,6 +35,7 @@ export default function Root(props) { currentTab, setCurrentTab, appbarExtraArea } = useContext(HeaderContext) + const { version } = useContext(ConfigContext) const [drawerDestinations, setDrawerDestinations] = useState(null) const currentYear = new Date().getFullYear() const [headerTabs, setHeaderTabs] = useState(null) @@ -197,15 +199,11 @@ export default function Root(props) { Spine Runtimes © 2013 - 2019 Esoteric Software LLC Assets © 2017 - {currentYear} Arknights/Hypergryph Co., Ltd Source Code © 2021 - {currentYear} Halyul - Version: {import.meta.env.VITE_VERSION} + Directory @ {version.directory} + Showcase @ {version.showcase} - { - // default behavior - return location.pathname; - }} - /> + ) } diff --git a/vite.config.js b/vite.config.js index 1ca21f0..afd7710 100644 --- a/vite.config.js +++ b/vite.config.js @@ -7,6 +7,7 @@ import getConfig from './libs/config.js' import { rmdir, writeSync } from './libs/file.js' import { increase } from './libs/version.js' import EnvGenerator from './libs/env_generator.js' +import directory from './libs/directory.js' global.__projetRoot = path.dirname(fileURLToPath(import.meta.url)) @@ -134,21 +135,17 @@ class ViteRunner { get #directoryConfig() { if (process.env.npm_lifecycle_event === 'vite:directory:build') { this.#globalConfig.version.directory = increase(path.join(__projetRoot, "directory")) + global.__config = this.#globalConfig + directory() } const directoryDir = path.resolve(__projetRoot, 'directory') writeSync((new EnvGenerator()).generate([ { key: "app_title", value: this.#globalConfig.directory.title - }, { - key: "version", - value: this.#globalConfig.version.directory - }, { + }, { key: "app_voice_url", value: this.#globalConfig.directory.voice - }, { - key: "showcase_version", - value: this.#globalConfig.version.showcase } ]), path.join(directoryDir, '.env')) this.#mode = process.argv[3]