157 lines
3.8 KiB
JavaScript
157 lines
3.8 KiB
JavaScript
// @ts-check
|
|
import { WebSocketServer } from "ws";
|
|
import { readFileSync, mkdirSync, writeFileSync } from "fs";
|
|
import { join as joinPath } from "path";
|
|
import matter from "gray-matter";
|
|
|
|
import { renderFile } from "./group-similar.js";
|
|
|
|
const MD_ROOT_DIR = "docs";
|
|
const IMG_ROOT_DIR = "docs/public/images";
|
|
|
|
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");
|
|
|
|
let filename = "";
|
|
|
|
ws.on("message", (message, isBinary) => {
|
|
if (message instanceof Buffer && isBinary) {
|
|
writeFileSync(joinPath(IMG_ROOT_DIR, filename), message);
|
|
|
|
return;
|
|
}
|
|
|
|
const { name, ...payload } = JSON.parse(message.toString("utf-8"));
|
|
|
|
switch (name) {
|
|
case "download_q":
|
|
{
|
|
const { q, duration } = payload;
|
|
console.log(`Start ${q}`);
|
|
|
|
const md = loadMdFile(q);
|
|
const q_stem = make_q_stem(q);
|
|
|
|
try {
|
|
mkdirSync(joinPath(IMG_ROOT_DIR, q_stem));
|
|
} catch (e) {}
|
|
|
|
let isChanged = false;
|
|
const ts = [];
|
|
|
|
md.data.video = "/" + q;
|
|
|
|
const { interval } = md.data;
|
|
if (typeof interval === "number") {
|
|
for (let t = 0; t < duration; t += interval) {
|
|
const min = Math.floor(t / 60);
|
|
const sec = Math.floor(t - min * 60);
|
|
|
|
md.content += `\n${min}:${sec.toString().padStart(2, "0")}\n`;
|
|
}
|
|
}
|
|
|
|
const re = /^(?<min>\d{1,2}):(?<sec>\d{2})\s*$/;
|
|
const lines = md.content.split("\n");
|
|
|
|
let newContent = "";
|
|
for (const line of lines) {
|
|
const m = re.exec(line);
|
|
if (m?.groups) {
|
|
const { min, sec } = m.groups;
|
|
const t = `${min}_${sec}`;
|
|
ts.push(t);
|
|
newContent += `\n`;
|
|
newContent += `${line}\n`;
|
|
newContent += `\n`;
|
|
isChanged = true;
|
|
} else {
|
|
newContent += `${line}\n`;
|
|
}
|
|
}
|
|
|
|
if (isChanged) {
|
|
writeFileSync(md.filename, matter.stringify(newContent, md.data));
|
|
|
|
ws.send(JSON.stringify({ name: "seek_q_ts", q, ts }));
|
|
}
|
|
}
|
|
break;
|
|
case "timed_q":
|
|
{
|
|
const { q, t } = payload;
|
|
const q_stem = make_q_stem(q);
|
|
filename = t ? joinPath(q_stem, `${t}.webp`) : "";
|
|
}
|
|
break;
|
|
case "done":
|
|
{
|
|
const { q } = payload;
|
|
const md = loadMdFile(q);
|
|
|
|
console.log(`Done basic parsing ${q}`);
|
|
|
|
const { dedup } = md.data;
|
|
if (dedup) {
|
|
console.log(`Deduping ${md.filename}`);
|
|
|
|
renderFile(
|
|
md.filename,
|
|
md.filename,
|
|
typeof dedup === "number" ? dedup : undefined,
|
|
).then((stats) => {
|
|
// Don't log a thing yet.
|
|
console.log(`Done deduping ${md.filename}`);
|
|
});
|
|
}
|
|
|
|
console.log(`Done ${q}`);
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
|
|
ws.on("close", () => {
|
|
console.log("Client disconnected");
|
|
});
|
|
});
|
|
|
|
/**
|
|
*
|
|
* @param {string} q
|
|
* @returns
|
|
*/
|
|
function loadMdFile(q) {
|
|
const q_stem = make_q_stem(q);
|
|
|
|
try {
|
|
mkdirSync(joinPath(MD_ROOT_DIR, q_stem));
|
|
} catch (e) {}
|
|
|
|
const filename = joinPath(MD_ROOT_DIR, `${q_stem}.md`);
|
|
try {
|
|
// create a blank md file if not exists
|
|
readFileSync(filename, { flag: "a" });
|
|
} catch (e) {}
|
|
|
|
return { filename, ...matter(readFileSync(filename, "utf-8")) };
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {string} q
|
|
* @returns
|
|
*/
|
|
function make_q_stem(q) {
|
|
return q
|
|
.replace(/\.[a-z0-9]+$/, "")
|
|
.replace(/\[.+?\]/g, "")
|
|
.trim()
|
|
.replace(/\s+/g, "_");
|
|
}
|