@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.
Files changed (48) hide show
  1. package/README.md +60 -0
  2. package/batch.sh +26 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +60 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/config.d.ts +38 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +97 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/constants.d.ts +19 -0
  12. package/dist/constants.d.ts.map +1 -0
  13. package/dist/constants.js +34 -0
  14. package/dist/constants.js.map +1 -0
  15. package/dist/getMeta.d.ts +18 -0
  16. package/dist/getMeta.d.ts.map +1 -0
  17. package/dist/getMeta.js +100 -0
  18. package/dist/getMeta.js.map +1 -0
  19. package/dist/index.d.ts +3 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +10 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/paths.d.ts +11 -0
  24. package/dist/paths.d.ts.map +1 -0
  25. package/dist/paths.js +26 -0
  26. package/dist/paths.js.map +1 -0
  27. package/dist/processEncoder.d.ts +24 -0
  28. package/dist/processEncoder.d.ts.map +1 -0
  29. package/dist/processEncoder.js +238 -0
  30. package/dist/processEncoder.js.map +1 -0
  31. package/dist/prompts.d.ts +12 -0
  32. package/dist/prompts.d.ts.map +1 -0
  33. package/dist/prompts.js +19 -0
  34. package/dist/prompts.js.map +1 -0
  35. package/dist/run.d.ts +27 -0
  36. package/dist/run.d.ts.map +1 -0
  37. package/dist/run.js +100 -0
  38. package/dist/run.js.map +1 -0
  39. package/dist/scripts.d.ts +13 -0
  40. package/dist/scripts.d.ts.map +1 -0
  41. package/dist/scripts.js +89 -0
  42. package/dist/scripts.js.map +1 -0
  43. package/dist/serve.d.ts +3 -0
  44. package/dist/serve.d.ts.map +1 -0
  45. package/dist/serve.js +137 -0
  46. package/dist/serve.js.map +1 -0
  47. package/dist/web/index.html +243 -0
  48. 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,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -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
@@ -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"}
@@ -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"}
@@ -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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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -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,10 @@
1
+ #!/usr/bin/env node
2
+ const [command] = process.argv.slice(2);
3
+ if (command === "serve") {
4
+ await import("./serve.js");
5
+ }
6
+ else {
7
+ await import("./cli.js");
8
+ }
9
+ export {};
10
+ //# sourceMappingURL=index.js.map
@@ -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"}
@@ -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"}