This build was committed by a bot.

This commit is contained in:
github-actions[bot]
2026-10-12 18:58:06 +00:00
parent e027cf96f0
commit de59761b35
6 changed files with 38799 additions and 81 deletions
+2
View File
@@ -0,0 +1,2 @@
import { t as require___vite_browser_external } from "./src-Bv2YeDx1.js";
export default require___vite_browser_external();
@@ -1,3 +1,4 @@
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/mediabunny-aac-encoder-CtuZhjiD.js","assets/src-Bv2YeDx1.js"])))=>i.map(i=>d[i]);
import mathjax3 from "https://esm.sh/markdown-it-mathjax3";
//#region \0vite/modulepreload-polyfill.js
(function polyfill() {
@@ -664,11 +665,213 @@ function kbBind() {
});
}
//#endregion
//#region \0vite/preload-helper.js
var scriptRel = "modulepreload";
var assetsURL = function(dep) {
return "/" + dep;
};
var seen = {};
var __vitePreload = function preload(baseModule, deps, importerUrl) {
let promise = Promise.resolve();
if (deps && deps.length > 0) {
const links = document.getElementsByTagName("link");
const cspNonceMeta = document.querySelector("meta[property=csp-nonce]");
const cspNonce = cspNonceMeta?.nonce || cspNonceMeta?.getAttribute("nonce");
function allSettled(promises) {
return Promise.all(promises.map((p) => Promise.resolve(p).then((value) => ({
status: "fulfilled",
value
}), (reason) => ({
status: "rejected",
reason
}))));
}
promise = allSettled(deps.map((dep) => {
dep = assetsURL(dep, importerUrl);
if (dep in seen) return;
seen[dep] = true;
const isCss = dep.endsWith(".css");
const cssSelector = isCss ? "[rel=\"stylesheet\"]" : "";
if (!!importerUrl) for (let i = links.length - 1; i >= 0; i--) {
const link = links[i];
if (link.href === dep && (!isCss || link.rel === "stylesheet")) return;
}
else if (document.querySelector(`link[href="${dep}"]${cssSelector}`)) return;
const link = document.createElement("link");
link.rel = isCss ? "stylesheet" : scriptRel;
if (!isCss) link.as = "script";
link.crossOrigin = "";
link.href = dep;
if (cspNonce) link.setAttribute("nonce", cspNonce);
document.head.appendChild(link);
if (isCss) return new Promise((res, rej) => {
link.addEventListener("load", res);
link.addEventListener("error", () => rej(/* @__PURE__ */ new Error(`Unable to preload CSS for ${dep}`)));
});
}));
}
function handlePreloadError(err) {
const e = new Event("vite:preloadError", { cancelable: true });
e.payload = err;
window.dispatchEvent(e);
if (!e.defaultPrevented) throw err;
}
return promise.then((res) => {
for (const item of res || []) {
if (item.status !== "rejected") continue;
handlePreloadError(item.reason);
}
return baseModule().catch(handlePreloadError);
});
};
//#endregion
//#region src/video.js
var SHORT_SIDE = 360, FPS = 4, VIDEO_BPS = {
hevc: 13e4,
avc: 16e4
}, AUDIO_BPS = 32e3;
var even = (n) => Math.max(2, Math.round(n / 2) * 2);
var mb;
var loadMb = async () => {
if (mb) return mb;
const m = await __vitePreload(() => import("./src-Bv2YeDx1.js"), []);
if (!await m.canEncodeAudio("aac", {
numberOfChannels: 1,
sampleRate: 48e3,
bitrate: AUDIO_BPS
})) (await __vitePreload(async () => {
const { registerAacEncoder } = await import("./mediabunny-aac-encoder-CtuZhjiD.js");
return { registerAacEncoder };
}, __vite__mapDeps([0,1]))).registerAacEncoder();
return mb = m;
};
var isVideo = (name, mime) => /^video\//.test(mime) || /\.(mp4|m4v|mov|webm|mkv|3gp)$/i.test(name);
async function compressVideo(file, { onProgress, signal } = {}) {
const { Input, Output, Conversion, ALL_FORMATS, BlobSource, BufferTarget, Mp4OutputFormat, Quality, canEncodeVideo } = await loadMb();
const input = new Input({
source: new BlobSource(file),
formats: ALL_FORMATS
}), track = await input.getPrimaryVideoTrack();
if (!track) throw new Error("no video track");
const w = await track.getDisplayWidth(), h = await track.getDisplayHeight(), s = Math.min(1, SHORT_SIDE / Math.min(w, h)), width = even(w * s), height = even(h * s);
let codec = null;
for (const c of ["hevc", "avc"]) if (await canEncodeVideo(c, {
width,
height,
frameRate: FPS,
bitrate: VIDEO_BPS[c]
})) {
codec = c;
break;
}
if (!codec) throw new Error("this device cannot encode HEVC or H.264");
const output = new Output({
format: new Mp4OutputFormat({ fastStart: "in-memory" }),
target: new BufferTarget()
});
const video = {
frameRate: FPS,
codec,
quality: new Quality({ bitrate: VIDEO_BPS[codec] }),
forceTranscode: true
};
if (await track.getFlip()) Object.assign(video, {
width,
height,
fit: "fill"
});
else {
const cx = new OffscreenCanvas(width, height).getContext("2d"), rot = await track.getRotation();
cx.imageSmoothingQuality = "high";
Object.assign(video, {
process: (f) => (f.draw(cx, 0, 0, width, height), cx.canvas),
processedWidth: width,
processedHeight: height,
rotate: (360 - rot) % 360
});
}
const conv = await Conversion.init({
input,
output,
tracks: "primary",
video,
audio: {
numberOfChannels: 1,
codec: "aac",
quality: new Quality({ bitrate: AUDIO_BPS }),
forceTranscode: true
}
});
if (!conv.isValid) throw new Error(conv.discardedTracks.map((t) => t.reason).join(", ") || "unsupported video");
if (signal) {
if (signal.aborted) return null;
signal.addEventListener("abort", () => conv.cancel(), { once: true });
}
conv.onProgress = (p) => onProgress?.(p);
try {
await conv.execute();
} catch (e) {
if (signal?.aborted) return null;
throw e;
}
return {
type: "video_url",
video_url: { url: await asDataURL(new Blob([output.target.buffer], { type: "video/mp4" })) }
};
}
var blobUrls = /* @__PURE__ */ new Set();
var toBlobUrl = async (u) => {
const o = URL.createObjectURL(await (await fetch(u)).blob());
blobUrls.add(o);
return o;
};
var revokeVideoUrls = () => {
blobUrls.forEach((u) => URL.revokeObjectURL(u));
blobUrls.clear();
};
function openPlayer(src) {
const o = document.createElement("div");
o.className = "fixed inset-0 z-[70] bg-black flex items-center justify-center";
o.innerHTML = "<video controls autoplay playsinline class=\"h-full w-full object-contain\"></video><button type=\"button\" aria-label=\"Close\" class=\"absolute top-3 right-3 h-10 w-10 rounded-full bg-white/15 text-white inline-flex items-center justify-center\"><i data-lucide=\"x\" class=\"h-6 w-6\"></i></button>";
const v = o.querySelector("video"), done = () => {
v.pause();
o.remove();
removeEventListener("keydown", esc);
document.fullscreenElement && document.exitFullscreen().catch(() => {});
}, esc = (e) => e.key === "Escape" && history.back();
v.src = src;
history.pushState({ video: 1 }, "");
addEventListener("popstate", done, { once: true });
addEventListener("keydown", esc);
o.querySelector("button").onclick = () => history.back();
o.addEventListener("fullscreenchange", () => !document.fullscreenElement && o.isConnected && history.back());
document.body.append(o);
window.lucide?.createIcons();
o.requestFullscreen?.().catch(() => {});
}
function videoStrip(parts) {
const wrap = document.createElement("div");
wrap.className = "flex gap-2 overflow-x-auto no-scrollbar px-4";
for (const p of parts) {
const b = document.createElement("button");
b.type = "button";
b.setAttribute("aria-label", "Play video");
b.className = "relative shrink-0 h-40 rounded-xl overflow-hidden bg-black";
b.innerHTML = "<video muted playsinline preload=\"metadata\" class=\"h-full w-auto min-w-24 object-cover pointer-events-none\"></video><span class=\"absolute inset-0 flex items-center justify-center\"><span class=\"h-10 w-10 rounded-full bg-black/60 text-white inline-flex items-center justify-center\"><i data-lucide=\"play\" class=\"h-5 w-5\"></i></span></span>";
const src = toBlobUrl(p.video_url?.url || "");
src.then((u) => b.querySelector("video").src = u + "#t=0.1").catch(() => {});
b.onclick = async () => openPlayer(await src);
wrap.append(b);
}
return wrap;
}
//#endregion
//#region src/attachments.js
async function toAttach(file) {
async function toAttach(file, opts) {
if (!file) return null;
if (file instanceof File) {
const name = file.name || "file", mime = (file.type || "application/octet-stream").toLowerCase();
if (isVideo(name, mime)) return compressVideo(file, opts);
if (/^image\//.test(mime) || /\.(png|jpe?g|webp|gif)$/i.test(name)) return {
type: "image_url",
image_url: { url: mime === "image/webp" || /\.webp$/i.test(name) ? await asDataURL(file) : await imgToWebp(file, 2048, 94) }
@@ -711,6 +914,10 @@ async function toAttach(file) {
file_data: file.data
}
};
if (/^video\//.test(mime)) return {
type: "video_url",
video_url: { url: `data:${mime};base64,${file.data}` }
};
if (/^audio\//.test(mime)) {
const fmt = /mp3/.test(mime) ? "mp3" : "wav";
return {
@@ -813,66 +1020,6 @@ var renderSuneHTML = async () => {
}
};
//#endregion
//#region \0vite/preload-helper.js
var scriptRel = "modulepreload";
var assetsURL = function(dep) {
return "/" + dep;
};
var seen = {};
var __vitePreload = function preload(baseModule, deps, importerUrl) {
let promise = Promise.resolve();
if (deps && deps.length > 0) {
const links = document.getElementsByTagName("link");
const cspNonceMeta = document.querySelector("meta[property=csp-nonce]");
const cspNonce = cspNonceMeta?.nonce || cspNonceMeta?.getAttribute("nonce");
function allSettled(promises) {
return Promise.all(promises.map((p) => Promise.resolve(p).then((value) => ({
status: "fulfilled",
value
}), (reason) => ({
status: "rejected",
reason
}))));
}
promise = allSettled(deps.map((dep) => {
dep = assetsURL(dep, importerUrl);
if (dep in seen) return;
seen[dep] = true;
const isCss = dep.endsWith(".css");
const cssSelector = isCss ? "[rel=\"stylesheet\"]" : "";
if (!!importerUrl) for (let i = links.length - 1; i >= 0; i--) {
const link = links[i];
if (link.href === dep && (!isCss || link.rel === "stylesheet")) return;
}
else if (document.querySelector(`link[href="${dep}"]${cssSelector}`)) return;
const link = document.createElement("link");
link.rel = isCss ? "stylesheet" : scriptRel;
if (!isCss) link.as = "script";
link.crossOrigin = "";
link.href = dep;
if (cspNonce) link.setAttribute("nonce", cspNonce);
document.head.appendChild(link);
if (isCss) return new Promise((res, rej) => {
link.addEventListener("load", res);
link.addEventListener("error", () => rej(/* @__PURE__ */ new Error(`Unable to preload CSS for ${dep}`)));
});
}));
}
function handlePreloadError(err) {
const e = new Event("vite:preloadError", { cancelable: true });
e.payload = err;
window.dispatchEvent(e);
if (!e.defaultPrevented) throw err;
}
return promise.then((res) => {
for (const item of res || []) {
if (item.status !== "rejected") continue;
handlePreloadError(item.reason);
}
return baseModule().catch(handlePreloadError);
});
};
//#endregion
//#region src/main.js
(() => {
let k, v = visualViewport;
@@ -1299,6 +1446,8 @@ function _createMessageRow(m) {
$head.append($avatar, $name, $copyBtn, $deleteBtn);
const $bubble = $(`<div class="${(isUser ? "bg-gray-50 border border-gray-200" : "bg-gray-100") + " msg-bubble markdown-body rounded-none px-4 py-3 w-full"}"></div>`);
$row.append($head, $bubble);
const vids = (Array.isArray(meta.content) ? meta.content : []).filter((p) => p?.type === "video_url");
if (vids.length) $row.append(videoStrip(vids));
return $row;
}
function msgRow(m) {
@@ -1334,9 +1483,8 @@ var clearChat = () => {
el.suneHtml.dispatchEvent(new CustomEvent("sune:unmount"));
state.messages = [];
el.messages.innerHTML = "";
state.attachments = [];
updateAttachBadge();
el.fileInput.value = "";
clearAttachments();
revokeVideoUrls();
};
var payloadWithSampling = (b) => {
const o = Object.assign({}, b), s = SUNE, p = {
@@ -1736,21 +1884,49 @@ $(el.sunesSyncDownloadBtn).on("click", () => {
hideSunesSyncPopover();
performSuneDownload(false);
});
var attachGen = 0, attachJob = null, attachQueue = Promise.resolve(), attachWait = false;
function updateAttachBadge() {
const n = state.attachments.length;
el.attachBadge.textContent = String(n);
el.attachBadge.classList.toggle("hidden", n === 0);
el.attachBadge.textContent = attachJob ? Math.floor(attachJob.p * 100) + "%" : String(n);
el.attachBadge.classList.toggle("hidden", !n && !attachJob);
}
var addAttachments = async (files) => {
for (const f of files) {
const at = await toAttach(f).catch(() => null);
if (at) state.attachments.push(at);
}
function clearAttachments() {
attachGen++;
attachJob?.ac.abort();
attachJob = null;
state.attachments = [];
updateAttachBadge();
el.fileInput.value = "";
}
var addAttachments = (files) => {
const g = attachGen;
attachQueue = attachQueue.then(async () => {
for (const f of files) {
if (g !== attachGen) return;
const job = attachJob = {
ac: new AbortController(),
p: 0
};
updateAttachBadge();
const at = await toAttach(f, {
signal: job.ac.signal,
onProgress: (p) => {
job.p = p;
updateAttachBadge();
}
}).catch((e) => {
if (g === attachGen) alert(`Couldn't attach ${f.name || "file"}: ${e?.message || e}`);
});
if (g !== attachGen) return;
attachJob = null;
if (at) state.attachments.push(at);
updateAttachBadge();
}
}).catch(() => {});
};
var hideAttachPopover = () => el.attachPopover.classList.add("hidden");
function showAttachPopover() {
if (!state.attachments.length || !el.attachPopover.classList.contains("hidden")) return;
if (!state.attachments.length && !attachJob || !el.attachPopover.classList.contains("hidden")) return;
haptic();
el.attachPopover.classList.remove("hidden");
positionPopover(el.attachBtn, el.attachPopover);
@@ -1774,8 +1950,7 @@ $(el.attachBtn).on("pointerdown", (e) => {
});
$(el.attachPopover).on("click", (e) => {
if (!e.target.closest("[data-action=\"clear\"]")) return;
state.attachments = [];
updateAttachBadge();
clearAttachments();
hideAttachPopover();
});
$(document).on("click", (e) => {
@@ -1784,20 +1959,23 @@ $(document).on("click", (e) => {
$(window).on("resize", () => {
if (!el.attachPopover.classList.contains("hidden")) positionPopover(el.attachBtn, el.attachPopover);
});
$(el.fileInput).on("change", async () => {
$(el.fileInput).on("change", () => {
const files = [...el.fileInput.files || []];
el.fileInput.value = "";
await addAttachments(files);
addAttachments(files);
});
$(el.composer).on("paste", async (e) => {
const files = [...(e.clipboardData || e.originalEvent?.clipboardData)?.files || []];
if (!files.length) return;
e.preventDefault();
await addAttachments(files);
addAttachments(files);
});
$(el.composer).on("submit", async (e) => {
e.preventDefault();
if (state.busy) return;
if (state.busy || attachWait) return;
attachWait = true;
await attachQueue;
attachWait = false;
const text = el.input.value.trim();
if (!text && !state.attachments.length) return SUNE.infer();
await ensureThreadOnFirstUser(text || "(attachments)");
@@ -2829,3 +3007,4 @@ Object.assign(window, {
cleanSuneStorage
});
//#endregion
export { __vitePreload as t };
File diff suppressed because one or more lines are too long
+35044
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -13,7 +13,7 @@
<script defer src="//unpkg.com/alpinejs"></script>
<script type="module" crossorigin src="/assets/index-DCxWcq5K.js"></script>
<script type="module" crossorigin src="/assets/index-BUD8Xh0Q.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DDqI2rlK.css">
<link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head>
<body class="bg-white text-gray-900 selection:bg-black/10" x-data @click.window="if($event.target.closest('button')) haptic(); if(!document.getElementById('threadPopover').contains($event.target)&&!$event.target.closest('[data-thread-menu]')) hideThreadPopover(); if(!document.getElementById('sunePopover').contains($event.target)&&!$event.target.closest('[data-sune-menu]')) hideSunePopover(); if(!document.getElementById('userMenu').contains($event.target)&&!document.getElementById('userMenuBtn').contains($event.target)) document.getElementById('userMenu').classList.add('hidden')">
@@ -36,7 +36,7 @@
<button id="sendBtn" type="submit" aria-label="Send" class="shrink-0 rounded-2xl bg-black text-white h-10 w-10 inline-flex items-center justify-center shadow-sm hover:bg-black/90 active:scale-[.98] transition"><i data-lucide="sparkles" class="h-5 w-5"></i></button>
<button id="attachBtn" type="button" aria-label="Attach" class="relative shrink-0 rounded-2xl bg-gray-100 text-gray-900 h-10 w-10 inline-flex items-center justify-center shadow-sm hover:bg-gray-200 active:scale-[.98] transition"><i data-lucide="paperclip" class="h-5 w-5"></i><span id="attachBadge" class="hidden absolute -top-1 -right-1 h-4 min-w-4 px-1 rounded-full bg-black text-white text-[10px] leading-4 text-center"></span></button>
</div>
<input id="fileInput" type="file" class="hidden" multiple accept="image/png,image/jpeg,image/webp,image/gif,application/pdf,audio/wav,audio/x-wav,audio/mpeg,audio/mp3"/>
<input id="fileInput" type="file" class="hidden" multiple accept="image/png,image/jpeg,image/webp,image/gif,application/pdf,audio/wav,audio/x-wav,audio/mpeg,audio/mp3,video/*"/>
</form>
</div>
</footer>
Vendored
+1 -1
View File
@@ -1 +1 @@
if(!self.define){let e,s={};const i=(i,n)=>(i=new URL(i+".js",n).href,s[i]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=s,document.head.appendChild(e)}else e=i,importScripts(i),s()}).then(()=>{let e=s[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e}));self.define=(n,r)=>{const t=e||("document"in self?document.currentScript.src:"")||location.href;if(s[t])return;let o={};const d=e=>i(e,t),c={module:{uri:t},exports:o,require:d};s[t]=Promise.all(n.map(e=>c[e]||d(e))).then(e=>(r(...e),o))}}define(["./workbox-9c191d2f"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"registerSW.js",revision:"1872c500de691dce40960bb85481de07"},{url:"index.html",revision:"c3f11cd6433cb8fbfa5ba522a8abdaca"},{url:"assets/index-DDqI2rlK.css",revision:null},{url:"assets/index-DCxWcq5K.js",revision:null},{url:"appstore_content/✺.png",revision:"06dd8ca13016278fc47e9a226acdb7f9"},{url:"manifest.webmanifest",revision:"70d853d7dcb45ddd8488db46950b4b33"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))});
if(!self.define){let e,s={};const n=(n,i)=>(n=new URL(n+".js",i).href,s[n]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=n,e.onload=s,document.head.appendChild(e)}else e=n,importScripts(n),s()}).then(()=>{let e=s[n];if(!e)throw new Error(`Module ${n} didn’t register its module`);return e}));self.define=(i,r)=>{const t=e||("document"in self?document.currentScript.src:"")||location.href;if(s[t])return;let l={};const o=e=>n(e,t),d={module:{uri:t},exports:l,require:o};s[t]=Promise.all(i.map(e=>d[e]||o(e))).then(e=>(r(...e),l))}}define(["./workbox-9c191d2f"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"registerSW.js",revision:"1872c500de691dce40960bb85481de07"},{url:"index.html",revision:"83d384dc5870ba8fbe678bc7c224f429"},{url:"assets/src-Bv2YeDx1.js",revision:null},{url:"assets/mediabunny-aac-encoder-CtuZhjiD.js",revision:null},{url:"assets/index-DDqI2rlK.css",revision:null},{url:"assets/index-BUD8Xh0Q.js",revision:null},{url:"assets/__vite-browser-external-BU5UGKjj.js",revision:null},{url:"appstore_content/✺.png",revision:"06dd8ca13016278fc47e9a226acdb7f9"},{url:"manifest.webmanifest",revision:"70d853d7dcb45ddd8488db46950b4b33"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))});