Removed ffmpeg downloading completely
This commit is contained in:
@@ -27,7 +27,6 @@
|
||||
- Watch sync parties!
|
||||
- Mini player.
|
||||
- Silence skipper (Experimental.)
|
||||
- ffmpeg integration for downloading videos with audio at any quality ([Configuration required](./docs/DOCKER.md#step-7-optional-enabling-downloads)).
|
||||
- [YouTube.js](https://github.com/LuanRT/YouTube.js) fallback if Invidious fails loading videos for Desktop & Android.
|
||||
- Preview video on hover.
|
||||
- Sponsorblock built-in.
|
||||
@@ -48,11 +47,13 @@
|
||||
- YT path redirects (So your redirect plugins should still work!)
|
||||
|
||||
# Support table
|
||||
| | Dash | HLS | Local video fallback | API-Extended | ffmpeg download merging | Dearrow | RYD |
|
||||
|---------|------|-----|----------------------|--------------|-------------------------|---------|-----|
|
||||
| Web | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ |
|
||||
| Desktop | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
|
||||
| Android | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ |
|
||||
Here’s the updated table with the "ffmpeg download merging" column completely removed:
|
||||
|
||||
| | Dash | HLS | Local video fallback | API-Extended | Dearrow | RYD |
|
||||
|---------|------|-----|----------------------|--------------|---------|-----|
|
||||
| Web | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ |
|
||||
| Desktop | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| Android | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
|
||||
# Public instances
|
||||
[Public instances are listed here](./docs/INSTANCES.md).
|
||||
|
||||
Generated
+2
-32
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "materialious",
|
||||
"version": "1.6.28",
|
||||
"version": "1.6.30",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "materialious",
|
||||
"version": "1.6.28",
|
||||
"version": "1.6.30",
|
||||
"dependencies": {
|
||||
"@capacitor-community/electron": "^5.0.1",
|
||||
"@capacitor/android": "^6.1.2",
|
||||
@@ -18,7 +18,6 @@
|
||||
"@capacitor/screen-orientation": "^6.0.2",
|
||||
"@capacitor/status-bar": "^6.0.1",
|
||||
"@capgo/inappbrowser": "^6.6.8",
|
||||
"@ffmpeg/ffmpeg": "^0.12.10",
|
||||
"@hugotomazi/capacitor-navigation-bar": "^4.0.1",
|
||||
"@mediagrid/capacitor-native-audio": "^1.0.0",
|
||||
"beercss": "^3.8.0",
|
||||
@@ -45,7 +44,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@capacitor/assets": "^3.0.5",
|
||||
"@ffmpeg/util": "^0.12.1",
|
||||
"@sveltejs/adapter-auto": "^3.2.5",
|
||||
"@sveltejs/adapter-static": "^3.0.5",
|
||||
"@sveltejs/kit": "^2.9.1",
|
||||
@@ -2084,34 +2082,6 @@
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@ffmpeg/ffmpeg": {
|
||||
"version": "0.12.10",
|
||||
"resolved": "https://registry.npmjs.org/@ffmpeg/ffmpeg/-/ffmpeg-0.12.10.tgz",
|
||||
"integrity": "sha512-lVtk8PW8e+NUzGZhPTWj2P1J4/NyuCrbDD3O9IGpSeLYtUZKBqZO8CNj1WYGghep/MXoM8e1qVY1GztTkf8YYQ==",
|
||||
"dependencies": {
|
||||
"@ffmpeg/types": "^0.12.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.x"
|
||||
}
|
||||
},
|
||||
"node_modules/@ffmpeg/types": {
|
||||
"version": "0.12.2",
|
||||
"resolved": "https://registry.npmjs.org/@ffmpeg/types/-/types-0.12.2.tgz",
|
||||
"integrity": "sha512-NJtxwPoLb60/z1Klv0ueshguWQ/7mNm106qdHkB4HL49LXszjhjCCiL+ldHJGQ9ai2Igx0s4F24ghigy//ERdA==",
|
||||
"engines": {
|
||||
"node": ">=16.x"
|
||||
}
|
||||
},
|
||||
"node_modules/@ffmpeg/util": {
|
||||
"version": "0.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@ffmpeg/util/-/util-0.12.1.tgz",
|
||||
"integrity": "sha512-10jjfAKWaDyb8+nAkijcsi9wgz/y26LOc1NKJradNMyCIl6usQcBbhkjX5qhALrSBcOy6TOeksunTYa+a03qNQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=18.x"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/core": {
|
||||
"version": "1.6.7",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.7.tgz",
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@capacitor/assets": "^3.0.5",
|
||||
"@ffmpeg/util": "^0.12.1",
|
||||
"@sveltejs/adapter-auto": "^3.2.5",
|
||||
"@sveltejs/adapter-static": "^3.0.5",
|
||||
"@sveltejs/kit": "^2.9.1",
|
||||
@@ -52,7 +51,6 @@
|
||||
"@capacitor/screen-orientation": "^6.0.2",
|
||||
"@capacitor/status-bar": "^6.0.1",
|
||||
"@capgo/inappbrowser": "^6.6.8",
|
||||
"@ffmpeg/ffmpeg": "^0.12.10",
|
||||
"@hugotomazi/capacitor-navigation-bar": "^4.0.1",
|
||||
"@mediagrid/capacitor-native-audio": "^1.0.0",
|
||||
"beercss": "^3.8.0",
|
||||
@@ -77,4 +75,4 @@
|
||||
"vidstack": "^1.12.9",
|
||||
"youtubei.js": "^12.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
interface MediaQuality {
|
||||
bandwidth: string;
|
||||
videoUrl: string;
|
||||
audioUrl: string;
|
||||
resolution?: string;
|
||||
frameRate?: string;
|
||||
audioChannels?: string;
|
||||
audioBandwidth?: string;
|
||||
}
|
||||
|
||||
// https://github.com/ffmpegwasm/ffmpeg.wasm/issues/603#issuecomment-1982289892
|
||||
// Ripped from https://github.com/ffmpegwasm/ffmpeg.wasm/blob/ae1cdac7db79c5315f9a1b716fcbd9bcfe27c902/packages/util/src/index.ts#L49
|
||||
export async function fetchFile(
|
||||
file: string,
|
||||
onProgress?: (progress: number) => void
|
||||
): Promise<Uint8Array> {
|
||||
const response = await fetch(file);
|
||||
|
||||
const contentLength = response.headers.get('content-length');
|
||||
|
||||
// If content-length is missing, download without progress tracking
|
||||
if (!contentLength) {
|
||||
const data = await response.arrayBuffer();
|
||||
return new Uint8Array(data);
|
||||
}
|
||||
|
||||
const totalBytes = parseInt(contentLength, 10);
|
||||
const data = new Uint8Array(totalBytes);
|
||||
let position = 0;
|
||||
let downloadBytes = 0;
|
||||
|
||||
const reader = response.body!.getReader();
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
|
||||
data.set(value, position);
|
||||
position += value.length;
|
||||
downloadBytes += value.byteLength;
|
||||
|
||||
if (onProgress) {
|
||||
onProgress((downloadBytes / totalBytes) * 100);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function toBlobURL(
|
||||
url: string,
|
||||
mimeType: string,
|
||||
onProgress?: (progress: number) => void
|
||||
): Promise<string> {
|
||||
return URL.createObjectURL(new Blob([await fetchFile(url, onProgress)], { type: mimeType }));
|
||||
}
|
||||
|
||||
|
||||
// Fetch and parse the DASH manifest
|
||||
async function fetchDASHManifest(manifestUrl: string) {
|
||||
const response = await fetch(manifestUrl);
|
||||
const manifestText = await response.text();
|
||||
const parser = new DOMParser();
|
||||
const manifest = parser.parseFromString(manifestText, "text/xml");
|
||||
return manifest;
|
||||
}
|
||||
|
||||
|
||||
export async function listCombinedQualities(manifestUrl: string): Promise<MediaQuality[]> {
|
||||
const manifest = await fetchDASHManifest(`${manifestUrl}?local=true`);
|
||||
const qualities: MediaQuality[] = [];
|
||||
|
||||
// Fetch all AdaptationSets (both video and audio)
|
||||
const adaptationSets = manifest.getElementsByTagName('AdaptationSet');
|
||||
|
||||
let videoRepresentations: Element[] = [];
|
||||
let audioRepresentations: Element[] = [];
|
||||
|
||||
// Separate video and audio AdaptationSets based on mimeType
|
||||
for (let i = 0; i < adaptationSets.length; i++) {
|
||||
const mimeType = adaptationSets[i].getAttribute('mimeType');
|
||||
const representations = adaptationSets[i].getElementsByTagName('Representation');
|
||||
|
||||
if (mimeType && mimeType === 'video/mp4') {
|
||||
videoRepresentations = [...videoRepresentations, ...Array.from(representations)];
|
||||
} else if (mimeType && mimeType === 'audio/mp4') {
|
||||
audioRepresentations = [...audioRepresentations, ...Array.from(representations)];
|
||||
}
|
||||
}
|
||||
|
||||
// Combine video and audio representations
|
||||
videoRepresentations.forEach((videoRep) => {
|
||||
const videoBandwidth = videoRep.getAttribute('bandwidth');
|
||||
const videoUrl = videoRep.getElementsByTagName('BaseURL')[0].textContent as string;
|
||||
const width = videoRep.getAttribute('width');
|
||||
const height = videoRep.getAttribute('height');
|
||||
const resolution = width && height ? `${width}x${height}` : undefined;
|
||||
const frameRate = videoRep.getAttribute('frameRate') || '';
|
||||
|
||||
// Pair this video representation with each audio representation
|
||||
audioRepresentations.forEach((audioRep) => {
|
||||
const audioUrl = audioRep.getElementsByTagName('BaseURL')[0].textContent as string;
|
||||
const audioChannels = audioRep.getElementsByTagName('AudioChannelConfiguration')[0]?.getAttribute('value') || '';
|
||||
const audioBandwidth = audioRep.getAttribute('bandwidth') || '';
|
||||
|
||||
qualities.push({
|
||||
bandwidth: videoBandwidth || '',
|
||||
videoUrl,
|
||||
audioUrl,
|
||||
resolution,
|
||||
frameRate,
|
||||
audioChannels,
|
||||
audioBandwidth
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return qualities;
|
||||
}
|
||||
|
||||
|
||||
export async function mergeMediaFromDASH(
|
||||
selectedQuality: MediaQuality,
|
||||
fileName: string,
|
||||
progressCallbacks?: {
|
||||
video?: (progress: number) => void,
|
||||
audio?: (progress: number) => void,
|
||||
merging?: (progress: number) => void,
|
||||
loadingFfmpeg?: (completed: boolean) => void;
|
||||
classWorker?: (progress: number) => void,
|
||||
core?: (progress: number) => void;
|
||||
wasm?: (progress: number) => void;
|
||||
worker?: (progress: number) => void;
|
||||
}
|
||||
) {
|
||||
if (progressCallbacks?.loadingFfmpeg) {
|
||||
progressCallbacks.loadingFfmpeg(false);
|
||||
}
|
||||
|
||||
const FFmpeg = await import('@ffmpeg/ffmpeg');
|
||||
|
||||
const ffmpeg = new FFmpeg.FFmpeg();
|
||||
|
||||
ffmpeg.on('progress', ({ progress }) => {
|
||||
if (progressCallbacks?.merging) {
|
||||
progressCallbacks.merging(progress * 100);
|
||||
}
|
||||
});
|
||||
|
||||
await ffmpeg.load({
|
||||
classWorkerURL: await toBlobURL('/ffmpeg/ffmpeg-worker.js', 'text/javascript', progressCallbacks?.classWorker),
|
||||
coreURL: await toBlobURL('/ffmpeg/ffmpeg-core.js', 'text/javascript', progressCallbacks?.core),
|
||||
wasmURL: await toBlobURL('/ffmpeg/ffmpeg-core.wasm', 'application/wasm', progressCallbacks?.wasm),
|
||||
workerURL: await toBlobURL('/ffmpeg/ffmpeg-core.worker.js', 'text/javascript', progressCallbacks?.worker)
|
||||
});
|
||||
|
||||
if (progressCallbacks?.loadingFfmpeg) {
|
||||
progressCallbacks.loadingFfmpeg(true);
|
||||
}
|
||||
|
||||
const { videoUrl, audioUrl } = selectedQuality;
|
||||
|
||||
ffmpeg.writeFile('input.mp4', await fetchFile(videoUrl, progressCallbacks?.video));
|
||||
ffmpeg.writeFile('input.mp3', await fetchFile(audioUrl, progressCallbacks?.audio));
|
||||
|
||||
await ffmpeg.exec(['-i', 'input.mp4', '-i', 'input.mp3', '-c:v', 'copy', '-c:a', 'aac', 'output.mp4']);
|
||||
|
||||
const data = await ffmpeg.readFile('output.mp4');
|
||||
const mergedFile = new Blob([data], { type: 'video/mp4' });
|
||||
const url = URL.createObjectURL(mergedFile);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `${fileName} - ${selectedQuality.resolution}.mp4`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
|
||||
URL.revokeObjectURL(url);
|
||||
document.body.removeChild(a);
|
||||
}
|
||||
@@ -321,9 +321,9 @@
|
||||
{@html $_('invidiousBlockWarning', {
|
||||
values: {
|
||||
android:
|
||||
'<a href="https://github.com/Materialious/Materialious/releases/latest" target="_blank" class="link" rel="noopener noreferrer">Android</a>',
|
||||
'<a href="https://github.com/Materialious/Materialious?tab=readme-ov-file#android" target="_blank" class="link" rel="noopener noreferrer">Android</a>',
|
||||
desktop:
|
||||
'<a href="https://github.com/Materialious/Materialious/releases/latest" target="_blank" class="link" rel="noopener noreferrer">Desktop</a>'
|
||||
'<a href="https://github.com/Materialious/Materialious?tab=readme-ov-file#desktop-windowsmacoslinux" target="_blank" class="link" rel="noopener noreferrer">Desktop</a>'
|
||||
}
|
||||
})}
|
||||
</p>
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
} from '$lib/store';
|
||||
import Thumbnail from '$lib/Thumbnail.svelte';
|
||||
import Transcript from '$lib/Transcript.svelte';
|
||||
import { mergeMediaFromDASH } from '$lib/videoDownload';
|
||||
import ui from 'beercss';
|
||||
import type { DataConnection } from 'peerjs';
|
||||
import { type Segment } from 'sponsorblock-api';
|
||||
@@ -434,50 +433,6 @@
|
||||
|
||||
let downloadStage: string | undefined;
|
||||
let downloadProgress: number = 0;
|
||||
|
||||
function onVideoDownloadProgress(progress: number) {
|
||||
downloadStage = $_('player.downloadSteps.video');
|
||||
downloadProgress = progress;
|
||||
}
|
||||
|
||||
function onAudioDownloadProgress(progress: number) {
|
||||
downloadStage = $_('player.downloadSteps.audio');
|
||||
downloadProgress = progress;
|
||||
}
|
||||
|
||||
function onMergingProgress(progress: number) {
|
||||
downloadStage = $_('player.downloadSteps.merging');
|
||||
downloadProgress = progress;
|
||||
|
||||
if (progress >= 100) {
|
||||
downloadStage = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function onLoadingFFmpeg(completed: boolean) {
|
||||
downloadProgress = 0;
|
||||
downloadStage = $_('player.downloadSteps.ffmpeg');
|
||||
}
|
||||
|
||||
function onClassWorkerProgress(progress: number) {
|
||||
downloadStage = $_('player.downloadSteps.classWorker');
|
||||
downloadProgress = progress;
|
||||
}
|
||||
|
||||
function onCoreProgress(progress: number) {
|
||||
downloadStage = $_('player.downloadSteps.core');
|
||||
downloadProgress = progress;
|
||||
}
|
||||
|
||||
function onWasmProgress(progress: number) {
|
||||
downloadStage = $_('player.downloadSteps.wasm');
|
||||
downloadProgress = progress;
|
||||
}
|
||||
|
||||
function onWorkerProgress(progress: number) {
|
||||
downloadStage = $_('player.downloadSteps.worker');
|
||||
downloadProgress = progress;
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
@@ -621,33 +576,6 @@
|
||||
<ShareVideo video={data.video} />
|
||||
</menu></button
|
||||
>
|
||||
{#await data.streamed.downloadQualitiesDash then downloadQualitiesDash}
|
||||
{#if downloadQualitiesDash}
|
||||
<button class="border"
|
||||
><i>download</i>
|
||||
<div class="tooltip">{$_('player.download')}</div>
|
||||
<menu class="no-wrap">
|
||||
{#each downloadQualitiesDash as quality}
|
||||
<a
|
||||
class="row"
|
||||
href="#download"
|
||||
on:click={async () =>
|
||||
await mergeMediaFromDASH(quality, data.video.title, {
|
||||
video: onVideoDownloadProgress,
|
||||
audio: onAudioDownloadProgress,
|
||||
merging: onMergingProgress,
|
||||
loadingFfmpeg: onLoadingFFmpeg,
|
||||
classWorker: onClassWorkerProgress,
|
||||
core: onCoreProgress,
|
||||
wasm: onWasmProgress,
|
||||
worker: onWorkerProgress
|
||||
})}>{quality.resolution}</a
|
||||
>
|
||||
{/each}
|
||||
</menu></button
|
||||
>
|
||||
{/if}
|
||||
{/await}
|
||||
{#if personalPlaylists}
|
||||
<button class="border">
|
||||
<i>add</i>
|
||||
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
returnYTDislikesInstanceStore,
|
||||
returnYtDislikesStore
|
||||
} from '$lib/store';
|
||||
import { listCombinedQualities } from '$lib/videoDownload';
|
||||
import { error } from '@sveltejs/kit';
|
||||
import { get } from 'svelte/store';
|
||||
|
||||
@@ -51,15 +50,6 @@ export async function load({ params, url }) {
|
||||
}
|
||||
|
||||
|
||||
let downloadQualitiesDash;
|
||||
if (
|
||||
import.meta.env.VITE_DEFAULT_DOWNLOAD_ENABLED &&
|
||||
import.meta.env.VITE_DEFAULT_DOWNLOAD_ENABLED.toString().toLowerCase() === 'true' &&
|
||||
!video.liveNow
|
||||
) {
|
||||
downloadQualitiesDash = listCombinedQualities(video.dashUrl);
|
||||
}
|
||||
|
||||
return {
|
||||
video: video,
|
||||
content: phaseDescription(video.descriptionHtml, video.fallbackPatch === 'youtubejs'),
|
||||
@@ -69,7 +59,6 @@ export async function load({ params, url }) {
|
||||
returnYTDislikes: returnYTDislikes,
|
||||
comments: comments,
|
||||
subscribed: amSubscribed(video.authorId),
|
||||
downloadQualitiesDash: downloadQualitiesDash
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -1 +0,0 @@
|
||||
"use strict";var Module={};var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";if(ENVIRONMENT_IS_NODE){var nodeWorkerThreads=require("worker_threads");var parentPort=nodeWorkerThreads.parentPort;parentPort.on("message",data=>onmessage({data:data}));var fs=require("fs");Object.assign(global,{self:global,require:require,Module:Module,location:{href:__filename},Worker:nodeWorkerThreads.Worker,importScripts:function(f){(0,eval)(fs.readFileSync(f,"utf8")+"//# sourceURL="+f)},postMessage:function(msg){parentPort.postMessage(msg)},performance:global.performance||{now:function(){return Date.now()}}})}var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");if(ENVIRONMENT_IS_NODE){fs.writeSync(2,text+"\n");return}console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=(info,receiveInstance)=>{var module=Module["wasmModule"];Module["wasmModule"]=null;var instance=new WebAssembly.Instance(module,info);return receiveInstance(instance)};self.onunhandledrejection=e=>{throw e.reason??e};function handleMessage(e){try{if(e.data.cmd==="load"){let messageQueue=[];self.onmessage=e=>messageQueue.push(e);self.startWorker=instance=>{Module=instance;postMessage({"cmd":"loaded"});for(let msg of messageQueue){handleMessage(msg)}self.onmessage=handleMessage};Module["wasmModule"]=e.data.wasmModule;for(const handler of e.data.handlers){Module[handler]=function(){postMessage({cmd:"callHandler",handler:handler,args:[...arguments]})}}Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;(e.data.urlOrBlob?import(e.data.urlOrBlob):import("./ffmpeg-core.js")).then(exports=>exports.default(Module))}else if(e.data.cmd==="run"){Module["__emscripten_thread_init"](e.data.pthread_ptr,0,0,1);Module["__emscripten_thread_mailbox_await"](e.data.pthread_ptr);Module["establishStackSpace"]();Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInitTLS();if(!initializedJS){initializedJS=true}try{Module["invokeEntryPoint"](e.data.start_routine,e.data.arg)}catch(ex){if(ex!="unwind"){throw ex}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["__emscripten_thread_exit"](-1)}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="checkMailbox"){if(initializedJS){Module["checkMailbox"]()}}else if(e.data.cmd){err("worker.js received unknown command "+e.data.cmd);err(e.data)}}catch(ex){if(Module["__emscripten_thread_crashed"]){Module["__emscripten_thread_crashed"]()}throw ex}}self.onmessage=handleMessage;
|
||||
@@ -1,146 +0,0 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
const R = "./ffmpeg-core.js";
|
||||
var E;
|
||||
(function (t) {
|
||||
t.LOAD = "LOAD", t.EXEC = "EXEC", t.WRITE_FILE = "WRITE_FILE", t.READ_FILE = "READ_FILE", t.DELETE_FILE = "DELETE_FILE", t.RENAME = "RENAME", t.CREATE_DIR = "CREATE_DIR", t.LIST_DIR = "LIST_DIR", t.DELETE_DIR = "DELETE_DIR", t.ERROR = "ERROR", t.DOWNLOAD = "DOWNLOAD", t.PROGRESS = "PROGRESS", t.LOG = "LOG", t.MOUNT = "MOUNT", t.UNMOUNT = "UNMOUNT"
|
||||
})(E || (E = {}));
|
||||
const a = new Error("unknown message type"),
|
||||
f = new Error("ffmpeg is not loaded, call `await ffmpeg.load()` first"),
|
||||
u = new Error("failed to import ffmpeg-core.js");
|
||||
let r;
|
||||
const O = async ({
|
||||
coreURL: t,
|
||||
wasmURL: n,
|
||||
workerURL: e
|
||||
}) => {
|
||||
const o = !r;
|
||||
try {
|
||||
t || (t = R), importScripts(t)
|
||||
} catch {
|
||||
if (t || (t = R.replace("/umd/", "/esm/")), self.createFFmpegCore = (await import(t)).default, !self.createFFmpegCore) throw u
|
||||
}
|
||||
const s = t,
|
||||
c = n || t.replace(/.js$/g, ".wasm"),
|
||||
b = e || t.replace(/.js$/g, ".worker.js");
|
||||
return r = await self.createFFmpegCore({
|
||||
mainScriptUrlOrBlob: `${s}#${btoa(JSON.stringify({ wasmURL: c, workerURL: b }))}`
|
||||
}), r.setLogger(i => self.postMessage({
|
||||
type: E.LOG,
|
||||
data: i
|
||||
})), r.setProgress(i => self.postMessage({
|
||||
type: E.PROGRESS,
|
||||
data: i
|
||||
})), o
|
||||
}, l = ({
|
||||
args: t,
|
||||
timeout: n = -1
|
||||
}) => {
|
||||
r.setTimeout(n), r.exec(...t);
|
||||
const e = r.ret;
|
||||
return r.reset(), e
|
||||
}, m = ({
|
||||
path: t,
|
||||
data: n
|
||||
}) => (r.FS.writeFile(t, n), !0), D = ({
|
||||
path: t,
|
||||
encoding: n
|
||||
}) => r.FS.readFile(t, {
|
||||
encoding: n
|
||||
}), S = ({
|
||||
path: t
|
||||
}) => (r.FS.unlink(t), !0), I = ({
|
||||
oldPath: t,
|
||||
newPath: n
|
||||
}) => (r.FS.rename(t, n), !0), L = ({
|
||||
path: t
|
||||
}) => (r.FS.mkdir(t), !0), N = ({
|
||||
path: t
|
||||
}) => {
|
||||
const n = r.FS.readdir(t),
|
||||
e = [];
|
||||
for (const o of n) {
|
||||
const s = r.FS.stat(`${t}/${o}`),
|
||||
c = r.FS.isDir(s.mode);
|
||||
e.push({
|
||||
name: o,
|
||||
isDir: c
|
||||
})
|
||||
}
|
||||
return e
|
||||
}, A = ({
|
||||
path: t
|
||||
}) => (r.FS.rmdir(t), !0), w = ({
|
||||
fsType: t,
|
||||
options: n,
|
||||
mountPoint: e
|
||||
}) => {
|
||||
const o = t,
|
||||
s = r.FS.filesystems[o];
|
||||
return s ? (r.FS.mount(s, n, e), !0) : !1
|
||||
}, k = ({
|
||||
mountPoint: t
|
||||
}) => (r.FS.unmount(t), !0);
|
||||
self.onmessage = async ({
|
||||
data: {
|
||||
id: t,
|
||||
type: n,
|
||||
data: e
|
||||
}
|
||||
}) => {
|
||||
const o = [];
|
||||
let s;
|
||||
try {
|
||||
if (n !== E.LOAD && !r) throw f;
|
||||
switch (n) {
|
||||
case E.LOAD:
|
||||
s = await O(e);
|
||||
break;
|
||||
case E.EXEC:
|
||||
s = l(e);
|
||||
break;
|
||||
case E.WRITE_FILE:
|
||||
s = m(e);
|
||||
break;
|
||||
case E.READ_FILE:
|
||||
s = D(e);
|
||||
break;
|
||||
case E.DELETE_FILE:
|
||||
s = S(e);
|
||||
break;
|
||||
case E.RENAME:
|
||||
s = I(e);
|
||||
break;
|
||||
case E.CREATE_DIR:
|
||||
s = L(e);
|
||||
break;
|
||||
case E.LIST_DIR:
|
||||
s = N(e);
|
||||
break;
|
||||
case E.DELETE_DIR:
|
||||
s = A(e);
|
||||
break;
|
||||
case E.MOUNT:
|
||||
s = w(e);
|
||||
break;
|
||||
case E.UNMOUNT:
|
||||
s = k(e);
|
||||
break;
|
||||
default:
|
||||
throw a
|
||||
}
|
||||
} catch (c) {
|
||||
self.postMessage({
|
||||
id: t,
|
||||
type: E.ERROR,
|
||||
data: c.toString()
|
||||
});
|
||||
return
|
||||
}
|
||||
s instanceof Uint8Array && o.push(s.buffer), self.postMessage({
|
||||
id: t,
|
||||
type: n,
|
||||
data: s
|
||||
}, o)
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user