@emgeebee/music_downcoder 1.0.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 +60 -0
- package/batch.sh +26 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +60 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +38 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +97 -0
- package/dist/config.js.map +1 -0
- package/dist/constants.d.ts +19 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +34 -0
- package/dist/constants.js.map +1 -0
- package/dist/getMeta.d.ts +18 -0
- package/dist/getMeta.d.ts.map +1 -0
- package/dist/getMeta.js +100 -0
- package/dist/getMeta.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/paths.d.ts +11 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +26 -0
- package/dist/paths.js.map +1 -0
- package/dist/processEncoder.d.ts +24 -0
- package/dist/processEncoder.d.ts.map +1 -0
- package/dist/processEncoder.js +238 -0
- package/dist/processEncoder.js.map +1 -0
- package/dist/prompts.d.ts +12 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +19 -0
- package/dist/prompts.js.map +1 -0
- package/dist/run.d.ts +27 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +100 -0
- package/dist/run.js.map +1 -0
- package/dist/scripts.d.ts +13 -0
- package/dist/scripts.d.ts.map +1 -0
- package/dist/scripts.js +89 -0
- package/dist/scripts.js.map +1 -0
- package/dist/serve.d.ts +3 -0
- package/dist/serve.d.ts.map +1 -0
- package/dist/serve.js +137 -0
- package/dist/serve.js.map +1 -0
- package/dist/web/index.html +243 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Music Downcoder
|
|
2
|
+
|
|
3
|
+
A TypeScript CLI and web UI that scans music folders and generates bash scripts with ffmpeg commands to transcode your music library. Supports multiple encoders (mp3, ogg, ALAC copy) and parallel execution.
|
|
4
|
+
|
|
5
|
+
Published as [`@emgeebee/music_downcoder`](https://www.npmjs.com/package/@emgeebee/music_downcoder) on npm.
|
|
6
|
+
|
|
7
|
+
## Quick start (npx)
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Interactive CLI (uses built-in defaults)
|
|
11
|
+
npx @emgeebee/music_downcoder
|
|
12
|
+
|
|
13
|
+
# Web UI on port 3798
|
|
14
|
+
npx @emgeebee/music_downcoder serve -c /path/to/conf.json -H 0.0.0.0 -p 3798
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Open `http://localhost:3798` to pick source folder, encoders, and artist filter. After scripts are generated under `cmd/`, the UI lists them and lets you run individually or all at once.
|
|
18
|
+
|
|
19
|
+
## Configuration
|
|
20
|
+
|
|
21
|
+
All paths and encoder settings live in a JSON config file. See [`docker/conf.json`](docker/conf.json) for a Synology/Docker example:
|
|
22
|
+
|
|
23
|
+
- `ffmpeg` — path to ffmpeg binary
|
|
24
|
+
- `startFolders` — source library folders shown in the UI/CLI
|
|
25
|
+
- `encoders` — output folders and formats (mp3, ogg, cp)
|
|
26
|
+
- `commandsFolder`, `queueFolder`, `metaFile` — working directories
|
|
27
|
+
- `numOfCores`, `rate`, `autoConfirm`
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npx @emgeebee/music_downcoder -c ./docker/conf.json
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Synology / Docker
|
|
34
|
+
|
|
35
|
+
See [`docker/synology-compose.yml`](docker/synology-compose.yml). Copy `docker/conf.json` to your NAS config volume and adjust paths. The container runs:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx @emgeebee/music_downcoder serve -H 0.0.0.0 -p 3798 -c /data/config/conf.json
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Development
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install
|
|
45
|
+
npm start # CLI
|
|
46
|
+
npm run serve -- -c docker/conf.json -p 3798 # web UI
|
|
47
|
+
npm run build
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## npm publish
|
|
51
|
+
|
|
52
|
+
Pushes to npm on merge to `main`/`master` via [`.github/workflows/publish.yml`](.github/workflows/publish.yml). Add an `NPM_TOKEN` secret to the repository (npm automation token with publish access to `@emgeebee`).
|
|
53
|
+
|
|
54
|
+
## How it works
|
|
55
|
+
|
|
56
|
+
1. Walk the selected music directory
|
|
57
|
+
2. Extract/cache metadata (artist, album, genre, year) via ffmpeg
|
|
58
|
+
3. Generate ffmpeg/rsync commands per encoder
|
|
59
|
+
4. Write scripts to `cmd/{core}/`
|
|
60
|
+
5. Optionally execute via CLI or web UI
|
package/batch.sh
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
shopt -s extglob
|
|
3
|
+
IFS=$'\n'
|
|
4
|
+
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
5
|
+
printf "%s\n" ${DIR}
|
|
6
|
+
cd ${DIR}
|
|
7
|
+
for file in $(find ./cmd -mindepth 2 -name "*.sh" | sort)
|
|
8
|
+
do
|
|
9
|
+
if [ -a ${file} ]; then
|
|
10
|
+
filename=$(basename "$file")
|
|
11
|
+
mv ${file} ./queueInProgress/${filename}
|
|
12
|
+
time=$(date +%k%M)
|
|
13
|
+
#echo ${time} "${filename}"
|
|
14
|
+
#if [[ "$time" -le 2359 ]];then
|
|
15
|
+
sh "./queueInProgress/${filename}"
|
|
16
|
+
rm "./queueInProgress/${filename}"
|
|
17
|
+
sleep 0
|
|
18
|
+
#else
|
|
19
|
+
#exit 0
|
|
20
|
+
#fi
|
|
21
|
+
fi
|
|
22
|
+
done
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
#queue.sh >> logs/queueoutput_$(date +%Y%m%d).txt 2>&1
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { checkbox, input, select } from "@inquirer/prompts";
|
|
4
|
+
import { getConfig, loadConfig } from "./config.js";
|
|
5
|
+
import { createCliPrompts, initRuntime, runBatchShell, runDowncoder, } from "./run.js";
|
|
6
|
+
const configArgIndex = process.argv.indexOf("-c");
|
|
7
|
+
const configPath = configArgIndex >= 0
|
|
8
|
+
? path.resolve(process.argv[configArgIndex + 1])
|
|
9
|
+
: undefined;
|
|
10
|
+
if (configPath) {
|
|
11
|
+
initRuntime(configPath);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
loadConfig();
|
|
15
|
+
}
|
|
16
|
+
const config = getConfig();
|
|
17
|
+
const startFolder = await select({
|
|
18
|
+
message: "Select start folder",
|
|
19
|
+
choices: config.startFolders.map((folder) => ({
|
|
20
|
+
name: folder.name,
|
|
21
|
+
value: folder.path,
|
|
22
|
+
})),
|
|
23
|
+
});
|
|
24
|
+
const configKeys = await checkbox({
|
|
25
|
+
message: "Select encoder",
|
|
26
|
+
choices: config.encoders.map((encoder) => ({
|
|
27
|
+
name: encoder.label,
|
|
28
|
+
value: encoder.id,
|
|
29
|
+
description: encoder.description,
|
|
30
|
+
checked: encoder.default ?? false,
|
|
31
|
+
})),
|
|
32
|
+
});
|
|
33
|
+
const filter = await input({
|
|
34
|
+
message: "Do you want to filter artists? Enter the start of the name",
|
|
35
|
+
default: "",
|
|
36
|
+
});
|
|
37
|
+
const result = await runDowncoder({
|
|
38
|
+
startFolder,
|
|
39
|
+
encoderIds: configKeys,
|
|
40
|
+
filter,
|
|
41
|
+
configPath,
|
|
42
|
+
prompts: createCliPrompts(),
|
|
43
|
+
});
|
|
44
|
+
console.log(`Time to run: ${result.elapsedSeconds}s`);
|
|
45
|
+
if (result.scripts.length === 0) {
|
|
46
|
+
console.log("no commands to run");
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
console.log("commands to run: ", result.scripts.join(", "));
|
|
50
|
+
const run = await select({
|
|
51
|
+
message: "Run commands?",
|
|
52
|
+
choices: [
|
|
53
|
+
{ value: true, name: "Yes" },
|
|
54
|
+
{ value: false, name: "No" },
|
|
55
|
+
],
|
|
56
|
+
});
|
|
57
|
+
if (run) {
|
|
58
|
+
runBatchShell();
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,aAAa,EACb,YAAY,GACb,MAAM,UAAU,CAAC;AAElB,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAClD,MAAM,UAAU,GACd,cAAc,IAAI,CAAC;IACjB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC;IAChD,CAAC,CAAC,SAAS,CAAC;AAEhB,IAAI,UAAU,EAAE,CAAC;IACf,WAAW,CAAC,UAAU,CAAC,CAAC;AAC1B,CAAC;KAAM,CAAC;IACN,UAAU,EAAE,CAAC;AACf,CAAC;AAED,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;AAE3B,MAAM,WAAW,GAAG,MAAM,MAAM,CAAS;IACvC,OAAO,EAAE,qBAAqB;IAC9B,OAAO,EAAE,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC5C,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,KAAK,EAAE,MAAM,CAAC,IAAI;KACnB,CAAC,CAAC;CACJ,CAAC,CAAC;AAEH,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAS;IACxC,OAAO,EAAE,gBAAgB;IACzB,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACzC,IAAI,EAAE,OAAO,CAAC,KAAK;QACnB,KAAK,EAAE,OAAO,CAAC,EAAE;QACjB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,KAAK;KAClC,CAAC,CAAC;CACJ,CAAC,CAAC;AAEH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC;IACzB,OAAO,EAAE,4DAA4D;IACrE,OAAO,EAAE,EAAE;CACZ,CAAC,CAAC;AAEH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC;IAChC,WAAW;IACX,UAAU,EAAE,UAAU;IACtB,MAAM;IACN,UAAU;IACV,OAAO,EAAE,gBAAgB,EAAE;CAC5B,CAAC,CAAC;AAEH,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM,CAAC,cAAc,GAAG,CAAC,CAAC;AAEtD,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;IAChC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAE5D,MAAM,GAAG,GAAG,MAAM,MAAM,CAAU;IAChC,OAAO,EAAE,eAAe;IACxB,OAAO,EAAE;QACP,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE;QAC5B,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE;KAC7B;CACF,CAAC,CAAC;AAEH,IAAI,GAAG,EAAE,CAAC;IACR,aAAa,EAAE,CAAC;AAClB,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export interface StartFolder {
|
|
2
|
+
name: string;
|
|
3
|
+
path: string;
|
|
4
|
+
}
|
|
5
|
+
export interface EncoderConfig {
|
|
6
|
+
id: string;
|
|
7
|
+
label: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
default?: boolean;
|
|
10
|
+
out: string;
|
|
11
|
+
format: string;
|
|
12
|
+
getImages?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface AppConfig {
|
|
15
|
+
ffmpeg: string;
|
|
16
|
+
rate: string;
|
|
17
|
+
numOfCores: number;
|
|
18
|
+
commandsFolder: string;
|
|
19
|
+
queueFolder: string;
|
|
20
|
+
metaFile: string;
|
|
21
|
+
workDir: string;
|
|
22
|
+
autoConfirm: boolean;
|
|
23
|
+
startFolders: StartFolder[];
|
|
24
|
+
encoders: EncoderConfig[];
|
|
25
|
+
}
|
|
26
|
+
export type ConfigKey = string;
|
|
27
|
+
export interface ConfigMap {
|
|
28
|
+
[key: string]: {
|
|
29
|
+
start: string;
|
|
30
|
+
out: string;
|
|
31
|
+
format: string;
|
|
32
|
+
getImages?: boolean;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export declare const getConfig: () => AppConfig;
|
|
36
|
+
export declare const buildConfigMap: (startFolder: string, encoderIds: ConfigKey[]) => ConfigMap;
|
|
37
|
+
export declare const loadConfig: (configPath?: string) => AppConfig;
|
|
38
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC;AAE/B,MAAM,WAAW,SAAS;IACxB,CAAC,GAAG,EAAE,MAAM,GAAG;QACb,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,OAAO,CAAC;KACrB,CAAC;CACH;AA8CD,eAAO,MAAM,SAAS,QAAO,SAAyB,CAAC;AAEvD,eAAO,MAAM,cAAc,GACzB,aAAa,MAAM,EACnB,YAAY,SAAS,EAAE,KACtB,SAcF,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,aAAa,MAAM,KAAG,SAuChD,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { normalizeDir, resolveConfigPath, } from "./paths.js";
|
|
4
|
+
const defaultConfig = {
|
|
5
|
+
ffmpeg: "/Applications/ffmpeg",
|
|
6
|
+
rate: "0",
|
|
7
|
+
numOfCores: 4,
|
|
8
|
+
commandsFolder: "./cmd",
|
|
9
|
+
queueFolder: "./queueInProgress",
|
|
10
|
+
metaFile: "./meta.json",
|
|
11
|
+
workDir: process.cwd(),
|
|
12
|
+
autoConfirm: false,
|
|
13
|
+
startFolders: [
|
|
14
|
+
{ name: "Itunes", path: "/Volumes/Itunes/Music/Music/" },
|
|
15
|
+
{ name: "Downloads", path: "/Volumes/Music/downloads/" },
|
|
16
|
+
{ name: "Youtube", path: "/Users/mat/Music/youtube" },
|
|
17
|
+
],
|
|
18
|
+
encoders: [
|
|
19
|
+
{
|
|
20
|
+
id: "alac",
|
|
21
|
+
label: "COPY",
|
|
22
|
+
description: "Copies the files directly",
|
|
23
|
+
default: true,
|
|
24
|
+
out: "/Volumes/Music/cds-alac",
|
|
25
|
+
format: "cp",
|
|
26
|
+
getImages: false,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: "main",
|
|
30
|
+
label: "mp3",
|
|
31
|
+
default: true,
|
|
32
|
+
out: "/Volumes/Music/cds-mp3",
|
|
33
|
+
format: "mp3",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: "ogg",
|
|
37
|
+
label: "ogg",
|
|
38
|
+
default: false,
|
|
39
|
+
out: "/Volumes/Music/cds-ogg",
|
|
40
|
+
format: "ogg",
|
|
41
|
+
getImages: false,
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
};
|
|
45
|
+
let activeConfig = { ...defaultConfig };
|
|
46
|
+
export const getConfig = () => activeConfig;
|
|
47
|
+
export const buildConfigMap = (startFolder, encoderIds) => {
|
|
48
|
+
const map = {};
|
|
49
|
+
for (const encoder of activeConfig.encoders) {
|
|
50
|
+
if (!encoderIds.includes(encoder.id)) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
map[encoder.id] = {
|
|
54
|
+
start: normalizeDir(startFolder),
|
|
55
|
+
out: normalizeDir(encoder.out),
|
|
56
|
+
format: encoder.format,
|
|
57
|
+
getImages: encoder.getImages,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return map;
|
|
61
|
+
};
|
|
62
|
+
export const loadConfig = (configPath) => {
|
|
63
|
+
if (!configPath) {
|
|
64
|
+
activeConfig = { ...defaultConfig, workDir: process.cwd() };
|
|
65
|
+
return activeConfig;
|
|
66
|
+
}
|
|
67
|
+
const resolved = path.resolve(configPath);
|
|
68
|
+
const raw = JSON.parse(fs.readFileSync(resolved, "utf-8"));
|
|
69
|
+
const configDir = path.dirname(resolved);
|
|
70
|
+
activeConfig = {
|
|
71
|
+
...defaultConfig,
|
|
72
|
+
...raw,
|
|
73
|
+
ffmpeg: raw.ffmpeg ?? defaultConfig.ffmpeg,
|
|
74
|
+
workDir: raw.workDir
|
|
75
|
+
? resolveConfigPath(configDir, raw.workDir)
|
|
76
|
+
: normalizeDir(configDir),
|
|
77
|
+
commandsFolder: raw.commandsFolder
|
|
78
|
+
? resolveConfigPath(configDir, raw.commandsFolder)
|
|
79
|
+
: resolveConfigPath(configDir, "cmd"),
|
|
80
|
+
queueFolder: raw.queueFolder
|
|
81
|
+
? resolveConfigPath(configDir, raw.queueFolder)
|
|
82
|
+
: resolveConfigPath(configDir, "queueInProgress"),
|
|
83
|
+
metaFile: raw.metaFile
|
|
84
|
+
? resolveConfigPath(configDir, raw.metaFile)
|
|
85
|
+
: path.join(configDir, "meta.json"),
|
|
86
|
+
startFolders: (raw.startFolders ?? defaultConfig.startFolders).map((folder) => ({
|
|
87
|
+
...folder,
|
|
88
|
+
path: normalizeDir(folder.path),
|
|
89
|
+
})),
|
|
90
|
+
encoders: (raw.encoders ?? defaultConfig.encoders).map((encoder) => ({
|
|
91
|
+
...encoder,
|
|
92
|
+
out: resolveConfigPath(configDir, encoder.out),
|
|
93
|
+
})),
|
|
94
|
+
};
|
|
95
|
+
return activeConfig;
|
|
96
|
+
};
|
|
97
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const rate = "0";
|
|
2
|
+
export declare const commandsFolder = "../cmd/";
|
|
3
|
+
export declare const numOfCores = 4;
|
|
4
|
+
export interface EncoderConfig {
|
|
5
|
+
start: string;
|
|
6
|
+
out: string;
|
|
7
|
+
format: string;
|
|
8
|
+
getImages?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface ConfigMap {
|
|
11
|
+
main: EncoderConfig;
|
|
12
|
+
ogg: EncoderConfig;
|
|
13
|
+
alac: EncoderConfig;
|
|
14
|
+
local: EncoderConfig;
|
|
15
|
+
localitunes: EncoderConfig;
|
|
16
|
+
}
|
|
17
|
+
export declare const config: ConfigMap;
|
|
18
|
+
export type ConfigKey = keyof ConfigMap;
|
|
19
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,IAAI,MAAM,CAAC;AACxB,eAAO,MAAM,cAAc,YAAY,CAAC;AACxC,eAAO,MAAM,UAAU,IAAI,CAAC;AAE5B,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,aAAa,CAAC;IACpB,GAAG,EAAE,aAAa,CAAC;IACnB,IAAI,EAAE,aAAa,CAAC;IACpB,KAAK,EAAE,aAAa,CAAC;IACrB,WAAW,EAAE,aAAa,CAAC;CAC5B;AAED,eAAO,MAAM,MAAM,EAAE,SA4BpB,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const start = "/Volumes/Itunes/Music/Music/";
|
|
2
|
+
export const rate = "0";
|
|
3
|
+
export const commandsFolder = "../cmd/";
|
|
4
|
+
export const numOfCores = 4;
|
|
5
|
+
export const config = {
|
|
6
|
+
main: {
|
|
7
|
+
start,
|
|
8
|
+
out: "/Volumes/Music/cds-mp3/",
|
|
9
|
+
format: "mp3",
|
|
10
|
+
},
|
|
11
|
+
ogg: {
|
|
12
|
+
start,
|
|
13
|
+
out: "/Volumes/Music/cds-ogg/",
|
|
14
|
+
format: "ogg",
|
|
15
|
+
getImages: false,
|
|
16
|
+
},
|
|
17
|
+
alac: {
|
|
18
|
+
start,
|
|
19
|
+
out: "/Volumes/Music/cds-alac/",
|
|
20
|
+
format: "cp",
|
|
21
|
+
getImages: false,
|
|
22
|
+
},
|
|
23
|
+
local: {
|
|
24
|
+
start: "/Users/mat/Music/Phile Audio/audio2/",
|
|
25
|
+
out: "/Users/mat/Music/" + rate + "/",
|
|
26
|
+
format: "mp3",
|
|
27
|
+
},
|
|
28
|
+
localitunes: {
|
|
29
|
+
start: "/Users/mat/Music/ripping library/iTunes Media/Music/",
|
|
30
|
+
out: "/Users/mat/Music/" + rate + "/",
|
|
31
|
+
format: "mp3",
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,KAAK,GAAG,8BAA8B,CAAC;AAE7C,MAAM,CAAC,MAAM,IAAI,GAAG,GAAG,CAAC;AACxB,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,CAAC;AACxC,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC;AAiB5B,MAAM,CAAC,MAAM,MAAM,GAAc;IAC/B,IAAI,EAAE;QACJ,KAAK;QACL,GAAG,EAAE,yBAAyB;QAC9B,MAAM,EAAE,KAAK;KACd;IACD,GAAG,EAAE;QACH,KAAK;QACL,GAAG,EAAE,yBAAyB;QAC9B,MAAM,EAAE,KAAK;QACb,SAAS,EAAE,KAAK;KACjB;IACD,IAAI,EAAE;QACJ,KAAK;QACL,GAAG,EAAE,0BAA0B;QAC/B,MAAM,EAAE,IAAI;QACZ,SAAS,EAAE,KAAK;KACjB;IACD,KAAK,EAAE;QACL,KAAK,EAAE,sCAAsC;QAC7C,GAAG,EAAE,mBAAmB,GAAG,IAAI,GAAG,GAAG;QACrC,MAAM,EAAE,KAAK;KACd;IACD,WAAW,EAAE;QACX,KAAK,EAAE,sDAAsD;QAC7D,GAAG,EAAE,mBAAmB,GAAG,IAAI,GAAG,GAAG;QACrC,MAAM,EAAE,KAAK;KACd;CACF,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { AppConfig } from "./config.js";
|
|
2
|
+
import type { Prompts } from "./prompts.js";
|
|
3
|
+
export interface Metadata {
|
|
4
|
+
fullArtist: string;
|
|
5
|
+
fullAlbum: string;
|
|
6
|
+
genre: string;
|
|
7
|
+
year: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class MetaGetter {
|
|
10
|
+
private readonly config;
|
|
11
|
+
private readonly prompts;
|
|
12
|
+
private metaData;
|
|
13
|
+
private usemetaFiles;
|
|
14
|
+
constructor(config: AppConfig, prompts: Prompts);
|
|
15
|
+
getMeta(dirPath: string, filename: string): Promise<Metadata>;
|
|
16
|
+
writeBack(): void;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=getMeta.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getMeta.d.ts","sourceRoot":"","sources":["../src/getMeta.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAG5C,MAAM,WAAW,QAAQ;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAMD,qBAAa,UAAU;IAKnB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAL1B,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,YAAY,CAAQ;gBAGT,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,OAAO;IAS7B,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IA4GnE,SAAS,IAAI,IAAI;CAMlB"}
|
package/dist/getMeta.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import term from "child_process";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { shellPath } from "./paths.js";
|
|
5
|
+
export class MetaGetter {
|
|
6
|
+
config;
|
|
7
|
+
prompts;
|
|
8
|
+
metaData = {};
|
|
9
|
+
usemetaFiles = true;
|
|
10
|
+
constructor(config, prompts) {
|
|
11
|
+
this.config = config;
|
|
12
|
+
this.prompts = prompts;
|
|
13
|
+
try {
|
|
14
|
+
this.metaData = JSON.parse(fs.readFileSync(config.metaFile, "utf-8"));
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
// File doesn't exist yet
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async getMeta(dirPath, filename) {
|
|
21
|
+
const backupFile = path.join(dirPath, "meta.json");
|
|
22
|
+
if (this.metaData[dirPath] &&
|
|
23
|
+
this.metaData[dirPath].year !== undefined &&
|
|
24
|
+
this.usemetaFiles) {
|
|
25
|
+
const { fullArtist, fullAlbum } = this.metaData[dirPath];
|
|
26
|
+
console.log("read meta for %s: %s", fullArtist, fullAlbum);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
try {
|
|
30
|
+
const backupMeta = fs.readFileSync(backupFile, "utf-8");
|
|
31
|
+
if (backupMeta && JSON.parse(backupMeta).year !== undefined) {
|
|
32
|
+
const { fullAlbum, fullArtist, genre, year } = JSON.parse(backupMeta);
|
|
33
|
+
console.log("read backup meta for %s: %s", fullArtist, fullAlbum);
|
|
34
|
+
this.metaData[dirPath] = { fullAlbum, fullArtist, genre, year };
|
|
35
|
+
}
|
|
36
|
+
throw new Error("no complete backup file");
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
console.log(` no backup file at ${backupFile}, falling back to ffmpeg`);
|
|
40
|
+
const inputPath = shellPath(dirPath, filename);
|
|
41
|
+
const meta = term.execSync(`${this.config.ffmpeg} -y -i "${inputPath}" -f ffmetaData pipe:1`, { encoding: "utf-8" });
|
|
42
|
+
const genreMatch = meta.match(/genre.*/gi);
|
|
43
|
+
const genre = genreMatch ? genreMatch[0].split("=")[1] : "";
|
|
44
|
+
const artistReg = new RegExp(/[\t]*artist=(.*)$/gim);
|
|
45
|
+
const albumArtistReg = new RegExp(/[\t]*album_artist=(.*)$/gim);
|
|
46
|
+
const albumReg = new RegExp(/[\t]*album=(.*)$/gim);
|
|
47
|
+
const yearReg = new RegExp(/[\t]*date=(.*)$/gim);
|
|
48
|
+
const fullArtistResults = artistReg.exec(meta);
|
|
49
|
+
const fullAlbumArtistResults = albumArtistReg.exec(meta);
|
|
50
|
+
const fullAlbumResults = albumReg.exec(meta);
|
|
51
|
+
const yearResults = yearReg.exec(meta);
|
|
52
|
+
console.log(fullAlbumResults, fullAlbumArtistResults, fullArtistResults, yearResults);
|
|
53
|
+
let fullArtist = "";
|
|
54
|
+
let fullAlbum = "";
|
|
55
|
+
if (fullAlbumResults && (fullArtistResults || fullAlbumArtistResults)) {
|
|
56
|
+
fullArtist = fullAlbumArtistResults
|
|
57
|
+
? fullAlbumArtistResults[1]
|
|
58
|
+
: fullArtistResults?.[1] ?? "";
|
|
59
|
+
fullAlbum = fullAlbumResults ? fullAlbumResults[1] : "";
|
|
60
|
+
}
|
|
61
|
+
const possibleYear = yearResults?.[1].slice(0, 4) ?? "0000";
|
|
62
|
+
const confirmedAll = await this.prompts.confirm(`Use genre = ${genre}, artist = ${fullArtist}, album = ${fullAlbum}, year = ${possibleYear}`);
|
|
63
|
+
let confirmedArtist = "";
|
|
64
|
+
let confirmedAlbum = "";
|
|
65
|
+
let confirmedGenre = "";
|
|
66
|
+
let confirmedYear = "";
|
|
67
|
+
if (confirmedAll) {
|
|
68
|
+
confirmedArtist = fullArtist;
|
|
69
|
+
confirmedAlbum = fullAlbum;
|
|
70
|
+
confirmedGenre = genre;
|
|
71
|
+
confirmedYear = possibleYear;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
confirmedGenre = await this.prompts.input(`Use Genre: ${genre}`, genre);
|
|
75
|
+
confirmedArtist = await this.prompts.input(`Use Artist: ${fullArtist}`, fullArtist);
|
|
76
|
+
confirmedAlbum = await this.prompts.input(`Use Album: ${fullAlbum}`, fullAlbum);
|
|
77
|
+
confirmedYear = await this.prompts.input(`Use Year: ${possibleYear}`, possibleYear);
|
|
78
|
+
}
|
|
79
|
+
this.metaData[dirPath] = {
|
|
80
|
+
fullArtist: confirmedArtist,
|
|
81
|
+
fullAlbum: confirmedAlbum,
|
|
82
|
+
genre: confirmedGenre,
|
|
83
|
+
year: confirmedYear,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const output = {
|
|
88
|
+
fullArtist: this.metaData[dirPath].fullArtist,
|
|
89
|
+
fullAlbum: this.metaData[dirPath].fullAlbum,
|
|
90
|
+
genre: this.metaData[dirPath].genre,
|
|
91
|
+
year: this.metaData[dirPath].year,
|
|
92
|
+
};
|
|
93
|
+
fs.writeFile(backupFile, JSON.stringify(output), () => { });
|
|
94
|
+
return output;
|
|
95
|
+
}
|
|
96
|
+
writeBack() {
|
|
97
|
+
fs.writeFileSync(this.config.metaFile, JSON.stringify(this.metaData, undefined, 2));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=getMeta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getMeta.js","sourceRoot":"","sources":["../src/getMeta.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAUA,OAAO,EAAE,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,MAAM,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAExC,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;IACxB,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC;AAC7B,CAAC;KAAM,CAAC;IACN,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;AAC3B,CAAC"}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Normalize a directory path (resolve, no trailing slash). */
|
|
2
|
+
export declare const normalizeDir: (dirPath: string) => string;
|
|
3
|
+
/** Resolve a config value relative to the config file directory when not absolute. */
|
|
4
|
+
export declare const resolveConfigPath: (configDir: string, value: string) => string;
|
|
5
|
+
/** Strip a base directory from a path safely (unlike string .replace). */
|
|
6
|
+
export declare const relativeFrom: (baseDir: string, fullPath: string) => string;
|
|
7
|
+
/** Collapse in-place terminal progress (\\r overwrites) into readable lines. */
|
|
8
|
+
export declare const normalizeTerminalOutput: (output: string) => string;
|
|
9
|
+
/** Join path segments for ffmpeg shell commands (always POSIX-style slashes). */
|
|
10
|
+
export declare const shellPath: (...segments: string[]) => string;
|
|
11
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAEA,+DAA+D;AAC/D,eAAO,MAAM,YAAY,GAAI,SAAS,MAAM,KAAG,MAG9C,CAAC;AAEF,sFAAsF;AACtF,eAAO,MAAM,iBAAiB,GAC5B,WAAW,MAAM,EACjB,OAAO,MAAM,KACZ,MAEF,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,YAAY,GAAI,SAAS,MAAM,EAAE,UAAU,MAAM,KAAG,MAQhE,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,uBAAuB,GAAI,QAAQ,MAAM,KAAG,MAM9C,CAAC;AAEZ,iFAAiF;AACjF,eAAO,MAAM,SAAS,GAAI,GAAG,UAAU,MAAM,EAAE,KAAG,MACN,CAAC"}
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
/** Normalize a directory path (resolve, no trailing slash). */
|
|
3
|
+
export const normalizeDir = (dirPath) => {
|
|
4
|
+
const normalized = path.normalize(dirPath);
|
|
5
|
+
return normalized.replace(/[/\\]+$/, "") || normalized;
|
|
6
|
+
};
|
|
7
|
+
/** Resolve a config value relative to the config file directory when not absolute. */
|
|
8
|
+
export const resolveConfigPath = (configDir, value) => normalizeDir(path.isAbsolute(value) ? value : path.resolve(configDir, value));
|
|
9
|
+
/** Strip a base directory from a path safely (unlike string .replace). */
|
|
10
|
+
export const relativeFrom = (baseDir, fullPath) => {
|
|
11
|
+
const rel = path.relative(normalizeDir(baseDir), fullPath);
|
|
12
|
+
if (rel.startsWith("..")) {
|
|
13
|
+
throw new Error(`Path "${fullPath}" is outside base directory "${baseDir}"`);
|
|
14
|
+
}
|
|
15
|
+
return rel;
|
|
16
|
+
};
|
|
17
|
+
/** Collapse in-place terminal progress (\\r overwrites) into readable lines. */
|
|
18
|
+
export const normalizeTerminalOutput = (output) => output
|
|
19
|
+
.split("\n")
|
|
20
|
+
.map((line) => line.split("\r").pop() ?? line)
|
|
21
|
+
.join("\n")
|
|
22
|
+
.replace(/\n{3,}/g, "\n\n")
|
|
23
|
+
.trim();
|
|
24
|
+
/** Join path segments for ffmpeg shell commands (always POSIX-style slashes). */
|
|
25
|
+
export const shellPath = (...segments) => path.join(...segments).replace(/\\/g, "/");
|
|
26
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,+DAA+D;AAC/D,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAe,EAAU,EAAE;IACtD,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC3C,OAAO,UAAU,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,IAAI,UAAU,CAAC;AACzD,CAAC,CAAC;AAEF,sFAAsF;AACtF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,SAAiB,EACjB,KAAa,EACL,EAAE,CAAC,YAAY,CACvB,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,CAChE,CAAC;AAEF,0EAA0E;AAC1E,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAe,EAAE,QAAgB,EAAU,EAAE;IACxE,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC3D,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,SAAS,QAAQ,gCAAgC,OAAO,GAAG,CAC5D,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AAEF,gFAAgF;AAChF,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,MAAc,EAAU,EAAE,CAChE,MAAM;KACH,KAAK,CAAC,IAAI,CAAC;KACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC;KAC7C,IAAI,CAAC,IAAI,CAAC;KACV,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC;KAC1B,IAAI,EAAE,CAAC;AAEZ,iFAAiF;AACjF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,GAAG,QAAkB,EAAU,EAAE,CACzD,IAAI,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import type { AppConfig, ConfigKey, ConfigMap } from "./config.js";
|
|
3
|
+
import { MetaGetter, Metadata } from "./getMeta.js";
|
|
4
|
+
import type { Prompts } from "./prompts.js";
|
|
5
|
+
interface MetadataCache {
|
|
6
|
+
[album: string]: Metadata;
|
|
7
|
+
}
|
|
8
|
+
interface CommandsMap {
|
|
9
|
+
[album: string]: string[];
|
|
10
|
+
}
|
|
11
|
+
interface ProcessResults {
|
|
12
|
+
commands: CommandsMap;
|
|
13
|
+
foldersToCreate: string[];
|
|
14
|
+
metaCache: MetadataCache;
|
|
15
|
+
}
|
|
16
|
+
type FileFilter = (name: string) => boolean;
|
|
17
|
+
type WalkCallback<T> = (dirPath: string, dirs: string[], files: string[]) => Promise<T>;
|
|
18
|
+
export declare const walkSync: <T>(start: string, callback: WalkCallback<T>, fileFilter?: FileFilter) => Promise<T[]>;
|
|
19
|
+
export declare const processEncoder: (configKey: ConfigKey, startFolder: string, filter: string, appConfig: AppConfig, configMap: ConfigMap, metaGetter: MetaGetter, prompts: Prompts) => Promise<ProcessResults>;
|
|
20
|
+
export declare const listCommandScripts: (appConfig: AppConfig) => string[];
|
|
21
|
+
export declare const prepareCommandFolders: (appConfig: AppConfig) => void;
|
|
22
|
+
export declare const clearCommandScripts: (appConfig: AppConfig) => number;
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=processEncoder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processEncoder.d.ts","sourceRoot":"","sources":["../src/processEncoder.ts"],"names":[],"mappings":";AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAwB5C,UAAU,aAAa;IACrB,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAAC;CAC3B;AAED,UAAU,WAAW;IACnB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CAC3B;AAED,UAAU,cAAc;IACtB,QAAQ,EAAE,WAAW,CAAC;IACtB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,SAAS,EAAE,aAAa,CAAC;CAC1B;AAED,KAAK,UAAU,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;AAC5C,KAAK,YAAY,CAAC,CAAC,IAAI,CACrB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,KAAK,EAAE,MAAM,EAAE,KACZ,OAAO,CAAC,CAAC,CAAC,CAAC;AAMhB,eAAO,MAAM,QAAQ,GAAmB,CAAC,EACvC,OAAO,MAAM,EACb,UAAU,YAAY,CAAC,CAAC,CAAC,EACzB,aAAY,UAAuB,KAClC,OAAO,CAAC,CAAC,EAAE,CAkCb,CAAC;AAgQF,eAAO,MAAM,cAAc,GACzB,WAAW,SAAS,EACpB,aAAa,MAAM,EACnB,QAAQ,MAAM,EACd,WAAW,SAAS,EACpB,WAAW,SAAS,EACpB,YAAY,UAAU,EACtB,SAAS,OAAO,KACf,OAAO,CAAC,cAAc,CA8CxB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,WAAW,SAAS,KAAG,MAAM,EAkB/D,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,WAAW,SAAS,KAAG,IAO5D,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,WAAW,SAAS,KAAG,MAI1D,CAAC"}
|