Merge branch 'feat/section-based-tool-urls' into chore/consolidate-v2.0.0

This commit is contained in:
SnapOtter
2026-06-21 02:09:14 +08:00
522 changed files with 4650 additions and 3866 deletions
+175 -169
View File
File diff suppressed because it is too large Load Diff
+13 -6
View File
@@ -1,7 +1,7 @@
/**
* Batch processing route.
*
* POST /api/v1/tools/:toolId/batch
* POST /api/v1/tools/:section/:toolId/batch
*
* Accepts multipart with multiple files + settings JSON.
* Each file is enqueued as a batch-child BullMQ job; a batch-finalize
@@ -12,7 +12,7 @@ import { randomUUID } from "node:crypto";
import { mkdir } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { getBundleForTool, TOOL_BUNDLE_MAP, TOOLS } from "@snapotter/shared";
import { getBundleForTool, TOOL_BUNDLE_MAP, TOOLS, toolSection } from "@snapotter/shared";
import archiver from "archiver";
import type { FlowJob } from "bullmq";
import { eq } from "drizzle-orm";
@@ -56,10 +56,17 @@ function injectTraceContextIntoFlow(node: FlowJob): void {
export async function registerBatchRoutes(app: FastifyInstance): Promise<void> {
app.post(
"/api/v1/tools/:toolId/batch",
"/api/v1/tools/:section/:toolId/batch",
{ config: { rateLimit: { max: 20, timeWindow: "1 minute" } } },
async (request: FastifyRequest<{ Params: { toolId: string } }>, reply: FastifyReply) => {
const { toolId } = request.params;
async (
request: FastifyRequest<{ Params: { section: string; toolId: string } }>,
reply: FastifyReply,
) => {
const { section, toolId } = request.params;
const tool = TOOLS.find((t) => t.id === toolId);
if (!tool || toolSection(tool) !== section) {
return reply.status(404).send({ error: "Not found", code: "NOT_FOUND" });
}
// Batch processing (especially with AI) can take tens of minutes.
// Disable the Node.js HTTP socket timeout so the connection is not
@@ -182,7 +189,7 @@ export async function registerBatchRoutes(app: FastifyInstance): Promise<void> {
// Resolve the tool's modality so non-image files (audio/video/document)
// validate through their own handler instead of the image validator.
const modality = TOOLS.find((t) => t.id === toolId)?.modality ?? "image";
const modality = tool.modality;
const batchScratch = join(tmpdir(), "snapotter-scratch", `batch-${parentId}`);
await mkdir(batchScratch, { recursive: true });
+18 -3
View File
@@ -2,7 +2,14 @@ import { randomUUID } from "node:crypto";
import { mkdir, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import { extname, join } from "node:path";
import { ANALYTICS_EVENTS, getBundleForTool, TOOL_BUNDLE_MAP, TOOLS } from "@snapotter/shared";
import {
ANALYTICS_EVENTS,
apiToolPath,
getBundleForTool,
type Section,
TOOL_BUNDLE_MAP,
TOOLS,
} from "@snapotter/shared";
import { and, inArray, sql } from "drizzle-orm";
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
import type { z } from "zod";
@@ -67,6 +74,12 @@ export type ToolProcessV2 = (ctx: ToolProcessCtxV2) => Promise<ToolProcessResult
export interface ToolRouteConfig<T> {
/** Unique tool identifier, used as the URL path segment. */
toolId: string;
/**
* Override the URL section for non-catalog alias routes kept for
* backwards-compatible URLs (e.g. adjust-colors' brightness-contrast).
* Catalog tools omit this; their section is derived via apiToolPath.
*/
section?: Section;
/**
* How many file parts the route accepts (default 1). Inputs beyond the
* first are validated by the same modality handler and appended to
@@ -186,7 +199,7 @@ export function registerToolProcessFn(config: AnyToolRouteConfig): void {
}
/**
* Factory that registers a POST /api/v1/tools/:toolId route.
* Factory that registers a POST /api/v1/tools/:section/:toolId route.
*
* The route accepts multipart with:
* - A file part (the image to process)
@@ -211,7 +224,9 @@ export function createToolRoute<T>(app: FastifyInstance, config: ToolRouteConfig
toolRegistry.set(config.toolId, resolved);
app.post(
`/api/v1/tools/${config.toolId}`,
config.section
? `/api/v1/tools/${config.section}/${config.toolId}`
: apiToolPath(config.toolId),
{ config: { rateLimit: { max: 60, timeWindow: "1 minute" } } },
async (request: FastifyRequest, reply: FastifyReply) => {
// Check per-tool access before processing uploads
+15 -9
View File
@@ -133,14 +133,20 @@ async function processColorAdjustments(
}
export function registerColorAdjustments(app: FastifyInstance) {
const allIds = [
"adjust-colors",
"brightness-contrast",
"saturation",
"color-channels",
"color-effects",
];
for (const toolId of allIds) {
createToolRoute(app, { toolId, settingsSchema, process: processColorAdjustments });
createToolRoute(app, {
toolId: "adjust-colors",
settingsSchema,
process: processColorAdjustments,
});
// Backwards-compatible alias routes consolidated into adjust-colors. These
// ids are not catalog TOOLS, so pass the section explicitly (all image).
const aliasIds = ["brightness-contrast", "saturation", "color-channels", "color-effects"];
for (const toolId of aliasIds) {
createToolRoute(app, {
toolId,
section: "image",
settingsSchema,
process: processColorAdjustments,
});
}
}
@@ -131,7 +131,7 @@ registerAiJobHandler("ai-canvas-expand", async (input, data, ctx) => {
export function registerAiCanvasExpand(app: FastifyInstance) {
app.post(
"/api/v1/tools/ai-canvas-expand",
"/api/v1/tools/image/ai-canvas-expand",
async (request: FastifyRequest, reply: FastifyReply) => {
const toolId = "ai-canvas-expand";
if (!isToolInstalled(toolId)) {
+1 -1
View File
@@ -90,7 +90,7 @@ registerAiJobHandler("auto-subtitles", async (input, data, ctx) => {
});
export function registerAutoSubtitles(app: FastifyInstance) {
app.post("/api/v1/tools/auto-subtitles", async (request: FastifyRequest, reply: FastifyReply) => {
app.post("/api/v1/tools/video/auto-subtitles", async (request: FastifyRequest, reply: FastifyReply) => {
const toolId = "auto-subtitles";
if (!isToolInstalled(toolId)) {
const bundle = getBundleForTool(toolId);
@@ -110,7 +110,7 @@ registerAiJobHandler("background-replace", async (input, data, ctx) => {
export function registerBackgroundReplace(app: FastifyInstance) {
app.post(
"/api/v1/tools/background-replace",
"/api/v1/tools/image/background-replace",
async (request: FastifyRequest, reply: FastifyReply) => {
const toolId = "background-replace";
if (!isToolInstalled(toolId)) {
@@ -19,7 +19,7 @@ const settingsSchema = z.object({
*/
export function registerBarcodeGenerate(app: FastifyInstance) {
app.post(
"/api/v1/tools/barcode-generate",
"/api/v1/tools/image/barcode-generate",
async (request: FastifyRequest, reply: FastifyReply) => {
let body: unknown;
try {
+1 -1
View File
@@ -79,7 +79,7 @@ function buildOverlaySvg(
* Read barcodes (all 1D + 2D types) from uploaded images using zxing-wasm.
*/
export function registerBarcodeRead(app: FastifyInstance) {
app.post("/api/v1/tools/barcode-read", async (request: FastifyRequest, reply: FastifyReply) => {
app.post("/api/v1/tools/image/barcode-read", async (request: FastifyRequest, reply: FastifyReply) => {
let fileBuffer: Buffer | null = null;
let filename = "image";
let settingsRaw: string | null = null;
+1 -1
View File
@@ -245,7 +245,7 @@ export async function processBeautify(
export function registerBeautify(app: FastifyInstance) {
// Custom HTTP route (multi-file upload: main image + optional background image)
app.post("/api/v1/tools/beautify", async (request, reply) => {
app.post("/api/v1/tools/image/beautify", async (request, reply) => {
let mainBuffer: Buffer | null = null;
let bgImageBuffer: Buffer | null = null;
let filename = "image";
+1 -1
View File
@@ -80,7 +80,7 @@ registerAiJobHandler("blur-background", async (input, data, ctx) => {
export function registerBlurBackground(app: FastifyInstance) {
app.post(
"/api/v1/tools/blur-background",
"/api/v1/tools/image/blur-background",
async (request: FastifyRequest, reply: FastifyReply) => {
const toolId = "blur-background";
if (!isToolInstalled(toolId)) {
+1 -1
View File
@@ -65,7 +65,7 @@ registerAiJobHandler("blur-faces", async (input, data, ctx) => {
/** Face detection and blurring route. */
export function registerBlurFaces(app: FastifyInstance) {
app.post("/api/v1/tools/blur-faces", async (request: FastifyRequest, reply: FastifyReply) => {
app.post("/api/v1/tools/image/blur-faces", async (request: FastifyRequest, reply: FastifyReply) => {
const toolId = "blur-faces";
if (!isToolInstalled(toolId)) {
const bundle = getBundleForTool(toolId);
+1 -1
View File
@@ -17,7 +17,7 @@ const settingsSchema = z.object({
* No image processing - just renames.
*/
export function registerBulkRename(app: FastifyInstance) {
app.post("/api/v1/tools/bulk-rename", async (request, reply) => {
app.post("/api/v1/tools/image/bulk-rename", async (request, reply) => {
const files: Array<{ buffer: Buffer; filename: string }> = [];
let settingsRaw: string | null = null;
+1 -1
View File
@@ -421,7 +421,7 @@ function getAspectMultiplier(ar: string): number | null {
// ── Route registration ─────────────────────────────────────────────
export function registerCollage(app: FastifyInstance) {
app.post("/api/v1/tools/collage", async (request, reply) => {
app.post("/api/v1/tools/image/collage", async (request, reply) => {
const files: Array<{ buffer: Buffer; filename: string }> = [];
let settingsRaw: string | null = null;
+1 -1
View File
@@ -151,7 +151,7 @@ function extractColors(
}
export function registerColorPalette(app: FastifyInstance) {
app.post("/api/v1/tools/color-palette", async (request, reply) => {
app.post("/api/v1/tools/image/color-palette", async (request, reply) => {
let fileBuffer: Buffer | null = null;
let filename = "image";
let rawSettings: string | undefined;
+1 -1
View File
@@ -66,7 +66,7 @@ registerAiJobHandler("colorize", async (input, data, ctx) => {
* with OpenCV DNN fallback.
*/
export function registerColorize(app: FastifyInstance) {
app.post("/api/v1/tools/colorize", async (request: FastifyRequest, reply: FastifyReply) => {
app.post("/api/v1/tools/image/colorize", async (request: FastifyRequest, reply: FastifyReply) => {
const toolId = "colorize";
if (!isToolInstalled(toolId)) {
const bundle = getBundleForTool(toolId);
+1 -1
View File
@@ -12,7 +12,7 @@ import { decompressSvgz, sanitizeSvg } from "../../lib/svg-sanitize.js";
* Compare two images: compute a pixel-level diff and similarity score.
*/
export function registerCompare(app: FastifyInstance) {
app.post("/api/v1/tools/compare", async (request, reply) => {
app.post("/api/v1/tools/image/compare", async (request, reply) => {
let bufferA: Buffer | null = null;
let bufferB: Buffer | null = null;
+1 -1
View File
@@ -52,7 +52,7 @@ const settingsSchema = z.object({
});
export function registerCompose(app: FastifyInstance) {
app.post("/api/v1/tools/compose", async (request, reply) => {
app.post("/api/v1/tools/image/compose", async (request, reply) => {
let baseBuffer: Buffer | null = null;
let overlayBuffer: Buffer | null = null;
let filename = "image";
@@ -28,7 +28,7 @@ type Settings = z.infer<typeof settingsSchema>;
/** Content-aware resize (seam carving via caire) route. */
export function registerContentAwareResize(app: FastifyInstance) {
app.post(
"/api/v1/tools/content-aware-resize",
"/api/v1/tools/image/content-aware-resize",
async (request: FastifyRequest, reply: FastifyReply) => {
let fileBuffer: Buffer | null = null;
let filename = "image";
+2 -2
View File
@@ -68,7 +68,7 @@ const BROWSER_PREVIEWABLE = new Set([
export function registerEditMetadata(app: FastifyInstance) {
// Inspect endpoint - returns parsed metadata via ExifTool
app.post(
"/api/v1/tools/edit-metadata/inspect",
"/api/v1/tools/image/edit-metadata/inspect",
async (request: FastifyRequest, reply: FastifyReply) => {
let fileBuffer: Buffer | null = null;
let filename = "image";
@@ -109,7 +109,7 @@ export function registerEditMetadata(app: FastifyInstance) {
);
// Edit endpoint - writes metadata in-place using ExifTool (no pixel re-encoding)
app.post("/api/v1/tools/edit-metadata", async (request: FastifyRequest, reply: FastifyReply) => {
app.post("/api/v1/tools/image/edit-metadata", async (request: FastifyRequest, reply: FastifyReply) => {
let fileBuffer: Buffer | null = null;
let filename = "image";
let settingsRaw: string | null = null;
+1 -1
View File
@@ -58,7 +58,7 @@ registerAiJobHandler("enhance-faces", async (input, data, ctx) => {
/** Face enhancement route using GFPGAN/CodeFormer. */
export function registerEnhanceFaces(app: FastifyInstance) {
app.post("/api/v1/tools/enhance-faces", async (request: FastifyRequest, reply: FastifyReply) => {
app.post("/api/v1/tools/image/enhance-faces", async (request: FastifyRequest, reply: FastifyReply) => {
const toolId = "enhance-faces";
if (!isToolInstalled(toolId)) {
const bundle = getBundleForTool(toolId);
+1 -1
View File
@@ -33,7 +33,7 @@ const settingsSchema = z.object({
* via getObjectBuffer(data.inputRefs[1]) inside the handler.
*/
export function registerEraseObject(app: FastifyInstance) {
app.post("/api/v1/tools/erase-object", async (request: FastifyRequest, reply: FastifyReply) => {
app.post("/api/v1/tools/image/erase-object", async (request: FastifyRequest, reply: FastifyReply) => {
const toolId = "erase-object";
if (!isToolInstalled(toolId)) {
const bundle = getBundleForTool(toolId);
+1 -1
View File
@@ -79,7 +79,7 @@ interface UploadedFile {
}
export function registerFavicon(app: FastifyInstance) {
app.post("/api/v1/tools/favicon", async (request, reply) => {
app.post("/api/v1/tools/image/favicon", async (request, reply) => {
const uploadedFiles: UploadedFile[] = [];
let settingsRaw: string | null = null;
+1 -1
View File
@@ -95,7 +95,7 @@ async function extractFileInfo(file: FileData): Promise<FileInfo> {
}
export function registerFindDuplicates(app: FastifyInstance) {
app.post("/api/v1/tools/find-duplicates", async (request, reply) => {
app.post("/api/v1/tools/image/find-duplicates", async (request, reply) => {
const files: FileData[] = [];
let settingsRaw: string | null = null;
+1 -1
View File
@@ -98,7 +98,7 @@ const settingsSchema = z.object({
export function registerGifTools(app: FastifyInstance) {
// ── Metadata endpoint ───────────────────────────────────────────
app.post("/api/v1/tools/gif-tools/info", async (request: FastifyRequest, reply: FastifyReply) => {
app.post("/api/v1/tools/image/gif-tools/info", async (request: FastifyRequest, reply: FastifyReply) => {
let fileBuffer: Buffer | null = null;
try {
+1 -1
View File
@@ -34,7 +34,7 @@ const settingsSchema = z
export function registerHtmlToImage(app: FastifyInstance) {
app.post(
"/api/v1/tools/html-to-image",
"/api/v1/tools/image/html-to-image",
{
config: {
rateLimit: { max: 120, timeWindow: "1 hour" },
@@ -110,7 +110,7 @@ export function registerImageEnhancement(app: FastifyInstance) {
});
app.post(
"/api/v1/tools/image-enhancement/analyze",
"/api/v1/tools/image/image-enhancement/analyze",
async (request: FastifyRequest, reply: FastifyReply) => {
let fileBuffer: Buffer | null = null;
let filename = "image";
+1 -1
View File
@@ -54,7 +54,7 @@ function detectMimeType(format: string): string {
export function registerImageToBase64(app: FastifyInstance) {
app.post(
"/api/v1/tools/image-to-base64",
"/api/v1/tools/image/image-to-base64",
async (request: FastifyRequest, reply: FastifyReply) => {
const files: Array<{ buffer: Buffer; filename: string }> = [];
let settings = {};
+1 -1
View File
@@ -97,7 +97,7 @@ async function flattenAlpha(buf: Buffer): Promise<Buffer> {
}
export function registerImageToPdf(app: FastifyInstance) {
app.post("/api/v1/tools/image-to-pdf", async (request, reply) => {
app.post("/api/v1/tools/image/image-to-pdf", async (request, reply) => {
const files: Array<{ buffer: Buffer; filename: string }> = [];
let settingsRaw: string | null = null;
+1 -1
View File
@@ -18,7 +18,7 @@ const execFileAsync = promisify(execFile);
* Does NOT use createToolRoute since it doesn't produce a processed file.
*/
export function registerInfo(app: FastifyInstance) {
app.post("/api/v1/tools/info", async (request: FastifyRequest, reply: FastifyReply) => {
app.post("/api/v1/tools/image/info", async (request: FastifyRequest, reply: FastifyReply) => {
let fileBuffer: Buffer | null = null;
let filename = "image";
+1 -1
View File
@@ -217,7 +217,7 @@ export function registerMemeGenerator(app: FastifyInstance) {
},
});
app.post("/api/v1/tools/meme-generator", async (request, reply) => {
app.post("/api/v1/tools/image/meme-generator", async (request, reply) => {
const contentTypeHeader = request.headers["content-type"] ?? "";
const isMultipart = contentTypeHeader.includes("multipart/form-data");
+1 -1
View File
@@ -69,7 +69,7 @@ registerAiJobHandler("noise-removal", async (input, data, ctx) => {
* Uses the Python sidecar for multi-tier denoising.
*/
export function registerNoiseRemoval(app: FastifyInstance) {
app.post("/api/v1/tools/noise-removal", async (request: FastifyRequest, reply: FastifyReply) => {
app.post("/api/v1/tools/image/noise-removal", async (request: FastifyRequest, reply: FastifyReply) => {
const toolId = "noise-removal";
if (!isToolInstalled(toolId)) {
const bundle = getBundleForTool(toolId);
+1 -1
View File
@@ -57,7 +57,7 @@ registerAiJobHandler("ocr-pdf", async (input, data, ctx) => {
});
export function registerOcrPdf(app: FastifyInstance) {
app.post("/api/v1/tools/ocr-pdf", async (request: FastifyRequest, reply: FastifyReply) => {
app.post("/api/v1/tools/pdf/ocr-pdf", async (request: FastifyRequest, reply: FastifyReply) => {
const toolId = "ocr-pdf";
if (!isToolInstalled(toolId)) {
const bundle = getBundleForTool(toolId);
+1 -1
View File
@@ -28,7 +28,7 @@ const settingsSchema = z.object({
* Returns JSON with extracted text rather than an image.
*/
export function registerOcr(app: FastifyInstance) {
app.post("/api/v1/tools/ocr", async (request: FastifyRequest, reply: FastifyReply) => {
app.post("/api/v1/tools/image/ocr", async (request: FastifyRequest, reply: FastifyReply) => {
const toolId = "ocr";
if (!isToolInstalled(toolId)) {
const bundle = getBundleForTool(toolId);
@@ -63,7 +63,7 @@ async function processImage(inputBuffer: Buffer, settings: Settings, filename: s
export function registerOptimizeForWeb(app: FastifyInstance) {
// Lightweight preview route for live parameter tuning
app.post(
"/api/v1/tools/optimize-for-web/preview",
"/api/v1/tools/image/optimize-for-web/preview",
async (request: FastifyRequest, reply: FastifyReply) => {
let fileBuffer: Buffer | null = null;
let filename = "image";
+4 -4
View File
@@ -131,7 +131,7 @@ async function generatePrintSheet(
export function registerPassportPhoto(app: FastifyInstance) {
// ── Phase 1: Analyze (face landmarks + bg removal) ────────────────
app.post(
"/api/v1/tools/passport-photo/analyze",
"/api/v1/tools/image/passport-photo/analyze",
async (request: FastifyRequest, reply: FastifyReply) => {
const toolId = "passport-photo";
if (!isToolInstalled(toolId)) {
@@ -310,7 +310,7 @@ export function registerPassportPhoto(app: FastifyInstance) {
// ── Base route: return 501 so generic callers don't get 404 ──────
app.post(
"/api/v1/tools/passport-photo",
"/api/v1/tools/image/passport-photo",
async (_request: FastifyRequest, reply: FastifyReply) => {
const toolId = "passport-photo";
if (!isToolInstalled(toolId)) {
@@ -324,14 +324,14 @@ export function registerPassportPhoto(app: FastifyInstance) {
});
}
return reply.status(400).send({
error: "Use /api/v1/tools/passport-photo/analyze or /generate",
error: "Use /api/v1/tools/image/passport-photo/analyze or /generate",
});
},
);
// ── Phase 2: Generate (crop + resize + tile) ─────────────────────
app.post(
"/api/v1/tools/passport-photo/generate",
"/api/v1/tools/image/passport-photo/generate",
async (request: FastifyRequest, reply: FastifyReply) => {
const parseResult = generateSettingsSchema.safeParse(request.body);
if (!parseResult.success) {
+3 -3
View File
@@ -181,7 +181,7 @@ function isPdfBuffer(buf: Buffer): boolean {
// ── Route registration ───────────────────────────────────────────
export function registerPdfToImage(app: FastifyInstance) {
// ── Info endpoint ────────────────────────────────────────────
app.post("/api/v1/tools/pdf-to-image/info", async (request, reply) => {
app.post("/api/v1/tools/pdf/pdf-to-image/info", async (request, reply) => {
let fileBuffer: Buffer | null = null;
try {
const result = await readPdfFromParts(request);
@@ -223,7 +223,7 @@ export function registerPdfToImage(app: FastifyInstance) {
});
// ── Preview endpoint (thumbnails) ─────────────────────────────
app.post("/api/v1/tools/pdf-to-image/preview", async (request, reply) => {
app.post("/api/v1/tools/pdf/pdf-to-image/preview", async (request, reply) => {
let fileBuffer: Buffer | null = null;
try {
const result = await readPdfFromParts(request);
@@ -288,7 +288,7 @@ export function registerPdfToImage(app: FastifyInstance) {
});
// ── Main processing endpoint ─────────────────────────────────
app.post("/api/v1/tools/pdf-to-image", async (request, reply) => {
app.post("/api/v1/tools/pdf/pdf-to-image", async (request, reply) => {
let fileBuffer: Buffer | null = null;
let settingsRaw: string | null = null;
+1 -1
View File
@@ -30,7 +30,7 @@ const settingsSchema = z.object({
* images from text input, not from uploaded files.
*/
export function registerQrGenerate(app: FastifyInstance) {
app.post("/api/v1/tools/qr-generate", async (request: FastifyRequest, reply: FastifyReply) => {
app.post("/api/v1/tools/image/qr-generate", async (request: FastifyRequest, reply: FastifyReply) => {
let body: unknown;
try {
body = request.body;
+1 -1
View File
@@ -58,7 +58,7 @@ registerAiJobHandler("red-eye-removal", async (input, data, ctx) => {
/** Red eye detection and removal route. */
export function registerRedEyeRemoval(app: FastifyInstance) {
app.post(
"/api/v1/tools/red-eye-removal",
"/api/v1/tools/image/red-eye-removal",
async (request: FastifyRequest, reply: FastifyReply) => {
const toolId = "red-eye-removal";
if (!isToolInstalled(toolId)) {
@@ -92,7 +92,7 @@ registerAiJobHandler("remove-background", async (input, data, ctx) => {
export function registerRemoveBackground(app: FastifyInstance) {
// ── Phase 1: Background removal ──────────────────────────────────
app.post(
"/api/v1/tools/remove-background",
"/api/v1/tools/image/remove-background",
async (request: FastifyRequest, reply: FastifyReply) => {
const toolId = "remove-background";
if (!isToolInstalled(toolId)) {
@@ -229,7 +229,7 @@ export function registerRemoveBackground(app: FastifyInstance) {
// ── Phase 2: Effects-only (no AI re-run) ─────────────────────────
app.post(
"/api/v1/tools/remove-background/effects",
"/api/v1/tools/image/remove-background/effects",
async (request: FastifyRequest, reply: FastifyReply) => {
let settingsRaw: string | null = null;
let bgImageBuffer: Buffer | null = null;
+1 -1
View File
@@ -83,7 +83,7 @@ registerAiJobHandler("restore-photo", async (input, data, ctx) => {
* optional colorization.
*/
export function registerRestorePhoto(app: FastifyInstance) {
app.post("/api/v1/tools/restore-photo", async (request: FastifyRequest, reply: FastifyReply) => {
app.post("/api/v1/tools/image/restore-photo", async (request: FastifyRequest, reply: FastifyReply) => {
if (!isToolInstalled("restore-photo")) {
const bundle = getBundleForTool("restore-photo");
return reply.status(501).send({
+1 -1
View File
@@ -44,7 +44,7 @@ function resolveOutputFormat(
}
export function registerSplit(app: FastifyInstance) {
app.post("/api/v1/tools/split", async (request, reply) => {
app.post("/api/v1/tools/image/split", async (request, reply) => {
let fileBuffer: Buffer | null = null;
let filename = "image";
let settingsRaw: string | null = null;
+1 -1
View File
@@ -44,7 +44,7 @@ interface PreparedImage {
}
export function registerStitch(app: FastifyInstance) {
app.post("/api/v1/tools/stitch", async (request, reply) => {
app.post("/api/v1/tools/image/stitch", async (request, reply) => {
const files: Array<{ buffer: Buffer; filename: string }> = [];
let settingsRaw: string | null = null;
+1 -1
View File
@@ -96,7 +96,7 @@ function parseIccProfile(iccBuffer: Buffer): Record<string, string> {
export function registerStripMetadata(app: FastifyInstance) {
// Inspect endpoint — returns parsed metadata as JSON
app.post(
"/api/v1/tools/strip-metadata/inspect",
"/api/v1/tools/image/strip-metadata/inspect",
async (request: FastifyRequest, reply: FastifyReply) => {
let fileBuffer: Buffer | null = null;
let filename = "image";
+2 -2
View File
@@ -105,7 +105,7 @@ async function convertSvg(
*/
export function registerSvgToRaster(app: FastifyInstance) {
// --- Batch endpoint (registered first for route priority) ---
app.post("/api/v1/tools/svg-to-raster/batch", async (request, reply) => {
app.post("/api/v1/tools/image/svg-to-raster/batch", async (request, reply) => {
const files: ParsedSvgFile[] = [];
let settingsRaw: string | null = null;
let clientJobId: string | null = null;
@@ -347,7 +347,7 @@ export function registerSvgToRaster(app: FastifyInstance) {
});
// --- Single-file endpoint ---
app.post("/api/v1/tools/svg-to-raster", async (request, reply) => {
app.post("/api/v1/tools/image/svg-to-raster", async (request, reply) => {
let fileBuffer: Buffer | null = null;
let filename = "output";
let settingsRaw: string | null = null;
@@ -79,7 +79,7 @@ registerAiJobHandler("transcribe-audio", async (input, data, ctx) => {
export function registerTranscribeAudio(app: FastifyInstance) {
app.post(
"/api/v1/tools/transcribe-audio",
"/api/v1/tools/audio/transcribe-audio",
async (request: FastifyRequest, reply: FastifyReply) => {
const toolId = "transcribe-audio";
if (!isToolInstalled(toolId)) {
@@ -152,7 +152,7 @@ registerAiJobHandler("transparency-fixer", async (input, data, ctx) => {
export function registerTransparencyFixer(app: FastifyInstance) {
app.post(
"/api/v1/tools/transparency-fixer",
"/api/v1/tools/image/transparency-fixer",
async (request: FastifyRequest, reply: FastifyReply) => {
if (!isToolInstalled(TOOL_ID)) {
const bundle = getBundleForTool(TOOL_ID);
+1 -1
View File
@@ -116,7 +116,7 @@ registerAiJobHandler("upscale", async (input, data, ctx) => {
* Uses Real-ESRGAN when available, falls back to Lanczos.
*/
export function registerUpscale(app: FastifyInstance) {
app.post("/api/v1/tools/upscale", async (request: FastifyRequest, reply: FastifyReply) => {
app.post("/api/v1/tools/image/upscale", async (request: FastifyRequest, reply: FastifyReply) => {
const toolId = "upscale";
if (!isToolInstalled(toolId)) {
const bundle = getBundleForTool(toolId);
+1 -1
View File
@@ -98,7 +98,7 @@ async function vectorizeBuffer(
}
export function registerVectorize(app: FastifyInstance) {
app.post("/api/v1/tools/vectorize", async (request, reply) => {
app.post("/api/v1/tools/image/vectorize", async (request, reply) => {
let fileBuffer: Buffer | null = null;
let filename = "output";
let settingsRaw: string | null = null;
+1 -1
View File
@@ -21,7 +21,7 @@ const settingsSchema = z.object({
export function registerWatermarkImage(app: FastifyInstance) {
// Custom route since we need two file uploads
app.post("/api/v1/tools/watermark-image", async (request, reply) => {
app.post("/api/v1/tools/image/watermark-image", async (request, reply) => {
let mainBuffer: Buffer | null = null;
let watermarkBuffer: Buffer | null = null;
let filename = "image";
+26 -26
View File
@@ -66,8 +66,8 @@ export default defineConfig({
- Base URL: \`http://localhost:1349\`
- Auth: Session token via \`POST /api/auth/login\` or API key (\`Authorization: Bearer si_...\`)
- Tools: \`POST /api/v1/tools/{toolId}\` (multipart: file + settings JSON)
- Batch: \`POST /api/v1/tools/{toolId}/batch\` (multiple files, returns ZIP)
- Tools: \`POST /api/v1/tools/{section}/{toolId}\` (multipart: file + settings JSON)
- Batch: \`POST /api/v1/tools/{section}/{toolId}/batch\` (multiple files, returns ZIP)
- Pipelines: \`POST /api/v1/pipeline/execute\` (chain tools sequentially)
- Interactive API docs on running instance: \`/api/docs\`
- OpenAPI spec on running instance: \`/api/v1/openapi.yaml\`
@@ -294,18 +294,13 @@ export default defineConfig({
],
},
{
text: "PDF & Documents",
text: "PDF",
items: [
{ text: "PDF to Image", link: "/tools/pdf/pdf-to-image" },
{ text: "Merge PDFs", link: "/tools/pdf/merge-pdf" },
{ text: "Split PDF", link: "/tools/pdf/split-pdf" },
{ text: "Compress PDF", link: "/tools/pdf/compress-pdf" },
{ text: "Rotate PDF", link: "/tools/pdf/rotate-pdf" },
{ text: "Convert Document", link: "/tools/pdf/convert-document" },
{ text: "Convert Presentation", link: "/tools/pdf/convert-presentation" },
{ text: "Convert Spreadsheet", link: "/tools/pdf/convert-spreadsheet" },
{ text: "Excel to PDF", link: "/tools/pdf/excel-to-pdf" },
{ text: "Word to PDF", link: "/tools/pdf/word-to-pdf" },
{ text: "Extract Pages", link: "/tools/pdf/extract-pages" },
{ text: "Remove Pages", link: "/tools/pdf/remove-pages" },
{ text: "Organize PDF", link: "/tools/pdf/organize-pdf" },
@@ -325,29 +320,34 @@ export default defineConfig({
{ text: "PDF to Text", link: "/tools/pdf/pdf-to-text" },
{ text: "PDF to Word", link: "/tools/pdf/pdf-to-word" },
{ text: "PDF Metadata", link: "/tools/pdf/pdf-metadata" },
{ text: "PowerPoint to PDF", link: "/tools/pdf/powerpoint-to-pdf" },
{ text: "HTML to PDF", link: "/tools/pdf/html-to-pdf" },
{ text: "Markdown to Word", link: "/tools/pdf/markdown-to-docx" },
{ text: "Markdown to HTML", link: "/tools/pdf/markdown-to-html" },
{ text: "Markdown to PDF", link: "/tools/pdf/markdown-to-pdf" },
{ text: "Convert EPUB", link: "/tools/pdf/epub-convert" },
{ text: "Convert to EPUB", link: "/tools/pdf/to-epub" },
{ text: "PDF OCR", link: "/tools/pdf/ocr-pdf" },
],
},
{
text: "Data",
text: "Files",
items: [
{ text: "Chart Maker", link: "/tools/data/chart-maker" },
{ text: "CSV to Excel", link: "/tools/data/csv-excel" },
{ text: "CSV to JSON", link: "/tools/data/csv-json" },
{ text: "JSON to XML", link: "/tools/data/json-xml" },
{ text: "Split CSV", link: "/tools/data/split-csv" },
{ text: "Merge CSVs", link: "/tools/data/merge-csvs" },
{ text: "YAML / JSON", link: "/tools/data/yaml-json" },
{ text: "XML to CSV", link: "/tools/data/xml-to-csv" },
{ text: "Create ZIP", link: "/tools/data/create-zip" },
{ text: "Extract ZIP", link: "/tools/data/extract-zip" },
{ text: "Convert Document", link: "/tools/files/convert-document" },
{ text: "Convert Presentation", link: "/tools/files/convert-presentation" },
{ text: "Convert Spreadsheet", link: "/tools/files/convert-spreadsheet" },
{ text: "Excel to PDF", link: "/tools/files/excel-to-pdf" },
{ text: "Word to PDF", link: "/tools/files/word-to-pdf" },
{ text: "PowerPoint to PDF", link: "/tools/files/powerpoint-to-pdf" },
{ text: "HTML to PDF", link: "/tools/files/html-to-pdf" },
{ text: "Markdown to Word", link: "/tools/files/markdown-to-docx" },
{ text: "Markdown to HTML", link: "/tools/files/markdown-to-html" },
{ text: "Markdown to PDF", link: "/tools/files/markdown-to-pdf" },
{ text: "Convert EPUB", link: "/tools/files/epub-convert" },
{ text: "Convert to EPUB", link: "/tools/files/to-epub" },
{ text: "Chart Maker", link: "/tools/files/chart-maker" },
{ text: "CSV to Excel", link: "/tools/files/csv-excel" },
{ text: "CSV to JSON", link: "/tools/files/csv-json" },
{ text: "JSON to XML", link: "/tools/files/json-xml" },
{ text: "Split CSV", link: "/tools/files/split-csv" },
{ text: "Merge CSVs", link: "/tools/files/merge-csvs" },
{ text: "YAML / JSON", link: "/tools/files/yaml-json" },
{ text: "XML to CSV", link: "/tools/files/xml-to-csv" },
{ text: "Create ZIP", link: "/tools/files/create-zip" },
{ text: "Extract ZIP", link: "/tools/files/extract-zip" },
],
},
],
+4 -4
View File
@@ -235,13 +235,13 @@ Two-phase workflow: analyze (detect face + remove background) then generate (cro
### Phase 1: Analyze
`POST /api/v1/tools/passport-photo/analyze`
`POST /api/v1/tools/image/passport-photo/analyze`
Accepts an image file (multipart). Returns face landmark data, a base64 preview, and image dimensions.
### Phase 2: Generate
`POST /api/v1/tools/passport-photo/generate`
`POST /api/v1/tools/image/passport-photo/generate`
Accepts a JSON body with the Phase 1 results plus generation settings:
@@ -370,7 +370,7 @@ Fixes "fake transparent" PNGs where the background was removed but left behind f
| `removeWatermark` | boolean | `false` | Apply watermark removal pre-processing (median filter) |
```bash
curl -X POST http://localhost:1349/api/v1/tools/transparency-fixer \
curl -X POST http://localhost:1349/api/v1/tools/image/transparency-fixer \
-H "Authorization: Bearer <token>" \
-F "file=@fake-transparent.png" \
-F 'settings={"defringe":30,"outputFormat":"png"}'
@@ -401,7 +401,7 @@ Analyzes the image and applies automatic corrections for exposure, contrast, whi
| `corrections.denoise` | boolean | `true` | Apply denoising |
| `deepEnhance` | boolean | `false` | Enable AI noise removal via SCUNet (requires `upscale-enhance` bundle) |
An additional analysis endpoint is available at `POST /api/v1/tools/image-enhancement/analyze` which returns the detected corrections without applying them.
An additional analysis endpoint is available at `POST /api/v1/tools/image/image-enhancement/analyze` which returns the detected corrections without applying them.
### Content-Aware Resize (Seam Carving)
+21 -19
View File
@@ -25,7 +25,7 @@ curl -X POST http://localhost:1349/api/auth/login \
# Returns: {"token":"<session-token>"}
# Use token
curl http://localhost:1349/api/v1/tools/resize \
curl http://localhost:1349/api/v1/tools/image/resize \
-H "Authorization: Bearer <session-token>"
```
@@ -42,7 +42,7 @@ curl -X POST http://localhost:1349/api/v1/api-keys \
# Returns: {"key":"si_<96 hex chars>","id":"...","name":"my-script"}
# Use the key
curl http://localhost:1349/api/v1/tools/resize \
curl http://localhost:1349/api/v1/tools/image/resize \
-H "Authorization: Bearer si_<your-key>"
```
@@ -87,19 +87,21 @@ Every tool follows the same pattern:
```bash
# Single file
curl -X POST http://localhost:1349/api/v1/tools/<toolId> \
curl -X POST http://localhost:1349/api/v1/tools/<section>/<toolId> \
-H "Authorization: Bearer <token>" \
-F "file=@input.jpg" \
-F 'settings={"width":800,"height":600}'
# Batch (returns ZIP)
curl -X POST http://localhost:1349/api/v1/tools/<toolId>/batch \
curl -X POST http://localhost:1349/api/v1/tools/<section>/<toolId>/batch \
-H "Authorization: Bearer <token>" \
-F "files=@a.jpg" \
-F "files=@b.jpg" \
-F 'settings={...}'
```
`<section>` is one of `image`, `video`, `audio`, `pdf`, or `files`.
- Upload is `multipart/form-data`.
- `settings` is a JSON string with tool-specific options.
- **Fast tools** (200) return JSON: `{"jobId":"...","downloadUrl":"/api/v1/download/<jobId>/<filename>","originalSize":1234,"processedSize":567}`. Fetch the processed file from `downloadUrl`.
@@ -331,7 +333,7 @@ All AI tools run on your hardware (CPU or NVIDIA GPU). No internet required.
Capture a webpage as an image. Unlike other tools, this endpoint accepts `application/json` instead of multipart form data (no file upload needed).
**Endpoint:** `POST /api/v1/tools/html-to-image`
**Endpoint:** `POST /api/v1/tools/image/html-to-image`
**Content-Type:** `application/json`
@@ -348,7 +350,7 @@ Capture a webpage as an image. Unlike other tools, this endpoint accepts `applic
**Example:**
```bash
curl -X POST http://localhost:1349/api/v1/tools/html-to-image \
curl -X POST http://localhost:1349/api/v1/tools/image/html-to-image \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"url": "https://snapotter.com", "format": "png", "devicePreset": "desktop"}'
@@ -367,28 +369,28 @@ curl -X POST http://localhost:1349/api/v1/tools/html-to-image \
### Tool Sub-Routes
Some tools expose additional endpoints beyond the standard `POST /api/v1/tools/<toolId>`:
Some tools expose additional endpoints beyond the standard `POST /api/v1/tools/<section>/<toolId>`:
| Method | Path | Description |
|--------|------|-------------|
| `POST` | `/api/v1/tools/remove-background/effects` | Apply background effects (color/gradient/blur/shadow) without re-running AI. Uses cached mask from initial removal. |
| `POST` | `/api/v1/tools/edit-metadata/inspect` | Read existing EXIF/IPTC/XMP metadata from an image |
| `POST` | `/api/v1/tools/strip-metadata/inspect` | Inspect metadata fields before stripping |
| `POST` | `/api/v1/tools/passport-photo/analyze` | Phase 1: AI face detection + background removal. Returns face landmarks and cached data. |
| `POST` | `/api/v1/tools/passport-photo/generate` | Phase 2: Crop, resize, and tile using cached analysis. No AI re-run. |
| `POST` | `/api/v1/tools/gif-tools/info` | Get GIF metadata (frame count, dimensions, duration) |
| `POST` | `/api/v1/tools/pdf-to-image/info` | Get PDF metadata (page count, dimensions) |
| `POST` | `/api/v1/tools/pdf-to-image/preview` | Generate a preview of a specific PDF page |
| `POST` | `/api/v1/tools/svg-to-raster/batch` | Batch convert multiple SVGs to raster |
| `POST` | `/api/v1/tools/image-enhancement/analyze` | Analyze image quality and return enhancement recommendations |
| `POST` | `/api/v1/tools/optimize-for-web/preview` | Lightweight preview for live parameter tuning. Returns optimized image with size headers. |
| `POST` | `/api/v1/tools/image/remove-background/effects` | Apply background effects (color/gradient/blur/shadow) without re-running AI. Uses cached mask from initial removal. |
| `POST` | `/api/v1/tools/image/edit-metadata/inspect` | Read existing EXIF/IPTC/XMP metadata from an image |
| `POST` | `/api/v1/tools/image/strip-metadata/inspect` | Inspect metadata fields before stripping |
| `POST` | `/api/v1/tools/image/passport-photo/analyze` | Phase 1: AI face detection + background removal. Returns face landmarks and cached data. |
| `POST` | `/api/v1/tools/image/passport-photo/generate` | Phase 2: Crop, resize, and tile using cached analysis. No AI re-run. |
| `POST` | `/api/v1/tools/image/gif-tools/info` | Get GIF metadata (frame count, dimensions, duration) |
| `POST` | `/api/v1/tools/pdf/pdf-to-image/info` | Get PDF metadata (page count, dimensions) |
| `POST` | `/api/v1/tools/pdf/pdf-to-image/preview` | Generate a preview of a specific PDF page |
| `POST` | `/api/v1/tools/image/svg-to-raster/batch` | Batch convert multiple SVGs to raster |
| `POST` | `/api/v1/tools/image/image-enhancement/analyze` | Analyze image quality and return enhancement recommendations |
| `POST` | `/api/v1/tools/image/optimize-for-web/preview` | Lightweight preview for live parameter tuning. Returns optimized image with size headers. |
## Batch Processing
Apply any tool to multiple files at once. Returns a ZIP archive.
```bash
curl -X POST http://localhost:1349/api/v1/tools/compress/batch \
curl -X POST http://localhost:1349/api/v1/tools/image/compress/batch \
-H "Authorization: Bearer <token>" \
-F "files=@a.jpg" \
-F "files=@b.jpg" \
+1 -1
View File
@@ -81,7 +81,7 @@ This VitePress site. Deployed to Cloudflare Pages automatically on push to `main
## How a request flows
1. The user picks a tool in the web UI and uploads a file.
2. The frontend sends a multipart POST to `/api/v1/tools/:toolId` with the file and settings.
2. The frontend sends a multipart POST to `/api/v1/tools/:section/:toolId` with the file and settings.
3. The API route validates the input with Zod, then dispatches processing.
4. For standard tools, the job is enqueued to the appropriate BullMQ pool (image, media, or docs based on modality). The in-process BullMQ worker auto-orients the image based on EXIF metadata, runs the tool's process function, and returns the result.
5. For AI tools, the TypeScript bridge sends a request to the persistent Python dispatcher (or spawns a fresh subprocess as fallback), waits for it to finish, and reads the output file.
+1 -1
View File
@@ -139,7 +139,7 @@ Every file you process can be saved to your **Files** library. SnapOtter tracks
Every tool is accessible via HTTP:
```bash
curl -X POST http://localhost:1349/api/v1/tools/resize \
curl -X POST http://localhost:1349/api/v1/tools/image/resize \
-H "Authorization: Bearer si_<your-api-key>" \
-F "file=@photo.jpg" \
-F 'settings={"width":800,"height":600,"fit":"cover"}'
+44 -44
View File
@@ -36,8 +36,8 @@
/tools/burn-subtitles.html /tools/video/burn-subtitles 301
/tools/change-fps /tools/video/change-fps 301
/tools/change-fps.html /tools/video/change-fps 301
/tools/chart-maker /tools/data/chart-maker 301
/tools/chart-maker.html /tools/data/chart-maker 301
/tools/chart-maker /tools/files/chart-maker 301
/tools/chart-maker.html /tools/files/chart-maker 301
/tools/circle-crop /tools/image/circle-crop 301
/tools/circle-crop.html /tools/image/circle-crop 301
/tools/collage /tools/image/collage 301
@@ -63,27 +63,27 @@
/tools/convert /tools/image/convert 301
/tools/convert-audio /tools/audio/convert-audio 301
/tools/convert-audio.html /tools/audio/convert-audio 301
/tools/convert-document /tools/pdf/convert-document 301
/tools/convert-document.html /tools/pdf/convert-document 301
/tools/convert-presentation /tools/pdf/convert-presentation 301
/tools/convert-presentation.html /tools/pdf/convert-presentation 301
/tools/convert-spreadsheet /tools/pdf/convert-spreadsheet 301
/tools/convert-spreadsheet.html /tools/pdf/convert-spreadsheet 301
/tools/convert-document /tools/files/convert-document 301
/tools/convert-document.html /tools/files/convert-document 301
/tools/convert-presentation /tools/files/convert-presentation 301
/tools/convert-presentation.html /tools/files/convert-presentation 301
/tools/convert-spreadsheet /tools/files/convert-spreadsheet 301
/tools/convert-spreadsheet.html /tools/files/convert-spreadsheet 301
/tools/convert-video /tools/video/convert-video 301
/tools/convert-video.html /tools/video/convert-video 301
/tools/convert.html /tools/image/convert 301
/tools/create-zip /tools/data/create-zip 301
/tools/create-zip.html /tools/data/create-zip 301
/tools/create-zip /tools/files/create-zip 301
/tools/create-zip.html /tools/files/create-zip 301
/tools/crop /tools/image/crop 301
/tools/crop-pdf /tools/pdf/crop-pdf 301
/tools/crop-pdf.html /tools/pdf/crop-pdf 301
/tools/crop-video /tools/video/crop-video 301
/tools/crop-video.html /tools/video/crop-video 301
/tools/crop.html /tools/image/crop 301
/tools/csv-excel /tools/data/csv-excel 301
/tools/csv-excel.html /tools/data/csv-excel 301
/tools/csv-json /tools/data/csv-json 301
/tools/csv-json.html /tools/data/csv-json 301
/tools/csv-excel /tools/files/csv-excel 301
/tools/csv-excel.html /tools/files/csv-excel 301
/tools/csv-json /tools/files/csv-json 301
/tools/csv-json.html /tools/files/csv-json 301
/tools/duotone /tools/image/duotone 301
/tools/duotone.html /tools/image/duotone 301
/tools/edit-metadata /tools/image/edit-metadata 301
@@ -92,20 +92,20 @@
/tools/embed-subtitles.html /tools/video/embed-subtitles 301
/tools/enhance-faces /tools/image/enhance-faces 301
/tools/enhance-faces.html /tools/image/enhance-faces 301
/tools/epub-convert /tools/pdf/epub-convert 301
/tools/epub-convert.html /tools/pdf/epub-convert 301
/tools/epub-convert /tools/files/epub-convert 301
/tools/epub-convert.html /tools/files/epub-convert 301
/tools/erase-object /tools/image/erase-object 301
/tools/erase-object.html /tools/image/erase-object 301
/tools/excel-to-pdf /tools/pdf/excel-to-pdf 301
/tools/excel-to-pdf.html /tools/pdf/excel-to-pdf 301
/tools/excel-to-pdf /tools/files/excel-to-pdf 301
/tools/excel-to-pdf.html /tools/files/excel-to-pdf 301
/tools/extract-audio /tools/video/extract-audio 301
/tools/extract-audio.html /tools/video/extract-audio 301
/tools/extract-pages /tools/pdf/extract-pages 301
/tools/extract-pages.html /tools/pdf/extract-pages 301
/tools/extract-subtitles /tools/video/extract-subtitles 301
/tools/extract-subtitles.html /tools/video/extract-subtitles 301
/tools/extract-zip /tools/data/extract-zip 301
/tools/extract-zip.html /tools/data/extract-zip 301
/tools/extract-zip /tools/files/extract-zip 301
/tools/extract-zip.html /tools/files/extract-zip 301
/tools/fade-audio /tools/audio/fade-audio 301
/tools/fade-audio.html /tools/audio/fade-audio 301
/tools/favicon /tools/image/favicon 301
@@ -126,8 +126,8 @@
/tools/histogram.html /tools/image/histogram 301
/tools/html-to-image /tools/image/html-to-image 301
/tools/html-to-image.html /tools/image/html-to-image 301
/tools/html-to-pdf /tools/pdf/html-to-pdf 301
/tools/html-to-pdf.html /tools/pdf/html-to-pdf 301
/tools/html-to-pdf /tools/files/html-to-pdf 301
/tools/html-to-pdf.html /tools/files/html-to-pdf 301
/tools/image-enhancement /tools/image/image-enhancement 301
/tools/image-enhancement.html /tools/image/image-enhancement 301
/tools/image-pad /tools/image/image-pad 301
@@ -140,24 +140,24 @@
/tools/images-to-video.html /tools/video/images-to-video 301
/tools/info /tools/image/info 301
/tools/info.html /tools/image/info 301
/tools/json-xml /tools/data/json-xml 301
/tools/json-xml.html /tools/data/json-xml 301
/tools/json-xml /tools/files/json-xml 301
/tools/json-xml.html /tools/files/json-xml 301
/tools/linearize-pdf /tools/pdf/linearize-pdf 301
/tools/linearize-pdf.html /tools/pdf/linearize-pdf 301
/tools/lqip-placeholder /tools/image/lqip-placeholder 301
/tools/lqip-placeholder.html /tools/image/lqip-placeholder 301
/tools/markdown-to-docx /tools/pdf/markdown-to-docx 301
/tools/markdown-to-docx.html /tools/pdf/markdown-to-docx 301
/tools/markdown-to-html /tools/pdf/markdown-to-html 301
/tools/markdown-to-html.html /tools/pdf/markdown-to-html 301
/tools/markdown-to-pdf /tools/pdf/markdown-to-pdf 301
/tools/markdown-to-pdf.html /tools/pdf/markdown-to-pdf 301
/tools/markdown-to-docx /tools/files/markdown-to-docx 301
/tools/markdown-to-docx.html /tools/files/markdown-to-docx 301
/tools/markdown-to-html /tools/files/markdown-to-html 301
/tools/markdown-to-html.html /tools/files/markdown-to-html 301
/tools/markdown-to-pdf /tools/files/markdown-to-pdf 301
/tools/markdown-to-pdf.html /tools/files/markdown-to-pdf 301
/tools/meme-generator /tools/image/meme-generator 301
/tools/meme-generator.html /tools/image/meme-generator 301
/tools/merge-audio /tools/audio/merge-audio 301
/tools/merge-audio.html /tools/audio/merge-audio 301
/tools/merge-csvs /tools/data/merge-csvs 301
/tools/merge-csvs.html /tools/data/merge-csvs 301
/tools/merge-csvs /tools/files/merge-csvs 301
/tools/merge-csvs.html /tools/files/merge-csvs 301
/tools/merge-pdf /tools/pdf/merge-pdf 301
/tools/merge-pdf.html /tools/pdf/merge-pdf 301
/tools/merge-videos /tools/video/merge-videos 301
@@ -198,8 +198,8 @@
/tools/pitch-shift.html /tools/audio/pitch-shift 301
/tools/pixelate /tools/image/pixelate 301
/tools/pixelate.html /tools/image/pixelate 301
/tools/powerpoint-to-pdf /tools/pdf/powerpoint-to-pdf 301
/tools/powerpoint-to-pdf.html /tools/pdf/powerpoint-to-pdf 301
/tools/powerpoint-to-pdf /tools/files/powerpoint-to-pdf 301
/tools/powerpoint-to-pdf.html /tools/files/powerpoint-to-pdf 301
/tools/protect-pdf /tools/pdf/protect-pdf 301
/tools/protect-pdf.html /tools/pdf/protect-pdf 301
/tools/qr-generate /tools/image/qr-generate 301
@@ -245,8 +245,8 @@
/tools/split /tools/image/split 301
/tools/split-audio /tools/audio/split-audio 301
/tools/split-audio.html /tools/audio/split-audio 301
/tools/split-csv /tools/data/split-csv 301
/tools/split-csv.html /tools/data/split-csv 301
/tools/split-csv /tools/files/split-csv 301
/tools/split-csv.html /tools/files/split-csv 301
/tools/split-pdf /tools/pdf/split-pdf 301
/tools/split-pdf.html /tools/pdf/split-pdf 301
/tools/split.html /tools/image/split 301
@@ -262,8 +262,8 @@
/tools/svg-to-raster.html /tools/image/svg-to-raster 301
/tools/text-overlay /tools/image/text-overlay 301
/tools/text-overlay.html /tools/image/text-overlay 301
/tools/to-epub /tools/pdf/to-epub 301
/tools/to-epub.html /tools/pdf/to-epub 301
/tools/to-epub /tools/files/to-epub 301
/tools/to-epub.html /tools/files/to-epub 301
/tools/transcribe-audio /tools/audio/transcribe-audio 301
/tools/transcribe-audio.html /tools/audio/transcribe-audio 301
/tools/transparency-fixer /tools/image/transparency-fixer 301
@@ -306,9 +306,9 @@
/tools/watermark-video.html /tools/video/watermark-video 301
/tools/waveform-image /tools/audio/waveform-image 301
/tools/waveform-image.html /tools/audio/waveform-image 301
/tools/word-to-pdf /tools/pdf/word-to-pdf 301
/tools/word-to-pdf.html /tools/pdf/word-to-pdf 301
/tools/xml-to-csv /tools/data/xml-to-csv 301
/tools/xml-to-csv.html /tools/data/xml-to-csv 301
/tools/yaml-json /tools/data/yaml-json 301
/tools/yaml-json.html /tools/data/yaml-json 301
/tools/word-to-pdf /tools/files/word-to-pdf 301
/tools/word-to-pdf.html /tools/files/word-to-pdf 301
/tools/xml-to-csv /tools/files/xml-to-csv 301
/tools/xml-to-csv.html /tools/files/xml-to-csv 301
/tools/yaml-json /tools/files/yaml-json 301
/tools/yaml-json.html /tools/files/yaml-json 301
+2 -2
View File
@@ -8,7 +8,7 @@ Convert audio between mono and stereo layouts, or swap the left and right channe
## API Endpoint
`POST /api/v1/tools/audio-channels`
`POST /api/v1/tools/audio/audio-channels`
Accepts multipart form data with an audio file and a JSON `settings` field.
@@ -21,7 +21,7 @@ Accepts multipart form data with an audio file and a JSON `settings` field.
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/audio-channels \
curl -X POST http://localhost:1349/api/v1/tools/audio/audio-channels \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@audio.mp3" \
-F 'settings={"mode": "stereo-to-mono"}'
+3 -3
View File
@@ -8,7 +8,7 @@ View, edit, or strip audio metadata tags such as title, artist, and album (ID3 a
## API Endpoint
`POST /api/v1/tools/audio-metadata`
`POST /api/v1/tools/audio/audio-metadata`
Accepts multipart form data with an audio file and a JSON `settings` field.
@@ -26,7 +26,7 @@ Accepts multipart form data with an audio file and a JSON `settings` field.
Edit metadata tags:
```bash
curl -X POST http://localhost:1349/api/v1/tools/audio-metadata \
curl -X POST http://localhost:1349/api/v1/tools/audio/audio-metadata \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@audio.mp3" \
-F 'settings={"title": "My Song", "artist": "Artist Name", "album": "Album Name"}'
@@ -35,7 +35,7 @@ curl -X POST http://localhost:1349/api/v1/tools/audio-metadata \
Strip all metadata:
```bash
curl -X POST http://localhost:1349/api/v1/tools/audio-metadata \
curl -X POST http://localhost:1349/api/v1/tools/audio/audio-metadata \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@audio.mp3" \
-F 'settings={"strip": true}'
+2 -2
View File
@@ -8,7 +8,7 @@ Speed up or slow down audio playback by applying a speed multiplier.
## API Endpoint
`POST /api/v1/tools/audio-speed`
`POST /api/v1/tools/audio/audio-speed`
Accepts multipart form data with an audio file and a JSON `settings` field.
@@ -21,7 +21,7 @@ Accepts multipart form data with an audio file and a JSON `settings` field.
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/audio-speed \
curl -X POST http://localhost:1349/api/v1/tools/audio/audio-speed \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@audio.mp3" \
-F 'settings={"factor": 2}'
+2 -2
View File
@@ -8,7 +8,7 @@ Convert audio files between common formats including MP3, WAV, OGG, FLAC, and M4
## API Endpoint
`POST /api/v1/tools/convert-audio`
`POST /api/v1/tools/audio/convert-audio`
Accepts multipart form data with an audio file and a JSON `settings` field.
@@ -22,7 +22,7 @@ Accepts multipart form data with an audio file and a JSON `settings` field.
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/convert-audio \
curl -X POST http://localhost:1349/api/v1/tools/audio/convert-audio \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@audio.mp3" \
-F 'settings={"format": "flac", "bitrateKbps": 256}'
+2 -2
View File
@@ -8,7 +8,7 @@ Add fade-in and fade-out effects to the beginning and end of an audio file.
## API Endpoint
`POST /api/v1/tools/fade-audio`
`POST /api/v1/tools/audio/fade-audio`
Accepts multipart form data with an audio file and a JSON `settings` field.
@@ -22,7 +22,7 @@ Accepts multipart form data with an audio file and a JSON `settings` field.
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/fade-audio \
curl -X POST http://localhost:1349/api/v1/tools/audio/fade-audio \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@audio.mp3" \
-F 'settings={"fadeInS": 2, "fadeOutS": 3}'
+2 -2
View File
@@ -8,7 +8,7 @@ Combine two or more audio files into a single sequential track, concatenated in
## API Endpoint
`POST /api/v1/tools/merge-audio`
`POST /api/v1/tools/audio/merge-audio`
Accepts multipart form data with multiple audio files and a JSON `settings` field.
@@ -21,7 +21,7 @@ Accepts multipart form data with multiple audio files and a JSON `settings` fiel
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/merge-audio \
curl -X POST http://localhost:1349/api/v1/tools/audio/merge-audio \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@intro.mp3" \
-F "file=@main.mp3" \
+2 -2
View File
@@ -8,7 +8,7 @@ Reduce background noise in an audio file using FFT-based denoising with selectab
## API Endpoint
`POST /api/v1/tools/noise-reduction`
`POST /api/v1/tools/audio/noise-reduction`
Accepts multipart form data with an audio file and a JSON `settings` field.
@@ -21,7 +21,7 @@ Accepts multipart form data with an audio file and a JSON `settings` field.
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/noise-reduction \
curl -X POST http://localhost:1349/api/v1/tools/audio/noise-reduction \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@audio.mp3" \
-F 'settings={"strength": "strong"}'
+2 -2
View File
@@ -8,7 +8,7 @@ Even out audio loudness to broadcast standard levels using EBU R128 normalizatio
## API Endpoint
`POST /api/v1/tools/normalize-audio`
`POST /api/v1/tools/audio/normalize-audio`
Accepts multipart form data with an audio file and a JSON `settings` field.
@@ -19,7 +19,7 @@ This tool has no configurable parameters. It applies EBU R128 loudness normaliza
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/normalize-audio \
curl -X POST http://localhost:1349/api/v1/tools/audio/normalize-audio \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@audio.mp3"
```
+2 -2
View File
@@ -8,7 +8,7 @@ Raise or lower the pitch of an audio file by a number of semitones without chang
## API Endpoint
`POST /api/v1/tools/pitch-shift`
`POST /api/v1/tools/audio/pitch-shift`
Accepts multipart form data with an audio file and a JSON `settings` field.
@@ -21,7 +21,7 @@ Accepts multipart form data with an audio file and a JSON `settings` field.
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/pitch-shift \
curl -X POST http://localhost:1349/api/v1/tools/audio/pitch-shift \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@audio.mp3" \
-F 'settings={"semitones": -5}'
+2 -2
View File
@@ -8,7 +8,7 @@ Reverse an audio file so it plays backwards.
## API Endpoint
`POST /api/v1/tools/reverse-audio`
`POST /api/v1/tools/audio/reverse-audio`
Accepts multipart form data with an audio file and a JSON `settings` field.
@@ -19,7 +19,7 @@ This tool has no configurable parameters. The entire audio file is reversed.
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/reverse-audio \
curl -X POST http://localhost:1349/api/v1/tools/audio/reverse-audio \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@audio.mp3"
```
+2 -2
View File
@@ -8,7 +8,7 @@ Create a ringtone clip (.m4r) from any audio file by selecting a start time and
## API Endpoint
`POST /api/v1/tools/ringtone-maker`
`POST /api/v1/tools/audio/ringtone-maker`
Accepts multipart form data with an audio file and a JSON `settings` field.
@@ -22,7 +22,7 @@ Accepts multipart form data with an audio file and a JSON `settings` field.
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/ringtone-maker \
curl -X POST http://localhost:1349/api/v1/tools/audio/ringtone-maker \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@audio.mp3" \
-F 'settings={"startS": 15, "durationS": 20}'
+2 -2
View File
@@ -8,7 +8,7 @@ Detect and remove silent sections from an audio file based on a configurable thr
## API Endpoint
`POST /api/v1/tools/silence-removal`
`POST /api/v1/tools/audio/silence-removal`
Accepts multipart form data with an audio file and a JSON `settings` field.
@@ -22,7 +22,7 @@ Accepts multipart form data with an audio file and a JSON `settings` field.
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/silence-removal \
curl -X POST http://localhost:1349/api/v1/tools/audio/silence-removal \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@audio.mp3" \
-F 'settings={"thresholdDb": -45, "minSilenceS": 1}'
+3 -3
View File
@@ -8,7 +8,7 @@ Split an audio file into segments by fixed time intervals, equal parts, or autom
## API Endpoint
`POST /api/v1/tools/split-audio`
`POST /api/v1/tools/audio/split-audio`
Accepts multipart form data with an audio file and a JSON `settings` field.
@@ -27,7 +27,7 @@ Accepts multipart form data with an audio file and a JSON `settings` field.
Split into 30-second segments:
```bash
curl -X POST http://localhost:1349/api/v1/tools/split-audio \
curl -X POST http://localhost:1349/api/v1/tools/audio/split-audio \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@audio.mp3" \
-F 'settings={"mode": "time", "segmentS": 30}'
@@ -36,7 +36,7 @@ curl -X POST http://localhost:1349/api/v1/tools/split-audio \
Split by silence detection:
```bash
curl -X POST http://localhost:1349/api/v1/tools/split-audio \
curl -X POST http://localhost:1349/api/v1/tools/audio/split-audio \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@audio.mp3" \
-F 'settings={"mode": "silence", "thresholdDb": -35, "minSilenceS": 0.5}'
+2 -2
View File
@@ -8,7 +8,7 @@ Convert speech to text using AI-powered transcription (faster-whisper). Supports
## API Endpoint
`POST /api/v1/tools/transcribe-audio`
`POST /api/v1/tools/audio/transcribe-audio`
Accepts multipart form data with an audio file and a JSON `settings` field.
@@ -22,7 +22,7 @@ Accepts multipart form data with an audio file and a JSON `settings` field.
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/transcribe-audio \
curl -X POST http://localhost:1349/api/v1/tools/audio/transcribe-audio \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@audio.mp3" \
-F 'settings={"language": "en", "outputFormat": "srt"}'
+2 -2
View File
@@ -8,7 +8,7 @@ Cut a section out of an audio file by specifying start and end times in seconds.
## API Endpoint
`POST /api/v1/tools/trim-audio`
`POST /api/v1/tools/audio/trim-audio`
Accepts multipart form data with an audio file and a JSON `settings` field.
@@ -22,7 +22,7 @@ Accepts multipart form data with an audio file and a JSON `settings` field.
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/trim-audio \
curl -X POST http://localhost:1349/api/v1/tools/audio/trim-audio \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@audio.mp3" \
-F 'settings={"startS": 10, "endS": 45}'
+2 -2
View File
@@ -8,7 +8,7 @@ Increase or decrease the volume of an audio file by applying a fixed gain in dec
## API Endpoint
`POST /api/v1/tools/volume-adjust`
`POST /api/v1/tools/audio/volume-adjust`
Accepts multipart form data with an audio file and a JSON `settings` field.
@@ -21,7 +21,7 @@ Accepts multipart form data with an audio file and a JSON `settings` field.
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/volume-adjust \
curl -X POST http://localhost:1349/api/v1/tools/audio/volume-adjust \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@audio.mp3" \
-F 'settings={"gainDb": 6}'
+2 -2
View File
@@ -8,7 +8,7 @@ Generate a waveform visualization as a PNG image from an audio file, with config
## API Endpoint
`POST /api/v1/tools/waveform-image`
`POST /api/v1/tools/audio/waveform-image`
Accepts multipart form data with an audio file and a JSON `settings` field.
@@ -23,7 +23,7 @@ Accepts multipart form data with an audio file and a JSON `settings` field.
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/waveform-image \
curl -X POST http://localhost:1349/api/v1/tools/audio/waveform-image \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@audio.mp3" \
-F 'settings={"width": 1920, "height": 400, "color": "#e07832"}'
@@ -8,7 +8,7 @@ Create bar, line, or pie charts from CSV or JSON data. Returns a PNG image of th
## API Endpoint
`POST /api/v1/tools/chart-maker`
`POST /api/v1/tools/files/chart-maker`
Accepts multipart form data with a CSV or JSON file and a JSON `settings` field.
@@ -24,7 +24,7 @@ Accepts multipart form data with a CSV or JSON file and a JSON `settings` field.
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/chart-maker \
curl -X POST http://localhost:1349/api/v1/tools/files/chart-maker \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@sales.csv" \
-F 'settings={"kind": "line", "title": "Monthly Sales", "width": 960, "height": 540}'
@@ -8,7 +8,7 @@ Convert documents between Word (DOCX), OpenDocument (ODT), RTF, and plain text f
## API Endpoint
`POST /api/v1/tools/convert-document`
`POST /api/v1/tools/files/convert-document`
Accepts multipart form data with a Word/ODT/RTF/TXT file and a JSON `settings` field.
@@ -21,7 +21,7 @@ Accepts multipart form data with a Word/ODT/RTF/TXT file and a JSON `settings` f
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/convert-document \
curl -X POST http://localhost:1349/api/v1/tools/files/convert-document \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@report.docx" \
-F 'settings={"format": "odt"}'
@@ -8,7 +8,7 @@ Convert presentations between PowerPoint (PPTX) and OpenDocument Presentation (O
## API Endpoint
`POST /api/v1/tools/convert-presentation`
`POST /api/v1/tools/files/convert-presentation`
Accepts multipart form data with a PowerPoint/ODP file and a JSON `settings` field.
@@ -21,7 +21,7 @@ Accepts multipart form data with a PowerPoint/ODP file and a JSON `settings` fie
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/convert-presentation \
curl -X POST http://localhost:1349/api/v1/tools/files/convert-presentation \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@slides.pptx" \
-F 'settings={"format": "odp"}'
@@ -8,7 +8,7 @@ Convert spreadsheets between Excel (XLSX), OpenDocument Spreadsheet (ODS), and C
## API Endpoint
`POST /api/v1/tools/convert-spreadsheet`
`POST /api/v1/tools/files/convert-spreadsheet`
Accepts multipart form data with an Excel/ODS/CSV file and a JSON `settings` field.
@@ -21,7 +21,7 @@ Accepts multipart form data with an Excel/ODS/CSV file and a JSON `settings` fie
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/convert-spreadsheet \
curl -X POST http://localhost:1349/api/v1/tools/files/convert-spreadsheet \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@data.xlsx" \
-F 'settings={"format": "csv"}'
@@ -8,7 +8,7 @@ Bundle multiple files of any type into a single ZIP archive. Duplicate filenames
## API Endpoint
`POST /api/v1/tools/create-zip`
`POST /api/v1/tools/files/create-zip`
Accepts multipart form data with two or more files. No settings field is required.
@@ -19,7 +19,7 @@ This tool has no configurable parameters. Upload 2--50 files of any type to bund
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/create-zip \
curl -X POST http://localhost:1349/api/v1/tools/files/create-zip \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@report.pdf" \
-F "file=@data.csv" \
@@ -8,7 +8,7 @@ Convert between CSV and Excel (XLSX) formats in both directions. Upload a CSV or
## API Endpoint
`POST /api/v1/tools/csv-excel`
`POST /api/v1/tools/files/csv-excel`
Accepts multipart form data with a CSV, TSV, or XLSX file and a JSON `settings` field.
@@ -23,7 +23,7 @@ Accepts multipart form data with a CSV, TSV, or XLSX file and a JSON `settings`
CSV to Excel:
```bash
curl -X POST http://localhost:1349/api/v1/tools/csv-excel \
curl -X POST http://localhost:1349/api/v1/tools/files/csv-excel \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@data.csv" \
-F 'settings={"sheet": 1}'
@@ -32,7 +32,7 @@ curl -X POST http://localhost:1349/api/v1/tools/csv-excel \
Excel to CSV:
```bash
curl -X POST http://localhost:1349/api/v1/tools/csv-excel \
curl -X POST http://localhost:1349/api/v1/tools/files/csv-excel \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@report.xlsx" \
-F 'settings={"sheet": 2}'
@@ -8,7 +8,7 @@ Convert between CSV and JSON formats in both directions. Upload a CSV or TSV fil
## API Endpoint
`POST /api/v1/tools/csv-json`
`POST /api/v1/tools/files/csv-json`
Accepts multipart form data with a CSV, TSV, or JSON file and a JSON `settings` field.
@@ -23,7 +23,7 @@ Accepts multipart form data with a CSV, TSV, or JSON file and a JSON `settings`
CSV to JSON:
```bash
curl -X POST http://localhost:1349/api/v1/tools/csv-json \
curl -X POST http://localhost:1349/api/v1/tools/files/csv-json \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@users.csv" \
-F 'settings={"pretty": true}'
@@ -32,7 +32,7 @@ curl -X POST http://localhost:1349/api/v1/tools/csv-json \
JSON to CSV:
```bash
curl -X POST http://localhost:1349/api/v1/tools/csv-json \
curl -X POST http://localhost:1349/api/v1/tools/files/csv-json \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@users.json" \
-F 'settings={}'
@@ -8,7 +8,7 @@ Convert an EPUB e-book to PDF, Word (DOCX), HTML, or Markdown. Remote resources
## API Endpoint
`POST /api/v1/tools/epub-convert`
`POST /api/v1/tools/files/epub-convert`
Accepts multipart form data with an EPUB file and a JSON `settings` field.
@@ -21,7 +21,7 @@ Accepts multipart form data with an EPUB file and a JSON `settings` field.
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/epub-convert \
curl -X POST http://localhost:1349/api/v1/tools/files/epub-convert \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@book.epub" \
-F 'settings={"format": "pdf"}'
@@ -8,7 +8,7 @@ Convert Excel, OpenDocument, or CSV spreadsheets to PDF. Wide sheets may paginat
## API Endpoint
`POST /api/v1/tools/excel-to-pdf`
`POST /api/v1/tools/files/excel-to-pdf`
Accepts multipart form data with an Excel/ODS/CSV file.
@@ -19,7 +19,7 @@ This tool has no configurable parameters. Upload a spreadsheet and it will be co
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/excel-to-pdf \
curl -X POST http://localhost:1349/api/v1/tools/files/excel-to-pdf \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@budget.xlsx"
```
@@ -8,7 +8,7 @@ Safely extract files from a ZIP archive. Single-file archives return the contain
## API Endpoint
`POST /api/v1/tools/extract-zip`
`POST /api/v1/tools/files/extract-zip`
Accepts multipart form data with a ZIP file. No settings field is required.
@@ -19,7 +19,7 @@ This tool has no configurable parameters. Upload a `.zip` file to extract.
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/extract-zip \
curl -X POST http://localhost:1349/api/v1/tools/files/extract-zip \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@archive.zip"
```
@@ -8,7 +8,7 @@ Convert an HTML file to a styled PDF document. Remote resources (external images
## API Endpoint
`POST /api/v1/tools/html-to-pdf`
`POST /api/v1/tools/files/html-to-pdf`
Accepts multipart form data with an HTML file.
@@ -19,7 +19,7 @@ This tool has no configurable parameters. Upload an HTML file and it will be con
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/html-to-pdf \
curl -X POST http://localhost:1349/api/v1/tools/files/html-to-pdf \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@page.html"
```
@@ -8,7 +8,7 @@ Convert between JSON and XML formats in both directions. Upload a JSON file to g
## API Endpoint
`POST /api/v1/tools/json-xml`
`POST /api/v1/tools/files/json-xml`
Accepts multipart form data with a JSON or XML file and a JSON `settings` field.
@@ -23,7 +23,7 @@ Accepts multipart form data with a JSON or XML file and a JSON `settings` field.
JSON to XML:
```bash
curl -X POST http://localhost:1349/api/v1/tools/json-xml \
curl -X POST http://localhost:1349/api/v1/tools/files/json-xml \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@config.json" \
-F 'settings={"pretty": true}'
@@ -32,7 +32,7 @@ curl -X POST http://localhost:1349/api/v1/tools/json-xml \
XML to JSON:
```bash
curl -X POST http://localhost:1349/api/v1/tools/json-xml \
curl -X POST http://localhost:1349/api/v1/tools/files/json-xml \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@config.xml" \
-F 'settings={"pretty": true}'
@@ -8,7 +8,7 @@ Convert a Markdown file to a Word document (DOCX), preserving headings, lists, c
## API Endpoint
`POST /api/v1/tools/markdown-to-docx`
`POST /api/v1/tools/files/markdown-to-docx`
Accepts multipart form data with a Markdown file.
@@ -19,7 +19,7 @@ This tool has no configurable parameters. Upload a Markdown file and it will be
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/markdown-to-docx \
curl -X POST http://localhost:1349/api/v1/tools/files/markdown-to-docx \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@README.md"
```
@@ -8,7 +8,7 @@ Convert a Markdown file to a standalone HTML page. Remote images referenced in t
## API Endpoint
`POST /api/v1/tools/markdown-to-html`
`POST /api/v1/tools/files/markdown-to-html`
Accepts multipart form data with a Markdown file.
@@ -19,7 +19,7 @@ This tool has no configurable parameters. Upload a Markdown file and it will be
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/markdown-to-html \
curl -X POST http://localhost:1349/api/v1/tools/files/markdown-to-html \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@notes.md"
```
@@ -8,7 +8,7 @@ Convert a Markdown file to a styled PDF document. Remote resources are disabled
## API Endpoint
`POST /api/v1/tools/markdown-to-pdf`
`POST /api/v1/tools/files/markdown-to-pdf`
Accepts multipart form data with a Markdown file.
@@ -19,7 +19,7 @@ This tool has no configurable parameters. Upload a Markdown file and it will be
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/markdown-to-pdf \
curl -X POST http://localhost:1349/api/v1/tools/files/markdown-to-pdf \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@document.md"
```
@@ -8,7 +8,7 @@ Combine multiple CSV or TSV files with matching columns into a single merged fil
## API Endpoint
`POST /api/v1/tools/merge-csvs`
`POST /api/v1/tools/files/merge-csvs`
Accepts multipart form data with two or more CSV files. No settings field is required.
@@ -19,7 +19,7 @@ This tool has no configurable parameters. Upload 2--20 CSV or TSV files with mat
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/merge-csvs \
curl -X POST http://localhost:1349/api/v1/tools/files/merge-csvs \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@january.csv" \
-F "file=@february.csv" \
@@ -8,7 +8,7 @@ Convert PowerPoint or OpenDocument presentations to PDF, with one slide per page
## API Endpoint
`POST /api/v1/tools/powerpoint-to-pdf`
`POST /api/v1/tools/files/powerpoint-to-pdf`
Accepts multipart form data with a PowerPoint/ODP file.
@@ -19,7 +19,7 @@ This tool has no configurable parameters. Upload a presentation and it will be c
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/powerpoint-to-pdf \
curl -X POST http://localhost:1349/api/v1/tools/files/powerpoint-to-pdf \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@slides.pptx"
```
@@ -8,7 +8,7 @@ Split a large CSV or TSV file into smaller files by row count. Returns a ZIP arc
## API Endpoint
`POST /api/v1/tools/split-csv`
`POST /api/v1/tools/files/split-csv`
Accepts multipart form data with a CSV file and a JSON `settings` field.
@@ -22,7 +22,7 @@ Accepts multipart form data with a CSV file and a JSON `settings` field.
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/split-csv \
curl -X POST http://localhost:1349/api/v1/tools/files/split-csv \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@large-dataset.csv" \
-F 'settings={"rowsPerFile": 500, "keepHeader": true}'
@@ -8,7 +8,7 @@ Convert Word documents, Markdown, HTML, or plain text files into the EPUB e-book
## API Endpoint
`POST /api/v1/tools/to-epub`
`POST /api/v1/tools/files/to-epub`
Accepts multipart form data with a Word/Markdown/HTML/TXT file.
@@ -19,7 +19,7 @@ This tool has no configurable parameters. Upload a document and it will be conve
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/to-epub \
curl -X POST http://localhost:1349/api/v1/tools/files/to-epub \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@manuscript.docx"
```
@@ -8,7 +8,7 @@ Convert Word documents, OpenDocument text, RTF, or plain text files to PDF.
## API Endpoint
`POST /api/v1/tools/word-to-pdf`
`POST /api/v1/tools/files/word-to-pdf`
Accepts multipart form data with a Word/ODT/RTF/TXT file.
@@ -19,7 +19,7 @@ This tool has no configurable parameters. Upload a document and it will be conve
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/word-to-pdf \
curl -X POST http://localhost:1349/api/v1/tools/files/word-to-pdf \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@report.docx"
```
@@ -8,7 +8,7 @@ Extract repeating elements from an XML file into a flat CSV table. The tool auto
## API Endpoint
`POST /api/v1/tools/xml-to-csv`
`POST /api/v1/tools/files/xml-to-csv`
Accepts multipart form data with an XML file. No settings field is required.
@@ -19,7 +19,7 @@ This tool has no configurable parameters. The repeating element is auto-detected
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/xml-to-csv \
curl -X POST http://localhost:1349/api/v1/tools/files/xml-to-csv \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@catalog.xml"
```
@@ -40,4 +40,4 @@ curl -X POST http://localhost:1349/api/v1/tools/xml-to-csv \
- Only `.xml` files are accepted as input.
- The tool scans the XML tree for the first repeating set of sibling elements and uses those as rows.
- Each unique child element or attribute name becomes a CSV column header.
- This is a one-way conversion. For bidirectional JSON/XML conversion, use the [JSON to XML](/tools/data/json-xml) tool.
- This is a one-way conversion. For bidirectional JSON/XML conversion, use the [JSON to XML](/tools/files/json-xml) tool.
@@ -8,7 +8,7 @@ Convert between YAML and JSON formats in both directions. Upload a YAML file to
## API Endpoint
`POST /api/v1/tools/yaml-json`
`POST /api/v1/tools/files/yaml-json`
Accepts multipart form data with a YAML or JSON file. No settings field is required.
@@ -21,7 +21,7 @@ This tool has no configurable parameters. The conversion direction is determined
YAML to JSON:
```bash
curl -X POST http://localhost:1349/api/v1/tools/yaml-json \
curl -X POST http://localhost:1349/api/v1/tools/files/yaml-json \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@config.yaml"
```
@@ -29,7 +29,7 @@ curl -X POST http://localhost:1349/api/v1/tools/yaml-json \
JSON to YAML:
```bash
curl -X POST http://localhost:1349/api/v1/tools/yaml-json \
curl -X POST http://localhost:1349/api/v1/tools/files/yaml-json \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@config.json"
```
+4 -4
View File
@@ -8,7 +8,7 @@ Comprehensive color adjustment tool combining brightness, contrast, exposure, sa
## API Endpoint
`POST /api/v1/tools/adjust-colors`
`POST /api/v1/tools/image/adjust-colors`
Accepts multipart form data with an image file and a JSON `settings` field.
@@ -32,7 +32,7 @@ Accepts multipart form data with an image file and a JSON `settings` field.
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/adjust-colors \
curl -X POST http://localhost:1349/api/v1/tools/image/adjust-colors \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@photo.jpg" \
-F 'settings={"brightness": 20, "contrast": 10, "saturation": -30, "effect": "none"}'
@@ -41,7 +41,7 @@ curl -X POST http://localhost:1349/api/v1/tools/adjust-colors \
Apply a warm vintage look:
```bash
curl -X POST http://localhost:1349/api/v1/tools/adjust-colors \
curl -X POST http://localhost:1349/api/v1/tools/image/adjust-colors \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@photo.jpg" \
-F 'settings={"temperature": 40, "saturation": -15, "contrast": 10, "effect": "sepia"}'
@@ -64,5 +64,5 @@ curl -X POST http://localhost:1349/api/v1/tools/adjust-colors \
- Adjustments are applied in this order: brightness, contrast, exposure, saturation/hue, temperature/tint, sharpness, channels, effects.
- Temperature uses a 3x3 color recombination matrix on the blue-orange and green-magenta axes.
- Exposure maps to Sharp's gamma function (positive brightens midtones, negative darkens them).
- This endpoint also responds at the legacy paths `/api/v1/tools/brightness-contrast`, `/api/v1/tools/saturation`, `/api/v1/tools/color-channels`, and `/api/v1/tools/color-effects`. All use the same schema.
- This endpoint also responds at the legacy paths `/api/v1/tools/image/brightness-contrast`, `/api/v1/tools/image/saturation`, `/api/v1/tools/image/color-channels`, and `/api/v1/tools/image/color-effects`. All use the same schema.
- Output format matches the input format. HEIC, RAW, PSD, and SVG inputs are automatically decoded before processing.
+2 -2
View File
@@ -4,7 +4,7 @@ Expand the canvas of an image with AI-powered fill (outpainting). Extends the im
## API Endpoint
`POST /api/v1/tools/ai-canvas-expand`
`POST /api/v1/tools/image/ai-canvas-expand`
**Processing:** Asynchronous (returns 202, poll `/api/v1/jobs/{jobId}/progress` for status via SSE)
@@ -28,7 +28,7 @@ At least one extend direction must be greater than 0.
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/ai-canvas-expand \
curl -X POST http://localhost:1349/api/v1/tools/image/ai-canvas-expand \
-F "file=@photo.jpg" \
-F 'settings={"extendTop":200,"extendBottom":200,"extendLeft":100,"extendRight":100,"tier":"balanced"}'
```
+2 -2
View File
@@ -8,7 +8,7 @@ Replace the background of an image with a solid color or gradient. The AI model
## API Endpoint
`POST /api/v1/tools/background-replace`
`POST /api/v1/tools/image/background-replace`
Accepts multipart form data with an image file and a JSON `settings` field.
@@ -27,7 +27,7 @@ Accepts multipart form data with an image file and a JSON `settings` field.
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/background-replace \
curl -X POST http://localhost:1349/api/v1/tools/image/background-replace \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@photo.jpg" \
-F 'settings={"backgroundType": "color", "color": "#2563eb", "feather": 2}'
+2 -2
View File
@@ -8,7 +8,7 @@ Generate barcode images from text input. Supports Code 128, EAN-13, UPC-A, Code
## API Endpoint
`POST /api/v1/tools/barcode-generate`
`POST /api/v1/tools/image/barcode-generate`
Accepts an `application/json` body (not multipart). The barcode is generated from the provided text, not from an uploaded file.
@@ -24,7 +24,7 @@ Accepts an `application/json` body (not multipart). The barcode is generated fro
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/barcode-generate \
curl -X POST http://localhost:1349/api/v1/tools/image/barcode-generate \
-H "Authorization: Bearer si_your-api-key" \
-H "Content-Type: application/json" \
-d '{"text": "5901234123457", "type": "ean13", "scale": 4}'
+2 -2
View File
@@ -8,7 +8,7 @@ Scan uploaded images for all types of barcodes and QR codes. Returns decoded tex
## API Endpoint
`POST /api/v1/tools/barcode-read`
`POST /api/v1/tools/image/barcode-read`
Accepts multipart form data with an image file and an optional JSON `settings` field.
@@ -21,7 +21,7 @@ Accepts multipart form data with an image file and an optional JSON `settings` f
## Example Request
```bash
curl -X POST http://localhost:1349/api/v1/tools/barcode-read \
curl -X POST http://localhost:1349/api/v1/tools/image/barcode-read \
-H "Authorization: Bearer si_your-api-key" \
-F "file=@receipt.jpg" \
-F 'settings={"tryHarder": true}'

Some files were not shown because too many files have changed in this diff Show More