File size: 3,004 Bytes
2cae2a9
2f67628
 
2cae2a9
1083ad0
2f67628
2cae2a9
3165afb
 
 
 
2cae2a9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
be866be
 
1fc1c4d
 
 
 
 
 
 
 
 
be866be
 
 
4cb7ad9
2cae2a9
be866be
4d290bc
 
4cb7ad9
 
 
 
 
 
 
 
 
 
 
2cae2a9
 
 
 
 
 
 
 
46fcec6
 
a975a07
a5053d8
 
4d290bc
46fcec6
 
 
 
4cb7ad9
4d290bc
 
46fcec6
 
 
 
74dba9a
46fcec6
 
2cae2a9
4d290bc
2cae2a9
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

import { Blob } from "node:buffer"

import express from "express"
import queryString from "query-string"
import { parseClap, ClapProject } from "@aitube/clap"

import { clapToTmpVideoFilePath } from "./main"
// import { defaultExportFormat, type SupportedExportFormat } from "@aitube/ffmpeg"
import { defaultExportFormat, type SupportedExportFormat } from "./bug-in-bun/aitube_ffmpeg"
import { deleteFile } from "@aitube/io"

const app = express()
const port = 7860

process.on('unhandledRejection', (reason: string, p: Promise<any>) => {
  console.error('Unhandled Rejection at:', p, 'reason:', reason);
})

process.on('uncaughtException', (error: Error) => {
  console.error(`Caught exception: ${error}\n` + `Exception origin: ${error.stack}`);
})

// fix this error: "PayloadTooLargeError: request entity too large"
// there are multiple version because.. yeah well, it's Express!
// app.use(bodyParser.json({limit: '50mb'}));
//app.use(bodyParser.urlencoded({limit: '50mb', extended: true}));
app.use(express.json({ limit: '200mb' }));
app.use(express.urlencoded({ limit: '200mb', extended: true }));

app.get("/", async (req, res) => {
  res.status(200)
  res.write(`<html>
  <head></head>
  <body>
    <p style="color: black; font-family: monospace;">
      This API is a component of the Clap-to-MP4 rendering service provided by AiTube.<br/>
      It is used for instance by the Stories Factory.
    </p>
  </body>
<html>`)
  res.end()
})


// the export robot has only one job: to export .clap files
app.post("/", async (req, res) => {
  console.log("receiving POST request")

  const qs = queryString.parseUrl(req.url || "")
  const query = (qs || {}).query

  let format: SupportedExportFormat = defaultExportFormat
  try {
    format = decodeURIComponent(query?.f?.toString() || defaultExportFormat).trim() as SupportedExportFormat
    if (format !== "mp4" && format !== "webm") {
      format = defaultExportFormat
    }
  } catch (err) {}

  let data: Uint8Array[] = [];

  req.on("data", (chunk) => {
    data.push(chunk);
  });

  req.on("end", async () => {
    try {
      let fileData = Buffer.concat(data)

      const clap: ClapProject = await parseClap(new Blob([fileData]));

      // not! that is too large!!!
      console.log("got a clap project:", clap?.meta?.description)

      const {
        tmpWorkDir,
        outputFilePath,
      } = await clapToTmpVideoFilePath({ clap, format })
      
      console.log(`got an output ${format} file at:`, outputFilePath)

      res.download(outputFilePath, async () => {
        // clean-up after ourselves (we clear the whole tmp directory)
        await deleteFile(tmpWorkDir)
        // console.log("cleared the temporary folder")
      })
      return
    } catch (err) {
      console.log(`failed to process the request\n${err}`)
      res.status(500)
      res.write(JSON.stringify({ "error": `${err}` }))
      res.end()
      return
    }
  });
})

app.listen(port, () => {
  console.log(`Open http://localhost:${port}`)
})