@involvex/youtube-music-cli 0.0.0 → 0.0.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.
- package/dist/source/components/layouts/PlayerLayout.js +1 -2
- package/dist/source/components/player/NowPlaying.js +8 -5
- package/dist/source/components/player/ProgressBar.js +6 -5
- package/dist/source/components/player/QueueList.d.ts +1 -1
- package/dist/source/components/player/QueueList.js +11 -5
- package/dist/source/services/plugin/plugin-installer.service.js +2 -1
- package/dist/source/stores/player.store.js +10 -3
- package/dist/youtube-music-cli.exe +0 -0
- package/package.json +1 -1
- /package/{README.md → readme.md} +0 -0
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { usePlayer } from "../../hooks/usePlayer.js";
|
|
3
3
|
import NowPlaying from "../player/NowPlaying.js";
|
|
4
|
-
import ProgressBar from "../player/ProgressBar.js";
|
|
5
4
|
import QueueList from "../player/QueueList.js";
|
|
6
5
|
import { Box } from 'ink';
|
|
7
6
|
export default function PlayerLayout() {
|
|
8
7
|
const { state: playerState } = usePlayer();
|
|
9
|
-
return (_jsxs(Box, { flexDirection: "column",
|
|
8
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(NowPlaying, {}), playerState.queue.length > 0 && _jsx(QueueList, {})] }));
|
|
10
9
|
}
|
|
@@ -10,12 +10,15 @@ export default function NowPlaying() {
|
|
|
10
10
|
const { state: playerState } = usePlayer();
|
|
11
11
|
const { columns } = useTerminalSize();
|
|
12
12
|
if (!playerState.currentTrack) {
|
|
13
|
-
return (_jsx(Box, { borderStyle: "round", borderColor: theme.colors.dim,
|
|
13
|
+
return (_jsx(Box, { borderStyle: "round", borderColor: theme.colors.dim, paddingX: 1, children: _jsx(Text, { color: theme.colors.dim, children: "No track playing" }) }));
|
|
14
14
|
}
|
|
15
15
|
const track = playerState.currentTrack;
|
|
16
16
|
const artists = track.artists?.map(a => a.name).join(', ') || 'Unknown Artist';
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
// Clamp progress to valid range
|
|
18
|
+
const progress = Math.max(0, Math.min(playerState.progress, playerState.duration || 0));
|
|
19
|
+
const duration = playerState.duration || 0;
|
|
20
|
+
const percentage = duration > 0 ? Math.min(100, Math.floor((progress / duration) * 100)) : 0;
|
|
21
|
+
const barWidth = Math.max(10, columns - 8);
|
|
22
|
+
const filledWidth = duration > 0 ? Math.floor((progress / duration) * barWidth) : 0;
|
|
23
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: theme.colors.primary, paddingX: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, color: theme.colors.primary, children: track.title }), _jsx(Text, { color: theme.colors.dim, children: " \u2022 " }), _jsx(Text, { color: theme.colors.secondary, children: artists })] }), track.album && _jsx(Text, { color: theme.colors.dim, children: track.album.name }), _jsxs(Box, { children: [_jsx(Text, { color: theme.colors.primary, children: '█'.repeat(Math.min(filledWidth, barWidth)) }), _jsx(Text, { color: theme.colors.dim, children: '░'.repeat(Math.max(0, barWidth - filledWidth)) })] }), _jsxs(Box, { children: [_jsx(Text, { color: theme.colors.text, children: formatTime(progress) }), _jsxs(Text, { color: theme.colors.dim, children: [" / ", formatTime(duration), " "] }), _jsxs(Text, { color: theme.colors.dim, children: ["[", percentage, "%]"] }), playerState.isLoading && (_jsx(Text, { color: theme.colors.accent, children: " Loading..." })), !playerState.isPlaying && progress > 0 && (_jsx(Text, { color: theme.colors.dim, children: " \u23F8" }))] }), playerState.error && (_jsx(Text, { color: theme.colors.error, children: playerState.error }))] }));
|
|
21
24
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
// Progress bar component
|
|
3
3
|
import { Box, Text } from 'ink';
|
|
4
4
|
import { useTheme } from "../../hooks/useTheme.js";
|
|
@@ -10,9 +10,10 @@ export default function ProgressBar() {
|
|
|
10
10
|
if (!playerState.currentTrack || !playerState.duration) {
|
|
11
11
|
return null;
|
|
12
12
|
}
|
|
13
|
-
|
|
13
|
+
// Clamp values to valid range
|
|
14
|
+
const progress = Math.max(0, Math.min(playerState.progress, playerState.duration));
|
|
14
15
|
const duration = playerState.duration;
|
|
15
|
-
const percentage = duration > 0 ? Math.floor((progress / duration) * 100) : 0;
|
|
16
|
-
const barWidth = Math.
|
|
17
|
-
return (_jsxs(Box, {
|
|
16
|
+
const percentage = duration > 0 ? Math.min(100, Math.floor((progress / duration) * 100)) : 0;
|
|
17
|
+
const barWidth = Math.min(20, Math.floor(percentage / 5));
|
|
18
|
+
return (_jsxs(Box, { children: [_jsx(Text, { color: theme.colors.text, children: formatTime(progress) }), _jsx(Text, { color: theme.colors.dim, children: "/" }), _jsx(Text, { color: theme.colors.text, children: formatTime(duration) }), _jsx(Text, { children: " " }), _jsx(Text, { color: theme.colors.primary, children: '█'.repeat(barWidth) }), _jsx(Text, { color: theme.colors.dim, children: '░'.repeat(20 - barWidth) }), _jsxs(Text, { color: theme.colors.dim, children: [" ", percentage, "%"] })] }));
|
|
18
19
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
declare function QueueList(): import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
declare function QueueList(): import("react/jsx-runtime").JSX.Element | null;
|
|
3
3
|
declare const _default: React.MemoExoticComponent<typeof QueueList>;
|
|
4
4
|
export default _default;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
// Queue management component
|
|
3
3
|
import { useState } from 'react';
|
|
4
4
|
import React from 'react';
|
|
@@ -18,13 +18,19 @@ function QueueList() {
|
|
|
18
18
|
return Math.max(20, Math.floor(baseLength * scale));
|
|
19
19
|
};
|
|
20
20
|
if (playerState.queue.length === 0) {
|
|
21
|
-
return
|
|
21
|
+
return null;
|
|
22
22
|
}
|
|
23
|
-
|
|
23
|
+
// Show only next 5 tracks
|
|
24
|
+
const visibleQueue = playerState.queue.slice(playerState.queuePosition + 1, playerState.queuePosition + 6);
|
|
25
|
+
if (visibleQueue.length === 0) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: theme.colors.dim, children: ["Up next (", playerState.queue.length - playerState.queuePosition - 1, ' ', "tracks)"] }), visibleQueue.map((track, idx) => {
|
|
29
|
+
const index = playerState.queuePosition + 1 + idx;
|
|
24
30
|
const isSelected = index === selectedIndex;
|
|
25
31
|
const artists = track.artists?.map(a => a.name).join(', ') || 'Unknown';
|
|
26
|
-
const title = truncate(track.title, getTruncateLength(
|
|
27
|
-
return (_jsxs(Box, {
|
|
32
|
+
const title = truncate(track.title, getTruncateLength(40));
|
|
33
|
+
return (_jsxs(Box, { children: [_jsxs(Text, { color: theme.colors.dim, children: [index + 1, ". "] }), _jsx(Text, { color: isSelected ? theme.colors.primary : theme.colors.text, children: title }), _jsxs(Text, { color: theme.colors.dim, children: [" \u2022 ", artists] })] }, track.videoId));
|
|
28
34
|
})] }));
|
|
29
35
|
}
|
|
30
36
|
export default React.memo(QueueList);
|
|
@@ -111,7 +111,8 @@ class PluginInstallerService {
|
|
|
111
111
|
windowsHide: true,
|
|
112
112
|
});
|
|
113
113
|
}
|
|
114
|
-
|
|
114
|
+
// Plugin is at root of repo (e.g., adblock/, lyrics/, etc.)
|
|
115
|
+
const pluginSourceDir = join(tempDir, pluginName);
|
|
115
116
|
if (!existsSync(pluginSourceDir)) {
|
|
116
117
|
rmSync(tempDir, { recursive: true, force: true });
|
|
117
118
|
return {
|
|
@@ -141,12 +141,19 @@ function playerReducer(state, action) {
|
|
|
141
141
|
}
|
|
142
142
|
return state;
|
|
143
143
|
case 'UPDATE_PROGRESS':
|
|
144
|
-
|
|
144
|
+
// Clamp progress to valid range
|
|
145
|
+
const clampedProgress = Math.max(0, Math.min(action.progress, state.duration || action.progress));
|
|
146
|
+
return { ...state, progress: clampedProgress };
|
|
145
147
|
case 'SET_DURATION':
|
|
146
148
|
return { ...state, duration: action.duration };
|
|
147
149
|
case 'TICK':
|
|
148
|
-
if (state.isPlaying) {
|
|
149
|
-
|
|
150
|
+
if (state.isPlaying && state.duration > 0) {
|
|
151
|
+
const newProgress = state.progress + 1;
|
|
152
|
+
// Don't exceed duration
|
|
153
|
+
if (newProgress >= state.duration) {
|
|
154
|
+
return { ...state, progress: state.duration, isPlaying: false };
|
|
155
|
+
}
|
|
156
|
+
return { ...state, progress: newProgress };
|
|
150
157
|
}
|
|
151
158
|
return state;
|
|
152
159
|
case 'SET_LOADING':
|
|
Binary file
|
package/package.json
CHANGED
/package/{README.md → readme.md}
RENAMED
|
File without changes
|