fix media downloader

This commit is contained in:
polv committed 2026-07-28 22:20:06 +07:00
1 parent 16aea2f26f
commit bc46de9e41
4 files changed
+45 -60

No files matched your search

+15 -50
View File
@@ -1,9 +1,8 @@
import fs from "node:fs"; import fs from "node:fs";
import { IncomingMessage, ServerResponse } from "node:http"; import type { IncomingMessage, ServerResponse } from "node:http";
import https from "node:https";
import path from "node:path"; import path from "node:path";
import { Connect, Plugin, ViteDevServer } from "vite"; import type { Connect, Plugin, ViteDevServer } from "vite";
import { defineConfig, MarkdownOptions } from "vitepress"; import { defineConfig, type MarkdownOptions } from "vitepress";
const host = process.env.TAURI_DEV_HOST; const host = process.env.TAURI_DEV_HOST;
@@ -130,68 +129,34 @@ function audioProxyPlugin(): Plugin {
}; };
} }
function proxyAudio( async function proxyAudio(
req: Connect.IncomingMessage, req: Connect.IncomingMessage,
res: ServerResponse<IncomingMessage>, res: ServerResponse<IncomingMessage>,
next: Connect.NextFunction, next: Connect.NextFunction,
) { ) {
const url = new URL( const url = new URL(`https://www.howtostudykorean.com/wp-content${req.url}`);
`https://www.howtostudykorean.com/wp-content/uploads${req.url}`,
);
// Forward common headers (important for Range streaming)
const headers = {
...req.headers,
host: url.host,
range: req.headers["range"],
};
const segs = req.url!.slice(1).split("/"); const segs = req.url!.slice(1).split("/");
const filename = segs.pop()!; const filename = segs.pop()!;
const saveroot = "docs/public"; const saveroot = "docs/public";
const savetemp = path.join(saveroot, ...segs, filename + ".temp");
const saveto = path.join(saveroot, ...segs, filename); const saveto = path.join(saveroot, ...segs, filename);
if (fs.existsSync(saveto)) { if (fs.existsSync(saveto)) {
next(); return next();
return;
} }
fs.mkdirSync(path.join(saveroot, ...segs), { recursive: true }); fs.mkdirSync(path.join(saveroot, ...segs), { recursive: true });
const fileStream = fs.createWriteStream(savetemp);
const upstreamReq = https.request( const r = await fetch(url, { redirect: "follow" });
{ if (!r.ok) {
protocol: url.protocol, console.error(r);
hostname: url.hostname, return next();
port: url.port || undefined, }
path: url.pathname + url.search,
method: req.method,
headers,
},
(upstreamRes) => {
// Pass status (200 or 206 for Range)
res.writeHead(upstreamRes.statusCode || 200, upstreamRes.headers);
// Stream through fs.writeFileSync(saveto, Buffer.from(await r.arrayBuffer()));
upstreamRes.pipe(res); // console.log(fs.statSync(saveto));
upstreamRes.pipe(fileStream);
},
);
fileStream.on("finish", () => {
fs.renameSync(savetemp, saveto);
console.log("saved to", saveto); console.log("saved to", saveto);
});
fileStream.on("error", (err) => { res.setHeader("Content-Type", "audio/mpeg");
console.error("write failed:", err); fs.createReadStream(saveto).pipe(res);
});
upstreamReq.on("error", (err) => {
res.statusCode = 502;
res.end(`Bad Gateway: ${err.message}`);
});
req.pipe(upstreamReq);
} }
@@ -30,9 +30,11 @@ async function playAudio() {
const uploadURL = "https://www.howtostudykorean.com/wp-content/uploads"; const uploadURL = "https://www.howtostudykorean.com/wp-content/uploads";
let src = props.src; let src = props.src;
if (src.startsWith(uploadURL)) { if (src.startsWith(uploadURL)) {
src = src.replace(uploadURL, "/uploads/"); src = src.replace(uploadURL, "/uploads");
audioEl.value.onerror = () => { audioEl.value.onerror = () => {
if (!audioEl.value) return; if (!audioEl.value) return;
console.log(audioEl.value.error, src);
audioEl.value.src = props.src; audioEl.value.src = props.src;
audioEl.value.currentTime = 0; audioEl.value.currentTime = 0;
audioEl.value.play(); audioEl.value.play();
+1
View File
@@ -26,6 +26,7 @@
}, },
"dependencies": { "dependencies": {
"@supabase/supabase-js": "^2.110.5", "@supabase/supabase-js": "^2.110.5",
"@types/node": "^24.13.3",
"pdfjs-dist": "^5.7.284", "pdfjs-dist": "^5.7.284",
"tauri-plugin-tts-api": "^0.1.11", "tauri-plugin-tts-api": "^0.1.11",
"vite": "^8.1.5", "vite": "^8.1.5",
+26 -9
View File
@@ -11,6 +11,9 @@ importers:
'@supabase/supabase-js': '@supabase/supabase-js':
specifier: ^2.110.5 specifier: ^2.110.5
version: 2.110.5 version: 2.110.5
'@types/node':
specifier: ^24.13.3
version: 24.13.3
pdfjs-dist: pdfjs-dist:
specifier: ^5.7.284 specifier: ^5.7.284
version: 5.7.284 version: 5.7.284
@@ -19,7 +22,7 @@ importers:
version: 0.1.11 version: 0.1.11
vite: vite:
specifier: ^8.1.5 specifier: ^8.1.5
version: 8.1.5(esbuild@0.28.1)(yaml@2.9.0) version: 8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(yaml@2.9.0)
yaml: yaml:
specifier: ^2.9.0 specifier: ^2.9.0
version: 2.9.0 version: 2.9.0
@@ -32,7 +35,7 @@ importers:
version: 2.11.4 version: 2.11.4
vitepress: vitepress:
specifier: 2.0.0-alpha.17 specifier: 2.0.0-alpha.17
version: 2.0.0-alpha.17(lightningcss@1.32.0)(postcss@8.5.19)(yaml@2.9.0) version: 2.0.0-alpha.17(@types/node@24.13.3)(lightningcss@1.32.0)(postcss@8.5.19)(yaml@2.9.0)
vue: vue:
specifier: ^3.5.39 specifier: ^3.5.39
version: 3.5.39 version: 3.5.39
@@ -710,6 +713,9 @@ packages:
'@types/mdurl@2.0.0': '@types/mdurl@2.0.0':
resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==} resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==}
'@types/node@24.13.3':
resolution: {integrity: sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==}
'@types/unist@3.0.3': '@types/unist@3.0.3':
resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
@@ -1078,6 +1084,9 @@ packages:
tslib@2.8.1: tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
undici-types@7.18.2:
resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}
unist-util-is@6.0.1: unist-util-is@6.0.1:
resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==}
@@ -1665,16 +1674,20 @@ snapshots:
'@types/mdurl@2.0.0': {} '@types/mdurl@2.0.0': {}
'@types/node@24.13.3':
dependencies:
undici-types: 7.18.2
'@types/unist@3.0.3': {} '@types/unist@3.0.3': {}
'@types/web-bluetooth@0.0.21': {} '@types/web-bluetooth@0.0.21': {}
'@ungap/structured-clone@1.3.2': {} '@ungap/structured-clone@1.3.2': {}
'@vitejs/plugin-vue@6.0.7(vite@7.3.6(lightningcss@1.32.0)(yaml@2.9.0))(vue@3.5.39)': '@vitejs/plugin-vue@6.0.7(vite@7.3.6(@types/node@24.13.3)(lightningcss@1.32.0)(yaml@2.9.0))(vue@3.5.39)':
dependencies: dependencies:
'@rolldown/pluginutils': 1.0.1 '@rolldown/pluginutils': 1.0.1
vite: 7.3.6(lightningcss@1.32.0)(yaml@2.9.0) vite: 7.3.6(@types/node@24.13.3)(lightningcss@1.32.0)(yaml@2.9.0)
vue: 3.5.39 vue: 3.5.39
'@vue/compiler-core@3.5.39': '@vue/compiler-core@3.5.39':
@@ -2070,6 +2083,8 @@ snapshots:
tslib@2.8.1: {} tslib@2.8.1: {}
undici-types@7.18.2: {}
unist-util-is@6.0.1: unist-util-is@6.0.1:
dependencies: dependencies:
'@types/unist': 3.0.3 '@types/unist': 3.0.3
@@ -2103,7 +2118,7 @@ snapshots:
'@types/unist': 3.0.3 '@types/unist': 3.0.3
vfile-message: 4.0.3 vfile-message: 4.0.3
vite@7.3.6(lightningcss@1.32.0)(yaml@2.9.0): vite@7.3.6(@types/node@24.13.3)(lightningcss@1.32.0)(yaml@2.9.0):
dependencies: dependencies:
esbuild: 0.28.1 esbuild: 0.28.1
fdir: 6.5.0(picomatch@4.0.5) fdir: 6.5.0(picomatch@4.0.5)
@@ -2112,11 +2127,12 @@ snapshots:
rollup: 4.62.2 rollup: 4.62.2
tinyglobby: 0.2.17 tinyglobby: 0.2.17
optionalDependencies: optionalDependencies:
'@types/node': 24.13.3
fsevents: 2.3.3 fsevents: 2.3.3
lightningcss: 1.32.0 lightningcss: 1.32.0
yaml: 2.9.0 yaml: 2.9.0
vite@8.1.5(esbuild@0.28.1)(yaml@2.9.0): vite@8.1.5(@types/node@24.13.3)(esbuild@0.28.1)(yaml@2.9.0):
dependencies: dependencies:
lightningcss: 1.32.0 lightningcss: 1.32.0
picomatch: 4.0.5 picomatch: 4.0.5
@@ -2124,11 +2140,12 @@ snapshots:
rolldown: 1.1.5 rolldown: 1.1.5
tinyglobby: 0.2.17 tinyglobby: 0.2.17
optionalDependencies: optionalDependencies:
'@types/node': 24.13.3
esbuild: 0.28.1 esbuild: 0.28.1
fsevents: 2.3.3 fsevents: 2.3.3
yaml: 2.9.0 yaml: 2.9.0
vitepress@2.0.0-alpha.17(lightningcss@1.32.0)(postcss@8.5.19)(yaml@2.9.0): vitepress@2.0.0-alpha.17(@types/node@24.13.3)(lightningcss@1.32.0)(postcss@8.5.19)(yaml@2.9.0):
dependencies: dependencies:
'@docsearch/css': 4.6.3 '@docsearch/css': 4.6.3
'@docsearch/js': 4.6.3 '@docsearch/js': 4.6.3
@@ -2138,7 +2155,7 @@ snapshots:
'@shikijs/transformers': 3.23.0 '@shikijs/transformers': 3.23.0
'@shikijs/types': 3.23.0 '@shikijs/types': 3.23.0
'@types/markdown-it': 14.1.2 '@types/markdown-it': 14.1.2
'@vitejs/plugin-vue': 6.0.7(vite@7.3.6(lightningcss@1.32.0)(yaml@2.9.0))(vue@3.5.39) '@vitejs/plugin-vue': 6.0.7(vite@7.3.6(@types/node@24.13.3)(lightningcss@1.32.0)(yaml@2.9.0))(vue@3.5.39)
'@vue/devtools-api': 8.1.5 '@vue/devtools-api': 8.1.5
'@vue/shared': 3.5.39 '@vue/shared': 3.5.39
'@vueuse/core': 14.3.0(vue@3.5.39) '@vueuse/core': 14.3.0(vue@3.5.39)
@@ -2147,7 +2164,7 @@ snapshots:
mark.js: 8.11.1 mark.js: 8.11.1
minisearch: 7.2.0 minisearch: 7.2.0
shiki: 3.23.0 shiki: 3.23.0
vite: 7.3.6(lightningcss@1.32.0)(yaml@2.9.0) vite: 7.3.6(@types/node@24.13.3)(lightningcss@1.32.0)(yaml@2.9.0)
vue: 3.5.39 vue: 3.5.39
optionalDependencies: optionalDependencies:
postcss: 8.5.19 postcss: 8.5.19