@involvex/youtube-music-cli 0.0.5 → 0.0.6
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/.github/FUNDING.yml +9 -0
- package/CHANGELOG.md +69 -0
- package/dist/source/components/player/Suggestions.js +4 -1
- package/dist/source/components/playlist/PlaylistList.js +13 -4
- package/dist/source/components/search/SearchResults.js +37 -4
- package/dist/youtube-music-cli.exe +0 -0
- package/package.json +12 -11
- package/dist/test.d.ts +0 -1
- package/dist/test.js +0 -13
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# These are supported funding model platforms
|
|
2
|
+
|
|
3
|
+
github: [involvex]
|
|
4
|
+
custom:
|
|
5
|
+
[
|
|
6
|
+
'https://buymeacoffee.com/involvex',
|
|
7
|
+
'https://paypal.me/involvex',
|
|
8
|
+
'https://rewards.bing.com/welcome?rh=14525F68&ref=rafsrchae&form=ML2XE3&OCID=ML2XE3&PUBL=RewardsDO&CREA=ML2XE3',
|
|
9
|
+
]
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
## [0.0.6](https://github.com/involvex/youtube-music-cli/compare/v0.0.5...v0.0.6) (2026-02-18)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
- **ui:** add playlist creation and artist playback features ([0f50fd2](https://github.com/involvex/youtube-music-cli/commit/0f50fd2eeda0d340aee26b8fa2f7e5f2356d8042))
|
|
6
|
+
|
|
7
|
+
## [0.0.5](https://github.com/involvex/youtube-music-cli/compare/v0.0.4...v0.0.5) (2026-02-18)
|
|
8
|
+
|
|
9
|
+
## [0.0.4](https://github.com/involvex/youtube-music-cli/compare/v0.0.3...v0.0.4) (2026-02-18)
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
- resolve three bugs - discord rpc, search history key, resume ([90c5306](https://github.com/involvex/youtube-music-cli/commit/90c530698f08c355e11d31048844b2e1d6a312ef))
|
|
14
|
+
- **youtube:** guard suggestions parsing errors ([aca832e](https://github.com/involvex/youtube-music-cli/commit/aca832e27bb244f8b42b33060f2640f3cc003f7f))
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
- **assets:** add new icons and images ([a0d6558](https://github.com/involvex/youtube-music-cli/commit/a0d6558ed2fd42b470e7123eaac5ce0c602db051))
|
|
19
|
+
|
|
20
|
+
## [0.0.3](https://github.com/involvex/youtube-music-cli/compare/v0.0.2...v0.0.3) (2026-02-18)
|
|
21
|
+
|
|
22
|
+
### Features
|
|
23
|
+
|
|
24
|
+
- add playback speed control, new themes, and notifications ([426360a](https://github.com/involvex/youtube-music-cli/commit/426360adfde0a19d7cf9706371f5bc15a4e7640b))
|
|
25
|
+
|
|
26
|
+
## [0.0.2](https://github.com/involvex/youtube-music-cli/compare/v0.0.1...v0.0.2) (2026-02-18)
|
|
27
|
+
|
|
28
|
+
## [0.0.1](https://github.com/involvex/youtube-music-cli/compare/32798e7dd129656b9786fc435466203a0c913705...v0.0.1) (2026-02-18)
|
|
29
|
+
|
|
30
|
+
### Bug Fixes
|
|
31
|
+
|
|
32
|
+
- **api:** resolve 404 error during search and improve reliability ([c26f80f](https://github.com/involvex/youtube-music-cli/commit/c26f80f3c7f4de075393da7cc378aada8809604a))
|
|
33
|
+
- **api:** resolve search runtime error and integrate real streaming ([3c8066c](https://github.com/involvex/youtube-music-cli/commit/3c8066c37386ed6b2d50249cbeec4b30e012960d))
|
|
34
|
+
- clear queue when playing from search results to match indices ([272690d](https://github.com/involvex/youtube-music-cli/commit/272690d2f1dd0f81fecfdad4e916f4a6f42392a2))
|
|
35
|
+
- **cli:** resolve Ink crash, prevent double instances, and add features ([2dfa274](https://github.com/involvex/youtube-music-cli/commit/2dfa2747a1729037e3f88656579042892aec0b26))
|
|
36
|
+
- **cli:** resolve search input issues, terminal auto-scrolling, and UI duplication ([f3898ad](https://github.com/involvex/youtube-music-cli/commit/f3898adde09d244e6705d970ab2c3af75cd7aec7))
|
|
37
|
+
- **cli:** resolve search trigger and improve UI stability ([ccce4b1](https://github.com/involvex/youtube-music-cli/commit/ccce4b1a354432f04e771a7ddd957bd7ec5b8e6d))
|
|
38
|
+
- **cli:** resolve terminal flooding, fix search selection, and modernize React imports ([1bdfae3](https://github.com/involvex/youtube-music-cli/commit/1bdfae307ee45cafe722590ed64c5c1fd22322ae))
|
|
39
|
+
- **hooks:** resolve memory leak in useKeyboard hook ([94f4d39](https://github.com/involvex/youtube-music-cli/commit/94f4d3974a4ad0a5e609f5cc3003933978fd9008))
|
|
40
|
+
- **lint:** disable no-explicit-any for react-hooks plugin in eslint.config.ts ([7a54c2a](https://github.com/involvex/youtube-music-cli/commit/7a54c2ab04dd6dfbfcc80a3c8ec86fdcb66c05c8))
|
|
41
|
+
- **lint:** resolve react-hooks/exhaustive-deps error and fix hook bugs ([19cf971](https://github.com/involvex/youtube-music-cli/commit/19cf9712b049e494fba1b86e5e08f37c5f24c91e))
|
|
42
|
+
- **security:** implement URL sanitization and resolve linting errors ([adb1d8f](https://github.com/involvex/youtube-music-cli/commit/adb1d8fa02830d470c14912a0c1155441224ec01))
|
|
43
|
+
- simplify VOLUME_UP and VOLUME_DOWN keybindings ([571b136](https://github.com/involvex/youtube-music-cli/commit/571b136bfefefc122e9da82ce4e615d3d576b9e3))
|
|
44
|
+
- **ui:** refine help display, fix help nav, and update key hints ([adb8afb](https://github.com/involvex/youtube-music-cli/commit/adb8afbba95c1495431502d9049e67bac10295a4))
|
|
45
|
+
|
|
46
|
+
### Features
|
|
47
|
+
|
|
48
|
+
- add .gemini agent config for CLI UI design ([e27269e](https://github.com/involvex/youtube-music-cli/commit/e27269e88bd73a23bf668ef1374f4525d06a69bd))
|
|
49
|
+
- add @distube/ytdl-core dependency for YouTube downloading ([da5a8a7](https://github.com/involvex/youtube-music-cli/commit/da5a8a70cf4d65ff90dff3e7956c5d4e72740b7d))
|
|
50
|
+
- add compile script for building standalone executable ([ce3d731](https://github.com/involvex/youtube-music-cli/commit/ce3d7314e42f852b4c05eb8436463a1572ef6ed0))
|
|
51
|
+
- add config screen with keyboard navigation ([f9566cd](https://github.com/involvex/youtube-music-cli/commit/f9566cdd4f4818b158ecc5c45dae73b2af544f44))
|
|
52
|
+
- add Help component for keyboard shortcuts display ([32798e7](https://github.com/involvex/youtube-music-cli/commit/32798e7dd129656b9786fc435466203a0c913705))
|
|
53
|
+
- add player state persistence and npm publish workflow ([df7e5ce](https://github.com/involvex/youtube-music-cli/commit/df7e5ce10d13406ec0e284ff91ab8d1c38c23084))
|
|
54
|
+
- add plugin system API docs, templates, and context provider ([06392dc](https://github.com/involvex/youtube-music-cli/commit/06392dc95253fe90ddfc77d0bfbb0455b517fff6))
|
|
55
|
+
- add plugin system infrastructure and improve navigation ([626ada6](https://github.com/involvex/youtube-music-cli/commit/626ada679d530b66733ad58a553e72bd7b94755a))
|
|
56
|
+
- add react-devtools-core dependency and bun build script ([44a2a90](https://github.com/involvex/youtube-music-cli/commit/44a2a90a6c738d3bc4637bccf0d8513b2967c363))
|
|
57
|
+
- add ShortcutsBar component and prevent duplicate track playback ([af1fe32](https://github.com/involvex/youtube-music-cli/commit/af1fe32c42a49ba3ac12bb5e081dcfb31b5771c6))
|
|
58
|
+
- **cli:** fix search typing, add headless mode and control commands ([506653d](https://github.com/involvex/youtube-music-cli/commit/506653d5e1e7098a87002f039a7051f7f8e7ce76))
|
|
59
|
+
- **layouts:** optimize components with React.memo and responsive padding ([924991c](https://github.com/involvex/youtube-music-cli/commit/924991cc85ae7c96f38760ecce139e58175af8d1))
|
|
60
|
+
- migrate audio player from play-sound to mpv ([ac1aeb3](https://github.com/involvex/youtube-music-cli/commit/ac1aeb3652ec49a5e74c0519d41055e715eb4499))
|
|
61
|
+
- move PlayerControls to MainLayout for global key bindings ([4190bf0](https://github.com/involvex/youtube-music-cli/commit/4190bf0393a4f1c8602d0603a953b36d4351d89d))
|
|
62
|
+
- **player:** Add IPC-based player event monitoring for mpv ([5a40ab0](https://github.com/involvex/youtube-music-cli/commit/5a40ab06679adf6569914075440dce833f1c1226))
|
|
63
|
+
- **ui:** implement responsive layout, adjustable search limit, and fix search navigation ([78150d6](https://github.com/involvex/youtube-music-cli/commit/78150d675746879cce2d329333009cd8cfe8cc4d))
|
|
64
|
+
|
|
65
|
+
### Performance Improvements
|
|
66
|
+
|
|
67
|
+
- **cli:** optimize UI rendering and fix search result selection ([17e9f7e](https://github.com/involvex/youtube-music-cli/commit/17e9f7efc07980852fa7b1c45e002b2abd93cfd8))
|
|
68
|
+
- memoize view components and remove redundant useEffect in SearchResults ([9b90902](https://github.com/involvex/youtube-music-cli/commit/9b90902d27416df0ca5bd2854e5afb46ab24b128))
|
|
69
|
+
- throttle progress updates and fix exit handler stale closure ([162b732](https://github.com/involvex/youtube-music-cli/commit/162b73292fb21a3eae2cf998a8a02dbb0adc5446))
|
|
@@ -16,7 +16,10 @@ export default function Suggestions() {
|
|
|
16
16
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
17
17
|
useEffect(() => {
|
|
18
18
|
if (playerState.currentTrack?.videoId) {
|
|
19
|
-
getSuggestions(playerState.currentTrack.videoId).then(
|
|
19
|
+
getSuggestions(playerState.currentTrack.videoId).then(tracks => {
|
|
20
|
+
setSuggestions(tracks);
|
|
21
|
+
setSelectedIndex(0);
|
|
22
|
+
});
|
|
20
23
|
}
|
|
21
24
|
}, [playerState.currentTrack?.videoId, getSuggestions]);
|
|
22
25
|
const navigateUp = useCallback(() => {
|
|
@@ -2,10 +2,19 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
// Playlist list component
|
|
3
3
|
import { Box, Text } from 'ink';
|
|
4
4
|
import { useTheme } from "../../hooks/useTheme.js";
|
|
5
|
-
import {
|
|
5
|
+
import { usePlaylist } from "../../hooks/usePlaylist.js";
|
|
6
|
+
import { useKeyBinding } from "../../hooks/useKeyboard.js";
|
|
7
|
+
import { KEYBINDINGS } from "../../utils/constants.js";
|
|
8
|
+
import { useState, useCallback } from 'react';
|
|
6
9
|
export default function PlaylistList() {
|
|
7
10
|
const { theme } = useTheme();
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
+
const { playlists, createPlaylist } = usePlaylist();
|
|
12
|
+
const [lastCreated, setLastCreated] = useState(null);
|
|
13
|
+
const handleCreate = useCallback(() => {
|
|
14
|
+
const name = `Playlist ${playlists.length + 1}`;
|
|
15
|
+
createPlaylist(name);
|
|
16
|
+
setLastCreated(name);
|
|
17
|
+
}, [playlists.length, createPlaylist]);
|
|
18
|
+
useKeyBinding(KEYBINDINGS.CREATE_PLAYLIST, handleCreate);
|
|
19
|
+
return (_jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Box, { borderStyle: "double", borderColor: theme.colors.secondary, paddingX: 1, marginBottom: 1, children: _jsx(Text, { bold: true, color: theme.colors.primary, children: "Playlists" }) }), playlists.length === 0 ? (_jsx(Text, { color: theme.colors.dim, children: "No playlists yet" })) : (playlists.map((playlist, index) => (_jsxs(Box, { paddingX: 1, children: [_jsxs(Text, { color: theme.colors.primary, children: [index + 1, "."] }), _jsx(Text, { children: " " }), _jsx(Text, { color: theme.colors.text, children: playlist.name }), _jsxs(Text, { color: theme.colors.dim, children: [_jsx(Text, { children: " " }), "(", playlist.tracks?.length || 0, " tracks)"] })] }, playlist.playlistId || index)))), _jsxs(Box, { marginTop: 1, children: [_jsxs(Text, { color: theme.colors.dim, children: ["Press ", _jsx(Text, { color: theme.colors.text, children: "c" }), " to create playlist", _jsx(Text, { children: " | " }), _jsx(Text, { color: theme.colors.text, children: "Esc" }), " to go back"] }), lastCreated && (_jsxs(Text, { color: theme.colors.accent, children: [" Created ", lastCreated] }))] })] }));
|
|
11
20
|
}
|
|
@@ -11,13 +11,15 @@ import { truncate } from "../../utils/format.js";
|
|
|
11
11
|
import { useCallback, useRef, useEffect } from 'react';
|
|
12
12
|
import { logger } from "../../services/logger/logger.service.js";
|
|
13
13
|
import { useTerminalSize } from "../../hooks/useTerminalSize.js";
|
|
14
|
+
import { getMusicService } from "../../services/youtube-music/api.js";
|
|
14
15
|
// Generate unique component instance ID
|
|
15
16
|
let instanceCounter = 0;
|
|
16
17
|
function SearchResults({ results, selectedIndex, isActive = true }) {
|
|
17
18
|
const { theme } = useTheme();
|
|
18
19
|
const { dispatch } = useNavigation();
|
|
19
|
-
const { play } = usePlayer();
|
|
20
|
+
const { play, dispatch: playerDispatch } = usePlayer();
|
|
20
21
|
const { columns } = useTerminalSize();
|
|
22
|
+
const musicService = getMusicService();
|
|
21
23
|
// Track component instance and last action time for debouncing
|
|
22
24
|
const instanceIdRef = useRef(++instanceCounter);
|
|
23
25
|
const lastSelectTime = useRef(0);
|
|
@@ -45,7 +47,7 @@ function SearchResults({ results, selectedIndex, isActive = true }) {
|
|
|
45
47
|
}
|
|
46
48
|
}, [selectedIndex, results.length, dispatch, isActive]);
|
|
47
49
|
// Play selected result
|
|
48
|
-
const playSelected = useCallback(() => {
|
|
50
|
+
const playSelected = useCallback(async () => {
|
|
49
51
|
logger.debug('SearchResults', 'playSelected called', {
|
|
50
52
|
isActive,
|
|
51
53
|
selectedIndex,
|
|
@@ -62,12 +64,43 @@ function SearchResults({ results, selectedIndex, isActive = true }) {
|
|
|
62
64
|
// Clear queue when playing from search results to ensure indices match
|
|
63
65
|
play(selected.data, { clearQueue: true });
|
|
64
66
|
}
|
|
67
|
+
else if (selected && selected.type === 'artist') {
|
|
68
|
+
const artistName = 'name' in selected.data ? selected.data.name : '';
|
|
69
|
+
if (!artistName) {
|
|
70
|
+
logger.warn('SearchResults', 'Artist name missing, cannot search songs');
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
const response = await musicService.search(artistName, {
|
|
75
|
+
type: 'songs',
|
|
76
|
+
limit: 20,
|
|
77
|
+
});
|
|
78
|
+
const tracks = response.results
|
|
79
|
+
.filter(result => result.type === 'song')
|
|
80
|
+
.map(result => result.data);
|
|
81
|
+
if (tracks.length === 0) {
|
|
82
|
+
logger.warn('SearchResults', 'No songs found for artist', {
|
|
83
|
+
artistName,
|
|
84
|
+
});
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// Replace queue with artist songs and start playback
|
|
88
|
+
playerDispatch({ category: 'CLEAR_QUEUE' });
|
|
89
|
+
playerDispatch({ category: 'SET_QUEUE', queue: tracks });
|
|
90
|
+
playerDispatch({ category: 'PLAY', track: tracks[0] });
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
logger.error('SearchResults', 'Failed to play artist songs', {
|
|
94
|
+
error,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
65
98
|
else {
|
|
66
|
-
logger.warn('SearchResults', 'Selected item is not
|
|
99
|
+
logger.warn('SearchResults', 'Selected item is not playable', {
|
|
67
100
|
type: selected?.type,
|
|
68
101
|
});
|
|
69
102
|
}
|
|
70
|
-
}, [selectedIndex, results, play, isActive]);
|
|
103
|
+
}, [selectedIndex, results, play, isActive, musicService, playerDispatch]);
|
|
71
104
|
// Play selected result handler (memoized to prevent duplicate registrations)
|
|
72
105
|
const handleSelect = useCallback(() => {
|
|
73
106
|
const now = Date.now();
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@involvex/youtube-music-cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "- A Commandline music player for youtube-music",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -15,7 +15,11 @@
|
|
|
15
15
|
"ymc": "dist/source/cli.js"
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
|
-
"dist"
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md",
|
|
20
|
+
"CHANGELOG.md",
|
|
21
|
+
"LICENSE",
|
|
22
|
+
".github/FUNDING.yml"
|
|
19
23
|
],
|
|
20
24
|
"scripts": {
|
|
21
25
|
"prebuild": "bun run format && bun run lint:fix && bun run typecheck",
|
|
@@ -29,27 +33,24 @@
|
|
|
29
33
|
"lint": "eslint . --ext .js,.jsx,.ts,.tsx --ignore-pattern dist",
|
|
30
34
|
"lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix --ignore-pattern dist",
|
|
31
35
|
"start": "bun run dist/source/cli.js",
|
|
32
|
-
"test": "prettier --check . &&
|
|
36
|
+
"test": "prettier --check . && bun run lint && ava",
|
|
33
37
|
"typecheck": "tsc --noEmit",
|
|
34
38
|
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
|
|
35
39
|
"clean": "rimraf dist",
|
|
36
40
|
"release": "powershell -File scripts/release.ps1"
|
|
37
41
|
},
|
|
38
42
|
"xo": {
|
|
39
|
-
"
|
|
43
|
+
"react": true,
|
|
40
44
|
"prettier": true,
|
|
41
45
|
"rules": {
|
|
42
46
|
"react/prop-types": "off"
|
|
43
|
-
}
|
|
47
|
+
},
|
|
48
|
+
"semicolon": true
|
|
44
49
|
},
|
|
45
50
|
"prettier": "@vdemedes/prettier-config",
|
|
46
51
|
"ava": {
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"tsx": "module"
|
|
50
|
-
},
|
|
51
|
-
"nodeArguments": [
|
|
52
|
-
"--loader=ts-node/esm"
|
|
52
|
+
"files": [
|
|
53
|
+
"tests/**/*.js"
|
|
53
54
|
]
|
|
54
55
|
},
|
|
55
56
|
"dependencies": {
|
package/dist/test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/test.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { render } from 'ink-testing-library';
|
|
3
|
-
import App from './source/app.js';
|
|
4
|
-
import chalk from 'chalk';
|
|
5
|
-
import test from 'ava';
|
|
6
|
-
test('greet unknown user', t => {
|
|
7
|
-
const { lastFrame } = render(_jsx(App, { flags: { help: true } }));
|
|
8
|
-
t.is(lastFrame(), `Hello, ${chalk.green('Stranger')}`);
|
|
9
|
-
});
|
|
10
|
-
test('greet user with a name', t => {
|
|
11
|
-
const { lastFrame } = render(_jsx(App, { flags: { version: true } }));
|
|
12
|
-
t.is(lastFrame(), `Hello, ${chalk.green('Jane')}`);
|
|
13
|
-
});
|