diff --git a/public/assets/boot/ctrl_boot_frontoffice.js b/public/assets/boot/ctrl_boot_frontoffice.js index bf786880..b2212e33 100644 --- a/public/assets/boot/ctrl_boot_frontoffice.js +++ b/public/assets/boot/ctrl_boot_frontoffice.js @@ -3,7 +3,6 @@ import { loadJS } from "../helpers/loader.js"; import { init as setup_translation } from "../locales/index.js"; import { init as setup_config } from "../model/config.js"; import { init as setup_plugin } from "../model/plugin.js"; -import { init as setup_chromecast } from "../model/chromecast.js"; import { init as setup_cache } from "../pages/filespage/cache.js"; import { report } from "../helpers/log.js"; import { $error } from "./common.js"; @@ -12,7 +11,6 @@ export default async function main() { try { await Promise.all([ setup_config().then((config) => Promise.all([ - setup_chromecast(config), setup_title(config), window.self === window.top ? verify_origin(config) : verify_iframe_origin(config), ])), diff --git a/public/assets/model/chromecast.js b/public/assets/model/chromecast.js index 02ab5f69..4c186adb 100644 --- a/public/assets/model/chromecast.js +++ b/public/assets/model/chromecast.js @@ -1,19 +1,19 @@ -export function init(config) { - if (navigator.onLine === false) return Promise.resolve(); - if (!config["enable_chromecast"]) { - return Promise.resolve(); - } else if (!("chrome" in window)) { - return Promise.resolve(); - } else if (location.hostname === "localhost" || location.hostname === "127.0.0.1") { - return Promise.resolve(); - } - return Chromecast.init(); -} +import { get as getConfig } from "./config.js"; export const Chromecast = new class ChromecastManager { init() { + if (navigator.onLine === false) return Promise.resolve(); + if (!getConfig("enable_chromecast", false)) { + return Promise.resolve(); + } else if (!("chrome" in window)) { + return Promise.resolve(); + } else if (location.hostname === "localhost" || location.hostname === "127.0.0.1") { + return Promise.resolve(); + } return new Promise((resolve) => { + if (document.head.querySelector("script#chromecast")) return resolve(null); const script = document.createElement("script"); + script.id = "chromecast"; script.src = "https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"; script.onerror = () => resolve(null); window["__onGCastApiAvailable"] = function(isAvailable) { diff --git a/public/assets/pages/filespage/model_files.js b/public/assets/pages/filespage/model_files.js index 0e92052e..1de7aa3a 100644 --- a/public/assets/pages/filespage/model_files.js +++ b/public/assets/pages/filespage/model_files.js @@ -27,7 +27,7 @@ import { ls as middlewareLs } from "./model_virtual_layer.js"; const handleSuccess = (text) => rxjs.tap(() => notification.info(text)); const handleError = rxjs.catchError((err) => { - notification.error(err); + notification.error(err.message); throw err; }); const handleErrorRedirectLogin = rxjs.catchError((err) => { diff --git a/public/assets/pages/filespage/model_virtual_layer.js b/public/assets/pages/filespage/model_virtual_layer.js index 7a37dfdd..2227fcb5 100644 --- a/public/assets/pages/filespage/model_virtual_layer.js +++ b/public/assets/pages/filespage/model_virtual_layer.js @@ -402,7 +402,7 @@ export function mv(fromPath, toPath) { ...file, loading: false, last: false, - } + }; return file; }, }); diff --git a/public/assets/pages/viewerpage/application_image.js b/public/assets/pages/viewerpage/application_image.js index fa6b961d..1227d426 100644 --- a/public/assets/pages/viewerpage/application_image.js +++ b/public/assets/pages/viewerpage/application_image.js @@ -114,7 +114,7 @@ export function init() { return Promise.all([ loadCSS(import.meta.url, "./application_image.css"), loadCSS(import.meta.url, "./component_menubar.css"), - initPagination(), initInformation(), + initPagination(), initInformation(), Chromecast.init(), ]); } diff --git a/public/index.frontoffice.html b/public/index.frontoffice.html index 9b4145cf..da45b01d 100644 --- a/public/index.frontoffice.html +++ b/public/index.frontoffice.html @@ -6,8 +6,8 @@ - + @@ -60,7 +60,7 @@ register.active.postMessage({ "type": "preload", "payload": URLS, - "version": "{{ .version }}".substring(0, 7) + "::{{ .hash }}", + "version": "{{ slice .version 0 7 }}::{{ .hash }}", "clear": {{ .clear }}, }); await new Promise((resolve, reject) => navigator.serviceWorker.addEventListener("message", (event) => { diff --git a/server/ctrl/static.go b/server/ctrl/static.go index 1ddff35a..b2ca2bb0 100644 --- a/server/ctrl/static.go +++ b/server/ctrl/static.go @@ -4,6 +4,7 @@ import ( "bytes" "compress/gzip" _ "embed" + "encoding/base64" "encoding/json" "fmt" "io" @@ -226,6 +227,24 @@ func ServeIndex(indexPath string) func(*App, http.ResponseWriter, *http.Request) return func(ctx *App, res http.ResponseWriter, req *http.Request) { head := res.Header() + sign := signature() + base := WithBase("/") + clear := req.Header.Get("Cache-Control") == "no-cache" + templateData := map[string]any{ + "base": base, + "version": BUILD_REF, + "license": LICENSE, + "preload": preload(), + "clear": clear, + "hash": sign, + "favicon": favicon(), + } + calculatedEtag := QuickHash(base+BUILD_REF+LICENSE+fmt.Sprintf("%t", clear)+sign, 10) + head.Set("ETag", calculatedEtag) + if etag := req.Header.Get("If-None-Match"); etag == calculatedEtag { + res.WriteHeader(http.StatusNotModified) + return + } var out io.Writer = res if strings.Contains(req.Header.Get("Accept-Encoding"), "gzip") { head.Set("Content-Encoding", "gzip") @@ -234,14 +253,7 @@ func ServeIndex(indexPath string) func(*App, http.ResponseWriter, *http.Request) out = gz } head.Set("Content-Type", "text/html") - tmpl.Execute(out, map[string]any{ - "base": WithBase("/"), - "version": BUILD_REF, - "license": LICENSE, - "preload": preload(), - "clear": req.Header.Get("Cache-Control") == "no-cache", - "hash": signature(), - }) + tmpl.Execute(out, templateData) } } @@ -496,3 +508,15 @@ func signature() string { } return strings.ToLower(QuickHash(text, 3)) } + +func favicon() string { + file, err := WWWPublic.Open("/assets/logo/favicon.svg") + if err != nil { + return "favicon.ico" + } + f, err := io.ReadAll(file) + if err != nil { + return "favicon.ico" + } + return "data:image/svg+xml;base64," + base64.StdEncoding.EncodeToString(f) +}