@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.
Files changed (136) hide show
  1. package/README.md +352 -0
  2. package/dist/eslint.config.d.ts +2 -0
  3. package/dist/eslint.config.js +55 -0
  4. package/dist/source/app.d.ts +4 -0
  5. package/dist/source/app.js +17 -0
  6. package/dist/source/cli.d.ts +2 -0
  7. package/dist/source/cli.js +241 -0
  8. package/dist/source/components/common/ErrorBoundary.d.ts +15 -0
  9. package/dist/source/components/common/ErrorBoundary.js +22 -0
  10. package/dist/source/components/common/Help.d.ts +1 -0
  11. package/dist/source/components/common/Help.js +10 -0
  12. package/dist/source/components/common/ShortcutsBar.d.ts +1 -0
  13. package/dist/source/components/common/ShortcutsBar.js +33 -0
  14. package/dist/source/components/config/ConfigLayout.d.ts +1 -0
  15. package/dist/source/components/config/ConfigLayout.js +84 -0
  16. package/dist/source/components/layouts/MainLayout.d.ts +4 -0
  17. package/dist/source/components/layouts/MainLayout.js +83 -0
  18. package/dist/source/components/layouts/PlayerLayout.d.ts +1 -0
  19. package/dist/source/components/layouts/PlayerLayout.js +10 -0
  20. package/dist/source/components/layouts/PluginsLayout.d.ts +1 -0
  21. package/dist/source/components/layouts/PluginsLayout.js +77 -0
  22. package/dist/source/components/layouts/SearchLayout.d.ts +4 -0
  23. package/dist/source/components/layouts/SearchLayout.js +81 -0
  24. package/dist/source/components/player/NowPlaying.d.ts +1 -0
  25. package/dist/source/components/player/NowPlaying.js +21 -0
  26. package/dist/source/components/player/PlayerControls.d.ts +1 -0
  27. package/dist/source/components/player/PlayerControls.js +41 -0
  28. package/dist/source/components/player/ProgressBar.d.ts +1 -0
  29. package/dist/source/components/player/ProgressBar.js +18 -0
  30. package/dist/source/components/player/QueueList.d.ts +4 -0
  31. package/dist/source/components/player/QueueList.js +30 -0
  32. package/dist/source/components/player/Suggestions.d.ts +1 -0
  33. package/dist/source/components/player/Suggestions.js +47 -0
  34. package/dist/source/components/playlist/PlaylistList.d.ts +1 -0
  35. package/dist/source/components/playlist/PlaylistList.js +11 -0
  36. package/dist/source/components/plugins/PluginInstallDialog.d.ts +5 -0
  37. package/dist/source/components/plugins/PluginInstallDialog.js +41 -0
  38. package/dist/source/components/plugins/PluginsAvailable.d.ts +5 -0
  39. package/dist/source/components/plugins/PluginsAvailable.js +55 -0
  40. package/dist/source/components/plugins/PluginsList.d.ts +8 -0
  41. package/dist/source/components/plugins/PluginsList.js +18 -0
  42. package/dist/source/components/search/SearchBar.d.ts +8 -0
  43. package/dist/source/components/search/SearchBar.js +50 -0
  44. package/dist/source/components/search/SearchResults.d.ts +10 -0
  45. package/dist/source/components/search/SearchResults.js +111 -0
  46. package/dist/source/components/settings/Settings.d.ts +1 -0
  47. package/dist/source/components/settings/Settings.js +42 -0
  48. package/dist/source/components/theme/ThemeSwitcher.d.ts +1 -0
  49. package/dist/source/components/theme/ThemeSwitcher.js +11 -0
  50. package/dist/source/config/themes.config.d.ts +3 -0
  51. package/dist/source/config/themes.config.js +63 -0
  52. package/dist/source/contexts/theme.context.d.ts +13 -0
  53. package/dist/source/contexts/theme.context.js +29 -0
  54. package/dist/source/hooks/useKeyboard.d.ts +10 -0
  55. package/dist/source/hooks/useKeyboard.js +104 -0
  56. package/dist/source/hooks/useNavigation.d.ts +1 -0
  57. package/dist/source/hooks/useNavigation.js +5 -0
  58. package/dist/source/hooks/usePlayer.d.ts +23 -0
  59. package/dist/source/hooks/usePlayer.js +35 -0
  60. package/dist/source/hooks/usePlaylist.d.ts +8 -0
  61. package/dist/source/hooks/usePlaylist.js +50 -0
  62. package/dist/source/hooks/useSearch.d.ts +8 -0
  63. package/dist/source/hooks/useSearch.js +76 -0
  64. package/dist/source/hooks/useTerminalSize.d.ts +4 -0
  65. package/dist/source/hooks/useTerminalSize.js +24 -0
  66. package/dist/source/hooks/useTheme.d.ts +6 -0
  67. package/dist/source/hooks/useTheme.js +5 -0
  68. package/dist/source/hooks/useYouTubeMusic.d.ts +11 -0
  69. package/dist/source/hooks/useYouTubeMusic.js +112 -0
  70. package/dist/source/main.d.ts +4 -0
  71. package/dist/source/main.js +69 -0
  72. package/dist/source/services/config/config.service.d.ts +26 -0
  73. package/dist/source/services/config/config.service.js +125 -0
  74. package/dist/source/services/logger/logger.service.d.ts +10 -0
  75. package/dist/source/services/logger/logger.service.js +52 -0
  76. package/dist/source/services/player/player.service.d.ts +58 -0
  77. package/dist/source/services/player/player.service.js +349 -0
  78. package/dist/source/services/player-state/player-state.service.d.ts +24 -0
  79. package/dist/source/services/player-state/player-state.service.js +122 -0
  80. package/dist/source/services/plugin/plugin-audio-api.d.ts +17 -0
  81. package/dist/source/services/plugin/plugin-audio-api.js +36 -0
  82. package/dist/source/services/plugin/plugin-context.d.ts +5 -0
  83. package/dist/source/services/plugin/plugin-context.js +256 -0
  84. package/dist/source/services/plugin/plugin-hooks.service.d.ts +62 -0
  85. package/dist/source/services/plugin/plugin-hooks.service.js +135 -0
  86. package/dist/source/services/plugin/plugin-installer.service.d.ts +27 -0
  87. package/dist/source/services/plugin/plugin-installer.service.js +247 -0
  88. package/dist/source/services/plugin/plugin-loader.service.d.ts +33 -0
  89. package/dist/source/services/plugin/plugin-loader.service.js +161 -0
  90. package/dist/source/services/plugin/plugin-permissions.service.d.ts +72 -0
  91. package/dist/source/services/plugin/plugin-permissions.service.js +194 -0
  92. package/dist/source/services/plugin/plugin-registry.service.d.ts +76 -0
  93. package/dist/source/services/plugin/plugin-registry.service.js +215 -0
  94. package/dist/source/services/plugin/plugin-ui-api.d.ts +25 -0
  95. package/dist/source/services/plugin/plugin-ui-api.js +46 -0
  96. package/dist/source/services/plugin/plugin-updater.service.d.ts +23 -0
  97. package/dist/source/services/plugin/plugin-updater.service.js +206 -0
  98. package/dist/source/services/youtube-music/api.d.ts +13 -0
  99. package/dist/source/services/youtube-music/api.js +371 -0
  100. package/dist/source/services/youtube-music/search.service.d.ts +11 -0
  101. package/dist/source/services/youtube-music/search.service.js +38 -0
  102. package/dist/source/stores/navigation.store.d.ts +10 -0
  103. package/dist/source/stores/navigation.store.js +67 -0
  104. package/dist/source/stores/player.store.d.ts +28 -0
  105. package/dist/source/stores/player.store.js +458 -0
  106. package/dist/source/stores/plugins.store.d.ts +46 -0
  107. package/dist/source/stores/plugins.store.js +177 -0
  108. package/dist/source/types/actions.d.ts +119 -0
  109. package/dist/source/types/actions.js +1 -0
  110. package/dist/source/types/cli.types.d.ts +14 -0
  111. package/dist/source/types/cli.types.js +1 -0
  112. package/dist/source/types/config.types.d.ts +19 -0
  113. package/dist/source/types/config.types.js +1 -0
  114. package/dist/source/types/keyboard.types.d.ts +5 -0
  115. package/dist/source/types/keyboard.types.js +1 -0
  116. package/dist/source/types/navigation.types.d.ts +14 -0
  117. package/dist/source/types/navigation.types.js +1 -0
  118. package/dist/source/types/player.types.d.ts +16 -0
  119. package/dist/source/types/player.types.js +1 -0
  120. package/dist/source/types/playlist.types.d.ts +12 -0
  121. package/dist/source/types/playlist.types.js +1 -0
  122. package/dist/source/types/plugin.types.d.ts +239 -0
  123. package/dist/source/types/plugin.types.js +1 -0
  124. package/dist/source/types/theme.types.d.ts +18 -0
  125. package/dist/source/types/theme.types.js +1 -0
  126. package/dist/source/types/youtube-music.types.d.ts +35 -0
  127. package/dist/source/types/youtube-music.types.js +1 -0
  128. package/dist/source/types/youtubei.types.d.ts +60 -0
  129. package/dist/source/types/youtubei.types.js +3 -0
  130. package/dist/source/utils/constants.d.ts +65 -0
  131. package/dist/source/utils/constants.js +82 -0
  132. package/dist/source/utils/format.d.ts +3 -0
  133. package/dist/source/utils/format.js +24 -0
  134. package/dist/test.d.ts +1 -0
  135. package/dist/test.js +13 -0
  136. 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,5 @@
1
+ export interface KeyBinding {
2
+ keys: string[];
3
+ description: string;
4
+ }
5
+ export type KeyBindings = Record<string, KeyBinding>;
@@ -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 {};