'use strict'; const vite = require('vite'); const getEtag = require('etag'); const cors = require('cors'); const fg = require('fast-glob'); const path = require('path'); const fs = require('fs'); function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; } const getEtag__default = /*#__PURE__*/_interopDefaultCompat(getEtag); const cors__default = /*#__PURE__*/_interopDefaultCompat(cors); const fg__default = /*#__PURE__*/_interopDefaultCompat(fg); const path__default = /*#__PURE__*/_interopDefaultCompat(path); const fs__default = /*#__PURE__*/_interopDefaultCompat(fs); const USE_SOUND_MODULE_NAME = "virtual:use-sound"; const USE_SOUND_IDS_MODULE_NAME = "virtual:use-sound-ids"; const createUseSoundPlugin = (opt) => { let isBuild = false; const cache = /* @__PURE__ */ new Map(); const options = { symbolId: "sound-[dir]-[name]", ...opt }; return { name: "vite:sound-sprite", configResolved(config) { isBuild = config.command === "build"; }, resolveId(id) { if (id === USE_SOUND_MODULE_NAME || id === USE_SOUND_IDS_MODULE_NAME) { return id; } return null; }, async load(id, ssr) { if (!isBuild && !ssr) { return null; } const isSsr = ssr && !isBuild; const isRegister = id === USE_SOUND_MODULE_NAME; const isClient = id === USE_SOUND_IDS_MODULE_NAME; if (isSsr && (isRegister || isClient)) { return `export default {}`; } const { code, idSet } = await createSoundModuleCode(cache, options); if (isRegister) { return code; } if (isClient) { return idSet; } }, configureServer: ({ middlewares }) => { middlewares.use(cors__default({ origin: "*" })); middlewares.use(async (req, res, next) => { const url = vite.normalizePath(req.url); const registerId = `/@id/${USE_SOUND_MODULE_NAME}`; const clientId = `/@id/${USE_SOUND_IDS_MODULE_NAME}`; if ([clientId, registerId].some((item) => url.endsWith(item))) { res.setHeader("Content-Type", "application/javascript"); res.setHeader("Cache-Control", "no-cache"); const { code, idSet } = await createSoundModuleCode(cache, options); const content = url.endsWith(registerId) ? code : idSet; res.setHeader("Etag", getEtag__default(content, { weak: true })); res.statusCode = 200; res.end(content); } else { next(); } }); } }; }; const createSoundModuleCode = async (cache, options) => { const { idSet, urlMap } = await compilerSounds(cache, options); const code = ` const soundUrls = { ${Array.from(urlMap).map(([key, value]) => `${JSON.stringify(key)}: ${JSON.stringify(value)}`).join(",\n")} } function defaultAudioPlayerCreator(url) { const audioPlayer = new Audio(); audioPlayer.src = url; audioPlayer.autoplay = false; return audioPlayer; } let playerCreator = defaultAudioPlayerCreator; export function setupUseSound(audioPlayerCreator) { playerCreator = audioPlayerCreator; } export function useSound(id, audioPlayerCreator = undefined) { audioPlayerCreator = audioPlayerCreator || playerCreator; const url = soundUrls[id]; if (!url && id) { if(id.startsWith('https://') || id.startsWith('http://') || id.startsWith('data:') || id.startsWith('blob:') || id.startsWith('file:')){ url = id } else { throw new Error(\`Sound id \${id} not found\`); } } const audioPlayer = audioPlayerCreator(url || ''); return { url: url, player: audioPlayer, onPlayEnded: (cb) => { audioPlayer.onended = cb; audioPlayer.onEnded && audioPlayer.onEnded(cb); }, play: (src = undefined) => { if(src){ audioPlayer.src = src; } if(audioPlayer.seek){ audioPlayer.seek(0); }else if(audioPlayer.currentTime){ audioPlayer.currentTime = 0; } audioPlayer.play(); }, pause: () => audioPlayer.pause && audioPlayer.pause(), destroy: () => { audioPlayer.pause(); audioPlayer.src = null; if(audioPlayer.destroy){ audioPlayer.destroy(); } if(audioPlayer.close){ audioPlayer.close(); } }, } } `; return { code: `${code} export default { }`, idSet: `export default ${JSON.stringify(Array.from(idSet))}` }; }; async function compilerSounds(cache, options) { const { soundDirs } = options; const idSet = /* @__PURE__ */ new Set(); const urlMap = /* @__PURE__ */ new Map(); for (const dir of soundDirs) { const soundFilsStats = fg__default.sync(["**/*.mp3", "**/*.wav", "**/*.m4a", "**/*.aac"], { cwd: dir, stats: true, absolute: true }); for (const fileStats of soundFilsStats) { const { path: filePath, stats: { mtimeMs } = {} } = fileStats; let cachedStat = cache.get(filePath); if (!cachedStat || cachedStat.mtimeMs !== mtimeMs) { cachedStat = compileSound(dir, filePath, mtimeMs, options); cache.set(filePath, cachedStat); } idSet.add(cachedStat.symbolId); urlMap.set(cachedStat.symbolId, cachedStat.code); } } return { idSet, urlMap }; } const compileSound = (dir, filePath, mtimeMs, options) => { const relativeName = vite.normalizePath(filePath).substring(vite.normalizePath(dir).length + 1); return { relativeName, mtimeMs, code: toBase64DataUrl(filePath), symbolId: createSymbolId(relativeName, options.symbolId) }; }; const toBase64DataUrl = (filePath) => { const ext = path__default.extname(filePath).substring(1); const base64 = fs__default.readFileSync(filePath, "base64"); return `data:audio/${ext};base64,${base64}`; }; const createSymbolId = (relativeName, symbolIdPattern) => { if (!symbolIdPattern) { return relativeName; } let id = symbolIdPattern; let fName = relativeName; const { fileName = "", dirName } = discreteDir(relativeName); if (symbolIdPattern.includes("[dir]")) { id = id.replace(/\[dir\]/g, dirName); if (!dirName) { id = id.replace("--", "-"); } fName = fileName; } id = id.replace(/\[name\]/g, fName); return id.replace(path__default.extname(id), ""); }; function discreteDir(name) { if (!vite.normalizePath(name).includes("/")) { return { fileName: name, dirName: "" }; } const strList = name.split("/"); const fileName = strList.pop(); const dirName = strList.join("-"); return { fileName, dirName }; } exports.compilerSounds = compilerSounds; exports.createUseSoundPlugin = createUseSoundPlugin; exports.discreteDir = discreteDir;