mediasnacks 0.26.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/index.js CHANGED
@@ -1,11 +1,14 @@
1
1
  export { avif } from './src/avif.js'
2
2
  export { countframes } from './src/countframes.js'
3
3
  export { detectdups } from './src/detectdups.js'
4
+ export { dlaudio } from './src/dlaudio.js'
5
+ export { dlvideo } from './src/dlvideo.js'
4
6
  export { dropdups } from './src/dropdups.js'
5
7
  export { edgespic } from './src/edgespic.js'
6
8
  export { frameseq } from './src/frameseq.js'
7
9
  export { hev1tohvc1 } from './src/hev1tohvc1.js'
8
10
  export { moov2front } from './src/moov2front.js'
11
+ export { png } from './src/png.js'
9
12
  export { play } from './src/play.js'
10
13
  export { prores } from './src/prores.js'
11
14
  export { qdir } from './src/qdir.js'
@@ -14,5 +17,6 @@ export { resize } from './src/resize.js'
14
17
  export { seqcheck } from './src/seqcheck.js'
15
18
  export { sqcrop } from './src/sqcrop.js'
16
19
  export { ssim } from './src/ssim.js'
20
+ export { unemoji } from './src/unemoji.js'
17
21
  export { vsplit } from './src/vsplit.js'
18
22
  export { vtrim } from './src/vtrim.js'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mediasnacks",
3
- "version": "0.26.0",
3
+ "version": "0.27.0",
4
4
  "description": "Utilities for optimizing and preparing videos and images",
5
5
  "license": "MIT",
6
6
  "author": "Eric Fortis",
package/src/cli.js CHANGED
@@ -8,7 +8,7 @@ import pkgJSON from '../package.json' with { type: 'json' }
8
8
 
9
9
  const COMMANDS = {
10
10
  avif: ['./avif.js', 'Converts images to AVIF'],
11
- png: ['./png.sh', 'Optimizes PNG images with oxipng'],
11
+ png: ['./png.js', 'Optimizes PNG images with oxipng'],
12
12
  sqcrop: ['./sqcrop.js', 'Square crops images\n'],
13
13
 
14
14
  resize: ['./resize.js', 'Resizes videos or images'],
@@ -35,10 +35,10 @@ const COMMANDS = {
35
35
  openrand: ['./openrand.js', 'Opens a random file (macOS only)'],
36
36
  play: ['./play.js', 'Plays filtered playlist with mpv\n'],
37
37
 
38
- dlaudio: ['./dlaudio.sh', 'yt-dlp best audio'],
39
- dlvideo: ['./dlvideo.sh', 'yt-dlp best video\n'],
38
+ dlaudio: ['./dlaudio.js', 'yt-dlp best audio'],
39
+ dlvideo: ['./dlvideo.js', 'yt-dlp best video\n'],
40
40
 
41
- unemoji: ['./unemoji.sh', 'Removes emojis from filenames'],
41
+ unemoji: ['./unemoji.js', 'Removes emojis from filenames'],
42
42
  rmcover: ['./rmcover.sh', 'Removes cover art'],
43
43
  }
44
44
 
package/src/dlaudio.js ADDED
@@ -0,0 +1,38 @@
1
+ import { parseOptions } from './utils/parseOptions.js'
2
+ import { runSilently } from './utils/subprocess.js'
3
+ import { unemoji } from './unemoji.js'
4
+
5
+
6
+ const HELP = `
7
+ SYNOPSIS
8
+ mediasnacks dlaudio <url>
9
+
10
+ DESCRIPTION
11
+ yt-dlp best m4a
12
+ `.trim()
13
+
14
+ export default async function main() {
15
+ const { values, positionals } = await parseOptions({
16
+ help: { short: 'h', type: 'boolean' }
17
+ })
18
+
19
+ if (values.help || !positionals[0]) {
20
+ console.log(HELP)
21
+ return
22
+ }
23
+
24
+ const f = await dlaudio(positionals[0])
25
+ console.log(f)
26
+ }
27
+
28
+ export async function dlaudio(url) {
29
+ const f = (await runSilently('yt-dlp', [
30
+ '--print', 'filename',
31
+ '--no-simulate',
32
+ '-o', '%(title)s.%(ext)s',
33
+ '-f', 'bestaudio[ext=m4a]/bestaudio',
34
+ url
35
+ ])).stdout.trim()
36
+
37
+ return await unemoji(f) || f
38
+ }
package/src/dlvideo.js ADDED
@@ -0,0 +1,32 @@
1
+ import { parseOptions } from './utils/parseOptions.js'
2
+ import { run } from './utils/subprocess.js'
3
+
4
+
5
+ const HELP = `
6
+ SYNOPSIS
7
+ mediasnacks dlvideo <url>
8
+
9
+ DESCRIPTION
10
+ yt-dlp best mp4
11
+ `.trim()
12
+
13
+ export default async function main() {
14
+ const { values, positionals } = await parseOptions({
15
+ help: { short: 'h', type: 'boolean' }
16
+ })
17
+
18
+ if (values.help || !positionals[0]) {
19
+ console.log(HELP)
20
+ return
21
+ }
22
+
23
+ await dlvideo(positionals[0])
24
+ }
25
+
26
+ export async function dlvideo(url) {
27
+ await run('yt-dlp', [
28
+ '-o', '%(title)s.%(ext)s',
29
+ '-f', 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/mp4',
30
+ url
31
+ ])
32
+ }
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/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()
package/src/dlaudio.sh DELETED
@@ -1,4 +0,0 @@
1
- #!/bin/sh
2
-
3
- yt-dlp -o '%(title)s.%(ext)s' \
4
- -f 'bestaudio[ext=m4a]/bestaudio' "$1"
package/src/dlvideo.sh DELETED
@@ -1,4 +0,0 @@
1
- #!/bin/sh
2
-
3
- yt-dlp -o '%(title)s.%(ext)s' \
4
- -f 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/mp4' "$1"
package/src/png.sh DELETED
@@ -1,20 +0,0 @@
1
- #!/bin/sh
2
-
3
- help() {
4
- /bin/cat << EOF
5
- SYNOPSIS
6
- mediasnacks png <img1> [img2 ...]
7
-
8
- DESCRIPTION
9
- Losslessly optimizes PNG images with oxipng at max level.
10
-
11
- EXAMPLE
12
- mediasnacks png *.png
13
- EOF
14
- exit "${1:-0}"
15
- }
16
-
17
- [ "$1" = "-h" ] && help
18
- [ $# -eq 0 ] && help 1
19
-
20
- oxipng --opt max "$@"
package/src/unemoji.sh DELETED
@@ -1,30 +0,0 @@
1
- #!/bin/sh
2
-
3
- # Removes emoji's from filenames on the current working directory.
4
- # Does not overwrite files.
5
-
6
- find . -depth | while IFS= read -r file; do
7
- dir=$(dirname "$file")
8
- base=$(basename "$file")
9
-
10
- # Remove Emojis
11
- newbase=$(printf '%s' "$base" | perl -CSD -pe '
12
- s/[\x{1F600}-\x{1F64F}]//g; # Emoticons
13
- s/[\x{1F300}-\x{1F5FF}]//g; # Misc Symbols and Pictographs
14
- s/[\x{1F680}-\x{1F6FF}]//g; # Transport and Map
15
- s/[\x{2600}-\x{26FF}]//g; # Misc symbols
16
- s/[\x{2700}-\x{27BF}]//g; # Dingbats
17
- s/[\x{1F900}-\x{1F9FF}]//g; # Supplemental Symbols and Pictographs
18
- s/[\x{1FA70}-\x{1FAFF}]//g; # Symbols and Pictographs Extended-A
19
- s/[\x{1F1E6}-\x{1F1FF}]//g; # Regional Indicator Symbols
20
- ')
21
-
22
- # Normalize to Unicode NFKC
23
- newbase=$(printf '%s' "$newbase" | perl -CSD -MUnicode::Normalize -pe '$_ = NFKC($_)')
24
-
25
- if [ "$base" != "$newbase" ]; then
26
- newpath="$dir/$newbase"
27
- echo "Renaming: $file -> $newpath"
28
- mv -n "$file" "$newpath"
29
- fi
30
- done