jbilcke-hf HF staff commited on
Commit
9571f2e
·
1 Parent(s): d0c6523

ready for release (sort of)

Browse files
src/index.mts CHANGED
@@ -1,6 +1,7 @@
1
  import { createReadStream, existsSync } from "node:fs"
2
  import path from "node:path"
3
 
 
4
  import express from "express"
5
 
6
  import { VideoTask, VideoTaskRequest } from "./types.mts"
@@ -12,7 +13,12 @@ import { completedFilesDirFilePath } from "./config.mts"
12
  import { deleteTask } from "./scheduler/deleteTask.mts"
13
  import { getPendingTasks } from "./scheduler/getPendingTasks.mts"
14
  import { hasValidAuthorization } from "./utils/hasValidAuthorization.mts"
 
 
15
 
 
 
 
16
  main()
17
 
18
  const app = express()
@@ -59,9 +65,8 @@ app.post("/", async (req, res) => {
59
  }
60
  })
61
 
62
- // get all pending tasks
63
- app.get("/", async (req, res) => {
64
-
65
  if (!hasValidAuthorization(req.headers)) {
66
  console.log("Invalid authorization")
67
  res.status(401)
@@ -70,21 +75,35 @@ app.get("/", async (req, res) => {
70
  return
71
  }
72
 
 
 
 
 
 
 
 
 
 
 
73
  try {
74
- const tasks = await getPendingTasks()
75
  res.status(200)
76
  res.write(JSON.stringify(tasks, null, 2))
77
  res.end()
78
  } catch (err) {
79
  console.error(err)
80
  res.status(500)
81
- res.write(JSON.stringify({ error: "couldn't get the tasks" }))
82
  res.end()
83
  }
84
  })
85
 
86
- app.get("/:id", async (req, res) => {
87
 
 
 
 
 
88
  if (!hasValidAuthorization(req.headers)) {
89
  console.log("Invalid authorization")
90
  res.status(401)
@@ -92,55 +111,96 @@ app.get("/:id", async (req, res) => {
92
  res.end()
93
  return
94
  }
 
95
 
96
- try {
97
- const task = await getTask(req.params.id)
98
- res.status(200)
99
- res.write(JSON.stringify(task))
 
 
 
 
 
 
 
 
 
 
 
100
  res.end()
 
 
 
 
 
 
 
101
  } catch (err) {
102
- console.error(err)
103
  res.status(404)
104
- res.write(JSON.stringify({ error: "couldn't find this task" }))
105
  res.end()
 
106
  }
107
- })
108
 
109
- app.delete("/:id", async (req, res) => {
110
-
111
- if (!hasValidAuthorization(req.headers)) {
112
- console.log("Invalid authorization")
113
- res.status(401)
114
- res.write(JSON.stringify({ error: "invalid token" }))
 
 
115
  res.end()
116
  return
117
  }
118
 
119
-
120
- let task: VideoTask = null
121
  try {
122
- task = await getTask(req.params.id)
 
 
 
 
 
 
 
 
 
 
 
123
  } catch (err) {
124
- console.error(err)
125
- res.status(404)
126
- res.write(JSON.stringify({ error: "couldn't find this task" }))
127
  res.end()
128
  }
 
 
 
 
 
 
 
 
 
 
 
129
 
130
  try {
131
- await deleteTask(task)
132
  res.status(200)
133
- res.write(JSON.stringify({ success: true }))
134
  res.end()
135
  } catch (err) {
136
  console.error(err)
137
  res.status(500)
138
- res.write(JSON.stringify({ success: false, error: "failed to delete the task" }))
139
  res.end()
140
  }
141
  })
142
 
143
- app.get("/video/:id\.mp4", async (req, res) => {
144
 
145
  if (!hasValidAuthorization(req.headers)) {
146
  console.log("Invalid authorization")
@@ -150,55 +210,85 @@ app.get("/video/:id\.mp4", async (req, res) => {
150
  return
151
  }
152
 
 
153
 
154
- if (!req.params.id) {
 
155
  res.status(400)
156
- res.write(JSON.stringify({ error: "please provide a valid video id" }))
 
 
 
 
 
 
 
 
 
157
  res.end()
158
  return
159
  }
160
 
161
- let task: VideoTask = null
162
  try {
163
- task = await getTask(req.params.id)
164
- console.log("returning result to user..")
 
 
165
  } catch (err) {
 
166
  res.status(404)
167
- res.write(JSON.stringify({ error: "this video doesn't exist" }))
 
 
 
 
 
 
 
 
 
 
168
  res.end()
169
  return
170
  }
171
 
172
- const completedFilePath = path.join(completedFilesDirFilePath, task.fileName)
173
 
174
- // note: we DON'T want to use the pending file path, as there may be operations on it
175
- // (ie. a process might be busy writing stuff to it)
176
- const filePath = existsSync(completedFilePath) ? completedFilePath : ""
177
- if (!filePath) {
178
  res.status(400)
179
- res.write(JSON.stringify({ error: "video exists, but cannot be previewed yet" }))
180
  res.end()
181
  return
182
  }
183
 
184
- // file path exists, let's try to read it
 
 
 
 
 
 
 
 
185
  try {
186
- // do we need this?
187
- // res.status(200)
188
- // res.setHeader("Content-Type", "media/mp4")
189
- console.log(`creating a video read stream from ${filePath}`)
190
- const stream = createReadStream(filePath)
191
-
192
- stream.on('close', () => {
193
- console.log(`finished streaming the video`)
194
- res.end()
195
- })
196
-
197
- stream.pipe(res)
198
  } catch (err) {
199
- console.error(`failed to read the video file at ${filePath}: ${err}`)
 
 
 
 
 
 
 
 
 
 
 
 
200
  res.status(500)
201
- res.write(JSON.stringify({ error: "failed to read the video file" }))
202
  res.end()
203
  }
204
  })
 
1
  import { createReadStream, existsSync } from "node:fs"
2
  import path from "node:path"
3
 
4
+ import { validate as uuidValidate } from "uuid"
5
  import express from "express"
6
 
7
  import { VideoTask, VideoTaskRequest } from "./types.mts"
 
13
  import { deleteTask } from "./scheduler/deleteTask.mts"
14
  import { getPendingTasks } from "./scheduler/getPendingTasks.mts"
15
  import { hasValidAuthorization } from "./utils/hasValidAuthorization.mts"
16
+ import { getAllTasksForOwner } from "./scheduler/getAllTasksForOwner.mts"
17
+ import { initFolders } from "./initFolders.mts"
18
 
19
+ initFolders()
20
+ // to disable all processing (eg. to debug)
21
+ // then comment the following line:
22
  main()
23
 
24
  const app = express()
 
65
  }
66
  })
67
 
68
+ // only get the tasks for a specific owner
69
+ app.get("/owner/:ownerId", async (req, res) => {
 
70
  if (!hasValidAuthorization(req.headers)) {
71
  console.log("Invalid authorization")
72
  res.status(401)
 
75
  return
76
  }
77
 
78
+ const ownerId = req.params.ownerId
79
+
80
+ if (!uuidValidate(ownerId)) {
81
+ console.error("invalid owner id")
82
+ res.status(400)
83
+ res.write(JSON.stringify({ error: `invalid owner id` }))
84
+ res.end()
85
+ return
86
+ }
87
+
88
  try {
89
+ const tasks = await getAllTasksForOwner(ownerId)
90
  res.status(200)
91
  res.write(JSON.stringify(tasks, null, 2))
92
  res.end()
93
  } catch (err) {
94
  console.error(err)
95
  res.status(500)
96
+ res.write(JSON.stringify({ error: `couldn't get the tasks for owner ${ownerId}` }))
97
  res.end()
98
  }
99
  })
100
 
101
+ app.get("/download/:id\.mp4", async (req, res) => {
102
 
103
+ /*
104
+ for simplicity, let's skip auth when fetching videos
105
+ the UUIDs cannot easily be guessed anyway
106
+
107
  if (!hasValidAuthorization(req.headers)) {
108
  console.log("Invalid authorization")
109
  res.status(401)
 
111
  res.end()
112
  return
113
  }
114
+ */
115
 
116
+ const [ownerId, videoId] = `${req.params.id}`.split("_")
117
+
118
+ if (!uuidValidate(ownerId)) {
119
+ console.error("invalid owner id")
120
+ res.status(400)
121
+ res.write(JSON.stringify({ error: `invalid owner id` }))
122
+ res.end()
123
+ return
124
+ }
125
+
126
+
127
+ if (!uuidValidate(videoId)) {
128
+ console.error("invalid video id")
129
+ res.status(400)
130
+ res.write(JSON.stringify({ error: `invalid video id` }))
131
  res.end()
132
+ return
133
+ }
134
+
135
+ let task: VideoTask = null
136
+ try {
137
+ task = await getTask(ownerId, videoId)
138
+ console.log(`returning video ${videoId} to owner ${ownerId}`)
139
  } catch (err) {
 
140
  res.status(404)
141
+ res.write(JSON.stringify({ error: "this video doesn't exist" }))
142
  res.end()
143
+ return
144
  }
 
145
 
146
+ const completedFilePath = path.join(completedFilesDirFilePath, task.fileName)
147
+
148
+ // note: we DON'T want to use the pending file path, as there may be operations on it
149
+ // (ie. a process might be busy writing stuff to it)
150
+ const filePath = existsSync(completedFilePath) ? completedFilePath : ""
151
+ if (!filePath) {
152
+ res.status(400)
153
+ res.write(JSON.stringify({ error: "video exists, but cannot be previewed yet" }))
154
  res.end()
155
  return
156
  }
157
 
158
+ // file path exists, let's try to read it
 
159
  try {
160
+ // do we need this?
161
+ // res.status(200)
162
+ // res.setHeader("Content-Type", "media/mp4")
163
+ console.log(`creating a video read stream from ${filePath}`)
164
+ const stream = createReadStream(filePath)
165
+
166
+ stream.on('close', () => {
167
+ console.log(`finished streaming the video`)
168
+ res.end()
169
+ })
170
+
171
+ stream.pipe(res)
172
  } catch (err) {
173
+ console.error(`failed to read the video file at ${filePath}: ${err}`)
174
+ res.status(500)
175
+ res.write(JSON.stringify({ error: "failed to read the video file" }))
176
  res.end()
177
  }
178
+ })
179
+
180
+ // get all pending tasks
181
+ app.get("/", async (req, res) => {
182
+ if (!hasValidAuthorization(req.headers)) {
183
+ console.log("Invalid authorization")
184
+ res.status(401)
185
+ res.write(JSON.stringify({ error: "invalid token" }))
186
+ res.end()
187
+ return
188
+ }
189
 
190
  try {
191
+ const tasks = await getPendingTasks()
192
  res.status(200)
193
+ res.write(JSON.stringify(tasks, null, 2))
194
  res.end()
195
  } catch (err) {
196
  console.error(err)
197
  res.status(500)
198
+ res.write(JSON.stringify({ error: "couldn't get the tasks" }))
199
  res.end()
200
  }
201
  })
202
 
203
+ app.get("/:id", async (req, res) => {
204
 
205
  if (!hasValidAuthorization(req.headers)) {
206
  console.log("Invalid authorization")
 
210
  return
211
  }
212
 
213
+ const [ownerId, videoId] = `${req.params.id}`.split("_")
214
 
215
+ if (!uuidValidate(ownerId)) {
216
+ console.error("invalid owner id")
217
  res.status(400)
218
+ res.write(JSON.stringify({ error: `invalid owner id` }))
219
+ res.end()
220
+ return
221
+ }
222
+
223
+
224
+ if (!uuidValidate(videoId)) {
225
+ console.error("invalid video id")
226
+ res.status(400)
227
+ res.write(JSON.stringify({ error: `invalid video id` }))
228
  res.end()
229
  return
230
  }
231
 
 
232
  try {
233
+ const task = await getTask(ownerId, videoId)
234
+ res.status(200)
235
+ res.write(JSON.stringify(task))
236
+ res.end()
237
  } catch (err) {
238
+ console.error(err)
239
  res.status(404)
240
+ res.write(JSON.stringify({ error: "couldn't find this task" }))
241
+ res.end()
242
+ }
243
+ })
244
+
245
+ app.delete("/:id", async (req, res) => {
246
+
247
+ if (!hasValidAuthorization(req.headers)) {
248
+ console.log("Invalid authorization")
249
+ res.status(401)
250
+ res.write(JSON.stringify({ error: "invalid token" }))
251
  res.end()
252
  return
253
  }
254
 
255
+ const [ownerId, videoId] = `${req.params.id}`.split("_")
256
 
257
+ if (!uuidValidate(ownerId)) {
258
+ console.error("invalid owner id")
 
 
259
  res.status(400)
260
+ res.write(JSON.stringify({ error: `invalid owner id` }))
261
  res.end()
262
  return
263
  }
264
 
265
+ if (!uuidValidate(videoId)) {
266
+ console.error("invalid video id")
267
+ res.status(400)
268
+ res.write(JSON.stringify({ error: `invalid video id` }))
269
+ res.end()
270
+ return
271
+ }
272
+
273
+ let task: VideoTask = null
274
  try {
275
+ task = await getTask(ownerId, videoId)
 
 
 
 
 
 
 
 
 
 
 
276
  } catch (err) {
277
+ console.error(err)
278
+ res.status(404)
279
+ res.write(JSON.stringify({ error: "couldn't find this task" }))
280
+ res.end()
281
+ }
282
+
283
+ try {
284
+ await deleteTask(task)
285
+ res.status(200)
286
+ res.write(JSON.stringify({ success: true }))
287
+ res.end()
288
+ } catch (err) {
289
+ console.error(err)
290
  res.status(500)
291
+ res.write(JSON.stringify({ success: false, error: "failed to delete the task" }))
292
  res.end()
293
  }
294
  })
src/main.mts CHANGED
@@ -2,8 +2,6 @@ import { initFolders } from "./initFolders.mts"
2
  import { getPendingTasks } from "./scheduler/getPendingTasks.mts"
3
  import { processTask } from "./scheduler/processTask.mts"
4
 
5
- initFolders()
6
-
7
  export const main = async () => {
8
 
9
  const tasks = await getPendingTasks()
 
2
  import { getPendingTasks } from "./scheduler/getPendingTasks.mts"
3
  import { processTask } from "./scheduler/processTask.mts"
4
 
 
 
5
  export const main = async () => {
6
 
7
  const tasks = await getPendingTasks()
src/scheduler/deleteTask.mts CHANGED
@@ -10,7 +10,7 @@ import { deleteFileIfExists } from "../utils/deleteFileIfExists.mts"
10
 
11
 
12
  export const deleteTask = async (task: VideoTask) => {
13
- const taskFileName = `${task.id}.json`
14
  const videoFileName = task.fileName
15
 
16
  // .mp4 files
 
10
 
11
 
12
  export const deleteTask = async (task: VideoTask) => {
13
+ const taskFileName = `${task.ownerId}_${task.id}.json`
14
  const videoFileName = task.fileName
15
 
16
  // .mp4 files
src/scheduler/getAllTasksForOwner.mts ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import { VideoTask } from "../types.mts"
2
+ import { getCompletedTasks } from "./getCompletedTasks.mts"
3
+ import { getPendingTasks } from "./getPendingTasks.mts"
4
+
5
+ export const getAllTasksForOwner = async (ownerId: string): Promise<VideoTask[]> => {
6
+ const pendingTasks = await getPendingTasks(ownerId)
7
+ const completedTasks = await getCompletedTasks(ownerId)
8
+ return [...pendingTasks, ...completedTasks]
9
+ }
src/scheduler/getCompletedTasks.mts CHANGED
@@ -2,8 +2,8 @@ import { VideoTask } from "../types.mts"
2
  import { completedTasksDirFilePath } from "../config.mts"
3
  import { readTasks } from "./readTasks.mts"
4
 
5
- export const getCompletedTasks = async (): Promise<VideoTask[]> => {
6
- const completedTasks = await readTasks(completedTasksDirFilePath)
7
 
8
  return completedTasks
9
  }
 
2
  import { completedTasksDirFilePath } from "../config.mts"
3
  import { readTasks } from "./readTasks.mts"
4
 
5
+ export const getCompletedTasks = async (ownerId?: string): Promise<VideoTask[]> => {
6
+ const completedTasks = await readTasks(completedTasksDirFilePath, ownerId)
7
 
8
  return completedTasks
9
  }
src/scheduler/getPendingTasks.mts CHANGED
@@ -2,8 +2,8 @@ import { VideoTask } from "../types.mts"
2
  import { pendingTasksDirFilePath } from "../config.mts"
3
  import { readTasks } from "./readTasks.mts"
4
 
5
- export const getPendingTasks = async (): Promise<VideoTask[]> => {
6
- const pendingTasks = await readTasks(pendingTasksDirFilePath)
7
 
8
  return pendingTasks
9
  }
 
2
  import { pendingTasksDirFilePath } from "../config.mts"
3
  import { readTasks } from "./readTasks.mts"
4
 
5
+ export const getPendingTasks = async (ownerId?: string): Promise<VideoTask[]> => {
6
+ const pendingTasks = await readTasks(pendingTasksDirFilePath, ownerId)
7
 
8
  return pendingTasks
9
  }
src/scheduler/getTask.mts CHANGED
@@ -3,8 +3,8 @@ import path from "node:path"
3
  import { completedTasksDirFilePath, pendingTasksDirFilePath } from "../config.mts"
4
  import { readTask } from "./readTask.mts"
5
 
6
- export const getTask = async (id: string) => {
7
- const taskFileName = `${id}.json`
8
 
9
  const completedTaskFilePath = path.join(completedTasksDirFilePath, taskFileName)
10
  const pendingTaskFilePath = path.join(pendingTasksDirFilePath, taskFileName)
@@ -17,7 +17,7 @@ export const getTask = async (id: string) => {
17
  const pendingTask = await readTask(pendingTaskFilePath)
18
  return pendingTask
19
  } catch (err) {
20
- throw new Error(`couldn't find task ${id}`)
21
  }
22
  }
23
  }
 
3
  import { completedTasksDirFilePath, pendingTasksDirFilePath } from "../config.mts"
4
  import { readTask } from "./readTask.mts"
5
 
6
+ export const getTask = async (ownerId: string, videoId: string) => {
7
+ const taskFileName = `${ownerId}_${videoId}.json`
8
 
9
  const completedTaskFilePath = path.join(completedTasksDirFilePath, taskFileName)
10
  const pendingTaskFilePath = path.join(pendingTasksDirFilePath, taskFileName)
 
17
  const pendingTask = await readTask(pendingTaskFilePath)
18
  return pendingTask
19
  } catch (err) {
20
+ throw new Error(`couldn't find video task ${videoId} for owner ${ownerId}`)
21
  }
22
  }
23
  }
src/scheduler/processTask.mts CHANGED
@@ -11,6 +11,7 @@ import { interpolateVideo } from "../production/interpolateVideo.mts"
11
  import { postInterpolation } from "../production/postInterpolation.mts"
12
  import { moveVideoFromPendingToCompleted } from "../utils/moveVideoFromPendingToCompleted.mts"
13
  import { assembleShots } from "../production/assembleShots.mts"
 
14
 
15
  export const processTask = async (task: VideoTask) => {
16
  console.log(`processing video task ${task.id}`)
@@ -118,6 +119,8 @@ export const processTask = async (task: VideoTask) => {
118
  shot.nbCompletedSteps++
119
 
120
  await updatePendingTask(task)
 
 
121
  } catch (err) {
122
  console.error(`failed to upscale shot ${shot.id} (${err})`)
123
  // something is wrong, let's put the whole thing back into the queue
@@ -155,6 +158,8 @@ export const processTask = async (task: VideoTask) => {
155
 
156
  await updatePendingTask(task)
157
 
 
 
158
  } catch (err) {
159
  console.error(`failed to interpolate shot ${shot.id} (${err})`)
160
  // something is wrong, let's put the whole thing back into the queue
@@ -183,6 +188,8 @@ export const processTask = async (task: VideoTask) => {
183
 
184
  await updatePendingTask(task)
185
 
 
 
186
  } catch (err) {
187
  console.error(`failed to post-process shot ${shot.id} (${err})`)
188
  // something is wrong, let's put the whole thing back into the queue
 
11
  import { postInterpolation } from "../production/postInterpolation.mts"
12
  import { moveVideoFromPendingToCompleted } from "../utils/moveVideoFromPendingToCompleted.mts"
13
  import { assembleShots } from "../production/assembleShots.mts"
14
+ import { copyVideoFromPendingToCompleted } from "../utils/copyVideoFromPendingToCompleted.mts"
15
 
16
  export const processTask = async (task: VideoTask) => {
17
  console.log(`processing video task ${task.id}`)
 
119
  shot.nbCompletedSteps++
120
 
121
  await updatePendingTask(task)
122
+
123
+ await copyVideoFromPendingToCompleted(shot.fileName, task.fileName)
124
  } catch (err) {
125
  console.error(`failed to upscale shot ${shot.id} (${err})`)
126
  // something is wrong, let's put the whole thing back into the queue
 
158
 
159
  await updatePendingTask(task)
160
 
161
+ await copyVideoFromPendingToCompleted(shot.fileName, task.fileName)
162
+
163
  } catch (err) {
164
  console.error(`failed to interpolate shot ${shot.id} (${err})`)
165
  // something is wrong, let's put the whole thing back into the queue
 
188
 
189
  await updatePendingTask(task)
190
 
191
+ await copyVideoFromPendingToCompleted(shot.fileName, task.fileName)
192
+
193
  } catch (err) {
194
  console.error(`failed to post-process shot ${shot.id} (${err})`)
195
  // something is wrong, let's put the whole thing back into the queue
src/scheduler/readTask.mts CHANGED
@@ -1,5 +1,4 @@
1
  import { promises as fs } from "node:fs"
2
- import path from "node:path"
3
 
4
  import { VideoTask } from "../types.mts"
5
 
 
1
  import { promises as fs } from "node:fs"
 
2
 
3
  import { VideoTask } from "../types.mts"
4
 
src/scheduler/readTasks.mts CHANGED
@@ -5,7 +5,7 @@ import { VideoTask } from "../types.mts"
5
  import { readTask } from "./readTask.mts"
6
 
7
 
8
- export const readTasks = async (taskDirFilePath: string): Promise<VideoTask[]> => {
9
 
10
  let tasksFiles: string[] = []
11
  try {
@@ -13,7 +13,9 @@ export const readTasks = async (taskDirFilePath: string): Promise<VideoTask[]> =
13
  // console.log("filesInDir:", filesInDir)
14
 
15
  // we only keep valid files (in UUID.json format)
16
- tasksFiles = filesInDir.filter(fileName => fileName.match(/[a-z0-9\-]\.json/i))
 
 
17
 
18
  // console.log("tasksfiles:", tasksFiles)
19
  } catch (err) {
 
5
  import { readTask } from "./readTask.mts"
6
 
7
 
8
+ export const readTasks = async (taskDirFilePath: string, ownerId?: string): Promise<VideoTask[]> => {
9
 
10
  let tasksFiles: string[] = []
11
  try {
 
13
  // console.log("filesInDir:", filesInDir)
14
 
15
  // we only keep valid files (in UUID.json format)
16
+ tasksFiles = filesInDir.filter(fileName =>
17
+ fileName.match(/[a-z0-9\-_]\.json/i) && (ownerId ? fileName.includes(ownerId): true)
18
+ )
19
 
20
  // console.log("tasksfiles:", tasksFiles)
21
  } catch (err) {
src/scheduler/saveCompletedTask.mts CHANGED
@@ -1,4 +1,3 @@
1
- import { promises as fs } from "node:fs"
2
  import path from "path"
3
 
4
  import { VideoTask } from "../types.mts"
@@ -6,7 +5,7 @@ import { completedTasksDirFilePath, pendingTasksDirFilePath } from "../config.mt
6
  import { moveFile } from "../utils/moveFile.mts"
7
 
8
  export const saveCompletedTask = async (task: VideoTask) => {
9
- const fileName = `${task.id}.json`
10
  const pendingFilePath = path.join(pendingTasksDirFilePath, fileName)
11
  const completedFilePath = path.join(completedTasksDirFilePath, fileName)
12
  await moveFile(pendingFilePath, completedFilePath)
 
 
1
  import path from "path"
2
 
3
  import { VideoTask } from "../types.mts"
 
5
  import { moveFile } from "../utils/moveFile.mts"
6
 
7
  export const saveCompletedTask = async (task: VideoTask) => {
8
+ const fileName = `${task.ownerId}_${task.id}.json`
9
  const pendingFilePath = path.join(pendingTasksDirFilePath, fileName)
10
  const completedFilePath = path.join(completedTasksDirFilePath, fileName)
11
  await moveFile(pendingFilePath, completedFilePath)
src/scheduler/savePendingTask.mts CHANGED
@@ -5,9 +5,7 @@ import { VideoTask } from "../types.mts"
5
  import { pendingTasksDirFilePath } from "../config.mts"
6
 
7
  export const savePendingTask = async (task: VideoTask) => {
8
- const fileName = `${task.id}.json`
9
  const filePath = path.join(pendingTasksDirFilePath, fileName)
10
- console.log("fileName:", fileName)
11
- console.log("filePath:", filePath)
12
  await fs.writeFile(filePath, JSON.stringify(task, null, 2), "utf8")
13
  }
 
5
  import { pendingTasksDirFilePath } from "../config.mts"
6
 
7
  export const savePendingTask = async (task: VideoTask) => {
8
+ const fileName = `${task.ownerId}_${task.id}.json`
9
  const filePath = path.join(pendingTasksDirFilePath, fileName)
 
 
10
  await fs.writeFile(filePath, JSON.stringify(task, null, 2), "utf8")
11
  }
src/scheduler/updatePendingTask.mts CHANGED
@@ -6,7 +6,7 @@ import { pendingTasksDirFilePath } from "../config.mts"
6
 
7
  export const updatePendingTask = async (task: VideoTask) => {
8
  try {
9
- const fileName = `${task.id}.json`
10
  const filePath = path.join(pendingTasksDirFilePath, fileName)
11
  await fs.writeFile(filePath, JSON.stringify(task, null, 2), "utf8")
12
  } catch (err) {
 
6
 
7
  export const updatePendingTask = async (task: VideoTask) => {
8
  try {
9
+ const fileName = `${task.ownerId}_${task.id}.json`
10
  const filePath = path.join(pendingTasksDirFilePath, fileName)
11
  await fs.writeFile(filePath, JSON.stringify(task, null, 2), "utf8")
12
  } catch (err) {
src/types.mts CHANGED
@@ -202,6 +202,8 @@ export interface VideoSequenceMeta {
202
  export interface VideoSequenceData {
203
  // must be unique
204
  id: string
 
 
205
 
206
  fileName: string
207
 
@@ -218,11 +220,12 @@ export interface VideoSequenceData {
218
 
219
  export type VideoSequence = VideoSequenceMeta & VideoSequenceData
220
 
221
- export type VideoTaskRequest = {
222
  prompt: string
 
223
  sequence: Partial<VideoSequenceMeta>
224
  shots: Array<Partial<VideoShotMeta>>
225
- }
226
 
227
  export type VideoTask = VideoSequence & {
228
  shots: VideoShot[]
 
202
  export interface VideoSequenceData {
203
  // must be unique
204
  id: string
205
+
206
+ ownerId: string
207
 
208
  fileName: string
209
 
 
220
 
221
  export type VideoSequence = VideoSequenceMeta & VideoSequenceData
222
 
223
+ export type VideoTaskRequest = Partial<{
224
  prompt: string
225
+ ownerId: string // to uniquely identify where the video come from
226
  sequence: Partial<VideoSequenceMeta>
227
  shots: Array<Partial<VideoShotMeta>>
228
+ }>
229
 
230
  export type VideoTask = VideoSequence & {
231
  shots: VideoShot[]
src/utils/copyVideoFromPendingToCompleted.mts CHANGED
@@ -1,14 +1,14 @@
1
  import path from "node:path"
2
  import { promises as fs } from "node:fs"
3
 
4
- import { completedTasksDirFilePath, pendingFilesDirFilePath } from "../config.mts"
5
 
6
  export const copyVideoFromPendingToCompleted = async (pendingFileName: string, completedFileName?: string) => {
7
  if (!completedFileName) {
8
  completedFileName = pendingFileName
9
  }
10
  const pendingFilePath = path.join(pendingFilesDirFilePath, pendingFileName)
11
- const completedFilePath = path.join(completedTasksDirFilePath, completedFileName)
12
 
13
  await fs.copyFile(pendingFilePath, completedFilePath)
14
  console.log(`copied file from ${pendingFilePath} to ${completedFilePath}`)
 
1
  import path from "node:path"
2
  import { promises as fs } from "node:fs"
3
 
4
+ import { completedFilesDirFilePath, pendingFilesDirFilePath } from "../config.mts"
5
 
6
  export const copyVideoFromPendingToCompleted = async (pendingFileName: string, completedFileName?: string) => {
7
  if (!completedFileName) {
8
  completedFileName = pendingFileName
9
  }
10
  const pendingFilePath = path.join(pendingFilesDirFilePath, pendingFileName)
11
+ const completedFilePath = path.join(completedFilesDirFilePath, completedFileName)
12
 
13
  await fs.copyFile(pendingFilePath, completedFilePath)
14
  console.log(`copied file from ${pendingFilePath} to ${completedFilePath}`)
src/utils/parseShotRequest.mts CHANGED
@@ -57,7 +57,7 @@ export const parseShotRequest = async (sequence: VideoSequence, maybeShotMeta: P
57
  // for internal use
58
 
59
  version: shotFormatVersion,
60
- fileName: `${id}.mp4`,
61
  hasGeneratedPreview: false,
62
  hasGeneratedVideo: false,
63
  hasUpscaledVideo: false,
 
57
  // for internal use
58
 
59
  version: shotFormatVersion,
60
+ fileName: `${sequence.ownerId}_${sequence.id}_${id}.mp4`,
61
  hasGeneratedPreview: false,
62
  hasGeneratedVideo: false,
63
  hasUpscaledVideo: false,
src/utils/parseVideoRequest.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { v4 as uuidv4 } from "uuid"
2
  import { HfInference } from "@huggingface/inference"
3
 
4
  // convert a request (which might be invalid)
@@ -29,11 +29,23 @@ export const parseVideoRequest = async (request: VideoTaskRequest): Promise<Vide
29
  }]
30
  }
31
 
32
- console.log("continuing..")
 
 
 
 
 
 
 
 
 
 
33
  const task: VideoTask = {
34
  // ------------ VideoSequenceMeta -------------
35
  id,
36
 
 
 
37
  // describe the whole movie
38
  videoPrompt: `${request.sequence.videoPrompt || ''}`,
39
 
@@ -67,7 +79,7 @@ export const parseVideoRequest = async (request: VideoTaskRequest): Promise<Vide
67
 
68
  // ---------- VideoSequenceData ---------
69
  version: sequenceFormatVersion,
70
- fileName: `${id}.mp4`,
71
  hasAssembledVideo: false,
72
  nbCompletedShots: 0,
73
  progressPercent: 0,
@@ -81,12 +93,12 @@ export const parseVideoRequest = async (request: VideoTaskRequest): Promise<Vide
81
  shots: [],
82
  }
83
 
84
- console.log("we are still good..")
85
  const maybeShots = Array.isArray(request.shots) ? request.shots : []
86
 
87
- console.log("let's try..")
88
  for (const maybeShot of maybeShots) {
89
- console.log("trying shot", maybeShot)
90
  try {
91
  const shot = await parseShotRequest(task, maybeShot)
92
  task.shots.push(shot)
 
1
+ import { v4 as uuidv4, validate as uuidValidate } from "uuid"
2
  import { HfInference } from "@huggingface/inference"
3
 
4
  // convert a request (which might be invalid)
 
29
  }]
30
  }
31
 
32
+ // more or less check that we have a UUID
33
+ // (I think we can also have an exact match over length === 34)
34
+ if (uuidValidate(request.ownerId)) {
35
+ console.log("we have a valid owner:", request.ownerId)
36
+ // TODO: use llama2 to populate this!
37
+ request.ownerId
38
+ } else {
39
+ request.ownerId = uuidv4()
40
+ }
41
+
42
+ // console.log("continuing..")
43
  const task: VideoTask = {
44
  // ------------ VideoSequenceMeta -------------
45
  id,
46
 
47
+ ownerId: request.ownerId,
48
+
49
  // describe the whole movie
50
  videoPrompt: `${request.sequence.videoPrompt || ''}`,
51
 
 
79
 
80
  // ---------- VideoSequenceData ---------
81
  version: sequenceFormatVersion,
82
+ fileName: `${request.ownerId}_${id}.mp4`,
83
  hasAssembledVideo: false,
84
  nbCompletedShots: 0,
85
  progressPercent: 0,
 
93
  shots: [],
94
  }
95
 
96
+ // console.log("we are still good..")
97
  const maybeShots = Array.isArray(request.shots) ? request.shots : []
98
 
99
+ // console.log("let's try..")
100
  for (const maybeShot of maybeShots) {
101
+ // console.log("trying shot", maybeShot)
102
  try {
103
  const shot = await parseShotRequest(task, maybeShot)
104
  task.shots.push(shot)