diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts
index b33247e2..97d85ac4 100644
--- a/docs/.vitepress/config.mts
+++ b/docs/.vitepress/config.mts
@@ -29,7 +29,14 @@ export default defineConfig({
},
vite: {
clearScreen: false,
- server: {
+ server: {
+ proxy: {
+ '/socket': {
+ target: 'ws://localhost:8080',
+ ws: true,
+ rewriteWsOrigin: true,
+ }
+ },
// make sure this port matches the devUrl port in tauri.conf.json file
port: 5173,
// Tauri expects a fixed port, fail if that port is not available
diff --git a/docs/.vitepress/theme/components/Downloader.vue b/docs/.vitepress/theme/components/Downloader.vue
index d1889d41..359a77a7 100644
--- a/docs/.vitepress/theme/components/Downloader.vue
+++ b/docs/.vitepress/theme/components/Downloader.vue
@@ -1,69 +1,97 @@
-
+
+
\ No newline at end of file
+
diff --git a/docs/qVVhBGT0K7Y/2636.png b/docs/qVVhBGT0K7Y/2636.png
new file mode 100644
index 00000000..7a8a702b
Binary files /dev/null and b/docs/qVVhBGT0K7Y/2636.png differ
diff --git a/package.json b/package.json
index 98f6ab83..a7ff74ed 100644
--- a/package.json
+++ b/package.json
@@ -1,21 +1,24 @@
{
"name": "yt2press",
"version": "1.0.0",
- "main": "index.js",
+ "main": "server.js",
+ "type": "module",
"license": "MIT",
"dependencies": {
"@tauri-apps/api": "^2",
- "@tauri-apps/plugin-opener": "^2"
+ "@tauri-apps/plugin-opener": "^2",
+ "ws": "^8.19.0"
},
"devDependencies": {
"@tauri-apps/cli": "^2.9.6",
"@types/node": "^20.19.30",
+ "@types/ws": "^8.18.1",
"vite": "^7.3.1",
"vitepress": "2.0.0-alpha.15",
"vue": "^3.5.27"
},
"scripts": {
- "start": "tauri dev",
+ "start": "node .",
"dev": "vitepress dev docs",
"build": "vitepress build docs",
"preview": "vitepress preview docs"
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 8dc140db..a8722171 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -14,6 +14,9 @@ importers:
'@tauri-apps/plugin-opener':
specifier: ^2
version: 2.5.3
+ ws:
+ specifier: ^8.19.0
+ version: 8.19.0
devDependencies:
'@tauri-apps/cli':
specifier: ^2.9.6
@@ -21,6 +24,9 @@ importers:
'@types/node':
specifier: ^20.19.30
version: 20.19.30
+ '@types/ws':
+ specifier: ^8.18.1
+ version: 8.18.1
vite:
specifier: ^7.3.1
version: 7.3.1(@types/node@20.19.30)
@@ -611,6 +617,9 @@ packages:
'@types/web-bluetooth@0.0.21':
resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==}
+ '@types/ws@8.18.1':
+ resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
+
'@ungap/structured-clone@1.3.0':
resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==}
@@ -1031,6 +1040,18 @@ packages:
typescript:
optional: true
+ ws@8.19.0:
+ resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==}
+ engines: {node: '>=10.0.0'}
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: '>=5.0.2'
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+
zod@4.3.5:
resolution: {integrity: sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==}
@@ -1504,6 +1525,10 @@ snapshots:
'@types/web-bluetooth@0.0.21': {}
+ '@types/ws@8.18.1':
+ dependencies:
+ '@types/node': 20.19.30
+
'@ungap/structured-clone@1.3.0': {}
'@vercel/oidc@3.1.0': {}
@@ -1994,6 +2019,8 @@ snapshots:
'@vue/server-renderer': 3.5.27(vue@3.5.27)
'@vue/shared': 3.5.27
+ ws@8.19.0: {}
+
zod@4.3.5: {}
zwitch@2.0.4: {}
diff --git a/server.js b/server.js
new file mode 100644
index 00000000..c9a5c050
--- /dev/null
+++ b/server.js
@@ -0,0 +1,58 @@
+// @ts-check
+import { WebSocketServer } from 'ws';
+import { readFileSync, mkdirSync, writeFileSync } from "fs";
+
+const PORT = 8080
+
+const wss = new WebSocketServer({ port: PORT });
+
+console.log(`WebSocket server running on ws://localhost:${PORT}`);
+
+wss.on('connection', (ws) => {
+ console.log('New client connected');
+
+ ws.on('message', (message) => {
+ const { name, ...payload } = JSON.parse(message.toString('utf-8'));
+ console.log(name, payload)
+ switch (name) {
+ case 'download_q': {
+ const { q } = payload;
+
+ try {
+ mkdirSync(`docs/${q}`);
+ } catch (e) {}
+
+ let outMd = "";
+
+ const re = /^(?\d{1,2}):(?\d{2})\s*$/;
+
+ for (const line of readFileSync(`docs/${q}.md`, "utf-8").trimEnd().split("\n")) {
+ const m = re.exec(line);
+ if (m?.groups) {
+ const { min, sec } = m.groups;
+ const t = parseInt(min) * 60 + parseInt(sec);
+ ws.send(JSON.stringify({ name: "seek_q", t }));
+ outMd += `\n[${line}](./${q}/${t}.png)\n\n`;
+ } else {
+ outMd += `${line}\n`;
+ }
+ }
+
+ writeFileSync(`docs/${q}.md`, outMd);
+ } break;
+ case 'timed_q' : {
+ const { q, t, data } = payload;
+
+ writeFileSync(
+ `docs/${q}/${t}.png`,
+ data.replace(/^data:image\/png;base64,/, ""),
+ "base64",
+ );
+ } break;
+ }
+ });
+
+ ws.on('close', () => {
+ console.log('Client disconnected');
+ });
+});
diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs
index c03488fd..47d3cbd1 100644
--- a/src-tauri/src/lib.rs
+++ b/src-tauri/src/lib.rs
@@ -1,9 +1,17 @@
-use tauri::Listener;
-use serde::Deserialize;
+use tauri::{Listener, AppHandle, Emitter};
+use serde::{Serialize, Deserialize};
+
+#[derive(Clone, Serialize)]
+#[serde(rename_all = "camelCase")]
+struct DownloadProgress {
+ t: u16,
+}
#[tauri::command]
-fn download_q(q: String) {
+fn download_q(app: AppHandle, q: String) {
println!("Download q! {q}");
+
+ app.emit("seek_q", DownloadProgress { t: 0 }).unwrap();
}
#[tauri::command]