@involvex/youtube-music-cli 0.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.
- package/README.md +352 -0
- package/dist/eslint.config.d.ts +2 -0
- package/dist/eslint.config.js +55 -0
- package/dist/source/app.d.ts +4 -0
- package/dist/source/app.js +17 -0
- package/dist/source/cli.d.ts +2 -0
- package/dist/source/cli.js +241 -0
- package/dist/source/components/common/ErrorBoundary.d.ts +15 -0
- package/dist/source/components/common/ErrorBoundary.js +22 -0
- package/dist/source/components/common/Help.d.ts +1 -0
- package/dist/source/components/common/Help.js +10 -0
- package/dist/source/components/common/ShortcutsBar.d.ts +1 -0
- package/dist/source/components/common/ShortcutsBar.js +33 -0
- package/dist/source/components/config/ConfigLayout.d.ts +1 -0
- package/dist/source/components/config/ConfigLayout.js +84 -0
- package/dist/source/components/layouts/MainLayout.d.ts +4 -0
- package/dist/source/components/layouts/MainLayout.js +83 -0
- package/dist/source/components/layouts/PlayerLayout.d.ts +1 -0
- package/dist/source/components/layouts/PlayerLayout.js +10 -0
- package/dist/source/components/layouts/PluginsLayout.d.ts +1 -0
- package/dist/source/components/layouts/PluginsLayout.js +77 -0
- package/dist/source/components/layouts/SearchLayout.d.ts +4 -0
- package/dist/source/components/layouts/SearchLayout.js +81 -0
- package/dist/source/components/player/NowPlaying.d.ts +1 -0
- package/dist/source/components/player/NowPlaying.js +21 -0
- package/dist/source/components/player/PlayerControls.d.ts +1 -0
- package/dist/source/components/player/PlayerControls.js +41 -0
- package/dist/source/components/player/ProgressBar.d.ts +1 -0
- package/dist/source/components/player/ProgressBar.js +18 -0
- package/dist/source/components/player/QueueList.d.ts +4 -0
- package/dist/source/components/player/QueueList.js +30 -0
- package/dist/source/components/player/Suggestions.d.ts +1 -0
- package/dist/source/components/player/Suggestions.js +47 -0
- package/dist/source/components/playlist/PlaylistList.d.ts +1 -0
- package/dist/source/components/playlist/PlaylistList.js +11 -0
- package/dist/source/components/plugins/PluginInstallDialog.d.ts +5 -0
- package/dist/source/components/plugins/PluginInstallDialog.js +41 -0
- package/dist/source/components/plugins/PluginsAvailable.d.ts +5 -0
- package/dist/source/components/plugins/PluginsAvailable.js +55 -0
- package/dist/source/components/plugins/PluginsList.d.ts +8 -0
- package/dist/source/components/plugins/PluginsList.js +18 -0
- package/dist/source/components/search/SearchBar.d.ts +8 -0
- package/dist/source/components/search/SearchBar.js +50 -0
- package/dist/source/components/search/SearchResults.d.ts +10 -0
- package/dist/source/components/search/SearchResults.js +111 -0
- package/dist/source/components/settings/Settings.d.ts +1 -0
- package/dist/source/components/settings/Settings.js +42 -0
- package/dist/source/components/theme/ThemeSwitcher.d.ts +1 -0
- package/dist/source/components/theme/ThemeSwitcher.js +11 -0
- package/dist/source/config/themes.config.d.ts +3 -0
- package/dist/source/config/themes.config.js +63 -0
- package/dist/source/contexts/theme.context.d.ts +13 -0
- package/dist/source/contexts/theme.context.js +29 -0
- package/dist/source/hooks/useKeyboard.d.ts +10 -0
- package/dist/source/hooks/useKeyboard.js +104 -0
- package/dist/source/hooks/useNavigation.d.ts +1 -0
- package/dist/source/hooks/useNavigation.js +5 -0
- package/dist/source/hooks/usePlayer.d.ts +23 -0
- package/dist/source/hooks/usePlayer.js +35 -0
- package/dist/source/hooks/usePlaylist.d.ts +8 -0
- package/dist/source/hooks/usePlaylist.js +50 -0
- package/dist/source/hooks/useSearch.d.ts +8 -0
- package/dist/source/hooks/useSearch.js +76 -0
- package/dist/source/hooks/useTerminalSize.d.ts +4 -0
- package/dist/source/hooks/useTerminalSize.js +24 -0
- package/dist/source/hooks/useTheme.d.ts +6 -0
- package/dist/source/hooks/useTheme.js +5 -0
- package/dist/source/hooks/useYouTubeMusic.d.ts +11 -0
- package/dist/source/hooks/useYouTubeMusic.js +112 -0
- package/dist/source/main.d.ts +4 -0
- package/dist/source/main.js +69 -0
- package/dist/source/services/config/config.service.d.ts +26 -0
- package/dist/source/services/config/config.service.js +125 -0
- package/dist/source/services/logger/logger.service.d.ts +10 -0
- package/dist/source/services/logger/logger.service.js +52 -0
- package/dist/source/services/player/player.service.d.ts +58 -0
- package/dist/source/services/player/player.service.js +349 -0
- package/dist/source/services/player-state/player-state.service.d.ts +24 -0
- package/dist/source/services/player-state/player-state.service.js +122 -0
- package/dist/source/services/plugin/plugin-audio-api.d.ts +17 -0
- package/dist/source/services/plugin/plugin-audio-api.js +36 -0
- package/dist/source/services/plugin/plugin-context.d.ts +5 -0
- package/dist/source/services/plugin/plugin-context.js +256 -0
- package/dist/source/services/plugin/plugin-hooks.service.d.ts +62 -0
- package/dist/source/services/plugin/plugin-hooks.service.js +135 -0
- package/dist/source/services/plugin/plugin-installer.service.d.ts +27 -0
- package/dist/source/services/plugin/plugin-installer.service.js +247 -0
- package/dist/source/services/plugin/plugin-loader.service.d.ts +33 -0
- package/dist/source/services/plugin/plugin-loader.service.js +161 -0
- package/dist/source/services/plugin/plugin-permissions.service.d.ts +72 -0
- package/dist/source/services/plugin/plugin-permissions.service.js +194 -0
- package/dist/source/services/plugin/plugin-registry.service.d.ts +76 -0
- package/dist/source/services/plugin/plugin-registry.service.js +215 -0
- package/dist/source/services/plugin/plugin-ui-api.d.ts +25 -0
- package/dist/source/services/plugin/plugin-ui-api.js +46 -0
- package/dist/source/services/plugin/plugin-updater.service.d.ts +23 -0
- package/dist/source/services/plugin/plugin-updater.service.js +206 -0
- package/dist/source/services/youtube-music/api.d.ts +13 -0
- package/dist/source/services/youtube-music/api.js +371 -0
- package/dist/source/services/youtube-music/search.service.d.ts +11 -0
- package/dist/source/services/youtube-music/search.service.js +38 -0
- package/dist/source/stores/navigation.store.d.ts +10 -0
- package/dist/source/stores/navigation.store.js +67 -0
- package/dist/source/stores/player.store.d.ts +28 -0
- package/dist/source/stores/player.store.js +458 -0
- package/dist/source/stores/plugins.store.d.ts +46 -0
- package/dist/source/stores/plugins.store.js +177 -0
- package/dist/source/types/actions.d.ts +119 -0
- package/dist/source/types/actions.js +1 -0
- package/dist/source/types/cli.types.d.ts +14 -0
- package/dist/source/types/cli.types.js +1 -0
- package/dist/source/types/config.types.d.ts +19 -0
- package/dist/source/types/config.types.js +1 -0
- package/dist/source/types/keyboard.types.d.ts +5 -0
- package/dist/source/types/keyboard.types.js +1 -0
- package/dist/source/types/navigation.types.d.ts +14 -0
- package/dist/source/types/navigation.types.js +1 -0
- package/dist/source/types/player.types.d.ts +16 -0
- package/dist/source/types/player.types.js +1 -0
- package/dist/source/types/playlist.types.d.ts +12 -0
- package/dist/source/types/playlist.types.js +1 -0
- package/dist/source/types/plugin.types.d.ts +239 -0
- package/dist/source/types/plugin.types.js +1 -0
- package/dist/source/types/theme.types.d.ts +18 -0
- package/dist/source/types/theme.types.js +1 -0
- package/dist/source/types/youtube-music.types.d.ts +35 -0
- package/dist/source/types/youtube-music.types.js +1 -0
- package/dist/source/types/youtubei.types.d.ts +60 -0
- package/dist/source/types/youtubei.types.js +3 -0
- package/dist/source/utils/constants.d.ts +65 -0
- package/dist/source/utils/constants.js +82 -0
- package/dist/source/utils/format.d.ts +3 -0
- package/dist/source/utils/format.js +24 -0
- package/dist/test.d.ts +1 -0
- package/dist/test.js +13 -0
- package/package.json +100 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// Plugin store - manages plugin state in the TUI
|
|
3
|
+
import { createContext, useContext, useReducer, useMemo, useEffect, } from 'react';
|
|
4
|
+
import { getPluginRegistryService } from "../services/plugin/plugin-registry.service.js";
|
|
5
|
+
import { getPluginInstallerService } from "../services/plugin/plugin-installer.service.js";
|
|
6
|
+
import { getPluginUpdaterService } from "../services/plugin/plugin-updater.service.js";
|
|
7
|
+
const initialState = {
|
|
8
|
+
installedPlugins: [],
|
|
9
|
+
availablePlugins: [],
|
|
10
|
+
selectedIndex: 0,
|
|
11
|
+
isLoading: false,
|
|
12
|
+
error: null,
|
|
13
|
+
lastAction: null,
|
|
14
|
+
};
|
|
15
|
+
function pluginsReducer(state, action) {
|
|
16
|
+
switch (action.type) {
|
|
17
|
+
case 'SET_INSTALLED':
|
|
18
|
+
return { ...state, installedPlugins: action.plugins };
|
|
19
|
+
case 'SET_AVAILABLE':
|
|
20
|
+
return { ...state, availablePlugins: action.plugins };
|
|
21
|
+
case 'SET_SELECTED':
|
|
22
|
+
return { ...state, selectedIndex: action.index };
|
|
23
|
+
case 'SET_LOADING':
|
|
24
|
+
return { ...state, isLoading: action.loading };
|
|
25
|
+
case 'SET_ERROR':
|
|
26
|
+
return { ...state, error: action.error };
|
|
27
|
+
case 'SET_LAST_ACTION':
|
|
28
|
+
return { ...state, lastAction: action.action };
|
|
29
|
+
case 'REFRESH':
|
|
30
|
+
return { ...state };
|
|
31
|
+
default:
|
|
32
|
+
return state;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const PluginsContext = createContext(null);
|
|
36
|
+
export function PluginsProvider({ children }) {
|
|
37
|
+
const [state, dispatch] = useReducer(pluginsReducer, initialState);
|
|
38
|
+
const registryService = getPluginRegistryService();
|
|
39
|
+
const installerService = getPluginInstallerService();
|
|
40
|
+
const updaterService = getPluginUpdaterService();
|
|
41
|
+
const refreshPlugins = () => {
|
|
42
|
+
const plugins = registryService.getAllPlugins();
|
|
43
|
+
dispatch({ type: 'SET_INSTALLED', plugins });
|
|
44
|
+
};
|
|
45
|
+
const installPlugin = async (nameOrUrl) => {
|
|
46
|
+
dispatch({ type: 'SET_LOADING', loading: true });
|
|
47
|
+
dispatch({ type: 'SET_ERROR', error: null });
|
|
48
|
+
try {
|
|
49
|
+
let result;
|
|
50
|
+
if (nameOrUrl.startsWith('http')) {
|
|
51
|
+
result = await installerService.installFromGitHub(nameOrUrl);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
result = await installerService.installFromDefaultRepo(nameOrUrl);
|
|
55
|
+
}
|
|
56
|
+
if (result.success) {
|
|
57
|
+
dispatch({
|
|
58
|
+
type: 'SET_LAST_ACTION',
|
|
59
|
+
action: `Installed ${result.pluginId}`,
|
|
60
|
+
});
|
|
61
|
+
// Reload plugins
|
|
62
|
+
await registryService.loadAllPlugins();
|
|
63
|
+
refreshPlugins();
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
dispatch({ type: 'SET_ERROR', error: result.error || 'Install failed' });
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
dispatch({ type: 'SET_LOADING', loading: false });
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const uninstallPlugin = async (pluginId) => {
|
|
75
|
+
dispatch({ type: 'SET_LOADING', loading: true });
|
|
76
|
+
try {
|
|
77
|
+
// Unload from registry first
|
|
78
|
+
await registryService.unloadPlugin(pluginId);
|
|
79
|
+
// Then uninstall from disk
|
|
80
|
+
const result = await installerService.uninstall(pluginId);
|
|
81
|
+
if (result.success) {
|
|
82
|
+
dispatch({
|
|
83
|
+
type: 'SET_LAST_ACTION',
|
|
84
|
+
action: `Uninstalled ${pluginId}`,
|
|
85
|
+
});
|
|
86
|
+
refreshPlugins();
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
dispatch({
|
|
90
|
+
type: 'SET_ERROR',
|
|
91
|
+
error: result.error || 'Uninstall failed',
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
finally {
|
|
97
|
+
dispatch({ type: 'SET_LOADING', loading: false });
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
const enablePlugin = async (pluginId) => {
|
|
101
|
+
try {
|
|
102
|
+
await registryService.enablePlugin(pluginId);
|
|
103
|
+
dispatch({ type: 'SET_LAST_ACTION', action: `Enabled ${pluginId}` });
|
|
104
|
+
refreshPlugins();
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
dispatch({
|
|
108
|
+
type: 'SET_ERROR',
|
|
109
|
+
error: error instanceof Error ? error.message : 'Enable failed',
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const disablePlugin = async (pluginId) => {
|
|
114
|
+
try {
|
|
115
|
+
await registryService.disablePlugin(pluginId);
|
|
116
|
+
dispatch({ type: 'SET_LAST_ACTION', action: `Disabled ${pluginId}` });
|
|
117
|
+
refreshPlugins();
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
dispatch({
|
|
121
|
+
type: 'SET_ERROR',
|
|
122
|
+
error: error instanceof Error ? error.message : 'Disable failed',
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const updatePlugin = async (pluginId) => {
|
|
127
|
+
dispatch({ type: 'SET_LOADING', loading: true });
|
|
128
|
+
try {
|
|
129
|
+
const result = await updaterService.updatePlugin(pluginId);
|
|
130
|
+
if (result.success) {
|
|
131
|
+
dispatch({
|
|
132
|
+
type: 'SET_LAST_ACTION',
|
|
133
|
+
action: `Updated ${pluginId} to ${result.newVersion}`,
|
|
134
|
+
});
|
|
135
|
+
// Reload the plugin
|
|
136
|
+
await registryService.loadAllPlugins();
|
|
137
|
+
refreshPlugins();
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
dispatch({ type: 'SET_ERROR', error: result.error || 'Update failed' });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
finally {
|
|
144
|
+
dispatch({ type: 'SET_LOADING', loading: false });
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
// Load plugins on mount
|
|
148
|
+
useEffect(() => {
|
|
149
|
+
const loadPlugins = async () => {
|
|
150
|
+
await registryService.loadAllPlugins();
|
|
151
|
+
const plugins = registryService.getAllPlugins();
|
|
152
|
+
dispatch({ type: 'SET_INSTALLED', plugins });
|
|
153
|
+
};
|
|
154
|
+
void loadPlugins();
|
|
155
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
156
|
+
}, []);
|
|
157
|
+
const contextValue = useMemo(() => ({
|
|
158
|
+
state,
|
|
159
|
+
dispatch,
|
|
160
|
+
refreshPlugins,
|
|
161
|
+
installPlugin,
|
|
162
|
+
uninstallPlugin,
|
|
163
|
+
enablePlugin,
|
|
164
|
+
disablePlugin,
|
|
165
|
+
updatePlugin,
|
|
166
|
+
}),
|
|
167
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
168
|
+
[state]);
|
|
169
|
+
return (_jsx(PluginsContext.Provider, { value: contextValue, children: children }));
|
|
170
|
+
}
|
|
171
|
+
export function usePlugins() {
|
|
172
|
+
const context = useContext(PluginsContext);
|
|
173
|
+
if (!context) {
|
|
174
|
+
throw new Error('usePlugins must be used within PluginsProvider');
|
|
175
|
+
}
|
|
176
|
+
return context;
|
|
177
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import type { Track } from './youtube-music.types.ts';
|
|
2
|
+
export interface PlayAction {
|
|
3
|
+
readonly category: 'PLAY';
|
|
4
|
+
track: Track;
|
|
5
|
+
}
|
|
6
|
+
export interface PauseAction {
|
|
7
|
+
readonly category: 'PAUSE';
|
|
8
|
+
}
|
|
9
|
+
export interface ResumeAction {
|
|
10
|
+
readonly category: 'RESUME';
|
|
11
|
+
}
|
|
12
|
+
export interface StopAction {
|
|
13
|
+
readonly category: 'STOP';
|
|
14
|
+
}
|
|
15
|
+
export interface NextAction {
|
|
16
|
+
readonly category: 'NEXT';
|
|
17
|
+
}
|
|
18
|
+
export interface PreviousAction {
|
|
19
|
+
readonly category: 'PREVIOUS';
|
|
20
|
+
}
|
|
21
|
+
export interface SeekAction {
|
|
22
|
+
readonly category: 'SEEK';
|
|
23
|
+
position: number;
|
|
24
|
+
}
|
|
25
|
+
export interface SetVolumeAction {
|
|
26
|
+
readonly category: 'SET_VOLUME';
|
|
27
|
+
volume: number;
|
|
28
|
+
}
|
|
29
|
+
export interface VolumeUpAction {
|
|
30
|
+
readonly category: 'VOLUME_UP';
|
|
31
|
+
}
|
|
32
|
+
export interface VolumeDownAction {
|
|
33
|
+
readonly category: 'VOLUME_DOWN';
|
|
34
|
+
}
|
|
35
|
+
export interface ToggleShuffleAction {
|
|
36
|
+
readonly category: 'TOGGLE_SHUFFLE';
|
|
37
|
+
}
|
|
38
|
+
export interface ToggleRepeatAction {
|
|
39
|
+
readonly category: 'TOGGLE_REPEAT';
|
|
40
|
+
}
|
|
41
|
+
export interface SetQueueAction {
|
|
42
|
+
readonly category: 'SET_QUEUE';
|
|
43
|
+
queue: Track[];
|
|
44
|
+
}
|
|
45
|
+
export interface AddToQueueAction {
|
|
46
|
+
readonly category: 'ADD_TO_QUEUE';
|
|
47
|
+
track: Track;
|
|
48
|
+
}
|
|
49
|
+
export interface RemoveFromQueueAction {
|
|
50
|
+
readonly category: 'REMOVE_FROM_QUEUE';
|
|
51
|
+
index: number;
|
|
52
|
+
}
|
|
53
|
+
export interface ClearQueueAction {
|
|
54
|
+
readonly category: 'CLEAR_QUEUE';
|
|
55
|
+
}
|
|
56
|
+
export interface SetQueuePositionAction {
|
|
57
|
+
readonly category: 'SET_QUEUE_POSITION';
|
|
58
|
+
position: number;
|
|
59
|
+
}
|
|
60
|
+
export interface UpdateProgressAction {
|
|
61
|
+
readonly category: 'UPDATE_PROGRESS';
|
|
62
|
+
progress: number;
|
|
63
|
+
}
|
|
64
|
+
export interface SetDurationAction {
|
|
65
|
+
readonly category: 'SET_DURATION';
|
|
66
|
+
duration: number;
|
|
67
|
+
}
|
|
68
|
+
export interface TickAction {
|
|
69
|
+
readonly category: 'TICK';
|
|
70
|
+
}
|
|
71
|
+
export interface SetLoadingAction {
|
|
72
|
+
readonly category: 'SET_LOADING';
|
|
73
|
+
loading: boolean;
|
|
74
|
+
}
|
|
75
|
+
export interface SetErrorAction {
|
|
76
|
+
readonly category: 'SET_ERROR';
|
|
77
|
+
error: string | null;
|
|
78
|
+
}
|
|
79
|
+
export interface RestoreStateAction {
|
|
80
|
+
readonly category: 'RESTORE_STATE';
|
|
81
|
+
currentTrack: Track | null;
|
|
82
|
+
queue: Track[];
|
|
83
|
+
queuePosition: number;
|
|
84
|
+
progress: number;
|
|
85
|
+
volume: number;
|
|
86
|
+
shuffle: boolean;
|
|
87
|
+
repeat: 'off' | 'all' | 'one';
|
|
88
|
+
}
|
|
89
|
+
export interface NavigateAction {
|
|
90
|
+
readonly category: 'NAVIGATE';
|
|
91
|
+
view: string;
|
|
92
|
+
}
|
|
93
|
+
export interface GoBackAction {
|
|
94
|
+
readonly category: 'GO_BACK';
|
|
95
|
+
}
|
|
96
|
+
export interface SetSearchQueryAction {
|
|
97
|
+
readonly category: 'SET_SEARCH_QUERY';
|
|
98
|
+
query: string;
|
|
99
|
+
}
|
|
100
|
+
export interface SetSearchCategoryAction {
|
|
101
|
+
readonly category: 'SET_SEARCH_CATEGORY';
|
|
102
|
+
searchType: string;
|
|
103
|
+
}
|
|
104
|
+
export interface SetSelectedResultAction {
|
|
105
|
+
readonly category: 'SET_SELECTED_RESULT';
|
|
106
|
+
index: number;
|
|
107
|
+
}
|
|
108
|
+
export interface SetSelectedPlaylistAction {
|
|
109
|
+
readonly category: 'SET_SELECTED_PLAYLIST';
|
|
110
|
+
index: number;
|
|
111
|
+
}
|
|
112
|
+
export interface SetHasSearchedAction {
|
|
113
|
+
readonly category: 'SET_HAS_SEARCHED';
|
|
114
|
+
hasSearched: boolean;
|
|
115
|
+
}
|
|
116
|
+
export interface SetSearchLimitAction {
|
|
117
|
+
readonly category: 'SET_SEARCH_LIMIT';
|
|
118
|
+
limit: number;
|
|
119
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface Flags {
|
|
2
|
+
help?: boolean;
|
|
3
|
+
version?: boolean;
|
|
4
|
+
theme?: string;
|
|
5
|
+
volume?: number;
|
|
6
|
+
shuffle?: boolean;
|
|
7
|
+
repeat?: string;
|
|
8
|
+
playTrack?: string;
|
|
9
|
+
searchQuery?: string;
|
|
10
|
+
playPlaylist?: string;
|
|
11
|
+
showSuggestions?: boolean;
|
|
12
|
+
headless?: boolean;
|
|
13
|
+
action?: 'pause' | 'resume' | 'next' | 'previous';
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Playlist } from './youtube-music.types.ts';
|
|
2
|
+
import type { Theme } from './theme.types.ts';
|
|
3
|
+
export type RepeatMode = 'off' | 'all' | 'one';
|
|
4
|
+
export interface KeybindingConfig {
|
|
5
|
+
keys: string[];
|
|
6
|
+
description: string;
|
|
7
|
+
}
|
|
8
|
+
export interface Config {
|
|
9
|
+
theme: 'dark' | 'light' | 'midnight' | 'matrix' | 'custom';
|
|
10
|
+
volume: number;
|
|
11
|
+
keybindings: Record<string, KeybindingConfig>;
|
|
12
|
+
playlists: Playlist[];
|
|
13
|
+
history: string[];
|
|
14
|
+
favorites: string[];
|
|
15
|
+
repeat: RepeatMode;
|
|
16
|
+
shuffle: boolean;
|
|
17
|
+
customTheme?: Theme;
|
|
18
|
+
streamQuality?: 'low' | 'medium' | 'high';
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { NavigateAction, GoBackAction, SetSearchQueryAction, SetSearchCategoryAction, SetSelectedResultAction, SetSelectedPlaylistAction, SetHasSearchedAction, SetSearchLimitAction } from './actions.ts';
|
|
2
|
+
export interface NavigationState {
|
|
3
|
+
currentView: string;
|
|
4
|
+
previousView: string | null;
|
|
5
|
+
searchQuery: string;
|
|
6
|
+
searchCategory: string;
|
|
7
|
+
searchType: 'all' | 'songs' | 'albums' | 'artists' | 'playlists';
|
|
8
|
+
selectedResult: number;
|
|
9
|
+
selectedPlaylist: number;
|
|
10
|
+
hasSearched: boolean;
|
|
11
|
+
searchLimit: number;
|
|
12
|
+
history: string[];
|
|
13
|
+
}
|
|
14
|
+
export type NavigationAction = NavigateAction | GoBackAction | SetSearchQueryAction | SetSearchCategoryAction | SetSelectedResultAction | SetSelectedPlaylistAction | SetHasSearchedAction | SetSearchLimitAction;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { PlayAction, PauseAction, ResumeAction, StopAction, NextAction, PreviousAction, SeekAction, SetVolumeAction, VolumeUpAction, VolumeDownAction, ToggleShuffleAction, ToggleRepeatAction, SetQueueAction, AddToQueueAction, RemoveFromQueueAction, ClearQueueAction, SetQueuePositionAction, UpdateProgressAction, SetDurationAction, TickAction, SetLoadingAction, SetErrorAction, RestoreStateAction } from './actions.ts';
|
|
2
|
+
import type { Track } from './youtube-music.types.ts';
|
|
3
|
+
export interface PlayerState {
|
|
4
|
+
currentTrack: Track | null;
|
|
5
|
+
isPlaying: boolean;
|
|
6
|
+
volume: number;
|
|
7
|
+
progress: number;
|
|
8
|
+
duration: number;
|
|
9
|
+
queue: Track[];
|
|
10
|
+
queuePosition: number;
|
|
11
|
+
repeat: 'off' | 'all' | 'one';
|
|
12
|
+
shuffle: boolean;
|
|
13
|
+
isLoading: boolean;
|
|
14
|
+
error: string | null;
|
|
15
|
+
}
|
|
16
|
+
export type PlayerAction = PlayAction | PauseAction | ResumeAction | StopAction | NextAction | PreviousAction | SeekAction | SetVolumeAction | VolumeUpAction | VolumeDownAction | ToggleShuffleAction | ToggleRepeatAction | SetQueueAction | AddToQueueAction | RemoveFromQueueAction | ClearQueueAction | SetQueuePositionAction | UpdateProgressAction | SetDurationAction | TickAction | SetLoadingAction | SetErrorAction | RestoreStateAction;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Track } from './youtube-music.types.ts';
|
|
2
|
+
export interface Playlist {
|
|
3
|
+
playlistId: string;
|
|
4
|
+
name: string;
|
|
5
|
+
tracks: Track[];
|
|
6
|
+
}
|
|
7
|
+
export interface PlaylistEntry {
|
|
8
|
+
playlistId: string;
|
|
9
|
+
}
|
|
10
|
+
export interface PlaylistWithEntries extends Playlist {
|
|
11
|
+
entries: PlaylistEntry[];
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import type { Track } from './youtube-music.types.ts';
|
|
2
|
+
import type { ReactElement } from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* Plugin permission types
|
|
5
|
+
*/
|
|
6
|
+
export type PluginPermission = 'filesystem' | 'network' | 'player' | 'ui' | 'config';
|
|
7
|
+
/**
|
|
8
|
+
* Permission request status
|
|
9
|
+
*/
|
|
10
|
+
export type PermissionStatus = 'granted' | 'denied' | 'prompt';
|
|
11
|
+
/**
|
|
12
|
+
* Plugin permissions mapping
|
|
13
|
+
*/
|
|
14
|
+
export interface PluginPermissions {
|
|
15
|
+
[permission: string]: PermissionStatus;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Player event types
|
|
19
|
+
*/
|
|
20
|
+
export interface PlayerEvent {
|
|
21
|
+
type: 'play' | 'pause' | 'stop' | 'resume' | 'next' | 'previous' | 'seek' | 'volume-change' | 'track-change' | 'queue-change' | 'shuffle-change' | 'repeat-change';
|
|
22
|
+
track?: Track;
|
|
23
|
+
position?: number;
|
|
24
|
+
volume?: number;
|
|
25
|
+
queue?: Track[];
|
|
26
|
+
shuffle?: boolean;
|
|
27
|
+
repeat?: 'off' | 'all' | 'one';
|
|
28
|
+
timestamp: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Navigation event types
|
|
32
|
+
*/
|
|
33
|
+
export interface NavigationEvent {
|
|
34
|
+
type: 'view-change' | 'search' | 'select-result';
|
|
35
|
+
view?: string;
|
|
36
|
+
previousView?: string;
|
|
37
|
+
query?: string;
|
|
38
|
+
timestamp: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Audio stream event types
|
|
42
|
+
*/
|
|
43
|
+
export interface AudioStreamEvent {
|
|
44
|
+
type: 'stream-request' | 'stream-start' | 'stream-end' | 'stream-error';
|
|
45
|
+
url?: string;
|
|
46
|
+
track?: Track;
|
|
47
|
+
error?: Error;
|
|
48
|
+
timestamp: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Plugin event types (union of all event types)
|
|
52
|
+
*/
|
|
53
|
+
export type PluginEvent = PlayerEvent | NavigationEvent | AudioStreamEvent;
|
|
54
|
+
/**
|
|
55
|
+
* Event handler callback
|
|
56
|
+
*/
|
|
57
|
+
export type EventHandler<T extends PluginEvent = PluginEvent> = (event: T) => void | Promise<void>;
|
|
58
|
+
/**
|
|
59
|
+
* Plugin manifest - metadata and declarations
|
|
60
|
+
*/
|
|
61
|
+
export interface PluginManifest {
|
|
62
|
+
id: string;
|
|
63
|
+
name: string;
|
|
64
|
+
version: string;
|
|
65
|
+
description: string;
|
|
66
|
+
author: string;
|
|
67
|
+
license?: string;
|
|
68
|
+
homepage?: string;
|
|
69
|
+
repository?: string;
|
|
70
|
+
main: string;
|
|
71
|
+
permissions: PluginPermission[];
|
|
72
|
+
hooks?: Array<PlayerEvent['type'] | NavigationEvent['type']>;
|
|
73
|
+
ui?: {
|
|
74
|
+
views?: string[];
|
|
75
|
+
shortcuts?: string[];
|
|
76
|
+
};
|
|
77
|
+
dependencies?: Record<string, string>;
|
|
78
|
+
configSchema?: Record<string, unknown>;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Plugin configuration
|
|
82
|
+
*/
|
|
83
|
+
export interface PluginConfig {
|
|
84
|
+
enabled: boolean;
|
|
85
|
+
config: Record<string, unknown>;
|
|
86
|
+
permissions: PluginPermissions;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Player API provided to plugins
|
|
90
|
+
*/
|
|
91
|
+
export interface PluginPlayerAPI {
|
|
92
|
+
play: (track: Track) => Promise<void>;
|
|
93
|
+
pause: () => void;
|
|
94
|
+
resume: () => void;
|
|
95
|
+
stop: () => void;
|
|
96
|
+
next: () => void;
|
|
97
|
+
previous: () => void;
|
|
98
|
+
seek: (position: number) => void;
|
|
99
|
+
setVolume: (volume: number) => void;
|
|
100
|
+
getVolume: () => number;
|
|
101
|
+
getCurrentTrack: () => Track | null;
|
|
102
|
+
getQueue: () => Track[];
|
|
103
|
+
addToQueue: (track: Track) => void;
|
|
104
|
+
removeFromQueue: (index: number) => void;
|
|
105
|
+
clearQueue: () => void;
|
|
106
|
+
shuffle: (enabled: boolean) => void;
|
|
107
|
+
setRepeat: (mode: 'off' | 'all' | 'one') => void;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Navigation API provided to plugins
|
|
111
|
+
*/
|
|
112
|
+
export interface PluginNavigationAPI {
|
|
113
|
+
navigate: (view: string) => void;
|
|
114
|
+
goBack: () => void;
|
|
115
|
+
getCurrentView: () => string;
|
|
116
|
+
registerView: (viewId: string, component: ReactElement) => void;
|
|
117
|
+
unregisterView: (viewId: string) => void;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Config API provided to plugins
|
|
121
|
+
*/
|
|
122
|
+
export interface PluginConfigAPI {
|
|
123
|
+
get: <T = unknown>(key: string, defaultValue?: T) => T;
|
|
124
|
+
set: (key: string, value: unknown) => void;
|
|
125
|
+
delete: (key: string) => void;
|
|
126
|
+
getAll: () => Record<string, unknown>;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Logger API provided to plugins
|
|
130
|
+
*/
|
|
131
|
+
export interface PluginLoggerAPI {
|
|
132
|
+
debug: (message: string, ...args: unknown[]) => void;
|
|
133
|
+
info: (message: string, ...args: unknown[]) => void;
|
|
134
|
+
warn: (message: string, ...args: unknown[]) => void;
|
|
135
|
+
error: (message: string, ...args: unknown[]) => void;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Filesystem API provided to plugins (scoped to plugin data directory)
|
|
139
|
+
*/
|
|
140
|
+
export interface PluginFilesystemAPI {
|
|
141
|
+
readFile: (path: string) => Promise<string>;
|
|
142
|
+
writeFile: (path: string, data: string) => Promise<void>;
|
|
143
|
+
deleteFile: (path: string) => Promise<void>;
|
|
144
|
+
exists: (path: string) => Promise<boolean>;
|
|
145
|
+
listFiles: (path?: string) => Promise<string[]>;
|
|
146
|
+
getDataDir: () => string;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Audio stream API provided to plugins
|
|
150
|
+
*/
|
|
151
|
+
export interface PluginAudioAPI {
|
|
152
|
+
transformStreamUrl: (url: string, track: Track) => Promise<string> | string | null;
|
|
153
|
+
onStreamRequest: (handler: (url: string, track: Track) => Promise<string> | string | null) => void;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Plugin context - API surface provided to plugins
|
|
157
|
+
*/
|
|
158
|
+
export interface PluginContext {
|
|
159
|
+
plugin: PluginManifest;
|
|
160
|
+
player: PluginPlayerAPI;
|
|
161
|
+
navigation: PluginNavigationAPI;
|
|
162
|
+
config: PluginConfigAPI;
|
|
163
|
+
logger: PluginLoggerAPI;
|
|
164
|
+
filesystem: PluginFilesystemAPI;
|
|
165
|
+
audio: PluginAudioAPI;
|
|
166
|
+
on: <T extends PluginEvent = PluginEvent>(eventType: T['type'], handler: EventHandler<T>) => void;
|
|
167
|
+
off: <T extends PluginEvent = PluginEvent>(eventType: T['type'], handler: EventHandler<T>) => void;
|
|
168
|
+
emit: <T extends PluginEvent = PluginEvent>(event: T) => void;
|
|
169
|
+
hasPermission: (permission: PluginPermission) => boolean;
|
|
170
|
+
requestPermission: (permission: PluginPermission) => Promise<boolean>;
|
|
171
|
+
registerShortcut: (keys: string[], handler: () => void) => void;
|
|
172
|
+
unregisterShortcut: (keys: string[]) => void;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Plugin lifecycle hooks
|
|
176
|
+
*/
|
|
177
|
+
export interface PluginHooks {
|
|
178
|
+
init?: (context: PluginContext) => Promise<void> | void;
|
|
179
|
+
enable?: (context: PluginContext) => Promise<void> | void;
|
|
180
|
+
disable?: (context: PluginContext) => Promise<void> | void;
|
|
181
|
+
destroy?: (context: PluginContext) => Promise<void> | void;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Plugin interface - what a plugin module must export
|
|
185
|
+
*/
|
|
186
|
+
export interface Plugin extends PluginHooks {
|
|
187
|
+
manifest: PluginManifest;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Plugin instance - runtime representation of a loaded plugin
|
|
191
|
+
*/
|
|
192
|
+
export interface PluginInstance {
|
|
193
|
+
manifest: PluginManifest;
|
|
194
|
+
plugin: Plugin;
|
|
195
|
+
context: PluginContext;
|
|
196
|
+
config: PluginConfig;
|
|
197
|
+
enabled: boolean;
|
|
198
|
+
loadedAt: number;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Plugin installation result
|
|
202
|
+
*/
|
|
203
|
+
export interface PluginInstallResult {
|
|
204
|
+
success: boolean;
|
|
205
|
+
pluginId?: string;
|
|
206
|
+
error?: string;
|
|
207
|
+
message?: string;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Plugin update result
|
|
211
|
+
*/
|
|
212
|
+
export interface PluginUpdateResult {
|
|
213
|
+
success: boolean;
|
|
214
|
+
pluginId?: string;
|
|
215
|
+
oldVersion?: string;
|
|
216
|
+
newVersion?: string;
|
|
217
|
+
error?: string;
|
|
218
|
+
message?: string;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Available plugin info from repository
|
|
222
|
+
*/
|
|
223
|
+
export interface AvailablePlugin {
|
|
224
|
+
id: string;
|
|
225
|
+
name: string;
|
|
226
|
+
version: string;
|
|
227
|
+
description: string;
|
|
228
|
+
author: string;
|
|
229
|
+
repository: string;
|
|
230
|
+
installUrl: string;
|
|
231
|
+
tags?: string[];
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Plugin repository manifest
|
|
235
|
+
*/
|
|
236
|
+
export interface PluginRepositoryManifest {
|
|
237
|
+
version: string;
|
|
238
|
+
plugins: AvailablePlugin[];
|
|
239
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type ColorName = 'black' | 'red' | 'green' | 'yellow' | 'blue' | 'magenta' | 'purple' | 'cyan' | 'white' | 'blackBright' | 'redBright' | 'greenBright' | 'yellowBright' | 'blueBright' | 'magentaBright' | 'cyanBright' | 'whiteBright' | 'gray';
|
|
2
|
+
export type ThemeColors = {
|
|
3
|
+
primary: ColorName;
|
|
4
|
+
secondary: ColorName;
|
|
5
|
+
background: ColorName;
|
|
6
|
+
text: ColorName;
|
|
7
|
+
accent: ColorName;
|
|
8
|
+
dim: ColorName;
|
|
9
|
+
error: ColorName;
|
|
10
|
+
success: ColorName;
|
|
11
|
+
warning: ColorName;
|
|
12
|
+
};
|
|
13
|
+
export type Theme = {
|
|
14
|
+
name: string;
|
|
15
|
+
colors: ThemeColors;
|
|
16
|
+
inverse?: boolean;
|
|
17
|
+
};
|
|
18
|
+
export type ThemeName = 'dark' | 'light' | 'midnight' | 'matrix' | 'custom';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|