Move exports/healthcheck to api path
This commit is contained in:
parent
3e8bcbcf43
commit
c8c5b64dc8
5 changed files with 190 additions and 181 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import { type ChildProcess, exec, execSync } from "node:child_process";
|
||||
import { readdir, mkdir, mkdtemp, writeFile, readFile } from "node:fs/promises";
|
||||
import { readdir, mkdir, mkdtemp, writeFile, readFile, copyFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join as pathJoin, normalize } from "node:path";
|
||||
import { setTimeout } from "node:timers/promises";
|
||||
|
|
@ -26,7 +26,34 @@ function getRTFStyles(rtfSource: string) {
|
|||
|
||||
const fetchRetry = fetchRetryWrapper(global.fetch);
|
||||
|
||||
interface AstroApiResponse {
|
||||
story: string;
|
||||
description: Record<string, string>;
|
||||
thumbnail: string | null;
|
||||
}
|
||||
|
||||
const isLibreOfficeRunning = async () =>
|
||||
new Promise<boolean>((res, rej) => {
|
||||
exec("ps -ax", (err, stdout) => {
|
||||
if (err) {
|
||||
rej(err);
|
||||
return;
|
||||
}
|
||||
res(
|
||||
stdout
|
||||
.toLowerCase()
|
||||
.split("\n")
|
||||
.some((line) => line.includes("libreoffice") && line.includes("--writer")),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
async function exportStory(slug: string, options: { outputDir: string }) {
|
||||
/* Check that LibreOffice is not running */
|
||||
if (await isLibreOfficeRunning()) {
|
||||
console.error("LibreOffice cannot be open while this command is running!");
|
||||
process.exit(1);
|
||||
}
|
||||
/* Check that outputDir is valid */
|
||||
const outputDir = normalize(options.outputDir);
|
||||
let files: string[];
|
||||
|
|
@ -41,17 +68,31 @@ async function exportStory(slug: string, options: { outputDir: string }) {
|
|||
process.exit(1);
|
||||
}
|
||||
/* Check if Astro development server needs to be spawned */
|
||||
const healthcheckURL = `http://localhost:4321/healthcheck`;
|
||||
const healthcheckURL = `http://localhost:4321/api/healthcheck`;
|
||||
let devServerProcess: ChildProcess | null = null;
|
||||
try {
|
||||
await fetchRetry(healthcheckURL, { retries: 3, retryDelay: 1000 });
|
||||
const response = await fetchRetry(healthcheckURL, { retries: 3, retryDelay: 1000 });
|
||||
if (!response.ok) {
|
||||
throw new Error();
|
||||
}
|
||||
const healthcheck = await response.json();
|
||||
if (!healthcheck.isAlive) {
|
||||
throw new Error();
|
||||
}
|
||||
} catch {
|
||||
/* Spawn Astro dev server */
|
||||
console.log("Starting Astro development server...");
|
||||
devServerProcess = exec("./node_modules/.bin/astro dev");
|
||||
await setTimeout(2000);
|
||||
try {
|
||||
await fetchRetry(healthcheckURL, { retries: 5, retryDelay: 2000 });
|
||||
const response = await fetchRetry(healthcheckURL, { retries: 5, retryDelay: 2000 });
|
||||
if (!response.ok) {
|
||||
throw new Error();
|
||||
}
|
||||
const healthcheck = await response.json();
|
||||
if (!healthcheck.isAlive) {
|
||||
throw new Error();
|
||||
}
|
||||
} catch {
|
||||
console.error("Astro dev server didn't respond in time!");
|
||||
devServerProcess && devServerProcess.kill("SIGINT");
|
||||
|
|
@ -64,35 +105,35 @@ async function exportStory(slug: string, options: { outputDir: string }) {
|
|||
try {
|
||||
console.log("Getting data from Astro...");
|
||||
|
||||
const exportStoryURL = `http://localhost:4321/stories/export/story/${slug}`;
|
||||
const exportThumbnailURL = `http://localhost:4321/stories/export/thumbnail/${slug}`;
|
||||
const exportDescriptionURLs = (website: string) =>
|
||||
`http://localhost:4321/stories/export/description/${website}/${slug}`;
|
||||
|
||||
const response = await fetch(`http://localhost:4321/api/export-story/${slug}`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to reach API (status code ${response.status})`);
|
||||
}
|
||||
const data: AstroApiResponse = await response.json();
|
||||
await Promise.all(
|
||||
["eka", "furaffinity", "inkbunny", "sofurry", "weasyl"].map(async (website) => {
|
||||
const description = await fetch(exportDescriptionURLs(website));
|
||||
if (!description.ok) {
|
||||
throw new Error(`Failed to get description for "${website}"`);
|
||||
}
|
||||
const descriptionExt = description.headers.get("Content-Type")?.startsWith("text/markdown") ? "md" : "txt";
|
||||
Object.entries(data.description).map(async ([website, description]) => {
|
||||
return await writeFile(
|
||||
pathJoin(outputDir, `description_${website}.${descriptionExt}`),
|
||||
await description.text(),
|
||||
pathJoin(outputDir, `description_${website}.${website === "weasyl" ? "md" : "txt"}`),
|
||||
description,
|
||||
);
|
||||
}),
|
||||
);
|
||||
const thumbnail = await fetch(exportThumbnailURL);
|
||||
if (!thumbnail.ok) {
|
||||
throw new Error("Failed to get thumbnail");
|
||||
if (data.thumbnail) {
|
||||
if (data.thumbnail.startsWith("/@fs/")) {
|
||||
const thumbnailPath = data.thumbnail
|
||||
.replace(/^\/@fs/, "")
|
||||
.replace(/\?(&?[a-z][a-zA-Z0-9_-]+=[a-zA-Z0-9_-]*)*$/, "");
|
||||
await copyFile(thumbnailPath, pathJoin(outputDir, `thumbnail${thumbnailPath.match(/\.[^.]+$/)![0]}`));
|
||||
} else {
|
||||
const thumbnail = await fetch(data.thumbnail);
|
||||
if (!thumbnail.ok) {
|
||||
throw new Error("Failed to get thumbnail");
|
||||
}
|
||||
const thumbnailExt = thumbnail.headers.get("Content-Type")?.startsWith("image/png") ? "png" : "jpg";
|
||||
await writeFile(pathJoin(outputDir, `thumbnail.${thumbnailExt}`), Buffer.from(await thumbnail.arrayBuffer()));
|
||||
}
|
||||
}
|
||||
const thumbnailExt = thumbnail.headers.get("Content-Type")?.startsWith("image/png") ? "png" : "jpg";
|
||||
writeFile(pathJoin(outputDir, `thumbnail.${thumbnailExt}`), Buffer.from(await thumbnail.arrayBuffer()));
|
||||
const story = await fetch(exportStoryURL);
|
||||
if (!story.ok) {
|
||||
throw new Error("Failed to get story");
|
||||
}
|
||||
storyText = await story.text();
|
||||
storyText = data.story;
|
||||
writeFile(pathJoin(outputDir, `${slug}.txt`), storyText);
|
||||
} finally {
|
||||
if (devServerProcess) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue