mediasnacks 0.22.1 → 0.22.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/avif.test.js +0 -16
- package/src/detectdups.test.js +0 -24
- package/src/edgespic.test.js +0 -36
- package/src/fixtures/60fps.csv +0 -7
- package/src/fixtures/60fps.mp4 +0 -0
- package/src/fixtures/big-buck-bunny/bbb_24_to_25fps_dup.mp4 +0 -0
- package/src/fixtures/big-buck-bunny/bbb_24_to_30fps_dup.mp4 +0 -0
- package/src/fixtures/big-buck-bunny/bbb_24_to_48fps_dup.mp4 +0 -0
- package/src/fixtures/big-buck-bunny/bbb_24fps_no_dups.mp4 +0 -0
- package/src/fixtures/big-buck-bunny/bbb_25_to_30fps_dup.mp4 +0 -0
- package/src/fixtures/big-buck-bunny/bbb_25_to_50fps_dup.mp4 +0 -0
- package/src/fixtures/big-buck-bunny/bbb_25_to_60fps_dup.mp4 +0 -0
- package/src/fixtures/big-buck-bunny/bbb_25fps_no_dups.mp4 +0 -0
- package/src/fixtures/big-buck-bunny/generate.md +0 -71
- package/src/fixtures/edgespic/60fps_first.png +0 -0
- package/src/fixtures/edgespic/60fps_last.png +0 -0
- package/src/fixtures/lenna.avif +0 -0
- package/src/fixtures/lenna.png +0 -0
- package/src/fixtures/qdir-jobs/job1_good.sh +0 -1
- package/src/fixtures/qdir-jobs/job2_bad.sh +0 -1
- package/src/fixtures/qdir-jobs/job3_good.sh +0 -2
- package/src/fixtures/qdir-jobs/job4_bad.sh +0 -1
- package/src/flattendir.test.js +0 -36
- package/src/qdir.test.js +0 -24
- package/src/seqcheck.test.js +0 -27
- package/src/utils/fs-utils.test.js +0 -21
- package/src/utils/parseOptions.test.js +0 -60
- package/src/vconcat.test.js +0 -23
- package/src/vsplit.test.js +0 -32
- package/src/vtrim.test.js +0 -40
package/package.json
CHANGED
package/src/avif.test.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { join } from 'node:path'
|
|
2
|
-
import { test } from 'node:test'
|
|
3
|
-
import { ok } from 'node:assert/strict'
|
|
4
|
-
|
|
5
|
-
import { ssim } from './ssim.js'
|
|
6
|
-
import { mkTempDir, cli } from './utils/test-utils.js'
|
|
7
|
-
|
|
8
|
-
const rel = f => join(import.meta.dirname, f)
|
|
9
|
-
|
|
10
|
-
test('PNG to AVIF', async () => {
|
|
11
|
-
const tmp = mkTempDir('avif')
|
|
12
|
-
cli('avif', '--output-dir', tmp, rel('fixtures/lenna.png'))
|
|
13
|
-
|
|
14
|
-
const similarityScore = await ssim(join(tmp, 'lenna.avif'), rel('fixtures/lenna.avif'))
|
|
15
|
-
ok(similarityScore > 0.99, `Similarity too low: ${similarityScore}`)
|
|
16
|
-
})
|
package/src/detectdups.test.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { test } from 'node:test'
|
|
2
|
-
import { join } from 'node:path'
|
|
3
|
-
import { equal } from 'node:assert/strict'
|
|
4
|
-
import { cli } from './utils/test-utils.js'
|
|
5
|
-
|
|
6
|
-
const rel = f => join(import.meta.dirname, f)
|
|
7
|
-
|
|
8
|
-
function detect(video) {
|
|
9
|
-
const { stdout } = cli('detectdups', rel(video))
|
|
10
|
-
return JSON.parse(stdout).n
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
test('no dups', () => equal(detect('fixtures/big-buck-bunny/bbb_24fps_no_dups.mp4'), null))
|
|
14
|
-
|
|
15
|
-
// These fixtures are badly retimed (non-interpolated, just duplicating a frame)
|
|
16
|
-
|
|
17
|
-
test('24 to 48 (has dup at n=2)', () => equal(detect('fixtures/big-buck-bunny/bbb_24_to_48fps_dup.mp4'), 2))
|
|
18
|
-
test('25 to 50 (has dup at n=2)', () => equal(detect('fixtures/big-buck-bunny/bbb_25_to_50fps_dup.mp4'), 2))
|
|
19
|
-
|
|
20
|
-
test('24 to 30 (has dup at n=5)', () => equal(detect('fixtures/big-buck-bunny/bbb_24_to_30fps_dup.mp4'), 5))
|
|
21
|
-
test('25 to 30 (has dup at n=6)', () => equal(detect('fixtures/big-buck-bunny/bbb_25_to_30fps_dup.mp4'), 6))
|
|
22
|
-
|
|
23
|
-
test('24 to 25 (has dup at n=25)', () => equal(detect('fixtures/big-buck-bunny/bbb_24_to_25fps_dup.mp4'), 25))
|
|
24
|
-
|
package/src/edgespic.test.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { ok } from 'node:assert/strict'
|
|
2
|
-
import { join } from 'node:path'
|
|
3
|
-
import { describe, test } from 'node:test'
|
|
4
|
-
import { cpSync, readdirSync, } from 'node:fs'
|
|
5
|
-
|
|
6
|
-
import { ssim } from './ssim.js'
|
|
7
|
-
import { cli, mkTempDir } from './utils/test-utils.js'
|
|
8
|
-
|
|
9
|
-
const rel = f => join(import.meta.dirname, f)
|
|
10
|
-
|
|
11
|
-
describe('edgespic', () => {
|
|
12
|
-
const tmp = mkTempDir('edgespic')
|
|
13
|
-
const inputFile = join(tmp, '60fps.mp4')
|
|
14
|
-
cpSync(rel('fixtures/60fps.mp4'), inputFile)
|
|
15
|
-
cli('edgespic', inputFile)
|
|
16
|
-
|
|
17
|
-
test('creates output directory', () => {
|
|
18
|
-
const files = readdirSync(join(tmp, 'edgespic'))
|
|
19
|
-
ok(files.length === 2, `Expected 2 PNG files, got ${files.length}`)
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
test('extracts first frame', async () => {
|
|
23
|
-
const out = join(tmp, 'edgespic', '60fps_first.png')
|
|
24
|
-
const fixture = rel('fixtures/edgespic/60fps_first.png')
|
|
25
|
-
const similarityScore = await ssim(out, fixture)
|
|
26
|
-
ok(similarityScore > 0.99, `Similarity too low: ${similarityScore}`)
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
test('extracts last frame', async () => {
|
|
30
|
-
const out = join(tmp, 'edgespic', '60fps_last.png')
|
|
31
|
-
const fixture = rel('fixtures/edgespic/60fps_last.png')
|
|
32
|
-
const similarityScore = await ssim(out, fixture)
|
|
33
|
-
ok(similarityScore > 0.99, `Similarity too low: ${similarityScore}`)
|
|
34
|
-
})
|
|
35
|
-
})
|
|
36
|
-
|
package/src/fixtures/60fps.csv
DELETED
package/src/fixtures/60fps.mp4
DELETED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
# Generating Fixtures
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
## 1. Download a video (Big Buck Bunny)
|
|
5
|
-
|
|
6
|
-
```sh
|
|
7
|
-
curl https://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_1080p_h264.mov -o bbb_full_24fps.mov
|
|
8
|
-
```
|
|
9
|
-
|
|
10
|
-
## 2. Extract a scene
|
|
11
|
-
Using the third scene because it's complex enough to cover many edge cases.
|
|
12
|
-
It has a bird flapping its wings with motion blur. Also, animated text titles,
|
|
13
|
-
and fairly static frames after the title ends.
|
|
14
|
-
|
|
15
|
-
The scene is 1080p, 24fps, 7.28sec, h.264.
|
|
16
|
-
```sh
|
|
17
|
-
brew tap ericfortis/fcpscene
|
|
18
|
-
brew install fcpscene
|
|
19
|
-
fcpscene -m files bbb_full_24fps.mov
|
|
20
|
-
|
|
21
|
-
cp bbb/bbb_full_24fps_003.mov ./bbb_24fps_no_dups.mov
|
|
22
|
-
rm -rf bbb
|
|
23
|
-
rm bbb_full_24fps.mov
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## 3. Re-encode the scene 24fps
|
|
27
|
-
This way all videos will share the same encoding, and no audio.
|
|
28
|
-
|
|
29
|
-
```sh
|
|
30
|
-
ffmpeg -i bbb_24fps_no_dups.mov \
|
|
31
|
-
-c:v libx264 -crf 18 -preset slow \
|
|
32
|
-
-an \
|
|
33
|
-
bbb_24fps_no_dups.mp4
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## 4. Retime (no dups) speed stretch to 25fps
|
|
37
|
-
For a good (no dups) 25fps, retiming by speeding it up.
|
|
38
|
-
```sh
|
|
39
|
-
ffmpeg -i bbb_24fps_no_dups.mp4 \
|
|
40
|
-
-vf "setpts=24/25*PTS" \
|
|
41
|
-
-r 25 \
|
|
42
|
-
bbb_25fps_no_dups.mp4
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
## 5. Retime by inserting duplicates (no interpolation)
|
|
47
|
-
```sh
|
|
48
|
-
for TARGET_FPS in 48 30 25; do
|
|
49
|
-
ffmpeg -i bbb_24fps_no_dups.mp4 \
|
|
50
|
-
-vf fps=$TARGET_FPS \
|
|
51
|
-
-c:v libx264 -crf 18 -preset slow \
|
|
52
|
-
-an \
|
|
53
|
-
"bbb_24_to_${TARGET_FPS}fps_dup.mp4"
|
|
54
|
-
done
|
|
55
|
-
|
|
56
|
-
for TARGET_FPS in 60 50 30; do
|
|
57
|
-
ffmpeg -i bbb_25fps_no_dups.mp4 \
|
|
58
|
-
-vf fps=$TARGET_FPS \
|
|
59
|
-
-c:v libx264 -crf 18 -preset slow \
|
|
60
|
-
-an \
|
|
61
|
-
"bbb_25_to_${TARGET_FPS}fps_dup.mp4"
|
|
62
|
-
done
|
|
63
|
-
```
|
|
64
|
-
Counting the cycle from 1 (not from 0):
|
|
65
|
-
|
|
66
|
-
- 24 to 48 (inserts dup at n=2) 0101
|
|
67
|
-
- 25 to 50 (inserts dup at n=2) 0101
|
|
68
|
-
- 24 to 30 (inserts dup at n=5) 0000100001
|
|
69
|
-
- 25 to 30 (inserts dup at n=6) 000001000001
|
|
70
|
-
- 24 to 25 (inserts dup at n=25) (0*24)1
|
|
71
|
-
- 25 to 60 (inserts dup at n=2 and n=3) 01011
|
|
Binary file
|
|
Binary file
|
package/src/fixtures/lenna.avif
DELETED
|
Binary file
|
package/src/fixtures/lenna.png
DELETED
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
exit 0
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
exit 1
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
exit 1
|
package/src/flattendir.test.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { test } from 'node:test'
|
|
2
|
-
import { deepEqual } from 'node:assert/strict'
|
|
3
|
-
import { readdirSync } from 'node:fs'
|
|
4
|
-
|
|
5
|
-
import { mkTempDir, cli, dir, touch } from './utils/test-utils.js'
|
|
6
|
-
|
|
7
|
-
test('flattendir moves files to top level and deletes empty dirs', () => {
|
|
8
|
-
const tmp = mkTempDir('flattendir')
|
|
9
|
-
dir(tmp, 'dir1', 'dir1-1')
|
|
10
|
-
dir(tmp, 'dir2')
|
|
11
|
-
touch(tmp, 'file1.txt')
|
|
12
|
-
touch(tmp, 'dir1', 'file2.txt')
|
|
13
|
-
touch(tmp, 'dir1', 'dir1-1', 'file3.txt')
|
|
14
|
-
touch(tmp, 'dir1', '.DS_Store')
|
|
15
|
-
|
|
16
|
-
cli('flattendir', tmp)
|
|
17
|
-
deepEqual(readdirSync(tmp).sort(), [
|
|
18
|
-
'file1.txt',
|
|
19
|
-
'file2.txt',
|
|
20
|
-
'file3.txt'
|
|
21
|
-
])
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
test('flattendir does not move files if filename collision occurs', () => {
|
|
25
|
-
const tmp = mkTempDir('flattendir-collision')
|
|
26
|
-
dir(tmp, 'dir1')
|
|
27
|
-
touch(tmp, 'file1.txt')
|
|
28
|
-
touch(tmp, 'dir1', 'file1.txt')
|
|
29
|
-
|
|
30
|
-
cli('flattendir', tmp)
|
|
31
|
-
deepEqual(readdirSync(tmp, { recursive: true }).sort(), [
|
|
32
|
-
'dir1',
|
|
33
|
-
'dir1/file1.txt',
|
|
34
|
-
'file1.txt'
|
|
35
|
-
])
|
|
36
|
-
})
|
package/src/qdir.test.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { test } from 'node:test'
|
|
2
|
-
import { join } from 'node:path'
|
|
3
|
-
import { equal, deepEqual } from 'node:assert/strict'
|
|
4
|
-
import { cpSync, readdirSync } from 'node:fs'
|
|
5
|
-
|
|
6
|
-
import { qdir } from './qdir.js'
|
|
7
|
-
import { mkTempDir } from './utils/test-utils.js'
|
|
8
|
-
|
|
9
|
-
const rel = f => join(import.meta.dirname, f)
|
|
10
|
-
|
|
11
|
-
test('qdir-jobs get renamed and failed have their exit status code', async () => {
|
|
12
|
-
const tmp = mkTempDir('qdir')
|
|
13
|
-
cpSync(rel('fixtures/qdir-jobs'), tmp, { recursive: true })
|
|
14
|
-
|
|
15
|
-
const err = await qdir(tmp, 0.2)
|
|
16
|
-
equal(err, null)
|
|
17
|
-
|
|
18
|
-
deepEqual(readdirSync(tmp).sort(), [
|
|
19
|
-
'job1_good.sh.done',
|
|
20
|
-
'job2_bad.sh.failed.1',
|
|
21
|
-
'job3_good.sh.done',
|
|
22
|
-
'job4_bad.sh.failed.1'
|
|
23
|
-
])
|
|
24
|
-
})
|
package/src/seqcheck.test.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { test } from 'node:test'
|
|
2
|
-
import { deepEqual } from 'node:assert/strict'
|
|
3
|
-
import { extractSeqNums, findMissingNumbers } from './seqcheck.js'
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
test('extractSeqNums extracts sequence numbers from filenames', () => {
|
|
7
|
-
const filenames = [
|
|
8
|
-
'video-111_001.mov',
|
|
9
|
-
'video-111_002.mov',
|
|
10
|
-
'video-111_004.mov',
|
|
11
|
-
'bad.mov',
|
|
12
|
-
'bad_too_a39.mov',
|
|
13
|
-
]
|
|
14
|
-
deepEqual(extractSeqNums(filenames, '_', '.'), [1, 2, 4])
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
test('findMissingNumbers ', () => {
|
|
19
|
-
test('finds gaps in a sequence', () =>
|
|
20
|
-
deepEqual(findMissingNumbers([1, 2, 4, 5, 8]), [3, 6, 7]))
|
|
21
|
-
|
|
22
|
-
test('returns empty array for empty input', () =>
|
|
23
|
-
deepEqual(findMissingNumbers([]), []))
|
|
24
|
-
|
|
25
|
-
test('returns empty array when there are no gaps', () =>
|
|
26
|
-
deepEqual(findMissingNumbers([10, 11, 12]), []))
|
|
27
|
-
})
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { equal } from 'node:assert/strict'
|
|
2
|
-
import test, { describe } from 'node:test'
|
|
3
|
-
import { replaceExt } from './fs-utils.js'
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
describe('replaceExt', () => {
|
|
7
|
-
test('replaces a simple extension', () =>
|
|
8
|
-
equal(replaceExt('file.txt', 'md'), 'file.md'))
|
|
9
|
-
|
|
10
|
-
test('replaces a multi-part extension', () =>
|
|
11
|
-
equal(replaceExt('archive.tar.gz', 'zip'), 'archive.tar.zip'))
|
|
12
|
-
|
|
13
|
-
test('adds extension when none exists', () =>
|
|
14
|
-
equal(replaceExt('README', 'md'), 'README.md'))
|
|
15
|
-
|
|
16
|
-
test('handles empty filename', () =>
|
|
17
|
-
equal(replaceExt('', 'ext'), '.ext'))
|
|
18
|
-
|
|
19
|
-
test('handles dot-files', () =>
|
|
20
|
-
equal(replaceExt('.env', 'txt'), '.env.txt'))
|
|
21
|
-
})
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { join } from 'node:path'
|
|
2
|
-
import { tmpdir } from 'node:os'
|
|
3
|
-
import { equal, deepEqual } from 'node:assert/strict'
|
|
4
|
-
import { mkdtemp, writeFile, rm } from 'node:fs/promises'
|
|
5
|
-
import { test, describe, before, after } from 'node:test'
|
|
6
|
-
|
|
7
|
-
import { parseOptions } from './parseOptions.js'
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
describe('parseOptions', () => {
|
|
11
|
-
let testDir
|
|
12
|
-
let inTmpDir = f => join(testDir, f)
|
|
13
|
-
const testFiles = ['file1.png', 'file2.png', 'file3.png']
|
|
14
|
-
|
|
15
|
-
before(async () => {
|
|
16
|
-
testDir = await mkdtemp(join(tmpdir(), 'parse-args-'))
|
|
17
|
-
for (const file of testFiles)
|
|
18
|
-
await writeFile(inTmpDir(file), '')
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
after(() => rm(testDir, { recursive: true }))
|
|
22
|
-
|
|
23
|
-
test('parses args and globs files', async () => {
|
|
24
|
-
const { values, positionals, files } = await parseOptions({
|
|
25
|
-
'output-dir': { type: 'string' }
|
|
26
|
-
}, {
|
|
27
|
-
args: ['--output-dir', '/tmp', inTmpDir('file[12].png')],
|
|
28
|
-
})
|
|
29
|
-
equal(values['output-dir'], '/tmp')
|
|
30
|
-
deepEqual(positionals, [inTmpDir('file[12].png')])
|
|
31
|
-
deepEqual(files, [
|
|
32
|
-
inTmpDir('file1.png'),
|
|
33
|
-
inTmpDir('file2.png')
|
|
34
|
-
])
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
test('respects verbatim tokens', async () => {
|
|
38
|
-
const literal0 = 'literal-file[98].png'
|
|
39
|
-
const literal1 = 'literal-file[99].png'
|
|
40
|
-
const { files } = await parseOptions({}, {
|
|
41
|
-
args: [inTmpDir('file[12].png'), '--', literal0, literal1]
|
|
42
|
-
})
|
|
43
|
-
deepEqual(files, [
|
|
44
|
-
inTmpDir('file1.png'),
|
|
45
|
-
inTmpDir('file2.png'),
|
|
46
|
-
literal0,
|
|
47
|
-
literal1,
|
|
48
|
-
])
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
test('empty files array when no positionals', async () => {
|
|
52
|
-
const { files, values } = await parseOptions({
|
|
53
|
-
foo: { type: 'boolean' }
|
|
54
|
-
}, {
|
|
55
|
-
args: ['--foo'],
|
|
56
|
-
})
|
|
57
|
-
equal(values.foo, true)
|
|
58
|
-
deepEqual(files, [])
|
|
59
|
-
})
|
|
60
|
-
})
|
package/src/vconcat.test.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { ok } from 'node:assert/strict'
|
|
2
|
-
import { join } from 'node:path'
|
|
3
|
-
import { test } from 'node:test'
|
|
4
|
-
import { cpSync } from 'node:fs'
|
|
5
|
-
|
|
6
|
-
import { videoAttrs } from './utils/subprocess.js'
|
|
7
|
-
import { mkTempDir, cli } from './utils/test-utils.js'
|
|
8
|
-
|
|
9
|
-
const rel = f => join(import.meta.dirname, f)
|
|
10
|
-
|
|
11
|
-
test('vconcat concatenates videos with single quotes in filenames', async () => {
|
|
12
|
-
const tmp = mkTempDir('vconcat')
|
|
13
|
-
|
|
14
|
-
const file1 = join(tmp, `video'1.mp4`)
|
|
15
|
-
const file2 = join(tmp, `video'2.mp4`)
|
|
16
|
-
cpSync(rel('fixtures/60fps.mp4'), file1)
|
|
17
|
-
cpSync(rel('fixtures/60fps.mp4'), file2)
|
|
18
|
-
|
|
19
|
-
cli('vconcat', file1, file2)
|
|
20
|
-
|
|
21
|
-
const { duration } = await videoAttrs(join(tmp, `video'1.concat.mp4`))
|
|
22
|
-
ok(parseFloat(duration) === 60, `Duration should be 60s, got ${duration}s`)
|
|
23
|
-
})
|
package/src/vsplit.test.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { ok } from 'node:assert/strict'
|
|
2
|
-
import { join } from 'node:path'
|
|
3
|
-
import { describe, test } from 'node:test'
|
|
4
|
-
import { cpSync, readdirSync } from 'node:fs'
|
|
5
|
-
|
|
6
|
-
import { videoAttrs } from './utils/subprocess.js'
|
|
7
|
-
import { mkTempDir, cli } from './utils/test-utils.js'
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const rel = f => join(import.meta.dirname, f)
|
|
11
|
-
|
|
12
|
-
describe('vsplit splits video into multiple clips from CSV', () => {
|
|
13
|
-
const tmp = mkTempDir('vsplit')
|
|
14
|
-
|
|
15
|
-
const csvFile = join(tmp, '60fps.csv')
|
|
16
|
-
const inputFile = join(tmp, '60fps.mp4')
|
|
17
|
-
|
|
18
|
-
cpSync(rel('fixtures/60fps.csv'), csvFile)
|
|
19
|
-
cpSync(rel('fixtures/60fps.mp4'), inputFile)
|
|
20
|
-
cli('vsplit', csvFile, inputFile)
|
|
21
|
-
|
|
22
|
-
test('all 6 clips were created', () => {
|
|
23
|
-
const files = readdirSync(tmp).filter(f => f.startsWith('60fps_'))
|
|
24
|
-
ok(files.length === 6, `Expected 6 clips, got ${files.length}`)
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
test('first clip has correct duration (5 seconds)', async () => {
|
|
28
|
-
const { duration } = await videoAttrs(join(tmp, '60fps_1.mp4'))
|
|
29
|
-
const EPSILON = 0.05
|
|
30
|
-
ok(Math.abs(parseFloat(duration) - 5) < EPSILON, `Duration should be 5s, got ${duration}s`)
|
|
31
|
-
})
|
|
32
|
-
})
|
package/src/vtrim.test.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { ok } from 'node:assert/strict'
|
|
2
|
-
import { join } from 'node:path'
|
|
3
|
-
import { cpSync } from 'node:fs'
|
|
4
|
-
import { describe, test } from 'node:test'
|
|
5
|
-
|
|
6
|
-
import { videoAttrs } from './utils/subprocess.js'
|
|
7
|
-
import { mkTempDir, cli } from './utils/test-utils.js'
|
|
8
|
-
|
|
9
|
-
const rel = f => join(import.meta.dirname, f)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
describe('vtrim', () => {
|
|
13
|
-
function almostEqual(actual, expected) {
|
|
14
|
-
const EPSILON = 0.05
|
|
15
|
-
ok(Math.abs(parseFloat(actual) - expected) < EPSILON,
|
|
16
|
-
`Duration should be around ${expected}s, got ${actual}s`)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const tmp = mkTempDir('vtrim')
|
|
20
|
-
const inputFile = join(tmp, '60fps.mp4')
|
|
21
|
-
cpSync(rel('fixtures/60fps.mp4'), inputFile)
|
|
22
|
-
|
|
23
|
-
test('from start to end time', async () => {
|
|
24
|
-
cli('vtrim', '--start', 5, '--end', 11, inputFile)
|
|
25
|
-
const { duration } = await videoAttrs(join(tmp, '60fps.trim.mp4'))
|
|
26
|
-
almostEqual(duration, 6)
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
test('start time only', async () => {
|
|
30
|
-
cli('vtrim', '--start', 5, inputFile)
|
|
31
|
-
const { duration } = await videoAttrs(join(tmp, '60fps.trim.mp4'))
|
|
32
|
-
almostEqual(duration, 25)
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
test('end time only', async () => {
|
|
36
|
-
cli('vtrim', '--end', 11, inputFile)
|
|
37
|
-
const { duration } = await videoAttrs(join(tmp, '60fps.trim.mp4'))
|
|
38
|
-
almostEqual(duration, 11)
|
|
39
|
-
})
|
|
40
|
-
})
|