mediasnacks 0.28.0 → 0.30.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/README.md +1 -0
- package/index.js +1 -0
- package/install-zsh-completions.js +3 -3
- package/package.json +1 -1
- package/src/base64.js +42 -0
- package/src/cli.js +2 -1
- package/src/moov2front.js +4 -6
- package/src/openrand.js +8 -6
- package/src/play.sh +10 -0
- package/src/qdir.js +3 -3
- package/src/utils/mimeFor.js +21 -0
package/README.md
CHANGED
package/index.js
CHANGED
|
@@ -25,7 +25,7 @@ function makeScript() {
|
|
|
25
25
|
return `#compdef mediasnacks
|
|
26
26
|
|
|
27
27
|
_mediasnacks_commands=(
|
|
28
|
-
${commandsSummary().map(([cmd, desc]) => `'${cmd}:${desc}'`).join('\n')}
|
|
28
|
+
${commandsSummary().map(([cmd, desc]) => `'${cmd}:${desc.trim()}'`).join('\n')}
|
|
29
29
|
)
|
|
30
30
|
|
|
31
31
|
if (( CURRENT == 2 )); then
|
|
@@ -35,8 +35,8 @@ fi
|
|
|
35
35
|
|
|
36
36
|
local cmd="$words[2]"
|
|
37
37
|
case "$cmd" in
|
|
38
|
-
qdir)
|
|
39
|
-
|
|
38
|
+
qdir|openrand)
|
|
39
|
+
_path_files -/
|
|
40
40
|
;;
|
|
41
41
|
*)
|
|
42
42
|
_files
|
package/package.json
CHANGED
package/src/base64.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
import { parseOptions } from './utils/parseOptions.js'
|
|
3
|
+
import { mimeFor } from './utils/mimeFor.js'
|
|
4
|
+
|
|
5
|
+
const HELP = `
|
|
6
|
+
SYNOPSIS
|
|
7
|
+
mediasnacks base64 [--css | --img] file
|
|
8
|
+
|
|
9
|
+
DESCRIPTION
|
|
10
|
+
Encodes a file to data URI.
|
|
11
|
+
|
|
12
|
+
EXAMPLES
|
|
13
|
+
mediasnacks base64 file
|
|
14
|
+
mediasnacks base64 --img file
|
|
15
|
+
mediasnacks base64 --css file
|
|
16
|
+
`
|
|
17
|
+
|
|
18
|
+
export default async function main() {
|
|
19
|
+
const { values, files } = await parseOptions(HELP, {
|
|
20
|
+
css: { type: 'boolean' },
|
|
21
|
+
img: { type: 'boolean' },
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
if (files.length !== 1)
|
|
25
|
+
throw 'Only one file is accepted'
|
|
26
|
+
|
|
27
|
+
const { data, mime } = await base64(files[0])
|
|
28
|
+
|
|
29
|
+
if (values.css)
|
|
30
|
+
console.log(`background-image: url(data:${mime};base64,${data})`)
|
|
31
|
+
else if (values.img)
|
|
32
|
+
console.log(`<img src="data:${mime};base64,${data}" />`)
|
|
33
|
+
else
|
|
34
|
+
console.log(data)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function base64(filePath) {
|
|
38
|
+
return {
|
|
39
|
+
data: readFileSync(filePath).toString('base64'),
|
|
40
|
+
mime: await mimeFor(filePath)
|
|
41
|
+
}
|
|
42
|
+
}
|
package/src/cli.js
CHANGED
|
@@ -9,7 +9,8 @@ import pkgJSON from '../package.json' with { type: 'json' }
|
|
|
9
9
|
const COMMANDS = {
|
|
10
10
|
avif: ['./avif.js', 'Converts images to AVIF'],
|
|
11
11
|
png: ['./png.js', 'Optimizes PNG images with oxipng'],
|
|
12
|
-
sqcrop: ['./sqcrop.js', 'Square crops images
|
|
12
|
+
sqcrop: ['./sqcrop.js', 'Square crops images'],
|
|
13
|
+
base64: ['./base64.js', 'Encodes a file to data URI\n'],
|
|
13
14
|
|
|
14
15
|
resize: ['./resize.js', 'Resizes videos or images'],
|
|
15
16
|
edgespic: ['./edgespic.js', 'Extracts first and last frames'],
|
package/src/moov2front.js
CHANGED
|
@@ -9,13 +9,11 @@ SYNOPSIS
|
|
|
9
9
|
|
|
10
10
|
DESCRIPTION
|
|
11
11
|
Rearranges .mov and .mp4 metadata to the start of the file for fast-start streaming.
|
|
12
|
-
|
|
13
|
-
What is Fast Start?
|
|
14
|
-
- https://wiki.avblocks.com/avblocks-for-cpp/muxer-parameters/mp4
|
|
15
|
-
- https://trac.ffmpeg.org/wiki/HowToCheckIfFaststartIsEnabledForPlayback
|
|
16
|
-
|
|
17
|
-
NOTES
|
|
18
12
|
Files are overwritten.
|
|
13
|
+
|
|
14
|
+
SEE ALSO
|
|
15
|
+
- https://wiki.avblocks.com/avblocks-for-cpp/muxer-parameters/mp4
|
|
16
|
+
- https://trac.ffmpeg.org/wiki/HowToCheckIfFaststartIsEnabledForPlayback
|
|
19
17
|
`
|
|
20
18
|
|
|
21
19
|
export default async function main() {
|
package/src/openrand.js
CHANGED
|
@@ -6,21 +6,23 @@ import { parseOptions } from './utils/parseOptions.js'
|
|
|
6
6
|
|
|
7
7
|
const HELP = `
|
|
8
8
|
SYNOPSIS
|
|
9
|
-
mediasnacks openrand [-r | --recursive]
|
|
9
|
+
mediasnacks openrand [-r | --recursive] [dir]
|
|
10
10
|
|
|
11
11
|
DESCRIPTION
|
|
12
|
-
Opens a random file in
|
|
12
|
+
Opens a random file in a dir on macOS.
|
|
13
|
+
The dir defaults to the current working directory.
|
|
13
14
|
`
|
|
14
15
|
|
|
15
16
|
export default async function main() {
|
|
16
|
-
const { values } = await parseOptions(HELP, {
|
|
17
|
+
const { values, positionals } = await parseOptions(HELP, {
|
|
17
18
|
recursive: { short: 'r', type: 'boolean' },
|
|
18
19
|
})
|
|
19
20
|
|
|
20
21
|
if (process.platform !== 'darwin')
|
|
21
22
|
throw 'This command is only supported on macOS.'
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
const dir = positionals[0] || '.'
|
|
25
|
+
openrand(dir, values.recursive)
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
export function openrand(dir = '.', recursive = false) {
|
|
@@ -29,7 +31,7 @@ export function openrand(dir = '.', recursive = false) {
|
|
|
29
31
|
|
|
30
32
|
export function pickRandomFile(dir = '.', recursive = false) {
|
|
31
33
|
const files = readdirSync(dir, { withFileTypes: true, recursive })
|
|
32
|
-
.filter(
|
|
33
|
-
.map(
|
|
34
|
+
.filter(dirent => !dirent.name.startsWith('.') && dirent.isFile())
|
|
35
|
+
.map(dirent => join(dirent.parentPath, dirent.name))
|
|
34
36
|
return files[Math.floor(Math.random() * files.length)]
|
|
35
37
|
}
|
package/src/play.sh
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
|
|
3
|
+
# mpv with a filtered playlist with recursive search
|
|
4
|
+
# usage: cd Music && play artistA artistB
|
|
5
|
+
|
|
6
|
+
regex=$(IFS='|'; echo "$*")
|
|
7
|
+
/usr/bin/find -E . -type f -iregex ".*(${regex}).*" \
|
|
8
|
+
-not -path "*.fcpbundle/*" \
|
|
9
|
+
-not -name ".DS_Store" \
|
|
10
|
+
-print | mpv --playlist=-
|
package/src/qdir.js
CHANGED
|
@@ -68,8 +68,8 @@ export async function qdir(dir, pollIntervalMs = 10_000) {
|
|
|
68
68
|
async function getNextJob(dir) {
|
|
69
69
|
const entries = await readdir(dir, { withFileTypes: true })
|
|
70
70
|
const scripts = entries
|
|
71
|
-
.filter(
|
|
72
|
-
.map(
|
|
71
|
+
.filter(dirent => dirent.isFile() && filter(dirent.name))
|
|
72
|
+
.map(dirent => dirent.name)
|
|
73
73
|
.sort()
|
|
74
74
|
return scripts.length
|
|
75
75
|
? join(dir, scripts[0])
|
|
@@ -81,7 +81,7 @@ async function runShell(scriptPath) {
|
|
|
81
81
|
return new Promise((resolve, reject) => {
|
|
82
82
|
const p = spawn('/bin/sh', [scriptPath], { stdio: 'inherit' })
|
|
83
83
|
p.on('error', reject)
|
|
84
|
-
p.on('exit',
|
|
84
|
+
p.on('exit', resolve)
|
|
85
85
|
})
|
|
86
86
|
}
|
|
87
87
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { parse } from 'node:path'
|
|
2
|
+
import { runSilently } from './subprocess.js'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export async function mimeFor(filePath) {
|
|
6
|
+
return process.platform === 'win32'
|
|
7
|
+
? await windowsMime(filePath)
|
|
8
|
+
: (await runSilently('file', ['--mime-type', '--brief', filePath])).stdout.trim()
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async function windowsMime(filePath) { // TODO test on windows
|
|
12
|
+
const ext = parse(filePath).ext.toLowerCase()
|
|
13
|
+
try {
|
|
14
|
+
const { stdout } = await runSilently('reg', ['query', `HKEY_CLASSES_ROOT\\${ext}`, '/v', 'Content Type'])
|
|
15
|
+
const match = stdout.match(/Content Type\s+REG_SZ\s+(\S+)/)
|
|
16
|
+
if (match)
|
|
17
|
+
return match[1]
|
|
18
|
+
}
|
|
19
|
+
catch {}
|
|
20
|
+
return 'application/octet-stream'
|
|
21
|
+
}
|