feat: add cache busting and hls query param

This commit is contained in:
2026-06-14 21:51:02 +02:00
parent f9f3322797
commit 4a74fdcf31
8 changed files with 23 additions and 6 deletions

View File

@@ -91,7 +91,7 @@ export const goToNextEpisode = async (): Promise<void> => {
// load new video (keep preferences) // load new video (keep preferences)
const preferredQuality = safeLocalStorage.getItem("mal:preferred-quality") || "best"; const preferredQuality = safeLocalStorage.getItem("mal:preferred-quality") || "best";
const source = state.modeSources[fallback]; const source = state.modeSources[fallback];
const nextSourceURL = `${state.streamURL}?mode=${encodeURIComponent(fallback)}&token=${encodeURIComponent(source.token)}${preferredQuality !== "best" ? `&quality=${encodeURIComponent(preferredQuality)}` : ""}`; const nextSourceURL = `${state.streamURL}?mode=${encodeURIComponent(fallback)}&token=${encodeURIComponent(source.token)}${source.type === "m3u8" ? "&hls=1" : ""}${preferredQuality !== "best" ? `&quality=${encodeURIComponent(preferredQuality)}` : ""}`;
loadVideoSource(nextSourceURL, source.type); loadVideoSource(nextSourceURL, source.type);
if (!state.video.paused) { if (!state.video.paused) {
state.video.play().catch(() => undefined); state.video.play().catch(() => undefined);

View File

@@ -120,7 +120,7 @@ const initPlayer = (): void => {
const streamToken = state.modeSources[state.currentMode]?.token; const streamToken = state.modeSources[state.currentMode]?.token;
if (streamToken) { if (streamToken) {
const source = state.modeSources[state.currentMode]; const source = state.modeSources[state.currentMode];
const url = `${state.streamURL}?mode=${encodeURIComponent(state.currentMode)}&token=${encodeURIComponent(streamToken)}${preferredQuality !== "best" ? `&quality=${encodeURIComponent(preferredQuality)}` : ""}`; const url = `${state.streamURL}?mode=${encodeURIComponent(state.currentMode)}&token=${encodeURIComponent(streamToken)}${source?.type === "m3u8" ? "&hls=1" : ""}${preferredQuality !== "best" ? `&quality=${encodeURIComponent(preferredQuality)}` : ""}`;
loadVideoSource(url, source?.type); loadVideoSource(url, source?.type);
} }

View File

@@ -5,6 +5,9 @@ export const streamUrlForMode = (mode: string, quality?: string): string => {
if (!src?.token) return ""; if (!src?.token) return "";
let url = `${state.streamURL}?mode=${encodeURIComponent(mode)}&token=${encodeURIComponent(src.token)}`; let url = `${state.streamURL}?mode=${encodeURIComponent(mode)}&token=${encodeURIComponent(src.token)}`;
if (src.type === "m3u8") {
url += "&hls=1";
}
if (quality && quality !== "best") { if (quality && quality !== "best") {
url += `&quality=${encodeURIComponent(quality)}`; url += `&quality=${encodeURIComponent(quality)}`;
} }

View File

@@ -20,6 +20,7 @@ const shouldUseHLS = (type: string | undefined, url: string): boolean => {
if (type === "m3u8") return true; if (type === "m3u8") return true;
try { try {
const parsed = new URL(url, window.location.href); const parsed = new URL(url, window.location.href);
if (parsed.searchParams.get("hls") === "1") return true;
return parsed.pathname.toLowerCase().endsWith(".m3u8"); return parsed.pathname.toLowerCase().endsWith(".m3u8");
} catch { } catch {
return url.toLowerCase().includes(".m3u8"); return url.toLowerCase().includes(".m3u8");

View File

@@ -19,14 +19,14 @@
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=DM+Sans:opsz,wght@9..40,400;9..40,500;9..40,600;9..40,700&display=swap"></noscript> <noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=DM+Sans:opsz,wght@9..40,400;9..40,500;9..40,600;9..40,700&display=swap"></noscript>
<link rel="preload" href="https://fonts.googleapis.com/css2?family=Newsreader:opsz,wght@6..72,400;6..72,600&display=swap" as="style" onload="this.onload=null;this.rel='stylesheet'"> <link rel="preload" href="https://fonts.googleapis.com/css2?family=Newsreader:opsz,wght@6..72,400;6..72,600&display=swap" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Newsreader:opsz,wght@6..72,400;6..72,600&display=swap"></noscript> <noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Newsreader:opsz,wght@6..72,400;6..72,600&display=swap"></noscript>
<link rel="stylesheet" href="/dist/tailwind.css"> <link rel="stylesheet" href="{{assetURL "/dist/tailwind.css"}}">
<style> <style>
[data-htmx-loading="true"] { [data-htmx-loading="true"] {
opacity: 0.65; opacity: 0.65;
pointer-events: none; pointer-events: none;
} }
</style> </style>
<script type="module" src="/dist/static/app.js" defer></script> <script type="module" src="{{assetURL "/dist/static/app.js"}}" defer></script>
<template id="toast-template"> <template id="toast-template">
<div class="toast pointer-events-auto w-88 max-w-[calc(100vw-2rem)] bg-background shadow-(--shadow-card) ring-1 ring-black/5 flex items-start gap-3 px-4 py-3 transform transition-all duration-300 translate-y-2 opacity-0"> <div class="toast pointer-events-auto w-88 max-w-[calc(100vw-2rem)] bg-background shadow-(--shadow-card) ring-1 ring-black/5 flex items-start gap-3 px-4 py-3 transform transition-all duration-300 translate-y-2 opacity-0">
<div class="min-w-0 flex-1"> <div class="min-w-0 flex-1">
@@ -39,7 +39,7 @@
</button> </button>
</div> </div>
</template> </template>
<script src="/dist/static/htmx-lib.js"></script> <script src="{{assetURL "/dist/static/htmx-lib.js"}}"></script>
{{block "scripts" .}}{{end}} {{block "scripts" .}}{{end}}
</head> </head>
<body class="bg-background text-foreground"> <body class="bg-background text-foreground">

View File

@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"html/template" "html/template"
"net/url" "net/url"
"os"
"slices" "slices"
"strconv" "strconv"
"strings" "strings"
@@ -284,3 +285,14 @@ func episodeRangeStart(epNum, step int) int {
} }
return ((epNum-1)/step)*step + 1 return ((epNum-1)/step)*step + 1
} }
func assetURL(assetPath string) string {
info, err := os.Stat(strings.TrimPrefix(assetPath, "/"))
if err != nil {
return assetPath
}
values := url.Values{}
values.Set("v", fmt.Sprintf("%d-%d", info.ModTime().Unix(), info.Size()))
return assetPath + "?" + values.Encode()
}

View File

@@ -69,6 +69,7 @@ func rendererFuncs() template.FuncMap {
"urlquery": url.QueryEscape, "urlquery": url.QueryEscape,
"posterURL": posterURL, "posterURL": posterURL,
"episodeRangeStart": episodeRangeStart, "episodeRangeStart": episodeRangeStart,
"assetURL": assetURL,
} }
} }

View File

@@ -1,5 +1,5 @@
{{define "title"}}Watch {{.Anime.Title}}{{end}} {{define "title"}}Watch {{.Anime.Title}}{{end}}
{{define "scripts"}}<script type="module" src="/dist/static/player/main.js" defer></script>{{end}} {{define "scripts"}}<script type="module" src="{{assetURL "/dist/static/player/main.js"}}" defer></script>{{end}}
{{define "page_container"}} {{define "page_container"}}
<div class="-m-4 h-[calc(100dvh-4rem)] overflow-hidden p-4 md:-m-8 md:p-6"> <div class="-m-4 h-[calc(100dvh-4rem)] overflow-hidden p-4 md:-m-8 md:p-6">
{{template "content" .}} {{template "content" .}}