@involvex/youtube-music-cli 0.0.39 → 0.0.44

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/CHANGELOG.md CHANGED
@@ -1,3 +1,25 @@
1
+ ## [0.0.44](https://github.com/involvex/youtube-music-cli/compare/v0.0.43...v0.0.44) (2026-02-23)
2
+
3
+ ### Features
4
+
5
+ - add standalone executable support with build-time versioning ([18f730c](https://github.com/involvex/youtube-music-cli/commit/18f730cef46dfe862cfbce0065af4b4989296ef0))
6
+
7
+ ## [0.0.43](https://github.com/involvex/youtube-music-cli/compare/v0.0.42...v0.0.43) (2026-02-23)
8
+
9
+ ## [0.0.42](https://github.com/involvex/youtube-music-cli/compare/v0.0.41...v0.0.42) (2026-02-23)
10
+
11
+ ## [0.0.41](https://github.com/involvex/youtube-music-cli/compare/v0.0.40...v0.0.41) (2026-02-23)
12
+
13
+ ### Features
14
+
15
+ - add shell completions for bash, zsh, powershell, and fish ([5adecc3](https://github.com/involvex/youtube-music-cli/commit/5adecc3af1cf6dae5a188c24c598e67c8260c844))
16
+
17
+ ## [0.0.40](https://github.com/involvex/youtube-music-cli/compare/v0.0.39...v0.0.40) (2026-02-23)
18
+
19
+ ### Features
20
+
21
+ - enable MSIX packaging for Windows distribution ([14eafbf](https://github.com/involvex/youtube-music-cli/commit/14eafbf522f1d2fbacf7ed1243df035cd254891b))
22
+
1
23
  ## [0.0.39](https://github.com/involvex/youtube-music-cli/compare/v0.0.38...v0.0.39) (2026-02-23)
2
24
 
3
25
  ### Features
@@ -0,0 +1,120 @@
1
+ {
2
+ "name": "@involvex/youtube-music-cli",
3
+ "version": "0.0.44",
4
+ "description": "- A Commandline music player for youtube-music",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/involvex/youtube-music-cli.git"
8
+ },
9
+ "funding": "https://github.com/sponsors/involvex",
10
+ "license": "MIT",
11
+ "author": "involvex",
12
+ "type": "module",
13
+ "bin": {
14
+ "youtube-music-cli": "dist/source/cli.js",
15
+ "ymc": "dist/source/cli.js"
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "README.md",
20
+ "CHANGELOG.md",
21
+ "LICENSE",
22
+ ".github/FUNDING.yml"
23
+ ],
24
+ "icon": "assets/icon2.PNG",
25
+ "sponsor": {
26
+ "url": "https://github.com/sponsors/involvex"
27
+ },
28
+ "homepage": "https://involvex.github.io/youtube-music-cli/",
29
+ "keywords": [
30
+ "cli",
31
+ "youtube",
32
+ "youtube-music",
33
+ "youtube-cli",
34
+ "youtube-music-cli",
35
+ "ink",
36
+ "cli-music"
37
+ ],
38
+ "scripts": {
39
+ "prebuild": "bun run format && bun run lint:fix && bun run typecheck",
40
+ "build": "tsc",
41
+ "bun:build": "bun build source/cli.tsx --outfile dist/index.js --target node --footer \"//Copyright (c) 2026 involvex\"",
42
+ "compile": "bun scripts/build-cli.ts",
43
+ "dev": "bun run --bun source/cli.tsx",
44
+ "dev:watch": "bun run --bun --watch source/cli.tsx",
45
+ "format": "prettier --write .",
46
+ "format:check": "prettier --check .",
47
+ "lint": "eslint . --ext .js,.jsx,.ts,.tsx --ignore-pattern dist",
48
+ "lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix --ignore-pattern dist",
49
+ "start": "bun run dist/source/cli.js",
50
+ "test": "bun run build && ava",
51
+ "typecheck": "tsc --noEmit",
52
+ "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
53
+ "clean": "rimraf dist",
54
+ "release": "powershell -File scripts/release.ps1",
55
+ "build:web": "cd web && bun run build",
56
+ "dev:web": "cd web && bun run dev",
57
+ "build:all": "bun run build && bun run build:web",
58
+ "msix": "bun run compile && msix-packager-cli package --config ./msix-config.json --skip-build"
59
+ },
60
+ "prettier": "@vdemedes/prettier-config",
61
+ "ava": {
62
+ "files": [
63
+ "tests/**/*.js"
64
+ ]
65
+ },
66
+ "dependencies": {
67
+ "@distube/ytdl-core": "^4.16.12",
68
+ "@types/bun": "^1.3.9",
69
+ "ansi-escapes": "^7.3.0",
70
+ "discord-rpc": "^4.0.1",
71
+ "ink": "^6.8.0",
72
+ "ink-table": "^3.1.0",
73
+ "ink-text-input": "^6.0.0",
74
+ "jiti": "^2.6.1",
75
+ "meow": "^14.1.0",
76
+ "node-notifier": "^10.0.1",
77
+ "node-youtube-music": "^0.10.3",
78
+ "play-sound": "^1.1.6",
79
+ "react": "^19.2.4",
80
+ "ws": "^8.19.0",
81
+ "youtube-ext": "^1.1.25",
82
+ "youtubei.js": "^16.0.1"
83
+ },
84
+ "devDependencies": {
85
+ "@eslint/js": "^10.0.1",
86
+ "@sindresorhus/tsconfig": "^8.1.0",
87
+ "@types/node": "^25.3.0",
88
+ "@types/node-notifier": "^8.0.5",
89
+ "@types/react": "^19.2.14",
90
+ "@types/ws": "^8.18.1",
91
+ "@vdemedes/prettier-config": "^2.0.1",
92
+ "ava": "^6.4.1",
93
+ "chalk": "^5.6.2",
94
+ "conventional-changelog-cli": "^5.0.0",
95
+ "eslint": "^10.0.1",
96
+ "eslint-plugin-react": "^7.37.5",
97
+ "eslint-plugin-react-hooks": "^7.0.1",
98
+ "globals": "^17.3.0",
99
+ "ink-testing-library": "^4.0.0",
100
+ "prettier": "^3.8.1",
101
+ "prettier-plugin-organize-imports": "^4.3.0",
102
+ "prettier-plugin-packagejson": "^3.0.0",
103
+ "prettier-plugin-sort-imports": "^1.8.11",
104
+ "react-devtools-core": "^7.0.1",
105
+ "rimraf": "^6.1.3",
106
+ "ts-node": "^10.9.2",
107
+ "typescript": "^5.9.3",
108
+ "typescript-eslint": "^8.56.0"
109
+ },
110
+ "engines": {
111
+ "node": ">=16"
112
+ },
113
+ "sponsors": "https://github.com/sponsors/involvex",
114
+ "overrides": {
115
+ "minimatch": "^10.2.1"
116
+ },
117
+ "trustedDependencies": [
118
+ "unrs-resolver"
119
+ ]
120
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,46 @@
1
+ import path from 'node:path';
2
+ import pkg from '../package.json' with { type: 'json' };
3
+ const rootDir = process.cwd();
4
+ const isWindows = process.platform === 'win32';
5
+ const outputName = isWindows ? 'youtube-music-cli.exe' : 'youtube-music-cli';
6
+ const outfile = path.join(rootDir, 'dist', outputName);
7
+ const banner = '//Copyright (c) 2026 involvex';
8
+ const iconPath = path.join(rootDir, 'assets', 'icon.ico');
9
+ const platformTarget = isWindows
10
+ ? 'bun-windows-x64'
11
+ : process.platform === 'darwin'
12
+ ? 'bun-darwin-x64'
13
+ : 'bun-linux-x64';
14
+ const compileOptions = isWindows
15
+ ? {
16
+ target: platformTarget,
17
+ outfile,
18
+ footer: banner,
19
+ windowsTitle: 'YouTube Music CLI',
20
+ windowsPublisher: 'involvex',
21
+ windowsIcon: iconPath,
22
+ windowsCopyright: 'Copyright (c) 2026 involvex',
23
+ windowsDescription: 'A Commandline music player for youtube-music',
24
+ }
25
+ : {
26
+ target: platformTarget,
27
+ outfile,
28
+ };
29
+ const buildOptions = {
30
+ entrypoints: [path.join(rootDir, 'source', 'cli.tsx')],
31
+ compile: compileOptions,
32
+ footer: banner,
33
+ minify: true,
34
+ sourcemap: 'linked',
35
+ bytecode: false,
36
+ define: {
37
+ 'process.env.NODE_ENV': JSON.stringify('production'),
38
+ VERSION: JSON.stringify(pkg.version ?? '0.0.0'),
39
+ },
40
+ };
41
+ const result = await Bun.build(buildOptions);
42
+ if (!result.success) {
43
+ console.error('Build failed', result.logs ?? result);
44
+ process.exit(1);
45
+ }
46
+ console.log('Build succeeded:', result.outputs.map(output => output.path));
@@ -10,12 +10,19 @@ import { getImportService } from "./services/import/import.service.js";
10
10
  import { getWebServerManager } from "./services/web/web-server-manager.js";
11
11
  import { getWebStreamingService } from "./services/web/web-streaming.service.js";
12
12
  import { getVersionCheckService } from "./services/version-check/version-check.service.js";
13
+ import { generateCompletion, } from "./services/completions/completions.service.js";
13
14
  import { getConfigService } from "./services/config/config.service.js";
14
15
  import { getPlayerService } from "./services/player/player.service.js";
15
16
  import { APP_VERSION } from "./utils/constants.js";
16
17
  import { ensurePlaybackDependencies } from "./services/player/dependency-check.service.js";
17
18
  import { getMusicService } from "./services/youtube-music/api.js";
19
+ const isStandalone = process
20
+ .isStandaloneExecutable ||
21
+ globalThis.Bun?.isStandalone;
22
+ const argv = isStandalone ? process.argv.slice(1) : process.argv.slice(2);
18
23
  const cli = meow(`
24
+ youtube-music-cli@${APP_VERSION}
25
+
19
26
  Usage
20
27
  $ youtube-music-cli
21
28
  $ youtube-music-cli play <track-id|youtube-url>
@@ -53,6 +60,12 @@ const cli = meow(`
53
60
  --name Custom name for imported playlist
54
61
  --help, -h Show this help
55
62
 
63
+ Shell Completions
64
+ $ youtube-music-cli completions bash
65
+ $ youtube-music-cli completions zsh
66
+ $ youtube-music-cli completions powershell
67
+ $ youtube-music-cli completions fish
68
+
56
69
  Examples
57
70
  $ youtube-music-cli
58
71
  $ youtube-music-cli play dQw4w9WgXcQ
@@ -61,8 +74,10 @@ const cli = meow(`
61
74
  $ youtube-music-cli plugins install adblock
62
75
  $ youtube-music-cli import spotify "https://open.spotify.com/playlist/..."
63
76
  $ youtube-music-cli --web --web-port 3000
77
+ $ youtube-music-cli completions powershell | Out-File $PROFILE
64
78
  `, {
65
79
  importMeta: import.meta,
80
+ argv,
66
81
  flags: {
67
82
  theme: {
68
83
  type: 'string',
@@ -307,7 +322,17 @@ if (command === 'plugins') {
307
322
  }
308
323
  else {
309
324
  // Handle other direct commands
310
- if (command === 'play' && args[0]) {
325
+ if (command === 'completions') {
326
+ const shell = args[0];
327
+ const validShells = ['bash', 'zsh', 'powershell', 'fish'];
328
+ if (!shell || !validShells.includes(shell)) {
329
+ console.error('Usage: youtube-music-cli completions <bash|zsh|powershell|fish>');
330
+ process.exit(1);
331
+ }
332
+ console.log(generateCompletion(shell));
333
+ process.exit(0);
334
+ }
335
+ else if (command === 'play' && args[0]) {
311
336
  // Play specific track
312
337
  cli.flags.playTrack = args[0];
313
338
  }
@@ -0,0 +1,2 @@
1
+ export type ShellType = 'bash' | 'zsh' | 'powershell' | 'fish';
2
+ export declare function generateCompletion(shell: ShellType): string;
@@ -0,0 +1,313 @@
1
+ const COMMANDS = [
2
+ 'play',
3
+ 'search',
4
+ 'playlist',
5
+ 'suggestions',
6
+ 'pause',
7
+ 'resume',
8
+ 'skip',
9
+ 'back',
10
+ 'plugins',
11
+ 'import',
12
+ 'completions',
13
+ ];
14
+ const PLUGINS_SUBCOMMANDS = [
15
+ 'list',
16
+ 'install',
17
+ 'remove',
18
+ 'uninstall',
19
+ 'update',
20
+ 'enable',
21
+ 'disable',
22
+ ];
23
+ const IMPORT_SUBCOMMANDS = ['spotify', 'youtube'];
24
+ const COMPLETIONS_SUBCOMMANDS = [
25
+ 'bash',
26
+ 'zsh',
27
+ 'powershell',
28
+ 'fish',
29
+ ];
30
+ const FLAGS = [
31
+ '--theme',
32
+ '--volume',
33
+ '--shuffle',
34
+ '--repeat',
35
+ '--headless',
36
+ '--web',
37
+ '--web-host',
38
+ '--web-port',
39
+ '--web-only',
40
+ '--web-auth',
41
+ '--name',
42
+ '--help',
43
+ '--version',
44
+ ];
45
+ export function generateCompletion(shell) {
46
+ switch (shell) {
47
+ case 'bash':
48
+ return generateBashCompletion();
49
+ case 'zsh':
50
+ return generateZshCompletion();
51
+ case 'powershell':
52
+ return generatePowerShellCompletion();
53
+ case 'fish':
54
+ return generateFishCompletion();
55
+ }
56
+ }
57
+ function generateBashCompletion() {
58
+ const cmds = COMMANDS.join(' ');
59
+ const pluginsSubs = PLUGINS_SUBCOMMANDS.join(' ');
60
+ const importSubs = IMPORT_SUBCOMMANDS.join(' ');
61
+ const completionsSubs = COMPLETIONS_SUBCOMMANDS.join(' ');
62
+ const flags = FLAGS.join(' ');
63
+ return `# youtube-music-cli bash completion
64
+ # Add to ~/.bashrc or ~/.bash_profile:
65
+ # source <(ymc completions bash)
66
+ # # or:
67
+ # ymc completions bash >> ~/.bash_completion
68
+
69
+ _ymc_completions() {
70
+ local cur prev words cword
71
+ _init_completion || return
72
+
73
+ local commands="${cmds}"
74
+ local flags="${flags}"
75
+
76
+ case "$prev" in
77
+ plugins)
78
+ COMPREPLY=($(compgen -W "${pluginsSubs}" -- "$cur"))
79
+ return ;;
80
+ import)
81
+ COMPREPLY=($(compgen -W "${importSubs}" -- "$cur"))
82
+ return ;;
83
+ completions)
84
+ COMPREPLY=($(compgen -W "${completionsSubs}" -- "$cur"))
85
+ return ;;
86
+ --theme|-t)
87
+ COMPREPLY=($(compgen -W "dark light midnight matrix" -- "$cur"))
88
+ return ;;
89
+ --repeat|-r)
90
+ COMPREPLY=($(compgen -W "off all one" -- "$cur"))
91
+ return ;;
92
+ esac
93
+
94
+ if [[ "$cur" == -* ]]; then
95
+ COMPREPLY=($(compgen -W "$flags" -- "$cur"))
96
+ else
97
+ COMPREPLY=($(compgen -W "$commands" -- "$cur"))
98
+ fi
99
+ }
100
+
101
+ complete -F _ymc_completions ymc youtube-music-cli
102
+ `;
103
+ }
104
+ function generateZshCompletion() {
105
+ return `#compdef ymc youtube-music-cli
106
+ # youtube-music-cli zsh completion
107
+ # Add to your zsh config:
108
+ # source <(ymc completions zsh)
109
+ # # or copy to a directory in $fpath:
110
+ # ymc completions zsh > ~/.zsh/completions/_ymc
111
+
112
+ _ymc() {
113
+ local -a commands subcommands flags
114
+
115
+ commands=(
116
+ 'play:Play a track by ID or YouTube URL'
117
+ 'search:Search for tracks'
118
+ 'playlist:Play a playlist by ID'
119
+ 'suggestions:Show music suggestions'
120
+ 'pause:Pause playback'
121
+ 'resume:Resume playback'
122
+ 'skip:Skip to next track'
123
+ 'back:Go to previous track'
124
+ 'plugins:Manage plugins'
125
+ 'import:Import playlists from Spotify or YouTube'
126
+ 'completions:Generate shell completion scripts'
127
+ )
128
+
129
+ flags=(
130
+ '--theme[Theme to use]:theme:(dark light midnight matrix)'
131
+ '--volume[Initial volume (0-100)]:volume:'
132
+ '--shuffle[Enable shuffle mode]'
133
+ '--repeat[Repeat mode]:mode:(off all one)'
134
+ '--headless[Run without TUI]'
135
+ '--web[Enable web UI server]'
136
+ '--web-host[Web server host]:host:'
137
+ '--web-port[Web server port]:port:'
138
+ '--web-only[Run web server without CLI UI]'
139
+ '--web-auth[Authentication token for web server]:token:'
140
+ '--name[Custom name for imported playlist]:name:'
141
+ '--help[Show help]'
142
+ '--version[Show version]'
143
+ )
144
+
145
+ case $words[2] in
146
+ plugins)
147
+ local -a plugin_cmds
148
+ plugin_cmds=(
149
+ 'list:List installed plugins'
150
+ 'install:Install a plugin'
151
+ 'remove:Remove a plugin'
152
+ 'uninstall:Alias for remove'
153
+ 'update:Update a plugin'
154
+ 'enable:Enable a plugin'
155
+ 'disable:Disable a plugin'
156
+ )
157
+ _describe 'plugin commands' plugin_cmds
158
+ return ;;
159
+ import)
160
+ local -a import_sources
161
+ import_sources=('spotify:Import from Spotify' 'youtube:Import from YouTube')
162
+ _describe 'import sources' import_sources
163
+ return ;;
164
+ completions)
165
+ local -a shells
166
+ shells=('bash:Bash completion' 'zsh:Zsh completion' 'powershell:PowerShell completion' 'fish:Fish completion')
167
+ _describe 'shells' shells
168
+ return ;;
169
+ esac
170
+
171
+ _arguments -s \\
172
+ $flags \\
173
+ '1:command:->cmd' \\
174
+ '*::args:->args'
175
+
176
+ case $state in
177
+ cmd)
178
+ _describe 'commands' commands ;;
179
+ args)
180
+ _message 'arguments' ;;
181
+ esac
182
+ }
183
+
184
+ _ymc
185
+ `;
186
+ }
187
+ function generatePowerShellCompletion() {
188
+ const cmds = COMMANDS.map(c => `'${c}'`).join(', ');
189
+ const pluginsSubs = PLUGINS_SUBCOMMANDS.map(c => `'${c}'`).join(', ');
190
+ const importSubs = IMPORT_SUBCOMMANDS.map(c => `'${c}'`).join(', ');
191
+ const completionsSubs = COMPLETIONS_SUBCOMMANDS.map(c => `'${c}'`).join(', ');
192
+ const flags = FLAGS.map(f => `'${f}'`).join(', ');
193
+ return `# youtube-music-cli PowerShell completion
194
+ # Add to your PowerShell profile ($PROFILE):
195
+ # ymc completions powershell | Out-File -Append $PROFILE
196
+ # # or:
197
+ # Invoke-Expression (ymc completions powershell | Out-String)
198
+
199
+ $ymcCompleterBlock = {
200
+ param($wordToComplete, $commandAst, $cursorPosition)
201
+
202
+ $commands = @(${cmds})
203
+ $pluginsSubCommands = @(${pluginsSubs})
204
+ $importSubCommands = @(${importSubs})
205
+ $completionsSubCommands = @(${completionsSubs})
206
+ $flags = @(${flags})
207
+ $themes = @('dark', 'light', 'midnight', 'matrix')
208
+ $repeatModes = @('off', 'all', 'one')
209
+
210
+ $tokens = $commandAst.CommandElements
211
+ $prevToken = if ($tokens.Count -ge 2) { $tokens[$tokens.Count - 2].ToString() } else { '' }
212
+ $firstArg = if ($tokens.Count -ge 2) { $tokens[1].ToString() } else { '' }
213
+
214
+ # Context-aware completions
215
+ switch ($prevToken) {
216
+ 'plugins' {
217
+ $pluginsSubCommands | Where-Object { $_ -like "$wordToComplete*" } |
218
+ ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }
219
+ return
220
+ }
221
+ 'import' {
222
+ $importSubCommands | Where-Object { $_ -like "$wordToComplete*" } |
223
+ ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }
224
+ return
225
+ }
226
+ 'completions' {
227
+ $completionsSubCommands | Where-Object { $_ -like "$wordToComplete*" } |
228
+ ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }
229
+ return
230
+ }
231
+ { $_ -in '--theme', '-t' } {
232
+ $themes | Where-Object { $_ -like "$wordToComplete*" } |
233
+ ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }
234
+ return
235
+ }
236
+ { $_ -in '--repeat', '-r' } {
237
+ $repeatModes | Where-Object { $_ -like "$wordToComplete*" } |
238
+ ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }
239
+ return
240
+ }
241
+ }
242
+
243
+ if ($wordToComplete.StartsWith('-')) {
244
+ $flags | Where-Object { $_ -like "$wordToComplete*" } |
245
+ ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }
246
+ } elseif ($firstArg -eq $wordToComplete -or $tokens.Count -le 1) {
247
+ $commands | Where-Object { $_ -like "$wordToComplete*" } |
248
+ ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }
249
+ }
250
+ }
251
+
252
+ Register-ArgumentCompleter -Native -CommandName @('ymc', 'youtube-music-cli') -ScriptBlock $ymcCompleterBlock
253
+ `;
254
+ }
255
+ function generateFishCompletion() {
256
+ const commandCompletions = COMMANDS.map(cmd => `complete -c ymc -n '__fish_use_subcommand' -f -a '${cmd}' -d '${getFishDescription(cmd)}'`).join('\n');
257
+ const pluginsCompletions = PLUGINS_SUBCOMMANDS.map(sub => `complete -c ymc -n '__fish_seen_subcommand_from plugins' -f -a '${sub}'`).join('\n');
258
+ const importCompletions = IMPORT_SUBCOMMANDS.map(sub => `complete -c ymc -n '__fish_seen_subcommand_from import' -f -a '${sub}'`).join('\n');
259
+ const completionsCompletions = COMPLETIONS_SUBCOMMANDS.map(sub => `complete -c ymc -n '__fish_seen_subcommand_from completions' -f -a '${sub}'`).join('\n');
260
+ return `# youtube-music-cli fish completion
261
+ # Save to: ~/.config/fish/completions/ymc.fish
262
+ # ymc completions fish > ~/.config/fish/completions/ymc.fish
263
+
264
+ # Disable file completions by default
265
+ complete -c ymc -f
266
+
267
+ # Main commands
268
+ ${commandCompletions}
269
+
270
+ # Plugins subcommands
271
+ ${pluginsCompletions}
272
+
273
+ # Import subcommands
274
+ ${importCompletions}
275
+
276
+ # Completions subcommands
277
+ ${completionsCompletions}
278
+
279
+ # Flags
280
+ complete -c ymc -l theme -s t -d 'Theme to use' -r -a 'dark light midnight matrix'
281
+ complete -c ymc -l volume -s v -d 'Initial volume (0-100)' -r
282
+ complete -c ymc -l shuffle -s s -d 'Enable shuffle mode'
283
+ complete -c ymc -l repeat -s r -d 'Repeat mode' -r -a 'off all one'
284
+ complete -c ymc -l headless -d 'Run without TUI'
285
+ complete -c ymc -l web -d 'Enable web UI server'
286
+ complete -c ymc -l web-host -d 'Web server host' -r
287
+ complete -c ymc -l web-port -d 'Web server port' -r
288
+ complete -c ymc -l web-only -d 'Run web server without CLI UI'
289
+ complete -c ymc -l web-auth -d 'Authentication token for web server' -r
290
+ complete -c ymc -l name -d 'Custom name for imported playlist' -r
291
+ complete -c ymc -l help -s h -d 'Show help'
292
+ complete -c ymc -l version -d 'Show version'
293
+
294
+ # Also register for youtube-music-cli
295
+ complete -c youtube-music-cli -w ymc
296
+ `;
297
+ }
298
+ function getFishDescription(cmd) {
299
+ const descriptions = {
300
+ play: 'Play a track by ID or YouTube URL',
301
+ search: 'Search for tracks',
302
+ playlist: 'Play a playlist by ID',
303
+ suggestions: 'Show music suggestions',
304
+ pause: 'Pause playback',
305
+ resume: 'Resume playback',
306
+ skip: 'Skip to next track',
307
+ back: 'Go to previous track',
308
+ plugins: 'Manage plugins',
309
+ import: 'Import playlists from Spotify or YouTube',
310
+ completions: 'Generate shell completion scripts',
311
+ };
312
+ return descriptions[cmd] ?? cmd;
313
+ }
@@ -1,5 +1,5 @@
1
1
  export declare const APP_NAME = "@involvex/youtube-music-cli";
2
- export declare const APP_VERSION = "0.0.20";
2
+ export declare const APP_VERSION: string;
3
3
  export declare const CONFIG_DIR: string;
4
4
  export declare const CONFIG_FILE: string;
5
5
  export declare const VIEW: {
@@ -1,6 +1,33 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { dirname, resolve } from 'node:path';
4
+ function loadAppVersion() {
5
+ if (typeof VERSION !== 'undefined') {
6
+ return VERSION;
7
+ }
8
+ let dir = dirname(fileURLToPath(import.meta.url));
9
+ for (let i = 0; i < 5; i++) {
10
+ try {
11
+ const content = readFileSync(resolve(dir, 'package.json'), 'utf8');
12
+ const pkg = JSON.parse(content);
13
+ if (typeof pkg.version === 'string' &&
14
+ pkg.name?.includes('youtube-music-cli')) {
15
+ return pkg.version;
16
+ }
17
+ }
18
+ catch {
19
+ /* ignore */
20
+ }
21
+ const parent = dirname(dir);
22
+ if (parent === dir)
23
+ break;
24
+ dir = parent;
25
+ }
26
+ return '0.0.0';
27
+ }
1
28
  // Application constants
2
29
  export const APP_NAME = '@involvex/youtube-music-cli';
3
- export const APP_VERSION = '0.0.20';
30
+ export const APP_VERSION = loadAppVersion();
4
31
  // Config directory
5
32
  export const CONFIG_DIR = process.platform === 'win32'
6
33
  ? `${process.env['USERPROFILE']}\\.youtube-music-cli`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@involvex/youtube-music-cli",
3
- "version": "0.0.39",
3
+ "version": "0.0.44",
4
4
  "description": "- A Commandline music player for youtube-music",
5
5
  "repository": {
6
6
  "type": "git",
@@ -38,8 +38,8 @@
38
38
  "scripts": {
39
39
  "prebuild": "bun run format && bun run lint:fix && bun run typecheck",
40
40
  "build": "tsc",
41
- "bun:build": "bun build source/cli.tsx --outfile dist/index.js --target node",
42
- "compile": "bun build --compile source/cli.tsx --outfile dist/youtube-music-cli.exe",
41
+ "bun:build": "bun build source/cli.tsx --outfile dist/index.js --target node --footer \"//Copyright (c) 2026 involvex\"",
42
+ "compile": "bun scripts/build-cli.ts",
43
43
  "dev": "bun run --bun source/cli.tsx",
44
44
  "dev:watch": "bun run --bun --watch source/cli.tsx",
45
45
  "format": "prettier --write .",
@@ -54,7 +54,8 @@
54
54
  "release": "powershell -File scripts/release.ps1",
55
55
  "build:web": "cd web && bun run build",
56
56
  "dev:web": "cd web && bun run dev",
57
- "build:all": "bun run build && bun run build:web"
57
+ "build:all": "bun run build && bun run build:web",
58
+ "msix": "bun run compile && msix-packager-cli package --config ./msix-config.json --skip-build"
58
59
  },
59
60
  "prettier": "@vdemedes/prettier-config",
60
61
  "ava": {
@@ -64,20 +65,21 @@
64
65
  },
65
66
  "dependencies": {
66
67
  "@distube/ytdl-core": "^4.16.12",
68
+ "@types/bun": "^1.3.9",
67
69
  "ansi-escapes": "^7.3.0",
70
+ "discord-rpc": "^4.0.1",
68
71
  "ink": "^6.8.0",
69
72
  "ink-table": "^3.1.0",
70
73
  "ink-text-input": "^6.0.0",
71
74
  "jiti": "^2.6.1",
72
75
  "meow": "^14.1.0",
73
76
  "node-notifier": "^10.0.1",
74
- "discord-rpc": "^4.0.1",
75
77
  "node-youtube-music": "^0.10.3",
76
78
  "play-sound": "^1.1.6",
77
79
  "react": "^19.2.4",
80
+ "ws": "^8.19.0",
78
81
  "youtube-ext": "^1.1.25",
79
- "youtubei.js": "^16.0.1",
80
- "ws": "^8.19.0"
82
+ "youtubei.js": "^16.0.1"
81
83
  },
82
84
  "devDependencies": {
83
85
  "@eslint/js": "^10.0.1",