mediasnacks 0.25.0 → 0.27.0

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/src/moov2front.js CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env node
2
1
  import { ffmpeg, assertUserHasFFmpeg } from './utils/subprocess.js'
3
2
  import { uniqueFilenameFor, overwrite } from './utils/fs-utils.js'
4
3
  import { parseOptions } from './utils/parseOptions.js'
@@ -20,7 +19,7 @@ NOTES
20
19
  `.trim()
21
20
 
22
21
 
23
- async function main() {
22
+ export default async function main() {
24
23
  await assertUserHasFFmpeg()
25
24
 
26
25
  const { values, files } = await parseOptions({
@@ -32,25 +31,23 @@ async function main() {
32
31
  return
33
32
  }
34
33
 
35
- if (!files.length)
36
- throw new Error(HELP)
34
+ if (!files.length) throw new Error('Missing input file(s)')
37
35
 
38
36
  console.log('Optimizing video for progressive download…')
39
37
  for (const file of files)
40
- await moov2front(file)
38
+ try {
39
+ await moov2front(file)
40
+ console.log(file)
41
+ }
42
+ catch (err) {
43
+ console.error(err?.message || err)
44
+ }
41
45
  }
42
46
 
43
- async function moov2front(file) {
44
- if (!/\.(mp4|mov)$/i.test(file)) {
45
- console.log('(skipped: not mp4/mov)', file)
46
- return
47
- }
48
- if (await moovIsBeforeMdat(file)) {
49
- console.log('(skipped: no changes needed)', file)
50
- return
51
- }
47
+ export async function moov2front(file) {
48
+ if (!/\.(mp4|mov)$/i.test(file)) throw new Error(`not mp4/mov. ${file}`)
49
+ if (await moovIsBeforeMdat(file)) throw new Error(`no changes needed. ${file}`)
52
50
 
53
- console.log(file)
54
51
  const tmp = uniqueFilenameFor(file)
55
52
  await ffmpeg([
56
53
  '-hide_banner',
@@ -71,9 +68,3 @@ async function moovIsBeforeMdat(file) {
71
68
  const firstMatchedAtom = stderr.match(/type:'(moov|mdat)'/)?.[1]
72
69
  return firstMatchedAtom === 'moov'
73
70
  }
74
-
75
-
76
- main().catch(err => {
77
- console.error(err.message)
78
- process.exit(1)
79
- })
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env node
2
1
  import { join } from 'node:path'
3
2
  import { spawn } from 'node:child_process'
4
3
  import { readdirSync } from 'node:fs'
@@ -7,13 +6,13 @@ import { parseOptions } from './utils/parseOptions.js'
7
6
 
8
7
  const HELP = `
9
8
  SYNOPSIS
10
- mediasnacks random [-r | --recursive]
9
+ mediasnacks openrand [-r | --recursive]
11
10
 
12
11
  DESCRIPTION
13
12
  Opens a random file in the current working directory
14
13
  `.trim()
15
14
 
16
- async function main() {
15
+ export default async function main() {
17
16
  if (process.platform !== 'darwin')
18
17
  throw new Error('Error: This command is only supported on macOS.')
19
18
 
@@ -27,17 +26,16 @@ async function main() {
27
26
  return
28
27
  }
29
28
 
30
- spawn('open', [pickRandomFile('.', values.recursive)])
29
+ openrand('.', values.recursive)
31
30
  }
32
31
 
33
- function pickRandomFile(dir, recursive) {
32
+ export function openrand(dir = '.', recursive = false) {
33
+ spawn('open', [pickRandomFile(dir, recursive)])
34
+ }
35
+
36
+ export function pickRandomFile(dir = '.', recursive = false) {
34
37
  const files = readdirSync(dir, { withFileTypes: true, recursive })
35
38
  .filter(entry => !entry.name.startsWith('.') && entry.isFile())
36
39
  .map(entry => join(entry.parentPath, entry.name))
37
40
  return files[Math.floor(Math.random() * files.length)]
38
41
  }
39
-
40
- main().catch(err => {
41
- console.error(err.message)
42
- process.exit(1)
43
- })
package/src/play.js CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env node
2
1
  import { spawn } from 'node:child_process'
3
2
  import { parseOptions } from './utils/parseOptions.js'
4
3
  import { findFiles } from './utils/fs-utils.js'
@@ -17,7 +16,7 @@ EXAMPLE
17
16
  `.trim()
18
17
 
19
18
 
20
- async function main() {
19
+ export default async function main() {
21
20
  const { values, positionals } = await parseOptions({
22
21
  recursive: { short: 'r', type: 'boolean', default: true },
23
22
  help: { short: 'h', type: 'boolean' }
@@ -41,7 +40,7 @@ async function main() {
41
40
  play(files)
42
41
  }
43
42
 
44
- function play(files) {
43
+ export function play(files) {
45
44
  const mpv = spawn('mpv', ['--playlist=-'], {
46
45
  detached: true,
47
46
  stdio: ['pipe', 'ignore', 'ignore']
@@ -57,8 +56,3 @@ function play(files) {
57
56
  process.exit(1)
58
57
  })
59
58
  }
60
-
61
- main().catch(err => {
62
- console.error(err.message)
63
- process.exit(1)
64
- })
package/src/png.js ADDED
@@ -0,0 +1,34 @@
1
+ import { parseOptions } from './utils/parseOptions.js'
2
+ import { run } from './utils/subprocess.js'
3
+
4
+
5
+ const HELP = `
6
+ SYNOPSIS
7
+ mediasnacks png <img1> [img2 ...]
8
+
9
+ DESCRIPTION
10
+ Losslessly optimizes PNG images with oxipng at max level.
11
+
12
+ EXAMPLE
13
+ mediasnacks png *.png
14
+ `.trim()
15
+
16
+ export default async function main() {
17
+ const { values, positionals } = await parseOptions({
18
+ help: { short: 'h', type: 'boolean' }
19
+ })
20
+
21
+ if (values.help || !positionals[0]) {
22
+ console.log(HELP)
23
+ return
24
+ }
25
+
26
+ await png(...positionals)
27
+ }
28
+
29
+ export async function png(...images) {
30
+ await run('oxipng', [
31
+ '--opt', 'max',
32
+ ...images
33
+ ])
34
+ }
package/src/prores.js CHANGED
@@ -1,10 +1,9 @@
1
- #!/usr/bin/env node
2
1
  import { resolve, parse, join } from 'node:path'
3
2
  import { parseOptions } from './utils/parseOptions.js'
4
3
  import { assertUserHasFFmpeg, run } from './utils/subprocess.js'
5
4
 
6
5
  export const ProresProfiles = new class {
7
- // https://github.com/oyvindln/vhs-decode/wiki/ProRes-The-Definitive-FFmpeg-Guide#profiles-can-be-the-following
6
+ // https://github.com/oyvindln/vhs-decode/wiki/ProRes-The-Definitive-FFmpeg-Guide#profiles-can-be-the-following
8
7
  profiles = {
9
8
  // 10-bit color depth
10
9
  0: '422 Proxy',
@@ -50,7 +49,7 @@ EXAMPLES
50
49
  `.trim()
51
50
 
52
51
 
53
- async function main() {
52
+ export default async function main() {
54
53
  await assertUserHasFFmpeg()
55
54
 
56
55
  const { values, files } = await parseOptions({
@@ -75,10 +74,11 @@ async function main() {
75
74
  const { name, dir } = parse(video)
76
75
  const output = join(dir, `${name}.prores.mov`)
77
76
 
78
- await prores(video, values.start, values.end, values.profile, output)
77
+ const { profile, start, end } = values
78
+ await prores({ video, profile, start, end, output })
79
79
  }
80
80
 
81
- async function prores(video, start, end, profile, output) {
81
+ export async function prores({ video, profile, start, end, output }) {
82
82
  await run('ffmpeg', [
83
83
  '-v', 'error',
84
84
  '-stats',
@@ -89,9 +89,3 @@ async function prores(video, start, end, profile, output) {
89
89
  output
90
90
  ].flat())
91
91
  }
92
-
93
- if (import.meta.main)
94
- main().catch(err => {
95
- console.error(err.message || err)
96
- process.exit(1)
97
- })
package/src/qdir.js CHANGED
@@ -1,5 +1,3 @@
1
- #!/usr/bin/env node
2
-
3
1
  import { join } from 'node:path'
4
2
  import { spawn } from 'node:child_process'
5
3
  import { readdir, writeFile, unlink, rename } from 'node:fs/promises'
@@ -30,7 +28,7 @@ function newExt(exitCode) {
30
28
  }
31
29
 
32
30
 
33
- async function main() {
31
+ export default async function main() {
34
32
  const { values, positionals } = await parseOptions({
35
33
  help: { short: 'h', type: 'boolean' }
36
34
  })
@@ -98,10 +96,3 @@ async function runShell(scriptPath) {
98
96
  function sleep(ms) {
99
97
  return new Promise(resolve => setTimeout(resolve, ms))
100
98
  }
101
-
102
-
103
- if (import.meta.main)
104
- main().catch(err => {
105
- console.error(err.message || err)
106
- process.exit(1)
107
- })
package/src/resize.js CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env node
2
1
  import { join } from 'node:path'
3
2
  import { rename } from 'node:fs/promises'
4
3
 
@@ -10,7 +9,7 @@ import { videoAttrs } from './utils/videoAttrs.js'
10
9
 
11
10
  const HELP = `
12
11
  SYNOPSIS
13
- mediasnacks resize [--width=<num>] [--height=<num>] [-y | --overwrite] [--output-dir=<dir>] <files>
12
+ mediasnacks resize [--width=<num>] [--height=<num>] [-y | --overwrite] [--outdir=<dir>] <files>
14
13
 
15
14
  DESCRIPTION
16
15
  Resizes videos and images. The aspect ratio is preserved when only one dimension is specified.
@@ -20,7 +19,7 @@ EXAMPLES
20
19
  mediasnacks resize -y --width 480 'dir-a/**/*.png' 'dir-b/**/*.mp4'
21
20
 
22
21
  Output directory (-o)
23
- mediasnacks resize --height 240 --output-dir /tmp/out video.mov
22
+ mediasnacks resize --height 240 --outdir /tmp/out video.mov
24
23
 
25
24
  OPTIONS
26
25
  --width and --height are -2 by default:
@@ -29,13 +28,13 @@ OPTIONS
29
28
  `.trim()
30
29
 
31
30
 
32
- async function main() {
31
+ export default async function main() {
33
32
  await assertUserHasFFmpeg()
34
33
 
35
34
  const { values, files } = await parseOptions({
36
35
  width: { type: 'string', default: '-2' },
37
36
  height: { type: 'string', default: '-2' },
38
- 'output-dir': { type: 'string', default: '' },
37
+ outdir: { type: 'string', default: '' },
39
38
  overwrite: { short: 'y', type: 'boolean' },
40
39
  help: { short: 'h', type: 'boolean' },
41
40
  })
@@ -57,31 +56,33 @@ async function main() {
57
56
 
58
57
  console.log('Resizing…')
59
58
  for (const file of files)
60
- await resize({
61
- file,
62
- outFile: join(values['output-dir'], file), // TODO basename ?
63
- overwrite: values.overwrite,
64
- width,
65
- height,
66
- })
59
+ try {
60
+ await resize({
61
+ file,
62
+ outFile: join(values.outdir, file), // TODO basename ?
63
+ overwrite: values.overwrite,
64
+ width,
65
+ height,
66
+ })
67
+ console.log(file)
68
+ }
69
+ catch (err) {
70
+ console.error(err?.message || err)
71
+ }
67
72
  }
68
73
 
69
74
 
70
- async function resize({ file, outFile, overwrite, width, height }) {
75
+ export async function resize({ file, outFile, overwrite, width, height }) {
71
76
  const v = await videoAttrs(file)
72
77
  if (width === v.width && height === v.height
73
78
  || width < 0 && height === v.height
74
- || height < 0 && width === v.width) {
75
- console.log('(skipped: no changes needed)', file)
76
- return
77
- }
79
+ || height < 0 && width === v.width
80
+ )
81
+ throw new Error(`no changes needed. ${file}`)
78
82
 
79
- if (!overwrite && isFile(outFile)) {
80
- console.log('(skipped: output file exists but --overwrite=false)', file)
81
- return
82
- }
83
+ if (!overwrite && isFile(outFile))
84
+ throw new Error(`output file exists but --overwrite=false. ${file}`)
83
85
 
84
- console.log(file)
85
86
  const tmp = uniqueFilenameFor(file)
86
87
  await ffmpeg([
87
88
  '-i', file,
@@ -91,9 +92,3 @@ async function resize({ file, outFile, overwrite, width, height }) {
91
92
  ])
92
93
  await rename(tmp, outFile)
93
94
  }
94
-
95
-
96
- main().catch(err => {
97
- console.error(err.message)
98
- process.exit(1)
99
- })
package/src/seqcheck.js CHANGED
@@ -1,7 +1,8 @@
1
- #!/usr/bin/env node
2
1
  import { parseArgs } from 'node:util'
3
2
  import { readdirSync } from 'node:fs'
4
3
 
4
+ const LEFT_DELIM = '_'
5
+ const RIGHT_DELIM = '.'
5
6
 
6
7
  const HELP = `
7
8
  SYNOPSIS
@@ -11,17 +12,17 @@ DESCRIPTION
11
12
  Find missing numbered files in a sequence.
12
13
 
13
14
  OPTIONS
14
- -ld, --left-delimiter <str> Delimiter before the number (default: "_")
15
- -rd, --right-delimiter <str> Delimiter after the number (default: ".")
15
+ -ld, --left-delimiter <str> Delimiter before the number (default: "${LEFT_DELIM}")
16
+ -rd, --right-delimiter <str> Delimiter after the number (default: "${RIGHT_DELIM}")
16
17
  -h, --help
17
18
  `.trim()
18
19
 
19
20
 
20
- function main() {
21
+ export default function main() {
21
22
  const { values, positionals } = parseArgs({
22
23
  options: {
23
- 'left-delimiter': { type: 'string', default: '_' },
24
- 'right-delimiter': { type: 'string', default: '.' },
24
+ 'left-delimiter': { type: 'string', default: LEFT_DELIM },
25
+ 'right-delimiter': { type: 'string', default: RIGHT_DELIM },
25
26
  help: { short: 'h', type: 'boolean' },
26
27
  },
27
28
  allowPositionals: true,
@@ -32,18 +33,19 @@ function main() {
32
33
  return
33
34
  }
34
35
 
35
- const seq = extractSeqNums(
36
- readdirSync(positionals[0] || process.cwd()),
37
- values['left-delimiter'],
38
- values['right-delimiter'])
39
-
40
- const missing = findMissingNumbers(seq)
36
+ const dir = positionals[0] || process.cwd()
37
+ const missing = seqcheck(dir, values['left-delimiter'], values['right-delimiter'])
41
38
  if (missing.length)
42
39
  console.log('Missing:', missing)
43
40
  }
44
41
 
45
- export function extractSeqNums(names, leftDelimiter, rightDelimiter) {
46
- const pattern = new RegExp(escapeRegex(leftDelimiter) + '(\\d+)' + escapeRegex(rightDelimiter))
42
+ export function seqcheck(dir, leftDelim = LEFT_DELIM, rightDelim = RIGHT_DELIM) {
43
+ const seq = extractSeqNums(readdirSync(dir), leftDelim, rightDelim)
44
+ return findMissingNumbers(seq)
45
+ }
46
+
47
+ export function extractSeqNums(names, leftDelim, rightDelim) {
48
+ const pattern = new RegExp(escapeRegex(leftDelim) + '(\\d+)' + escapeRegex(rightDelim))
47
49
  const seq = []
48
50
  for (const name of names) {
49
51
  const match = name.match(pattern)
@@ -66,7 +68,3 @@ export function findMissingNumbers(seq) {
66
68
  function escapeRegex(str) {
67
69
  return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
68
70
  }
69
-
70
-
71
- if (import.meta.main)
72
- main()
package/src/sqcrop.js CHANGED
@@ -1,5 +1,3 @@
1
- #!/usr/bin/env node
2
-
3
1
  import { join } from 'node:path'
4
2
  import { rename } from 'node:fs/promises'
5
3
 
@@ -10,18 +8,18 @@ import { parseOptions } from './utils/parseOptions.js'
10
8
 
11
9
  const HELP = `
12
10
  SYNOPSIS
13
- mediasnacks sqcrop [-y | --overwrite] [--output-dir=<dir>] <images>
11
+ mediasnacks sqcrop [-y | --overwrite] [--outdir=<dir>] <images>
14
12
 
15
13
  DESCRIPTION
16
14
  Square crops images
17
15
  `.trim()
18
16
 
19
17
 
20
- async function main() {
18
+ export default async function main() {
21
19
  await assertUserHasFFmpeg()
22
20
 
23
21
  const { values, files } = await parseOptions({
24
- 'output-dir': { type: 'string', default: '' },
22
+ outdir: { type: 'string', default: '' },
25
23
  overwrite: { short: 'y', type: 'boolean' },
26
24
  help: { short: 'h', type: 'boolean' },
27
25
  })
@@ -36,26 +34,25 @@ async function main() {
36
34
 
37
35
  console.log('Cropping…')
38
36
  for (const file of files)
39
- await sqcrop({
40
- file,
41
- outFile: join(values['output-dir'], file),
42
- overwrite: values.overwrite
43
- })
37
+ try {
38
+ await sqcrop({
39
+ file,
40
+ outFile: join(values.outdir, file),
41
+ overwrite: values.overwrite
42
+ })
43
+ console.log(file)
44
+ }
45
+ catch (err) {
46
+ console.error(err?.message || err)
47
+ }
44
48
  }
45
49
 
46
- async function sqcrop({ file, outFile, overwrite }) {
50
+ export async function sqcrop({ file, outFile, overwrite }) {
47
51
  const stOut = lstat(outFile)
48
52
 
49
- if (!overwrite && stOut?.isFile()) {
50
- console.log('(skipped: output file exists but --overwrite=false)', file)
51
- return
52
- }
53
- if (stOut?.mtimeMs > lstat(file)?.mtimeMs) {
54
- console.log('(skipped: outputFile is newer)', file)
55
- return
56
- }
53
+ if (!overwrite && stOut?.isFile()) throw new Error(`output file exists but --overwrite=false. ${file}`)
54
+ if (stOut?.mtimeMs > lstat(file)?.mtimeMs) throw new Error(`outputFile is newer. ${file}`)
57
55
 
58
- console.log(file)
59
56
  const tmp = uniqueFilenameFor(file)
60
57
  await ffmpeg([
61
58
  '-v', 'error',
@@ -66,8 +63,3 @@ async function sqcrop({ file, outFile, overwrite }) {
66
63
  ])
67
64
  await rename(tmp, outFile)
68
65
  }
69
-
70
- main().catch(err => {
71
- console.error(err.message)
72
- process.exit(1)
73
- })
package/src/ssim.js CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env node
2
1
  import { ffmpeg } from './utils/subprocess.js'
3
2
  import { parseOptions } from './utils/parseOptions.js'
4
3
 
@@ -12,7 +11,7 @@ DESCRIPTION
12
11
  `.trim()
13
12
 
14
13
 
15
- async function main() {
14
+ export default async function main() {
16
15
  const { values, positionals } = await parseOptions({
17
16
  help: { short: 'h', type: 'boolean' }
18
17
  })
@@ -41,10 +40,3 @@ export async function ssim(img1, img2) {
41
40
  throw new Error(`Could not parse SSIM output:\n${stderr}`)
42
41
  return parseFloat(match[1])
43
42
  }
44
-
45
-
46
- if (import.meta.main)
47
- main().catch(err => {
48
- console.error(err.message)
49
- process.exit(1)
50
- })
package/src/unemoji.js ADDED
@@ -0,0 +1,79 @@
1
+ import { rename } from 'node:fs/promises'
2
+ import { existsSync } from 'node:fs'
3
+ import { dirname, basename, join } from 'node:path'
4
+ import { parseOptions } from './utils/parseOptions.js'
5
+ import { findFiles } from './utils/fs-utils.js'
6
+
7
+ const EMOJI_RE = new RegExp(
8
+ '[' +
9
+ '\u{1F600}-\u{1F64F}' + // Emoticons
10
+ '\u{1F300}-\u{1F5FF}' + // Misc Symbols and Pictographs
11
+ '\u{1F680}-\u{1F6FF}' + // Transport and Map
12
+ '\u{2600}-\u{26FF}' + // Misc symbols
13
+ '\u{2700}-\u{27BF}' + // Dingbats
14
+ '\u{1F900}-\u{1F9FF}' + // Supplemental Symbols and Pictographs
15
+ '\u{1FA70}-\u{1FAFF}' + // Symbols and Pictographs Extended-A
16
+ '\u{1F1E6}-\u{1F1FF}' + // Regional Indicator Symbols
17
+ ']',
18
+ 'gu'
19
+ )
20
+
21
+ const HELP = `
22
+ SYNOPSIS
23
+ mediasnacks unemoji [-r | --recursive] <dir>
24
+
25
+ DESCRIPTION
26
+ Removes emoji from filenames in the current directory.
27
+ Does not overwrite files.
28
+
29
+ OPTIONS
30
+ -r, --recursive
31
+ `.trim()
32
+
33
+ export default async function main() {
34
+ const { values, positionals } = await parseOptions({
35
+ help: { short: 'h', type: 'boolean' },
36
+ recursive: { short: 'r', type: 'boolean' }
37
+ })
38
+
39
+ if (values.help) {
40
+ console.log(HELP)
41
+ return
42
+ }
43
+
44
+ if (positionals.length !== 1) throw new Error('Only one dir is accepted')
45
+
46
+ const files = findFiles({
47
+ dir: positionals[0],
48
+ regex: EMOJI_RE,
49
+ recursive: values.recursive,
50
+ })
51
+
52
+ for (const file of files)
53
+ try {
54
+ const newpath = await unemoji(file)
55
+ if (newpath)
56
+ console.log(`Renaming: ${file} -> ${newpath}`)
57
+ }
58
+ catch (err) {
59
+ console.error(err?.message || err)
60
+ }
61
+ }
62
+
63
+ export async function unemoji(file) {
64
+ const dir = dirname(file)
65
+ const base = basename(file)
66
+ const newbase = base.replace(EMOJI_RE, '')
67
+ .normalize('NFKC')
68
+ .replace(/\s+/g, ' ')
69
+ .replace(/\s+\./g, '.')
70
+ .trim()
71
+ if (base === newbase)
72
+ return null
73
+
74
+ const newpath = join(dir, newbase)
75
+ if (existsSync(newpath)) throw new Error(`Skipping (exists): ${file} -> ${newpath}`)
76
+
77
+ await rename(file, newpath)
78
+ return newpath
79
+ }
@@ -34,7 +34,7 @@ export async function mkDir(path) {
34
34
  }
35
35
  }
36
36
 
37
- export function findFiles({ dir, regex, recursive, ignoredDirs }) {
37
+ export function findFiles({ dir, regex, recursive, ignoredDirs = [] }) {
38
38
  return readdirSync(dir, { withFileTypes: true, recursive })
39
39
  .filter(entry =>
40
40
  entry.isFile()
@@ -6,6 +6,7 @@ const glob = promisify(_glob)
6
6
 
7
7
  export async function parseOptions(options = {}, config = {}) {
8
8
  const { values, positionals, tokens } = parseArgs({
9
+ args: process.argv.slice(3),
9
10
  allowPositionals: true,
10
11
  options,
11
12
  ...config,
package/src/vsplit.js CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env node
2
1
  import { readFileSync } from 'node:fs'
3
2
  import { resolve, parse, join } from 'node:path'
4
3
 
@@ -35,7 +34,7 @@ SEE ALSO
35
34
  `.trim()
36
35
 
37
36
 
38
- async function main() {
37
+ export default async function main() {
39
38
  await assertUserHasFFmpeg()
40
39
 
41
40
  const { values, files } = await parseOptions({
@@ -79,7 +78,7 @@ function parseCSV(csvPath) {
79
78
  return clips
80
79
  }
81
80
 
82
- async function vsplit(videoPath, clips) {
81
+ export async function vsplit(videoPath, clips) {
83
82
  const { dir, name, ext } = parse(videoPath)
84
83
  const seqLen = Math.log10(clips.length) + 1 | 0
85
84
 
@@ -97,8 +96,3 @@ async function vsplit(videoPath, clips) {
97
96
  ])
98
97
  }
99
98
  }
100
-
101
- main().catch(err => {
102
- console.error(err.message || err)
103
- process.exit(1)
104
- })
package/src/vtrim.js CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env node
2
1
  import { resolve, parse } from 'node:path'
3
2
  import { parseOptions } from './utils/parseOptions.js'
4
3
  import { ffmpeg, assertUserHasFFmpeg } from './utils/subprocess.js'
@@ -14,14 +13,13 @@ DESCRIPTION
14
13
  OPTIONS
15
14
  -s, --start <time> Start time (e.g. 10, 00:00:10, 1:23.5). Default: beginning.
16
15
  -e, --end <time> End time (e.g. 30, 00:00:30, 2:45.0). Default: end of video.
17
- -h, --help
18
16
 
19
17
  SEE ALSO
20
18
  mediasnacks vsplit
21
19
  `.trim()
22
20
 
23
21
 
24
- async function main() {
22
+ export default async function main() {
25
23
  await assertUserHasFFmpeg()
26
24
 
27
25
  const { values, files } = await parseOptions({
@@ -39,10 +37,14 @@ async function main() {
39
37
  throw new Error('No video specified. See mediasnacks vtrim --help')
40
38
 
41
39
  for (const file of files)
42
- await vtrim(resolve(file), values.start, values.end)
40
+ await vtrim({
41
+ video: resolve(file),
42
+ start: values.start,
43
+ end: values.end
44
+ })
43
45
  }
44
46
 
45
- async function vtrim(video, start, end) {
47
+ export async function vtrim({ video, start, end }) {
46
48
  const { dir, name, ext } = parse(video)
47
49
  await ffmpeg([
48
50
  '-v', 'error',
@@ -54,8 +56,3 @@ async function vtrim(video, start, end) {
54
56
  resolve(dir, `${name}.trim${ext}`)
55
57
  ].flat())
56
58
  }
57
-
58
- main().catch(err => {
59
- console.error(err.message || err)
60
- process.exit(1)
61
- })