jbilcke-hf HF staff commited on
Commit
b84093c
1 Parent(s): 7eb3b9c

ready for the update

Browse files
database.json CHANGED
@@ -2,6 +2,93 @@
2
  "version": 1,
3
  "startAtShotId": "",
4
  "sequences": [
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  {
6
  "sequenceId": "3b7fb664-f50a-4e2d-b63b-e1fedb22e501",
7
  "skip": false,
@@ -382,7 +469,7 @@
382
  },
383
  {
384
  "sequenceId": "a8ea6aac-c857-436c-877a-28ebe3420209",
385
- "skip": false,
386
  "lastGenerationAt": "",
387
  "videoPrompt": "a photorealistic movie, experimental horror movie showing creepy places, pool of blood, a creepy mansion, a woman in white near the road in the forest, mist and foggy woods, a cemetery, a creepy animal or deer-like monster creeping around. The movie is esoteric, there are some dreamy places.",
388
  "audioPrompt": "ambient electronic music from the 50s kraftwerk inspiration",
 
2
  "version": 1,
3
  "startAtShotId": "",
4
  "sequences": [
5
+ {
6
+ "sequenceId": "da6329e1-c863-45e0-aa18-5161cf5eeacd",
7
+ "skip": false,
8
+ "lastGenerationAt": "",
9
+ "videoPrompt": "a photorealistic of a space opera movie",
10
+ "audioPrompt": "intense and fast-paced electronic and orchestra music for a space opera with synthetisers, electronic drum machine",
11
+ "tags": [
12
+ "trailer",
13
+ "comedy",
14
+ "action",
15
+ "adventure",
16
+ "science-fiction"
17
+ ],
18
+ "channel": "main",
19
+ "shots": [
20
+ {
21
+ "shotId": "63462eef-7fa0-46b6-855a-c70dcebfb414",
22
+ "index": 0,
23
+ "lastGenerationAt": "",
24
+ "videoPrompt": "Photorealistic movie footage of a detailed NASA-inspired, pyramid-shaped spaceship soaring towards a strange planet laden with a colossal castle, glinting enchantingly under the golden hour sunlight, viewed from the perspective of an ultra wide-angle cinema camera, a spectacular, cinematic, photorealistic, movie quality shot.",
25
+ "audioPrompt": ""
26
+ },
27
+ {
28
+ "shotId": "5d4b89f0-ba68-499c-be41-61ca447720c7",
29
+ "index": 1,
30
+ "lastGenerationAt": "",
31
+ "videoPrompt": "Photorealistic film of a raccoon pilot in an expansive spaceship cockpit, wearing an airman's leather jacket and goggles, illuminated by ambient lighting from the spacecraft's controls, shot with high details, digitally remastered, award-winning.",
32
+ "audioPrompt": ""
33
+ },
34
+ {
35
+ "shotId": "c1d2e49d-abb2-42c8-8ed7-d9eadcbfc152",
36
+ "index": 2,
37
+ "lastGenerationAt": "",
38
+ "videoPrompt": "Ultra-wide angle photorealistic shot of huge, freeze-breathing dragons, their scales glistening unnervingly under the sunlight, amid massive octopus creatures upturning alien houses, shot with a mix of ambient lighting and backlighting in superb photorealistic, cinematic, movie quality.",
39
+ "audioPrompt": ""
40
+ },
41
+ {
42
+ "shotId": "268fdad6-07db-426b-812d-dc03c30ffe49",
43
+ "index": 3,
44
+ "lastGenerationAt": "",
45
+ "videoPrompt": "Captivating photorealistic footage of our raccoon pilot passionately manipulating the spaceship's controls amidst the tumultuous situation outdoors, captured in soft lighting from a Canon EOS cinema-grade camera, showcasing splendid, award-winning composition and detail",
46
+ "audioPrompt": ""
47
+ },
48
+ {
49
+ "shotId": "c431acda-a572-4fc0-ba4a-179d98219f48",
50
+ "index": 4,
51
+ "lastGenerationAt": "",
52
+ "videoPrompt": "Space opera drama unfolding in a photorealistic footage of phenomenal, giant icy dragons sweeping over expansive, medieval-style castle, casting long, dramatic shadows under the slowly setting sun, captured in sublime movie quality.",
53
+ "audioPrompt": ""
54
+ },
55
+ {
56
+ "shotId": "62971863-1448-4044-a50c-242af4de953e",
57
+ "index": 5,
58
+ "lastGenerationAt": "",
59
+ "videoPrompt": "Photorealistic film shot of the ecstatic raccoon pilot reacting to the chaos outside, speeding towards the planet in his spaceship, the merriment in his beady eyes reflected in the surreal and breathtaking high-quality, movie lighting, captured with stunning detail.",
60
+ "audioPrompt": ""
61
+ },
62
+ {
63
+ "shotId": "4aa96204-c78f-47b3-b6ca-a9e1faf5b7a0",
64
+ "index": 6,
65
+ "lastGenerationAt": "",
66
+ "videoPrompt": "Highly detailed, photorealistic footage of ominous eight-legged giant octopuses briskly roaming a wild, otherworldly landscape, crushing alien houses in their path, as our raccoon hero watches in awe, their movement fluid like in an epic space opera movie.",
67
+ "audioPrompt": ""
68
+ },
69
+ {
70
+ "shotId": "bd89e7ce-01e9-449a-b468-550e43956e77",
71
+ "index": 7,
72
+ "lastGenerationAt": "",
73
+ "videoPrompt": "Photorealistic movie shot of intricate details of the spaceship cockpit with the dedicated and absorbed raccoon pilot urgently plotting a course for escape, shadows and lights from the control panels play on his fur, showcasing stunning detail.",
74
+ "audioPrompt": ""
75
+ },
76
+ {
77
+ "shotId": "4eba4b78-1d2f-4795-82b0-f56e6004e8fe",
78
+ "index": 8,
79
+ "lastGenerationAt": "",
80
+ "videoPrompt": "Ultra-wide angle, photorealistic shot of the planet's dawn, with the iridescent glow revealing the frozen wreckage caused by the dragons, taking on an ethereal quality amidst the chaos, shot in a cinematic manner, maintaining high details to procure an award-winning shot.",
81
+ "audioPrompt": ""
82
+ },
83
+ {
84
+ "shotId": "c3f5a185-cace-46bf-a74c-27f7114e75ce",
85
+ "index": 9,
86
+ "lastGenerationAt": "",
87
+ "videoPrompt": "Cinematic, photorealistic video of our raccoon hero in his spaceship, glancing back at the strange planet, a mix of pride and melancholy in his gaze as his spaceship disappears into the starry void, lighting from the control panel casting a soft glow on his figure, award-winning filmography.",
88
+ "audioPrompt": ""
89
+ }
90
+ ]
91
+ },
92
  {
93
  "sequenceId": "3b7fb664-f50a-4e2d-b63b-e1fedb22e501",
94
  "skip": false,
 
469
  },
470
  {
471
  "sequenceId": "a8ea6aac-c857-436c-877a-28ebe3420209",
472
+ "skip": true,
473
  "lastGenerationAt": "",
474
  "videoPrompt": "a photorealistic movie, experimental horror movie showing creepy places, pool of blood, a creepy mansion, a woman in white near the road in the forest, mist and foggy woods, a cemetery, a creepy animal or deer-like monster creeping around. The movie is esoteric, there are some dreamy places.",
475
  "audioPrompt": "ambient electronic music from the 50s kraftwerk inspiration",
scripts/README.md ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+ ## Scripts
4
+
5
+ ### interpolate.sh
6
+
7
+ This is a script meant to be run on an existing video database.
8
+ This can help making quick trials of interpolation algorithms,
9
+ without modifying the video creating pipeline.
scripts/init.sh CHANGED
@@ -5,10 +5,6 @@ echo "creating the storage folders for channel 1.."
5
  mkdir -p $WEBTV_VIDEO_STORAGE_PATH_CHANNEL_1
6
  mkdir -p $WEBTV_AUDIO_STORAGE_PATH_CHANNEL_1
7
 
8
- bash scripts/download_fresh_music.sh
9
-
10
- bash scripts/censorship.sh
11
-
12
  echo "creating the playlists for channel 1.."
13
  echo "ffconcat version 1.0" > channel_1_video.txt
14
  echo "ffconcat version 1.0" > channel_1_audio.txt
@@ -21,3 +17,29 @@ mkdir -p $WEBTV_AUDIO_STORAGE_PATH_CHANNEL_2
21
  echo "creating the playlists for channel 2.."
22
  echo "ffconcat version 1.0" > channel_2_video.txt
23
  echo "ffconcat version 1.0" > channel_2_video.txt
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  mkdir -p $WEBTV_VIDEO_STORAGE_PATH_CHANNEL_1
6
  mkdir -p $WEBTV_AUDIO_STORAGE_PATH_CHANNEL_1
7
 
 
 
 
 
8
  echo "creating the playlists for channel 1.."
9
  echo "ffconcat version 1.0" > channel_1_video.txt
10
  echo "ffconcat version 1.0" > channel_1_audio.txt
 
17
  echo "creating the playlists for channel 2.."
18
  echo "ffconcat version 1.0" > channel_2_video.txt
19
  echo "ffconcat version 1.0" > channel_2_video.txt
20
+
21
+
22
+ # ------------- CHANNEL 3 --------------
23
+ echo "creating the storage folders for channel 3.."
24
+ mkdir -p $WEBTV_VIDEO_STORAGE_PATH_CHANNEL_3
25
+ mkdir -p $WEBTV_AUDIO_STORAGE_PATH_CHANNEL_3
26
+
27
+ echo "creating the playlists for channel 3.."
28
+ echo "ffconcat version 1.0" > channel_3_video.txt
29
+ echo "ffconcat version 1.0" > channel_3_video.txt
30
+
31
+
32
+ # ------------- CHANNEL 4 --------------
33
+ echo "creating the storage folders for channel 4.."
34
+ mkdir -p $WEBTV_VIDEO_STORAGE_PATH_CHANNEL_4
35
+ mkdir -p $WEBTV_AUDIO_STORAGE_PATH_CHANNEL_4
36
+
37
+ echo "creating the playlists for channel 4.."
38
+ echo "ffconcat version 1.0" > channel_4_video.txt
39
+ echo "ffconcat version 1.0" > channel_4_video.txt
40
+
41
+ # ------------ UPDATE MUSIC ------------
42
+ bash scripts/download_fresh_music.sh
43
+
44
+ # ---------- CONTENT ALIGNMENT ---------
45
+ bash scripts/censorship.sh
scripts/interpolate.sh ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # Make sure to provide your directories paths
4
+ INPUT_DIR=$WEBTV_VIDEO_STORAGE_PATH_CHANNEL_2
5
+ OUTPUT_DIR=$WEBTV_VIDEO_STORAGE_PATH_CHANNEL_3
6
+ TEMP_DIR=$(mktemp -d)
7
+
8
+ # Loop through all .mp4 files in input directory
9
+ for FILE_PATH in $INPUT_DIR*.mp4; do
10
+ # get the base file name
11
+ FILE_NAME=$(basename "$FILE_PATH")
12
+
13
+ # Create a temp file path
14
+ TEMP_FILE_PATH=$TEMP_DIR"/"$FILE_NAME
15
+
16
+ # Check if file does not exist in output directory
17
+ if [ ! -f "$OUTPUT_DIR$FILE_NAME" ]; then
18
+ echo "Processing $FILE_NAME, output will be saved in $OUTPUT_DIR$FILE_NAME"
19
+
20
+ # Run your node command
21
+ if ! npm run postprod:interpolate "$FILE_PATH" "$TEMP_FILE_PATH"
22
+ then
23
+ # The first attempt has failed, retrying
24
+ echo "Attempt 1 failed for $FILE_NAME, retrying..."
25
+
26
+ if ! npm run postprod:interpolate "$FILE_PATH" "$TEMP_FILE_PATH"
27
+ then
28
+ # Both attempts have failed, skipping the file
29
+ echo "Both attempts failed for $FILE_NAME, skipping the file..."
30
+ continue
31
+ fi
32
+ fi
33
+
34
+ # Running ffmpeg to resize and apply unsharp mask
35
+ # Also we speed things up, and re-add the noise
36
+ if ! ffmpeg -hide_banner -v fatal -nostats -loglevel 0 -i "$TEMP_FILE_PATH" -vf "setpts=0.35*PTS,scale=-1:576:lanczos,unsharp=5:5:0.2:5:5:0.2,noise=c0s=10:c0f=t+u" -r 24 "$OUTPUT_DIR$FILE_NAME"
37
+ then
38
+ # ffmpeg command failed
39
+ echo "ffmpeg command failed for $FILE_NAME, skipping the file..."
40
+ fi
41
+
42
+ else
43
+ echo "File $FILE_NAME already exists in the output directory, skipping."
44
+ fi
45
+ done
46
+
47
+ # Remove temp folder
48
+ rm -r "$TEMP_DIR"
scripts/stream3.sh ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ COUNT=0
4
+
5
+ echo "Starting FFMPEG live stream for channel 3"
6
+ while true; do
7
+ # Note: for now we also use channel 1 for audio!
8
+ ffmpeg -y -nostdin -re -f concat -safe 0 -i channel_3_video.txt -stream_loop -1 -safe 0 -i channel_1_audio.txt -loglevel error -c:v libx264 -preset veryfast -tune zerolatency -c:a aac -ar 44100 -shortest -f flv rtmp://localhost/live/smooth
9
+ done
scripts/stream4.sh ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ COUNT=0
4
+
5
+ echo "Starting FFMPEG live stream for channel 4"
6
+ while true; do
7
+ # Note: for now we also use channel 1 for audio!
8
+ ffmpeg -y -nostdin -re -f concat -safe 0 -i channel_4_video.txt -stream_loop -1 -safe 0 -i channel_1_audio.txt -loglevel error -c:v libx264 -preset veryfast -tune zerolatency -c:a aac -ar 44100 -shortest -f flv rtmp://localhost/live/interactive
9
+ done
scripts/video3.sh ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ echo "Starting the video collection stream for channel 3.."
4
+ echo "listing files in $WEBTV_VIDEO_STORAGE_PATH_CHANNEL_3*.mp4"
5
+ current_count=0
6
+
7
+ while true; do
8
+ new_count=$(ls $WEBTV_VIDEO_STORAGE_PATH_CHANNEL_3*.mp4 2> /dev/null | wc -l)
9
+
10
+ if [ $new_count -ne $current_count ]; then
11
+ echo "there are $new_count videos files for channel 3"
12
+
13
+ echo "Updating playliss for channel 3.."
14
+ current_count=$new_count
15
+ files=($WEBTV_VIDEO_STORAGE_PATH_CHANNEL_2*.mp4)
16
+
17
+ echo "ffconcat version 1.0" > channel_3_video_tmp.txt
18
+ for (( i=0; i<${#files[@]}; i++ )); do
19
+ echo "file '${files[$i]}'" >> channel_3_video_tmp.txt
20
+ done
21
+ mv channel_3_video_tmp.txt channel_3_video.txt
22
+ fi
23
+
24
+ # the new playlist will only be updated after the current playlist ended
25
+ # so there is no emergency here
26
+ sleep 60
27
+ done
scripts/video4.sh ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ echo "Starting the video collection stream for channel 4.."
4
+ echo "listing files in $WEBTV_VIDEO_STORAGE_PATH_CHANNEL_4*.mp4"
5
+ current_count=0
6
+
7
+ while true; do
8
+ new_count=$(ls $WEBTV_VIDEO_STORAGE_PATH_CHANNEL_4*.mp4 2> /dev/null | wc -l)
9
+
10
+ if [ $new_count -ne $current_count ]; then
11
+ echo "there are $new_count videos files for channel 4"
12
+
13
+ echo "Updating playliss for channel 4.."
14
+ current_count=$new_count
15
+ files=($WEBTV_VIDEO_STORAGE_PATH_CHANNEL_4*.mp4)
16
+
17
+ echo "ffconcat version 1.0" > channel_4_video_tmp.txt
18
+ for (( i=0; i<${#files[@]}; i++ )); do
19
+ echo "file '${files[$i]}'" >> channel_4_video_tmp.txt
20
+ done
21
+ mv channel_4_video_tmp.txt channel_4_video.txt
22
+ fi
23
+
24
+ # channel 4 is an interactive channel, so we have tighter delays
25
+ sleep 20
26
+ done
src/index.mts CHANGED
@@ -8,6 +8,7 @@ import { callZeroscope } from './callZeroscope.mts'
8
  import { downloadVideo } from './downloadVideo.mts'
9
  import { getDatabase } from './getDatabase.mts'
10
  import { callMusicgen } from './callMusicgen.mts'
 
11
 
12
  let hasReachedStartingPoint = false
13
 
@@ -125,6 +126,9 @@ ${sequence.videoPrompt}
125
  await upscaleVideo(shotFileName, shot.videoPrompt)
126
  }
127
 
 
 
 
128
  console.log('- enhancing shot..')
129
  await enhanceVideo(shotFileName)
130
 
 
8
  import { downloadVideo } from './downloadVideo.mts'
9
  import { getDatabase } from './getDatabase.mts'
10
  import { callMusicgen } from './callMusicgen.mts'
11
+ import { interpolateVideo } from './interpolateVideo.mts'
12
 
13
  let hasReachedStartingPoint = false
14
 
 
126
  await upscaleVideo(shotFileName, shot.videoPrompt)
127
  }
128
 
129
+ console.log('- enhancing shot..')
130
+ // await interpolateVideo(shotFileName)
131
+
132
  console.log('- enhancing shot..')
133
  await enhanceVideo(shotFileName)
134
 
src/interpolate/TODO_USE_ME.mts ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { promises as fs } from "node:fs"
2
+ import path from "node:path"
3
+
4
+ import { client } from "@gradio/client"
5
+ import tmpDir from "temp-dir"
6
+
7
+ const spaceUrl = "https://jbilcke-hf-video-frame-interpolation.hf.space"
8
+
9
+ export const interpolateVideo = (fileName: string) {
10
+
11
+ const filePath = path.join(tmpDir, fileName)
12
+
13
+ const app = await client(spaceUrl)
14
+
15
+ const video = await fs.readFile(filePath)
16
+
17
+ const result = await app.predict(1, [
18
+ video.toString('base64'), // blob in 'parameter_5' Video component
19
+ 1, // number (numeric value between 1 and 4) in 'Interpolation Steps' Slider component
20
+ "24", // string in 'FPS output' Radio component
21
+ ])
22
+
23
+ const data = (result as any).data
24
+
25
+ console.log(data)
26
+
27
+ }
src/interpolateVideo.mts CHANGED
@@ -1,27 +1,65 @@
1
- import { promises as fs } from "node:fs"
2
- import path from "node:path"
3
 
4
- import { client } from "@gradio/client"
5
- import tmpDir from "temp-dir"
 
6
 
7
- const spaceUrl = "https://jbilcke-hf-video-frame-interpolation.hf.space"
 
 
 
 
 
 
8
 
9
- export const interpolateVideo = (fileName: string) {
10
 
11
- const filePath = path.join(tmpDir, fileName)
12
-
13
- const app = await client(spaceUrl)
14
 
15
- const video = await fs.readFile(filePath)
 
 
 
 
 
16
 
17
- const result = await app.predict(1, [
18
- video.toString('base64'), // blob in 'parameter_5' Video component
19
- 1, // number (numeric value between 1 and 4) in 'Interpolation Steps' Slider component
20
- "24", // string in 'FPS output' Radio component
21
- ])
 
 
 
 
 
 
 
22
 
23
- const data = (result as any).data
24
 
25
- console.log(data)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
 
27
  }
 
1
+ import path from 'node:path'
2
+ import fs from 'node:fs'
3
 
4
+ import tmpDir from 'temp-dir'
5
+ import puppeteer from 'puppeteer'
6
+ import { downloadVideo } from './downloadVideo.mts'
7
 
8
+ // TODO we should use an inference endpoint instead
9
+ export async function interpolateVideo(fileName: string) {
10
+
11
+ const browser = await puppeteer.launch({
12
+ // headless: true,
13
+ protocolTimeout: 300000,
14
+ })
15
 
16
+ const spaceUrl = process.env.WEBTV_INTERPOLATION_SPACE_URL
17
 
18
+ const page = await browser.newPage()
 
 
19
 
20
+ await page.goto(spaceUrl, {
21
+ waitUntil: 'networkidle2',
22
+ })
23
+
24
+ const inputFilePath = path.join(tmpDir, fileName)
25
+ // console.log(`local file to upscale: ${inputFilePath}`)
26
 
27
+ await new Promise(r => setTimeout(r, 3000))
28
+
29
+ const fileField = await page.$('input[type=file]')
30
+
31
+ // console.log(`uploading file..`)
32
+ await fileField.uploadFile(inputFilePath)
33
+
34
+ // console.log('looking for the button to submit')
35
+ const submitButton = await page.$('button.lg')
36
+
37
+ // console.log('clicking on the button')
38
+ await submitButton.click()
39
 
 
40
 
41
+ await page.waitForSelector('a[download="interpolated_result.mp4"]', {
42
+ timeout: 300000, // need to be large enough in case someone else attemps to use our space
43
+ })
44
+
45
+ const interpolatedFileUrl = await page.$$eval('a[download="interpolated_result.mp4"]', el => el.map(x => x.getAttribute("href"))[0])
46
+
47
+ const tmpFileName = `${fileName}_xl`
48
+
49
+ // console.log('downloading file from space..')
50
+ console.log(`- downloading ${fileName} from ${interpolatedFileUrl}`)
51
+
52
+ await downloadVideo(interpolatedFileUrl, tmpFileName)
53
+
54
+ const tmpFilePath = path.join(tmpDir, tmpFileName)
55
+ const filePath = path.join(tmpDir, fileName)
56
+
57
+ await fs.promises.copyFile(tmpFilePath, filePath)
58
+ try {
59
+ await fs.promises.unlink(tmpFilePath)
60
+ } catch (err) {
61
+ console.log('failed to cleanup (no big deal..)')
62
+ }
63
 
64
+ return fileName
65
  }
src/postprod/interpolate.mts CHANGED
@@ -1,26 +1,12 @@
1
- import { promises as fs } from "node:fs"
2
- import { client } from "@gradio/client"
3
 
4
  // to test this file:
5
- // npm run postprod:interpolate sandbox/video/1688471841394.mp4
6
 
7
- const spaceUrl = "https://jbilcke-hf-video-frame-interpolation.hf.space"
8
- const filePath = process.argv[2]
9
 
10
- console.log('filePath:', filePath)
11
- const vid = await fs.readFile(filePath)
12
-
13
- const b64 = vid.toString('base64')
14
 
15
- console.log(b64.slice(0, 20))
16
-
17
- const app = await client(spaceUrl)
18
-
19
- /*
20
- const result = await app.predict(1, [
21
- exampleVideo, // blob in 'parameter_5' Video component
22
- 1, // number (numeric value between 1 and 4) in 'Interpolation Steps' Slider component
23
- "8", // string in 'FPS output' Radio component
24
- ]);
25
- console.log(result?.data)
26
- */
 
1
+ import { interpolateVideo } from "./interpolateVideoForScript.mts"
 
2
 
3
  // to test this file:
4
+ // npm run postprod:interpolate sandbox/video/1688471841394.mp4 sandbox/video/output.mp4
5
 
6
+ const inputFilePath = process.argv[2]
7
+ const outputFilePath = process.argv[3]
8
 
9
+ console.log('input file path:', inputFilePath)
10
+ console.log('output file path:', outputFilePath)
 
 
11
 
12
+ await interpolateVideo(inputFilePath, outputFilePath)
 
 
 
 
 
 
 
 
 
 
 
src/postprod/interpolateVideoForScript.mts ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import fs from 'node:fs'
2
+
3
+ import puppeteer from 'puppeteer'
4
+
5
+ // TODO we should use an inference endpoint instead
6
+ export async function interpolateVideo(inputFilePath: string, outputFilePath: string) {
7
+
8
+ const browser = await puppeteer.launch({
9
+ headless: true,
10
+ protocolTimeout: 400000,
11
+ })
12
+
13
+ const spaceUrl = process.env.WEBTV_INTERPOLATION_SPACE_URL
14
+
15
+ const page = await browser.newPage()
16
+ await page.goto(spaceUrl, { waitUntil: 'networkidle2' })
17
+
18
+ await new Promise(r => setTimeout(r, 3000))
19
+
20
+ const fileField = await page.$('input[type=file]')
21
+
22
+ // console.log(`uploading file..`)
23
+ await fileField.uploadFile(inputFilePath)
24
+
25
+ // console.log('looking for the button to submit')
26
+ const submitButton = await page.$('button.lg')
27
+
28
+ // console.log('clicking on the button')
29
+ await submitButton.click()
30
+
31
+ await page.waitForSelector('a[download="interpolated_result.mp4"]', {
32
+ timeout: 400000, // need to be large enough in case someone else attemps to use our space
33
+ })
34
+
35
+ const interpolatedFileUrl = await page.$$eval('a[download="interpolated_result.mp4"]', el => el.map(x => x.getAttribute("href"))[0])
36
+
37
+ // console.log('downloading file from space..')
38
+ console.log(`- downloading from ${interpolatedFileUrl}`)
39
+
40
+
41
+ // download the video
42
+ const response = await fetch(interpolatedFileUrl)
43
+ // write it to the disk
44
+ const arrayBuffer = await response.arrayBuffer()
45
+
46
+ await fs.promises.writeFile(
47
+ outputFilePath,
48
+ Buffer.from(arrayBuffer)
49
+ )
50
+ console.log('success! wrote to:', outputFilePath)
51
+
52
+ process.exit()
53
+ }
test.sh ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ echo "$FOO$BAR"
2
+