0.2.6-dev: the client fetches a served manifest's content-hashed audio as /media/~<hash>/… (download-manager route kept), and the token death sound derived beside charDie drops charDie's hash — host bandwidth layer 1.3; golden: unchanged

This commit is contained in:
sganggs committed 2026-10-12 16:25:16 +08:00
1 parent 893d17e725
commit 35b09bb63b
7 files changed
+54 -5

No files matched your search

+6 -2
View File
@@ -70,6 +70,7 @@
import { sanitizeVoiceOverrides, voiceLangFor } from './voicePrefs.js';
import { PHASE } from '../../shared/constants.js';
import { mediaUrl } from './media.js';
import { unhashedUrl } from '../../shared/assetPaths.js';
const MAX_VOICES = 8;
const UNIT_COOLDOWN_MS = 160;
@@ -193,11 +194,14 @@ export function unitSoundClass(info) {
return 'char';
}
/** URL of the generic token death sound (b_char_tokendead): sfx.battle.tokenDie, else next to charDie. */
/**
* URL of the generic token death sound (b_char_tokendead): sfx.battle.tokenDie, else next to charDie — without charDie's
* content-hash segment, which names charDie's bytes, not this file's (the plain URL is cached for a day).
*/
function tokenDieUrl(manifest) {
const b = manifest?.audio?.sfx?.battle;
if (typeof b?.tokenDie === 'string') return b.tokenDie;
return typeof b?.charDie === 'string' && /b_char_dead\.mp3$/.test(b.charDie) ? b.charDie.replace(/b_char_dead\.mp3$/, 'b_char_tokendead.mp3') : null;
return typeof b?.charDie === 'string' && /b_char_dead\.mp3$/.test(b.charDie) ? unhashedUrl(b.charDie).replace(/b_char_dead\.mp3$/, 'b_char_tokendead.mp3') : null;
}
/**
+7 -2
View File
@@ -11,10 +11,14 @@
//
// `server/http/media.js` resolves /media/… back to the real file under public/assets/audio and still answers with
// `Content-Type: audio/mpeg` + range support; Web Audio sniffs the container, so the URL is all the same to it.
// A served manifest's content-hashed URL keeps its segment (shared/assetPaths.js; host bandwidth, layer 1):
//
// /assets/~0123456789abcdef/audio/bgm/act1.mp3 → /media/~0123456789abcdef/bgm/act1
// A host that does not implement /media/ keeps working: `audio.js` falls back to the original URL whenever the
// /media/ response is unusable (a 404, or a 200 that is not audio at all — some static hosts answer a missing
// path with the SPA's index.html).
import { MEDIA_PREFIX, AUDIO_EXTS } from '../../shared/media.js';
import { splitHashedPath } from '../../shared/assetPaths.js';
const AUDIO_PATH = /^\/assets\/audio\/(.+)$/i;
@@ -36,7 +40,8 @@ export function mediaUrl(url, origin = globalThis.location?.origin) {
// Cross-origin (or absolute while the page origin is unknown) stays untouched: that host serves its own media.
const absolute = /^[a-z][a-z0-9+.-]*:/i.test(url) || url.startsWith('//');
if (origin ? u.origin !== origin : absolute) return url;
const m = AUDIO_PATH.exec(u.pathname);
const { hash, path: plain } = splitHashedPath(u.pathname);
const m = AUDIO_PATH.exec(plain);
if (!m) return url;
let rest = m[1];
const ext = AUDIO_EXTS.find((e) => rest.toLowerCase().endsWith(e));
@@ -44,5 +49,5 @@ export function mediaUrl(url, origin = globalThis.location?.origin) {
rest = rest.slice(0, -ext.length);
const segments = rest.split('/');
if (!rest || segments.some((s) => !s || s === '.' || s === '..' || s.startsWith('.'))) return url;
return `${MEDIA_PREFIX}${rest}${u.search}`;
return `${MEDIA_PREFIX}${hash ? `~${hash}/` : ''}${rest}${u.search}`;
}