goblin-malin 0.1.0 → 0.1.2

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.
@@ -75,6 +75,7 @@ var LogLevel = /* @__PURE__ */ (function(LogLevel2) {
75
75
 
76
76
  // src/utils/appPaths.ts
77
77
  import path3 from "path";
78
+ import { fileURLToPath as fileURLToPath2 } from "url";
78
79
 
79
80
  // src/settings/settingsStore.ts
80
81
  import * as fs from "fs";
@@ -84,19 +85,38 @@ import { EventEmitter } from "events";
84
85
  // src/constants.ts
85
86
  import dotenv from "dotenv";
86
87
  import path from "path";
88
+ import os from "os";
87
89
  import { fileURLToPath } from "url";
88
- dotenv.config();
89
90
  var __filename = fileURLToPath(import.meta.url);
90
91
  var __dirname = path.dirname(__filename);
91
92
  var PROJECT_ROOT = path.join(__dirname, "..");
93
+ var IS_DEV = __filename.endsWith(".ts");
94
+ function getPlatformDefaultDataDir() {
95
+ switch (process.platform) {
96
+ case "win32":
97
+ return path.join(process.env.APPDATA ?? path.join(os.homedir(), "AppData", "Roaming"), "goblin-malin");
98
+ case "darwin":
99
+ return path.join(os.homedir(), "Library", "Application Support", "goblin-malin");
100
+ default:
101
+ return path.join(process.env.XDG_DATA_HOME ?? path.join(os.homedir(), ".local", "share"), "goblin-malin");
102
+ }
103
+ }
104
+ __name(getPlatformDefaultDataDir, "getPlatformDefaultDataDir");
105
+ var DEFAULT_APP_DATA_DIR = IS_DEV ? path.join(PROJECT_ROOT, "data") : getPlatformDefaultDataDir();
106
+ dotenv.config({
107
+ path: path.join(DEFAULT_APP_DATA_DIR, ".env")
108
+ });
92
109
 
93
110
  // src/settings/appSettings.ts
94
111
  var DEFAULT_APP_SETTINGS = {
95
112
  general: {
96
113
  reopenLastSession: false,
97
- appDataDir: PROJECT_ROOT,
98
- animationsEnabled: false
99
- }
114
+ appDataDir: DEFAULT_APP_DATA_DIR,
115
+ animationsEnabled: false,
116
+ theme: "dark",
117
+ showWelcomeTutorial: true
118
+ },
119
+ keybindings: {}
100
120
  };
101
121
 
102
122
  // src/utils/deepMerge.ts
@@ -122,8 +142,7 @@ function deepMerge(target, source) {
122
142
  __name(deepMerge, "deepMerge");
123
143
 
124
144
  // src/settings/settingsStore.ts
125
- var CONFIG_DIR = path2.join(PROJECT_ROOT, "config");
126
- var SETTINGS_PATH = path2.join(CONFIG_DIR, "settings.json");
145
+ var SETTINGS_PATH = path2.join(DEFAULT_APP_DATA_DIR, "settings.json");
127
146
  var SettingsStore = class _SettingsStore {
128
147
  static {
129
148
  __name(this, "SettingsStore");
@@ -142,12 +161,13 @@ var SettingsStore = class _SettingsStore {
142
161
  } catch {
143
162
  return {
144
163
  general: DEFAULT_APP_SETTINGS.general,
164
+ keybindings: {},
145
165
  flows: {}
146
166
  };
147
167
  }
148
168
  }
149
169
  writeToDisk(settings) {
150
- fs.mkdirSync(CONFIG_DIR, {
170
+ fs.mkdirSync(path2.dirname(SETTINGS_PATH), {
151
171
  recursive: true
152
172
  });
153
173
  const tmp = SETTINGS_PATH + ".tmp";
@@ -164,14 +184,32 @@ var SettingsStore = class _SettingsStore {
164
184
  getAppSettings() {
165
185
  const s = this.getCached();
166
186
  return deepMerge(DEFAULT_APP_SETTINGS, {
167
- general: s.general
187
+ general: s.general,
188
+ keybindings: s.keybindings ?? {}
168
189
  });
169
190
  }
170
191
  writeAppSettings(settings) {
171
192
  const current = this.getCached();
172
193
  this.writeToDisk({
173
194
  ...current,
174
- general: settings.general
195
+ general: settings.general,
196
+ keybindings: settings.keybindings ?? {}
197
+ });
198
+ }
199
+ /** Save a single key binding override. */
200
+ setKeybinding(actionId, shortcut) {
201
+ const current = this.getAppSettings();
202
+ const keybindings = {
203
+ ...current.keybindings
204
+ };
205
+ if (shortcut === null) {
206
+ delete keybindings[actionId];
207
+ } else {
208
+ keybindings[actionId] = shortcut;
209
+ }
210
+ this.writeAppSettings({
211
+ ...current,
212
+ keybindings
175
213
  });
176
214
  }
177
215
  // ── Flow settings ──────────────────────────────────────────────────────────
@@ -189,6 +227,10 @@ var SettingsStore = class _SettingsStore {
189
227
  }
190
228
  });
191
229
  }
230
+ patchFlowSettings(flowId, patch) {
231
+ const current = this.getFlowSettings(flowId, {});
232
+ this.writeFlowSettings(flowId, deepMerge(current, patch));
233
+ }
192
234
  // ── Change notifications ───────────────────────────────────────────────────
193
235
  onSettingsChanged(callback) {
194
236
  this.emitter.on("change", callback);
@@ -199,20 +241,25 @@ var SettingsStore = class _SettingsStore {
199
241
  };
200
242
 
201
243
  // src/utils/appPaths.ts
202
- function dataDir() {
244
+ var _assetsDir = path3.join(path3.dirname(fileURLToPath2(import.meta.url)), import.meta.url.endsWith(".ts") ? "../assets" : "assets");
245
+ function getAssetPath(...segments) {
246
+ return path3.join(_assetsDir, ...segments);
247
+ }
248
+ __name(getAssetPath, "getAssetPath");
249
+ function getAppDataDir() {
203
250
  return SettingsStore.getInstance().getAppSettings().general.appDataDir;
204
251
  }
205
- __name(dataDir, "dataDir");
252
+ __name(getAppDataDir, "getAppDataDir");
206
253
  function getCacheDir() {
207
- return path3.join(dataDir(), "cache");
254
+ return path3.join(getAppDataDir(), "cache");
208
255
  }
209
256
  __name(getCacheDir, "getCacheDir");
210
257
  function getBinDir() {
211
- return path3.join(dataDir(), "bin");
258
+ return path3.join(getAppDataDir(), "bin");
212
259
  }
213
260
  __name(getBinDir, "getBinDir");
214
261
  function getLogsPath() {
215
- return path3.join(dataDir(), "app.log");
262
+ return path3.join(getAppDataDir(), "app.log");
216
263
  }
217
264
  __name(getLogsPath, "getLogsPath");
218
265
 
@@ -412,9 +459,12 @@ __name(moveFile, "moveFile");
412
459
 
413
460
  export {
414
461
  __name,
462
+ DEFAULT_APP_DATA_DIR,
415
463
  deepMerge,
464
+ SETTINGS_PATH,
416
465
  SettingsStore,
417
466
  inkTransport,
467
+ getAssetPath,
418
468
  getCacheDir,
419
469
  getBinDir,
420
470
  globalLogger,
package/dist/cli.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  start
4
- } from "./chunk-DJTET7PY.js";
5
- import "./chunk-ECLAXOR2.js";
4
+ } from "./chunk-Y4ZGX5NZ.js";
5
+ import "./chunk-ZZ35YTR2.js";
6
6
 
7
7
  // src/cli.ts
8
8
  start();
package/dist/index.js CHANGED
@@ -2,8 +2,8 @@ import {
2
2
  src_default,
3
3
  start,
4
4
  withFullScreen
5
- } from "./chunk-DJTET7PY.js";
6
- import "./chunk-ECLAXOR2.js";
5
+ } from "./chunk-Y4ZGX5NZ.js";
6
+ import "./chunk-ZZ35YTR2.js";
7
7
  export {
8
8
  src_default as default,
9
9
  start,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  cleanAndTagFlac,
3
3
  moveFile
4
- } from "./chunk-ECLAXOR2.js";
4
+ } from "./chunk-ZZ35YTR2.js";
5
5
  export {
6
6
  cleanAndTagFlac,
7
7
  moveFile
package/package.json CHANGED
@@ -1,89 +1,125 @@
1
1
  {
2
- "name": "goblin-malin",
3
- "version": "0.1.0",
4
- "description": "A keyboard-driven terminal UI for downloading and tagging music tracks with metadata from Spotify and YouTube",
5
- "type": "module",
6
- "main": "./dist/index.js",
7
- "types": "./dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/index.d.ts",
11
- "default": "./dist/index.js"
2
+ "name": "goblin-malin",
3
+ "version": "0.1.2",
4
+ "description": "A keyboard-driven terminal UI for downloading and tagging music tracks with metadata from Spotify and YouTube",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "imports": {
9
+ "#base": "./src/base/index.ts",
10
+ "#base/*": "./src/base/*.ts",
11
+ "#components": "./src/components/index.ts",
12
+ "#components/*": "./src/components/*.ts",
13
+ "#contexts": "./src/contexts/index.ts",
14
+ "#contexts/*": "./src/contexts/*.ts",
15
+ "#exceptions": "./src/exceptions/index.ts",
16
+ "#exceptions/*": "./src/exceptions/*.ts",
17
+ "#flows": "./src/flows/index.ts",
18
+ "#flows/*": "./src/flows/*.ts",
19
+ "#hooks": "./src/hooks/index.ts",
20
+ "#hooks/*": "./src/hooks/*.ts",
21
+ "#settings": "./src/settings/index.ts",
22
+ "#settings/*": "./src/settings/*.ts",
23
+ "#utils": "./src/utils/index.ts",
24
+ "#utils/*": "./src/utils/*.ts",
25
+ "#assets/*": "./src/assets/*",
26
+ "#types": "./src/types/index.ts",
27
+ "#types/*": "./src/types/*.ts"
28
+ },
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/index.d.ts",
32
+ "default": "./dist/index.js"
33
+ }
34
+ },
35
+ "bin": {
36
+ "goblin-malin": "dist/cli.js"
37
+ },
38
+ "files": [
39
+ "dist",
40
+ "README.md"
41
+ ],
42
+ "scripts": {
43
+ "dev": "tsx src/cli.ts",
44
+ "start": "ts-node src/index.ts",
45
+ "build": "tsup",
46
+ "type-check": "tsc --noEmit",
47
+ "lint": "eslint src/",
48
+ "format": "prettier --write src/",
49
+ "format:check": "prettier --check src/",
50
+ "prepack": "node scripts/patch-readme.mjs",
51
+ "postpack": "git checkout -- README.md",
52
+ "prepublishOnly": "tsup"
53
+ },
54
+ "keywords": [
55
+ "music",
56
+ "download",
57
+ "downloader",
58
+ "tui",
59
+ "cli",
60
+ "terminal",
61
+ "spotify",
62
+ "youtube",
63
+ "yt-dlp",
64
+ "metadata",
65
+ "tags",
66
+ "ink",
67
+ "react"
68
+ ],
69
+ "author": "Tetraxel",
70
+ "license": "SEE LICENSE IN LICENSE",
71
+ "repository": {
72
+ "type": "git",
73
+ "url": "git+https://github.com/Tetraxel/goblin-malin.git"
74
+ },
75
+ "devDependencies": {
76
+ "@eslint/js": "^9.39.4",
77
+ "@swc/core": "^1.10.0",
78
+ "@types/adm-zip": "^0.5.7",
79
+ "@types/dotenv": "^8.2.3",
80
+ "@types/ink": "^2.0.3",
81
+ "@types/ink-select-input": "^3.0.5",
82
+ "@types/ink-spinner": "^3.0.5",
83
+ "@types/ink-text-input": "^2.0.5",
84
+ "@types/node": "^25.6.2",
85
+ "@types/react": "^19.2.14",
86
+ "eslint": "^9.39.4",
87
+ "eslint-plugin-react": "^7.37.5",
88
+ "eslint-plugin-react-hooks": "^7.1.1",
89
+ "prettier": "^3.8.3",
90
+ "ts-node": "^10.9.2",
91
+ "tsup": "^8.0.0",
92
+ "tsx": "^4.21.0",
93
+ "typescript": "^6.0.3",
94
+ "typescript-eslint": "^8.59.3"
95
+ },
96
+ "dependencies": {
97
+ "7zip-bin": "^5.2.0",
98
+ "@spotify/web-api-ts-sdk": "^1.2.0",
99
+ "adm-zip": "^0.5.17",
100
+ "chalk": "^5.6.2",
101
+ "clipboardy": "^5.3.1",
102
+ "dotenv": "^17.4.2",
103
+ "flac-tagger": "^2.0.0",
104
+ "flat-cache": "^6.1.22",
105
+ "fullscreen-ink": "^0.1.0",
106
+ "ink": "^7.0.2",
107
+ "ink-big-text": "^2.0.0",
108
+ "ink-form": "^2.0.1",
109
+ "ink-gradient": "^4.0.0",
110
+ "ink-link": "^5.0.0",
111
+ "ink-picture": "^1.3.5",
112
+ "ink-select-input": "^6.2.0",
113
+ "ink-spinner": "^5.0.0",
114
+ "ink-text-input": "^6.0.0",
115
+ "musicbrainz-api": "^1.2.1",
116
+ "node-id3": "^0.2.9",
117
+ "open": "^11.0.0",
118
+ "react": "^19.2.6",
119
+ "slsk-client": "^1.1.0",
120
+ "winston": "^3.19.0",
121
+ "winston-transport": "^4.9.0",
122
+ "ytdlp-nodejs": "^3.4.4",
123
+ "ytmusic-api": "^5.3.1"
12
124
  }
13
- },
14
- "bin": {
15
- "goblin-malin": "dist/cli.js"
16
- },
17
- "files": [
18
- "dist",
19
- "README.md"
20
- ],
21
- "scripts": {
22
- "dev": "tsx src/cli.ts",
23
- "start": "ts-node src/index.ts",
24
- "build": "tsup",
25
- "type-check": "tsc --noEmit",
26
- "prepublishOnly": "tsup"
27
- },
28
- "keywords": [
29
- "music",
30
- "download",
31
- "downloader",
32
- "tui",
33
- "cli",
34
- "terminal",
35
- "spotify",
36
- "youtube",
37
- "yt-dlp",
38
- "metadata",
39
- "tags",
40
- "ink",
41
- "react"
42
- ],
43
- "author": "Tetraxel",
44
- "license": "SEE LICENSE IN LICENSE",
45
- "devDependencies": {
46
- "@types/adm-zip": "^0.5.7",
47
- "@types/dotenv": "^8.2.3",
48
- "@types/ink": "^2.0.3",
49
- "@types/ink-select-input": "^3.0.5",
50
- "@types/ink-spinner": "^3.0.5",
51
- "@types/ink-text-input": "^2.0.5",
52
- "@types/node": "^25.6.2",
53
- "@types/react": "^19.2.14",
54
- "@swc/core": "^1.10.0",
55
- "ts-node": "^10.9.2",
56
- "tsup": "^8.0.0",
57
- "tsx": "^4.21.0",
58
- "typescript": "^6.0.3"
59
- },
60
- "dependencies": {
61
- "7zip-bin": "^5.2.0",
62
- "@spotify/web-api-ts-sdk": "^1.2.0",
63
- "adm-zip": "^0.5.17",
64
- "chalk": "^5.6.2",
65
- "clipboardy": "^5.3.1",
66
- "dotenv": "^17.4.2",
67
- "flac-tagger": "^2.0.0",
68
- "flat-cache": "^6.1.22",
69
- "fullscreen-ink": "^0.1.0",
70
- "ink": "^7.0.2",
71
- "ink-big-text": "^2.0.0",
72
- "ink-form": "^2.0.1",
73
- "ink-gradient": "^4.0.0",
74
- "ink-link": "^5.0.0",
75
- "ink-picture": "^1.3.5",
76
- "ink-select-input": "^6.2.0",
77
- "ink-spinner": "^5.0.0",
78
- "ink-text-input": "^6.0.0",
79
- "musicbrainz-api": "^1.2.1",
80
- "node-id3": "^0.2.9",
81
- "open": "^11.0.0",
82
- "react": "^19.2.6",
83
- "slsk-client": "^1.1.0",
84
- "winston": "^3.19.0",
85
- "winston-transport": "^4.9.0",
86
- "ytdlp-nodejs": "^3.4.4",
87
- "ytmusic-api": "^5.3.1"
88
- }
89
- }
125
+ }