diff --git a/web/src/lib/libav.ts b/web/src/lib/libav.ts index 4f540cf5..048323e1 100644 --- a/web/src/lib/libav.ts +++ b/web/src/lib/libav.ts @@ -39,7 +39,7 @@ export default class LibAVWrapper { try { await libav.ffprobe([ - '-v', 'quiet', + //'-v', 'quiet', '-print_format', 'json', '-show_format', '-show_streams', diff --git a/web/src/lib/workers/removebg.ts b/web/src/lib/workers/removebg.ts index 4f8e7bd8..0ab8d6ed 100644 --- a/web/src/lib/workers/removebg.ts +++ b/web/src/lib/workers/removebg.ts @@ -32,7 +32,7 @@ export const maskImage = async (source: Blob, mask: RawImage) => { return canvas; } -export const removeImageBackground = async (file: File) => { +const removeImageBackground = async (file: File) => { const originalImageBlob = new Blob([file]); const image = await RawImage.fromBlob(originalImageBlob); diff --git a/web/src/lib/workers/remux.ts b/web/src/lib/workers/remux.ts new file mode 100644 index 00000000..cd4f73fd --- /dev/null +++ b/web/src/lib/workers/remux.ts @@ -0,0 +1,89 @@ +import mime from "mime"; +import LibAVWrapper from "$lib/libav"; + +const error = (code: string) => { + return { + error: `error.${code}`, + } +} + +const ff = new LibAVWrapper((progress) => { + self.postMessage({ + progress: { + durationProcessed: progress.out_time_sec, + speed: progress.speed, + } + }) +}); + +ff.init(); + +const remux = async (file: File) => { + if (!file) return; + + await ff.init(); + + try { + const file_info = await ff.probe(file).catch((e) => { + if (e?.message?.toLowerCase().includes("out of memory")) { + console.error("uh oh! out of memory"); + console.error(e); + + self.postMessage(error("remux.out_of_resources")); + } + }); + + if (!file_info?.format) { + self.postMessage(error("remux.corrupted")); + return; + } + + self.postMessage({ + progressInfo: { + duration: Number(file_info.format.duration), + } + }); + + if (file instanceof File && !file.type) { + file = new File([file], file.name, { + type: mime.getType(file.name) ?? undefined, + }); + } + + const render = await ff + .render({ + blob: file, + args: ["-c", "copy", "-map", "0"], + }) + .catch((e) => { + console.error("uh-oh! render error"); + console.error(e); + + self.postMessage(error("remux.out_of_resources")); + }); + + if (!render) { + return console.log("not a valid file"); + } + + const filenameParts = file.name.split("."); + const filenameExt = filenameParts.pop(); + + const filename = `${filenameParts.join(".")} (remux).${filenameExt}`; + + self.postMessage({ + render, + filename + }); + } catch (e) { + console.log(e); + } +} + +self.onmessage = async (event: MessageEvent) => { + console.log(event.data); + + if (event.data.file) { + await remux(event.data.file); + } +} diff --git a/web/src/routes/remux/+page.svelte b/web/src/routes/remux/+page.svelte index 4e929b09..0c9e00f7 100644 --- a/web/src/routes/remux/+page.svelte +++ b/web/src/routes/remux/+page.svelte @@ -1,6 +1,6 @@ @@ -235,6 +174,19 @@ "m4a", ]} /> + + {#if file} +
+ + +
+ {/if}
@@ -272,11 +224,22 @@
processing ({progress}%, {speed}x)...
+ {:else if currentProgress && speed} +
+ processing ({currentProgress}s, {speed}x)... +
{:else} - processing... +
processing...
{/if} - {:else} - done! + {/if}
@@ -311,7 +274,6 @@ transition: transform 0.2s, opacity 0.2s; - pointer-events: none; } #remux-processing.processing { @@ -331,6 +293,7 @@ padding: var(--padding); gap: var(--padding); justify-content: center; + align-items: center; } .progress-bar { @@ -348,6 +311,9 @@ #remux-receiver { max-width: 450px; + display: flex; + flex-direction: column; + gap: var(--padding); } #remux-bullets { @@ -357,6 +323,18 @@ max-width: 450px; } + .button-row { + display: flex; + flex-direction: row; + gap: 6px; + } + + button { + padding: 12px 24px; + border-radius: 200px; + width: fit-content; + } + @media screen and (max-width: 920px) { #remux-open { flex-direction: column; diff --git a/web/src/routes/remux/+page.ts b/web/src/routes/remux/+page.ts new file mode 100644 index 00000000..a3d15781 --- /dev/null +++ b/web/src/routes/remux/+page.ts @@ -0,0 +1 @@ +export const ssr = false;