mediasnacks 0.30.1 → 0.30.3

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mediasnacks",
3
- "version": "0.30.1",
3
+ "version": "0.30.3",
4
4
  "description": "Utilities for optimizing and preparing videos and images",
5
5
  "license": "MIT",
6
6
  "author": "Eric Fortis",
package/src/avif.js CHANGED
@@ -17,13 +17,13 @@ EXAMPLES
17
17
  `
18
18
 
19
19
  export default async function main() {
20
- const { values, files } = await parseOptions(HELP, {
20
+ const { values, files, usage } = await parseOptions(HELP, {
21
21
  outdir: { type: 'string', default: '' },
22
22
  overwrite: { short: 'y', type: 'boolean' },
23
23
  })
24
24
 
25
25
  if (!files.length)
26
- throw 'Invalid input image'
26
+ throw usage('Invalid input image')
27
27
 
28
28
  for (const file of files) {
29
29
  await avif({
package/src/base64.js CHANGED
@@ -9,45 +9,59 @@ SYNOPSIS
9
9
 
10
10
  DESCRIPTION
11
11
  Encodes image to data URI
12
+
13
+ OPTIONS
14
+ --css Outputs CSS background-image
15
+ --img Outputs HTML img tag with encoded src
12
16
 
13
17
  EXAMPLES
14
18
  mediasnacks base64 img
15
- mediasnacks base64 --img img
16
19
  mediasnacks base64 --css img
20
+ mediasnacks base64 --img img
17
21
  `
18
22
 
19
- const MIMES = {
20
- avif: 'image/avif',
21
- gif: 'image/gif',
22
- jpg: 'image/jpeg',
23
- jpeg: 'image/jpeg',
24
- png: 'image/png',
25
- svg: 'image/svg+xml',
26
- webp: 'image/webp',
23
+ const mimes = new class {
24
+ #MIMES = {
25
+ apng: 'image/apng',
26
+ avif: 'image/avif',
27
+ bmp: 'image/bmp',
28
+ gif: 'image/gif',
29
+ heic: 'image/heic',
30
+ heif: 'image/heif',
31
+ ico: 'image/vnd.microsoft.icon',
32
+ jpeg: 'image/jpeg',
33
+ jpg: 'image/jpeg',
34
+ jxl: 'image/jxl',
35
+ png: 'image/png',
36
+ svg: 'image/svg+xml',
37
+ tga: 'image/x-targa',
38
+ tif: 'image/tiff',
39
+ webp: 'image/webp',
40
+ }
41
+ mimeFor(file) {
42
+ return this.#MIMES[parse(file).ext.toLowerCase().replace('.', '')] || 'application/octect'
43
+ }
27
44
  }
28
45
 
46
+
29
47
  export default async function main() {
30
- const { values, files } = await parseOptions(HELP, {
48
+ const { values, files, usage } = await parseOptions(HELP, {
31
49
  css: { type: 'boolean' },
32
50
  img: { type: 'boolean' },
33
51
  })
34
52
 
35
- if (files.length !== 1)
36
- throw 'Only one file is accepted'
37
-
38
- const { data, mime } = await base64(files[0])
53
+ if (files.length === 0) throw usage('Missing or invalid file')
54
+ if (files.length !== 1) throw usage('Only one file is accepted')
39
55
 
40
- if (values.css)
41
- console.log(`background-image: url(data:${mime};base64,${data})`)
42
- else if (values.img)
43
- console.log(`<img src="data:${mime};base64,${data}" />`)
44
- else
45
- console.log(data)
56
+ const { data, mime } = base64(files[0])
57
+ if (values.css) console.log(`background-image: url(data:${mime};base64,${data});`)
58
+ else if (values.img) console.log(`<img src="data:${mime};base64,${data}" />`)
59
+ else console.log(data)
46
60
  }
47
61
 
48
- export async function base64(file) {
62
+ export function base64(file) {
49
63
  return {
50
64
  data: readFileSync(file).toString('base64'),
51
- mime: MIMES[parse(file).ext.toLowerCase().replace('.', '')] || 'application/octect'
65
+ mime: mimes.mimeFor(file)
52
66
  }
53
67
  }
@@ -22,7 +22,7 @@ EXAMPLES
22
22
 
23
23
 
24
24
  export default async function main() {
25
- const { values, files } = await parseOptions(HELP, {
25
+ const { values, files, usage } = await parseOptions(HELP, {
26
26
  fps: { type: 'string' },
27
27
  start: { short: 's', type: 'string' },
28
28
  end: { short: 'e', type: 'string' },
@@ -31,7 +31,7 @@ export default async function main() {
31
31
  const { fps, start, end } = values
32
32
  const video = files[0]
33
33
  if (!video)
34
- throw 'No video file specified'
34
+ throw usage('No video file specified')
35
35
 
36
36
  const n = await countframes({ video, fps, start, end })
37
37
  console.log(String(n))
package/src/detectdups.js CHANGED
@@ -29,18 +29,18 @@ SEE ALSO
29
29
 
30
30
 
31
31
  export default async function main() {
32
- const { values, files } = await parseOptions(HELP, {
32
+ const { values, files, usage } = await parseOptions(HELP, {
33
33
  seek: { short: 's', type: 'string', },
34
34
  duration: { short: 'd', type: 'string' },
35
35
  })
36
36
 
37
37
  if (files.length !== 1)
38
- throw 'Invalid input file. One video file must be specified.'
38
+ throw usage('Invalid input file. One video file must be specified.')
39
39
 
40
40
  const video = files[0]
41
41
  const v = await videoAttrs(video)
42
42
  if (v.codec_type !== 'video')
43
- throw 'Invalid input file. Must be a video.'
43
+ throw usage('Invalid input file. Must be a video.')
44
44
 
45
45
  const vDur = Number(v.duration)
46
46
 
@@ -52,9 +52,9 @@ export default async function main() {
52
52
  ? Number(values.duration)
53
53
  : vDur > 60 ? 20 : vDur
54
54
 
55
- if (isNaN(seek) || seek < 0) throw `Invalid --seek value: ${values.seek}`
56
- if (isNaN(duration) || duration < 1) throw `Invalid --duration value: ${values.duration}`
57
- if ((seek + duration) > vDur) throw `Invalid analysis range. Exceeds video duration: ${vDur}`
55
+ if (isNaN(seek) || seek < 0) throw usage(`Invalid --seek value: ${values.seek}`)
56
+ if (isNaN(duration) || duration < 1) throw usage(`Invalid --duration value: ${values.duration}`)
57
+ if ((seek + duration) > vDur) throw usage(`Invalid analysis range. Exceeds video duration: ${vDur}`)
58
58
 
59
59
  const dups = await detectdups({ video: files[0], seek, duration })
60
60
  const h = deltaHistogram(dups)
package/src/dlaudio.js CHANGED
@@ -12,10 +12,10 @@ DESCRIPTION
12
12
  `
13
13
 
14
14
  export default async function main() {
15
- const { values, positionals } = await parseOptions(HELP)
15
+ const { values, positionals, usage } = await parseOptions(HELP)
16
16
 
17
17
  if (!positionals[0])
18
- throw 'Missing URL'
18
+ throw usage('Missing URL')
19
19
 
20
20
  const f = await dlaudio(positionals[0])
21
21
  console.log(f)
package/src/dlvideo.js CHANGED
@@ -11,10 +11,10 @@ DESCRIPTION
11
11
  `
12
12
 
13
13
  export default async function main() {
14
- const { values, positionals } = await parseOptions(HELP)
14
+ const { values, positionals, usage } = await parseOptions(HELP)
15
15
 
16
16
  if (!positionals[0])
17
- throw 'Missing URL'
17
+ throw usage('Missing URL')
18
18
 
19
19
  await dlvideo(positionals[0])
20
20
  }
package/src/dropdups.js CHANGED
@@ -27,16 +27,16 @@ EXAMPLES
27
27
 
28
28
 
29
29
  export default async function main() {
30
- const { values, files } = await parseOptions(HELP, {
30
+ const { values, files, usage } = await parseOptions(HELP, {
31
31
  'dup-frame-num': { short: 'n', type: 'string' },
32
32
  })
33
33
 
34
34
  if (!files.length)
35
- throw 'No video specified.'
35
+ throw usage('No video specified.')
36
36
 
37
37
  let dupFrameNum = values['dup-frame-num']
38
38
  if (dupFrameNum && !Number.isInteger(+dupFrameNum))
39
- throw 'Invalid -n. It must be a positive integer.'
39
+ throw usage('Invalid -n. It must be a positive integer.')
40
40
 
41
41
  for (const file of files)
42
42
  await dropdups(resolve(file), dupFrameNum)
package/src/edgespic.js CHANGED
@@ -24,13 +24,13 @@ EXAMPLES
24
24
  `
25
25
 
26
26
  export default async function main() {
27
- const { values, files } = await parseOptions(HELP, {
27
+ const { values, files, usage } = await parseOptions(HELP, {
28
28
  width: { short: 'w', type: 'string', default: String(WIDTH) }
29
29
  })
30
30
 
31
31
  const width = Number(values.width)
32
- if (width <= 0 || !Number.isInteger(width)) throw '--width must be a positive number'
33
- if (!files.length) throw 'No video files specified'
32
+ if (width <= 0 || !Number.isInteger(width)) throw usage('--width must be a positive number')
33
+ if (!files.length) throw usage('No video files specified')
34
34
 
35
35
  const outDir = join(parse(files[0]).dir, 'edgespic')
36
36
  await mkDir(outDir)
package/src/frameseq.js CHANGED
@@ -28,7 +28,7 @@ EXAMPLES
28
28
 
29
29
 
30
30
  export default async function main() {
31
- const { values, files } = await parseOptions(HELP, {
31
+ const { values, files, usage } = await parseOptions(HELP, {
32
32
  fps: { short: 'f', type: 'string' },
33
33
  start: { short: 's', type: 'string' },
34
34
  end: { short: 'e', type: 'string' },
@@ -37,10 +37,10 @@ export default async function main() {
37
37
 
38
38
  const { fps, start, end, outdir } = values
39
39
  const video = files[0]
40
- if (!video) throw 'No video files specified'
41
- if (fps && isNaN(parseFloat(fps))) throw 'Invalid --fps'
42
- if (start && isNaN(parseFloat(start))) throw 'Invalid --start'
43
- if (end && isNaN(parseFloat(end))) throw 'Invalid --end'
40
+ if (!video) throw usage('No video files specified')
41
+ if (fps && isNaN(parseFloat(fps))) throw usage('Invalid --fps')
42
+ if (start && isNaN(parseFloat(start))) throw usage('Invalid --start')
43
+ if (end && isNaN(parseFloat(end))) throw usage('Invalid --end')
44
44
 
45
45
  const nFrames = await countframes({ video, fps, start, end })
46
46
  const pad = String(nFrames).length
package/src/gif.js CHANGED
@@ -19,13 +19,13 @@ OPTIONS
19
19
  `
20
20
 
21
21
  export default async function main() {
22
- const { values, files } = await parseOptions(HELP, {
22
+ const { values, files, usage } = await parseOptions(HELP, {
23
23
  fps: { short: 'f', type: 'string', default: String(FPS) },
24
24
  width: { short: 'w', type: 'string', default: String(WIDTH) },
25
25
  })
26
26
 
27
27
  if (!files.length)
28
- throw 'Missing input file'
28
+ throw usage('Missing input file')
29
29
 
30
30
  await gif(files[0], values.fps, values.width)
31
31
  }
package/src/hev1tohvc1.js CHANGED
@@ -16,10 +16,10 @@ DESCRIPTION
16
16
 
17
17
 
18
18
  export default async function main() {
19
- const { values, files } = await parseOptions(HELP)
19
+ const { values, files, usage } = await parseOptions(HELP)
20
20
 
21
21
  if (!files.length)
22
- throw 'Missing input file(s)'
22
+ throw usage('Missing input file(s)')
23
23
 
24
24
  for (const file of files) {
25
25
  await hev1tohvc1(file)
package/src/moov2front.js CHANGED
@@ -17,10 +17,10 @@ SEE ALSO
17
17
  `
18
18
 
19
19
  export default async function main() {
20
- const { values, files } = await parseOptions(HELP)
20
+ const { values, files, usage } = await parseOptions(HELP)
21
21
 
22
22
  if (!files.length)
23
- throw 'Missing input file(s)'
23
+ throw usage('Missing input file(s)')
24
24
 
25
25
  for (const file of files) {
26
26
  await moov2front(file)
package/src/openrand.js CHANGED
@@ -14,12 +14,12 @@ DESCRIPTION
14
14
  `
15
15
 
16
16
  export default async function main() {
17
- const { values, positionals } = await parseOptions(HELP, {
17
+ const { values, positionals, usage } = await parseOptions(HELP, {
18
18
  recursive: { short: 'r', type: 'boolean' },
19
19
  })
20
20
 
21
21
  if (process.platform !== 'darwin')
22
- throw 'This command is only supported on macOS.'
22
+ throw usage('This command is only supported on macOS.')
23
23
 
24
24
  const dir = positionals[0] || '.'
25
25
  openrand(dir, values.recursive)
package/src/play.js CHANGED
@@ -17,7 +17,7 @@ EXAMPLE
17
17
 
18
18
 
19
19
  export default async function main() {
20
- const { values, positionals } = await parseOptions(HELP, {
20
+ const { values, positionals, usage } = await parseOptions(HELP, {
21
21
  recursive: { short: 'r', type: 'boolean', default: true },
22
22
  }, { allowNegative: true })
23
23
 
@@ -29,7 +29,7 @@ export default async function main() {
29
29
  })
30
30
 
31
31
  if (!files.length)
32
- throw 'No matching files found.'
32
+ throw usage('No matching files found.')
33
33
 
34
34
  play(files)
35
35
  }
package/src/png.js CHANGED
@@ -14,10 +14,10 @@ EXAMPLE
14
14
  `
15
15
 
16
16
  export default async function main() {
17
- const { values, files } = await parseOptions(HELP)
17
+ const { values, files, usage } = await parseOptions(HELP)
18
18
 
19
19
  if (!files.length)
20
- throw 'Missing input image(s)'
20
+ throw usage('Missing input image(s)')
21
21
 
22
22
  await png(...files)
23
23
  }
package/src/prores.js CHANGED
@@ -51,17 +51,17 @@ EXAMPLES
51
51
 
52
52
 
53
53
  export default async function main() {
54
- const { values, files } = await parseOptions(HELP, {
54
+ const { values, files, usage } = await parseOptions(HELP, {
55
55
  profile: { short: 'p', type: 'string', default: String(ProresProfiles.default) },
56
56
  start: { short: 's', type: 'string' },
57
57
  end: { short: 'e', type: 'string' },
58
58
  })
59
59
 
60
60
  if (!ProresProfiles.isValid(Number(values.profile)))
61
- throw 'Invalid profile. Must be one of: ' + ProresProfiles.list().join(',')
61
+ throw usage('Invalid profile. Must be one of: ' + ProresProfiles.list().join(','))
62
62
 
63
63
  if (files.length !== 1)
64
- throw 'Expected 1 argument: video file.'
64
+ throw usage('Expected 1 argument: video file.')
65
65
 
66
66
  const video = resolve(files[0])
67
67
  const { name, dir } = parse(video)
package/src/resize.js CHANGED
@@ -32,7 +32,7 @@ EXAMPLES
32
32
  `
33
33
 
34
34
  export default async function main() {
35
- const { values, files } = await parseOptions(HELP, {
35
+ const { values, files, usage } = await parseOptions(HELP, {
36
36
  width: { type: 'string', default: '-2' },
37
37
  height: { type: 'string', default: '-2' },
38
38
  outdir: { type: 'string', default: '' },
@@ -42,8 +42,8 @@ export default async function main() {
42
42
  const width = Number(values.width)
43
43
  const height = Number(values.height)
44
44
 
45
- if (!files.length) throw 'No video files specified'
46
- if (width <= 0 && height <= 0) throw '--width or --height must be > 0'
45
+ if (!files.length) throw usage('No video files specified')
46
+ if (width <= 0 && height <= 0) throw usage('--width or --height must be > 0')
47
47
 
48
48
  for (const file of files) {
49
49
  await resize({
package/src/sqcrop.js CHANGED
@@ -16,13 +16,13 @@ DESCRIPTION
16
16
  `
17
17
 
18
18
  export default async function main() {
19
- const { values, files } = await parseOptions(HELP, {
19
+ const { values, files, usage } = await parseOptions(HELP, {
20
20
  outdir: { type: 'string', default: '' },
21
21
  overwrite: { short: 'y', type: 'boolean' },
22
22
  })
23
23
 
24
24
  if (!files.length)
25
- throw 'No images specified'
25
+ throw usage('No images specified')
26
26
 
27
27
  for (const file of files) {
28
28
  await sqcrop({
package/src/ssim.js CHANGED
@@ -11,10 +11,10 @@ DESCRIPTION
11
11
  `
12
12
 
13
13
  export default async function main() {
14
- const { values, positionals } = await parseOptions(HELP)
14
+ const { values, positionals, usage } = await parseOptions(HELP)
15
15
 
16
16
  if (positionals.length !== 2)
17
- throw 'Expected two images'
17
+ throw usage('Expected two images')
18
18
 
19
19
  const score = await ssim(...positionals)
20
20
  console.log(score.toString())
package/src/unemoji.js CHANGED
@@ -29,12 +29,12 @@ const EMOJI_RE = new RegExp(
29
29
  )
30
30
 
31
31
  export default async function main() {
32
- const { values, positionals } = await parseOptions(HELP, {
32
+ const { values, positionals, usage } = await parseOptions(HELP, {
33
33
  recursive: { short: 'r', type: 'boolean' }
34
34
  })
35
35
 
36
36
  if (positionals.length !== 1)
37
- throw 'Must pass only one dir'
37
+ throw usage('Must pass only one dir')
38
38
 
39
39
  const files = findFiles({
40
40
  dir: positionals[0],
@@ -1,4 +1,4 @@
1
- import { promisify, parseArgs } from 'node:util'
1
+ import { promisify, parseArgs, styleText } from 'node:util'
2
2
  import { glob as _glob } from 'node:fs'
3
3
 
4
4
  const glob = promisify(_glob)
@@ -28,7 +28,10 @@ export async function parseOptions(helpText, options = {}, config = {}) {
28
28
  return {
29
29
  values,
30
30
  positionals,
31
- files: await resolveGlobs(positionals, tokens)
31
+ files: await resolveGlobs(positionals, tokens),
32
+ usage: err => err
33
+ ? styleText('redBright', '' + err + '\n') + helpText
34
+ : helpText
32
35
  }
33
36
  }
34
37
 
package/src/vsplit.js CHANGED
@@ -35,10 +35,10 @@ SEE ALSO
35
35
 
36
36
 
37
37
  export default async function main() {
38
- const { values, files } = await parseOptions(HELP)
38
+ const { values, files, usage } = await parseOptions(HELP)
39
39
 
40
40
  if (files.length !== 2)
41
- throw 'Expected 2 arguments: CSV file and video file.'
41
+ throw usage('Expected 2 arguments: CSV file and video file.')
42
42
 
43
43
  const [csvPath, videoPath] = files.map(f => resolve(f))
44
44
 
package/src/vtrim.js CHANGED
@@ -20,13 +20,13 @@ SEE ALSO
20
20
 
21
21
 
22
22
  export default async function main() {
23
- const { values, files } = await parseOptions(HELP, {
23
+ const { values, files, usage } = await parseOptions(HELP, {
24
24
  start: { short: 's', type: 'string' },
25
25
  end: { short: 'e', type: 'string' },
26
26
  })
27
27
 
28
28
  if (!files.length)
29
- throw 'No video specified.'
29
+ throw usage('No video specified.')
30
30
 
31
31
  for (const file of files)
32
32
  await vtrim({