UNPKG

short-video-maker

Version:

Creates short videos for TikTok, Instagram Reels, and YouTube Shorts using the Model Context Protocol (MCP) and a REST API.

176 lines (175 loc) 6.81 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.APIRouter = void 0; const express_1 = __importDefault(require("express")); const fs_extra_1 = __importDefault(require("fs-extra")); const path_1 = __importDefault(require("path")); const validator_1 = require("../validator"); const logger_1 = require("../../logger"); // todo abstract class class APIRouter { router; shortCreator; config; constructor(config, shortCreator) { this.config = config; this.router = express_1.default.Router(); this.shortCreator = shortCreator; this.router.use(express_1.default.json()); this.setupRoutes(); } setupRoutes() { this.router.post("/short-video", async (req, res) => { try { const input = (0, validator_1.validateCreateShortInput)(req.body); logger_1.logger.info({ input }, "Creating short video"); const videoId = this.shortCreator.addToQueue(input.scenes, input.config); res.status(201).json({ videoId, }); } catch (error) { logger_1.logger.error(error, "Error validating input"); // Handle validation errors specifically if (error instanceof Error && error.message.startsWith("{")) { try { const errorData = JSON.parse(error.message); res.status(400).json({ error: "Validation failed", message: errorData.message, missingFields: errorData.missingFields, }); return; } catch (parseError) { logger_1.logger.error(parseError, "Error parsing validation error"); } } // Fallback for other errors res.status(400).json({ error: "Invalid input", message: error instanceof Error ? error.message : "Unknown error", }); } }); this.router.get("/short-video/:videoId/status", async (req, res) => { const { videoId } = req.params; if (!videoId) { res.status(400).json({ error: "videoId is required", }); return; } const status = this.shortCreator.status(videoId); res.status(200).json({ status, }); }); this.router.get("/music-tags", (req, res) => { res.status(200).json(this.shortCreator.ListAvailableMusicTags()); }); this.router.get("/voices", (req, res) => { res.status(200).json(this.shortCreator.ListAvailableVoices()); }); this.router.get("/short-videos", (req, res) => { const videos = this.shortCreator.listAllVideos(); res.status(200).json({ videos, }); }); this.router.delete("/short-video/:videoId", (req, res) => { const { videoId } = req.params; if (!videoId) { res.status(400).json({ error: "videoId is required", }); return; } this.shortCreator.deleteVideo(videoId); res.status(200).json({ success: true, }); }); this.router.get("/tmp/:tmpFile", (req, res) => { const { tmpFile } = req.params; if (!tmpFile) { res.status(400).json({ error: "tmpFile is required", }); return; } const tmpFilePath = path_1.default.join(this.config.tempDirPath, tmpFile); if (!fs_extra_1.default.existsSync(tmpFilePath)) { res.status(404).json({ error: "tmpFile not found", }); return; } if (tmpFile.endsWith(".mp3")) { res.setHeader("Content-Type", "audio/mpeg"); } if (tmpFile.endsWith(".wav")) { res.setHeader("Content-Type", "audio/wav"); } const tmpFileStream = fs_extra_1.default.createReadStream(tmpFilePath); tmpFileStream.on("error", (error) => { logger_1.logger.error(error, "Error reading tmp file"); res.status(500).json({ error: "Error reading tmp file", tmpFile, }); }); tmpFileStream.pipe(res); }); this.router.get("/music/:fileName", (req, res) => { const { fileName } = req.params; if (!fileName) { res.status(400).json({ error: "fileName is required", }); return; } const musicFilePath = path_1.default.join(this.config.musicDirPath, fileName); if (!fs_extra_1.default.existsSync(musicFilePath)) { res.status(404).json({ error: "music file not found", }); return; } const musicFileStream = fs_extra_1.default.createReadStream(musicFilePath); musicFileStream.on("error", (error) => { logger_1.logger.error(error, "Error reading music file"); res.status(500).json({ error: "Error reading music file", fileName, }); }); musicFileStream.pipe(res); }); this.router.get("/short-video/:videoId", (req, res) => { try { const { videoId } = req.params; if (!videoId) { res.status(400).json({ error: "videoId is required", }); return; } const video = this.shortCreator.getVideo(videoId); res.setHeader("Content-Type", "video/mp4"); res.setHeader("Content-Disposition", `inline; filename=${videoId}.mp4`); res.send(video); } catch (error) { logger_1.logger.error(error, "Error getting video"); res.status(404).json({ error: "Video not found", }); } }); } } exports.APIRouter = APIRouter;