@involvex/youtube-music-cli 0.0.46 → 0.0.48

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 (118) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/cli.js.map +1004 -0
  3. package/dist/source/hooks/usePlayer.d.ts +1 -0
  4. package/dist/source/services/player-state/player-state.service.d.ts +1 -0
  5. package/dist/source/stores/player.store.d.ts +1 -0
  6. package/dist/source/types/actions.d.ts +4 -0
  7. package/dist/source/types/player.types.d.ts +3 -2
  8. package/dist/source/utils/constants.d.ts +1 -0
  9. package/dist/source/utils/icons.d.ts +1 -0
  10. package/dist/youtube-music-cli +0 -0
  11. package/package.json +1 -1
  12. package/dist/eslint.config.js +0 -55
  13. package/dist/package.json +0 -120
  14. package/dist/scripts/build-cli.js +0 -46
  15. package/dist/source/app.js +0 -17
  16. package/dist/source/cli.js +0 -504
  17. package/dist/source/components/common/ErrorBoundary.js +0 -22
  18. package/dist/source/components/common/Help.js +0 -18
  19. package/dist/source/components/common/ShortcutsBar.js +0 -80
  20. package/dist/source/components/config/ConfigLayout.js +0 -84
  21. package/dist/source/components/config/KeybindingsLayout.js +0 -107
  22. package/dist/source/components/export/ExportLayout.js +0 -111
  23. package/dist/source/components/import/ImportLayout.js +0 -119
  24. package/dist/source/components/import/ImportProgress.js +0 -73
  25. package/dist/source/components/layouts/ExploreLayout.js +0 -72
  26. package/dist/source/components/layouts/HistoryLayout.js +0 -37
  27. package/dist/source/components/layouts/LyricsLayout.js +0 -89
  28. package/dist/source/components/layouts/MainLayout.js +0 -190
  29. package/dist/source/components/layouts/MiniPlayerLayout.js +0 -20
  30. package/dist/source/components/layouts/PlayerLayout.js +0 -9
  31. package/dist/source/components/layouts/PluginsLayout.js +0 -77
  32. package/dist/source/components/layouts/SearchLayout.js +0 -193
  33. package/dist/source/components/layouts/TrendingLayout.js +0 -59
  34. package/dist/source/components/player/NowPlaying.js +0 -45
  35. package/dist/source/components/player/PlayerControls.js +0 -83
  36. package/dist/source/components/player/ProgressBar.js +0 -19
  37. package/dist/source/components/player/QueueList.js +0 -36
  38. package/dist/source/components/player/Suggestions.js +0 -50
  39. package/dist/source/components/playlist/PlaylistList.js +0 -138
  40. package/dist/source/components/plugins/PluginInstallDialog.js +0 -41
  41. package/dist/source/components/plugins/PluginsAvailable.js +0 -55
  42. package/dist/source/components/plugins/PluginsList.js +0 -18
  43. package/dist/source/components/search/SearchBar.js +0 -55
  44. package/dist/source/components/search/SearchHistory.js +0 -35
  45. package/dist/source/components/search/SearchResults.js +0 -280
  46. package/dist/source/components/settings/Settings.js +0 -211
  47. package/dist/source/components/theme/ThemeSwitcher.js +0 -11
  48. package/dist/source/config/themes.config.js +0 -123
  49. package/dist/source/contexts/theme.context.js +0 -29
  50. package/dist/source/hooks/useKeyboard.js +0 -188
  51. package/dist/source/hooks/useKeyboardBlocker.js +0 -45
  52. package/dist/source/hooks/useNavigation.js +0 -5
  53. package/dist/source/hooks/usePlayer.js +0 -43
  54. package/dist/source/hooks/usePlaylist.js +0 -65
  55. package/dist/source/hooks/useSearch.js +0 -76
  56. package/dist/source/hooks/useSleepTimer.js +0 -48
  57. package/dist/source/hooks/useTerminalSize.js +0 -24
  58. package/dist/source/hooks/useTheme.js +0 -5
  59. package/dist/source/hooks/useYouTubeMusic.js +0 -112
  60. package/dist/source/main.js +0 -127
  61. package/dist/source/services/cache/cache.service.js +0 -67
  62. package/dist/source/services/completions/completions.service.js +0 -313
  63. package/dist/source/services/config/config.service.js +0 -191
  64. package/dist/source/services/discord/discord-rpc.service.js +0 -95
  65. package/dist/source/services/download/download.service.js +0 -350
  66. package/dist/source/services/export/export.service.js +0 -131
  67. package/dist/source/services/history/history.service.js +0 -83
  68. package/dist/source/services/import/import.service.js +0 -272
  69. package/dist/source/services/import/spotify.service.js +0 -171
  70. package/dist/source/services/import/track-matcher.service.js +0 -271
  71. package/dist/source/services/import/youtube-import.service.js +0 -84
  72. package/dist/source/services/logger/logger.service.js +0 -52
  73. package/dist/source/services/lyrics/lyrics.service.js +0 -93
  74. package/dist/source/services/mpris/mpris.service.js +0 -78
  75. package/dist/source/services/notification/notification.service.js +0 -57
  76. package/dist/source/services/player/dependency-check.service.js +0 -140
  77. package/dist/source/services/player/player.service.js +0 -478
  78. package/dist/source/services/player-state/player-state.service.js +0 -122
  79. package/dist/source/services/plugin/plugin-audio-api.js +0 -36
  80. package/dist/source/services/plugin/plugin-context.js +0 -256
  81. package/dist/source/services/plugin/plugin-hooks.service.js +0 -135
  82. package/dist/source/services/plugin/plugin-installer.service.js +0 -248
  83. package/dist/source/services/plugin/plugin-loader.service.js +0 -161
  84. package/dist/source/services/plugin/plugin-permissions.service.js +0 -194
  85. package/dist/source/services/plugin/plugin-registry.service.js +0 -215
  86. package/dist/source/services/plugin/plugin-ui-api.js +0 -46
  87. package/dist/source/services/plugin/plugin-updater.service.js +0 -206
  88. package/dist/source/services/scrobbling/scrobbling.service.js +0 -115
  89. package/dist/source/services/sleep-timer/sleep-timer.service.js +0 -45
  90. package/dist/source/services/version-check/version-check.service.js +0 -121
  91. package/dist/source/services/web/static-file.service.js +0 -185
  92. package/dist/source/services/web/web-server-manager.js +0 -506
  93. package/dist/source/services/web/web-streaming.service.js +0 -290
  94. package/dist/source/services/web/websocket.server.js +0 -267
  95. package/dist/source/services/youtube-music/api.js +0 -649
  96. package/dist/source/services/youtube-music/search.service.js +0 -38
  97. package/dist/source/stores/history.store.js +0 -64
  98. package/dist/source/stores/navigation.store.js +0 -90
  99. package/dist/source/stores/player.store.js +0 -724
  100. package/dist/source/stores/plugins.store.js +0 -177
  101. package/dist/source/types/actions.js +0 -1
  102. package/dist/source/types/cli.types.js +0 -1
  103. package/dist/source/types/config.types.js +0 -1
  104. package/dist/source/types/history.types.js +0 -1
  105. package/dist/source/types/import.types.js +0 -2
  106. package/dist/source/types/keyboard.types.js +0 -1
  107. package/dist/source/types/navigation.types.js +0 -1
  108. package/dist/source/types/player.types.js +0 -1
  109. package/dist/source/types/playlist.types.js +0 -1
  110. package/dist/source/types/plugin.types.js +0 -1
  111. package/dist/source/types/theme.types.js +0 -1
  112. package/dist/source/types/web.types.js +0 -2
  113. package/dist/source/types/youtube-music.types.js +0 -1
  114. package/dist/source/types/youtubei.types.js +0 -3
  115. package/dist/source/utils/constants.js +0 -134
  116. package/dist/source/utils/format.js +0 -24
  117. package/dist/source/utils/icons.js +0 -26
  118. package/dist/source/utils/search-filters.js +0 -100
@@ -1,506 +0,0 @@
1
- import { getWebSocketServer } from "./websocket.server.js";
2
- import { getWebStreamingService } from "./web-streaming.service.js";
3
- import { getConfigService } from "../config/config.service.js";
4
- import { getImportService } from "../import/import.service.js";
5
- import { getPlayerService } from "../player/player.service.js";
6
- import { getSearchService } from "../youtube-music/search.service.js";
7
- import { logger } from "../logger/logger.service.js";
8
- class WebServerManager {
9
- config;
10
- isRunning = false;
11
- cleanupHooks = [];
12
- // Internal state for web-only mode (when PlayerProvider is not mounted)
13
- internalState = {
14
- currentTrack: null,
15
- isPlaying: false,
16
- volume: 70,
17
- speed: 1,
18
- progress: 0,
19
- duration: 0,
20
- queue: [],
21
- queuePosition: 0,
22
- repeat: 'off',
23
- shuffle: false,
24
- isLoading: false,
25
- error: null,
26
- playRequestId: 0,
27
- };
28
- constructor() {
29
- // Load config or use defaults
30
- const configService = getConfigService();
31
- const savedConfig = configService.get('webServer');
32
- this.config = savedConfig ?? {
33
- enabled: false,
34
- host: 'localhost',
35
- port: 8080,
36
- enableCors: true,
37
- allowedOrigins: ['*'],
38
- auth: { enabled: false },
39
- };
40
- // Save default config if not present
41
- if (!savedConfig) {
42
- configService.set('webServer', this.config);
43
- }
44
- // Initialize volume from config
45
- this.internalState.volume = configService.get('volume') ?? 70;
46
- }
47
- /**
48
- * Start the web server
49
- */
50
- async start(options) {
51
- if (this.isRunning) {
52
- logger.warn('WebServerManager', 'Server already running');
53
- return;
54
- }
55
- // Apply CLI options
56
- const finalConfig = { ...this.config };
57
- if (options) {
58
- if (options.host !== undefined) {
59
- finalConfig.host = options.host;
60
- }
61
- if (options.port !== undefined) {
62
- finalConfig.port = options.port;
63
- }
64
- if (options.auth !== undefined) {
65
- finalConfig.auth.enabled = true;
66
- finalConfig.auth.token = options.auth;
67
- }
68
- }
69
- logger.info('WebServerManager', 'Starting web server', finalConfig);
70
- try {
71
- const wsServer = getWebSocketServer();
72
- // Set up command handler
73
- const cleanupCommand = this.setupCommandHandler();
74
- this.cleanupHooks.push(cleanupCommand);
75
- // Set up import handler
76
- const cleanupImport = this.setupImportHandler();
77
- this.cleanupHooks.push(cleanupImport);
78
- // Start the server
79
- await wsServer.start({
80
- config: finalConfig,
81
- onCommand: this.handleCommand.bind(this),
82
- onImportRequest: this.handleImportRequest.bind(this),
83
- onSearchRequest: this.handleSearchRequest.bind(this),
84
- onConfigUpdate: this.handleConfigUpdate.bind(this),
85
- });
86
- this.isRunning = true;
87
- // Set up graceful shutdown
88
- this.setupShutdownHooks();
89
- }
90
- catch (error) {
91
- logger.error('WebServerManager', 'Failed to start server', {
92
- error: error instanceof Error ? error.message : String(error),
93
- });
94
- throw error;
95
- }
96
- }
97
- /**
98
- * Stop the web server
99
- */
100
- async stop() {
101
- if (!this.isRunning) {
102
- return;
103
- }
104
- logger.info('WebServerManager', 'Stopping web server');
105
- // Clean up hooks
106
- for (const cleanup of this.cleanupHooks) {
107
- cleanup();
108
- }
109
- this.cleanupHooks = [];
110
- // Stop the WebSocket server
111
- const wsServer = getWebSocketServer();
112
- await wsServer.stop();
113
- this.isRunning = false;
114
- }
115
- /**
116
- * Set up player command handler
117
- */
118
- setupCommandHandler() {
119
- const streamingService = getWebStreamingService();
120
- const unsubscribe = streamingService.onMessage(message => {
121
- if (message.type === 'command') {
122
- this.handleCommand(message.action);
123
- }
124
- });
125
- return unsubscribe;
126
- }
127
- /**
128
- * Set up import progress handler
129
- */
130
- setupImportHandler() {
131
- const importService = getImportService();
132
- const streamingService = getWebStreamingService();
133
- const unsubscribe = importService.onProgress(progress => {
134
- streamingService.onImportProgress(progress);
135
- });
136
- return unsubscribe;
137
- }
138
- /**
139
- * Handle command from web client
140
- */
141
- handleCommand(action) {
142
- logger.debug('WebServerManager', 'Executing command from client', { action });
143
- const playerService = getPlayerService();
144
- const config = getConfigService();
145
- // Execute command and update internal state
146
- switch (action.category) {
147
- case 'PLAY': {
148
- if (action.track) {
149
- this.internalState.currentTrack = action.track;
150
- this.internalState.isPlaying = true;
151
- this.internalState.progress = 0;
152
- this.internalState.error = null;
153
- const youtubeUrl = `https://www.youtube.com/watch?v=${action.track.videoId}`;
154
- void playerService.play(youtubeUrl, {
155
- volume: this.internalState.volume,
156
- volumeFadeDuration: config.get('volumeFadeDuration'),
157
- });
158
- }
159
- break;
160
- }
161
- case 'PAUSE':
162
- this.internalState.isPlaying = false;
163
- playerService.pause();
164
- break;
165
- case 'RESUME':
166
- this.internalState.isPlaying = true;
167
- playerService.resume();
168
- break;
169
- case 'STOP':
170
- this.internalState.isPlaying = false;
171
- this.internalState.progress = 0;
172
- this.internalState.currentTrack = null;
173
- playerService.stop();
174
- break;
175
- case 'NEXT': {
176
- if (this.internalState.queue.length === 0)
177
- break;
178
- if (this.internalState.shuffle && this.internalState.queue.length > 1) {
179
- let randomIndex;
180
- do {
181
- randomIndex = Math.floor(Math.random() * this.internalState.queue.length);
182
- } while (randomIndex === this.internalState.queuePosition);
183
- this.internalState.queuePosition = randomIndex;
184
- }
185
- else {
186
- const nextPosition = this.internalState.queuePosition + 1;
187
- if (nextPosition >= this.internalState.queue.length) {
188
- if (this.internalState.repeat === 'all') {
189
- this.internalState.queuePosition = 0;
190
- }
191
- else {
192
- break;
193
- }
194
- }
195
- else {
196
- this.internalState.queuePosition = nextPosition;
197
- }
198
- }
199
- this.internalState.currentTrack =
200
- this.internalState.queue[this.internalState.queuePosition] ?? null;
201
- this.internalState.isPlaying = true;
202
- this.internalState.progress = 0;
203
- if (this.internalState.currentTrack) {
204
- const youtubeUrl = `https://www.youtube.com/watch?v=${this.internalState.currentTrack.videoId}`;
205
- void playerService.play(youtubeUrl, {
206
- volume: this.internalState.volume,
207
- volumeFadeDuration: config.get('volumeFadeDuration'),
208
- });
209
- }
210
- break;
211
- }
212
- case 'PREVIOUS': {
213
- const prevPosition = this.internalState.queuePosition - 1;
214
- if (prevPosition < 0)
215
- break;
216
- if (this.internalState.progress > 3) {
217
- this.internalState.progress = 0;
218
- break;
219
- }
220
- this.internalState.queuePosition = prevPosition;
221
- this.internalState.currentTrack =
222
- this.internalState.queue[prevPosition] ?? null;
223
- this.internalState.progress = 0;
224
- break;
225
- }
226
- case 'SEEK':
227
- if (action.position !== undefined) {
228
- this.internalState.progress = Math.max(0, Math.min(action.position, this.internalState.duration));
229
- // Note: Seeking via mpv IPC would require additional implementation
230
- }
231
- break;
232
- case 'SET_VOLUME':
233
- if (action.volume !== undefined) {
234
- this.internalState.volume = Math.max(0, Math.min(100, action.volume));
235
- playerService.setVolume(this.internalState.volume);
236
- }
237
- break;
238
- case 'VOLUME_UP':
239
- this.internalState.volume = Math.min(100, this.internalState.volume + 10);
240
- playerService.setVolume(this.internalState.volume);
241
- break;
242
- case 'VOLUME_DOWN':
243
- this.internalState.volume = Math.max(0, this.internalState.volume - 10);
244
- playerService.setVolume(this.internalState.volume);
245
- break;
246
- case 'VOLUME_FINE_UP':
247
- this.internalState.volume = Math.min(100, this.internalState.volume + 1);
248
- playerService.setVolume(this.internalState.volume);
249
- break;
250
- case 'VOLUME_FINE_DOWN':
251
- this.internalState.volume = Math.max(0, this.internalState.volume - 1);
252
- playerService.setVolume(this.internalState.volume);
253
- break;
254
- case 'TOGGLE_SHUFFLE':
255
- this.internalState.shuffle = !this.internalState.shuffle;
256
- break;
257
- case 'TOGGLE_REPEAT': {
258
- const repeatModes = ['off', 'all', 'one'];
259
- const currentIndex = repeatModes.indexOf(this.internalState.repeat);
260
- this.internalState.repeat =
261
- repeatModes[(currentIndex + 1) % 3] ?? 'off';
262
- break;
263
- }
264
- case 'SET_QUEUE':
265
- if (action.queue) {
266
- this.internalState.queue = action.queue;
267
- this.internalState.queuePosition = 0;
268
- }
269
- break;
270
- case 'ADD_TO_QUEUE':
271
- if (action.track) {
272
- this.internalState.queue = [
273
- ...this.internalState.queue,
274
- action.track,
275
- ];
276
- }
277
- break;
278
- case 'REMOVE_FROM_QUEUE':
279
- if (action.index !== undefined) {
280
- const newQueue = [...this.internalState.queue];
281
- newQueue.splice(action.index, 1);
282
- this.internalState.queue = newQueue;
283
- }
284
- break;
285
- case 'CLEAR_QUEUE':
286
- this.internalState.queue = [];
287
- this.internalState.queuePosition = 0;
288
- this.internalState.isPlaying = false;
289
- break;
290
- case 'SET_QUEUE_POSITION':
291
- if (action.position >= 0 &&
292
- action.position < this.internalState.queue.length) {
293
- this.internalState.queuePosition = action.position;
294
- this.internalState.currentTrack =
295
- this.internalState.queue[action.position] ?? null;
296
- this.internalState.progress = 0;
297
- }
298
- break;
299
- case 'SET_SPEED':
300
- if (action.speed !== undefined) {
301
- const clampedSpeed = Math.max(0.25, Math.min(4.0, action.speed));
302
- this.internalState.speed = clampedSpeed;
303
- playerService.setSpeed(clampedSpeed);
304
- }
305
- break;
306
- case 'UPDATE_PROGRESS':
307
- if (action.progress !== undefined) {
308
- this.internalState.progress = Math.max(0, Math.min(action.progress, this.internalState.duration || action.progress));
309
- }
310
- break;
311
- case 'SET_DURATION':
312
- if (action.duration !== undefined) {
313
- this.internalState.duration = action.duration;
314
- }
315
- break;
316
- case 'SET_LOADING':
317
- if (action.loading !== undefined) {
318
- this.internalState.isLoading = action.loading;
319
- }
320
- break;
321
- case 'SET_ERROR':
322
- if (action.error !== undefined) {
323
- this.internalState.error = action.error;
324
- this.internalState.isLoading = false;
325
- }
326
- break;
327
- default:
328
- logger.debug('WebServerManager', 'Unhandled command category', {
329
- category: action.category,
330
- });
331
- }
332
- // Broadcast updated state after command
333
- this.broadcastState();
334
- }
335
- /**
336
- * Handle import request from web client
337
- */
338
- async handleImportRequest(source, url, name) {
339
- logger.info('WebServerManager', 'Import request from client', {
340
- source,
341
- url,
342
- name,
343
- });
344
- try {
345
- const importService = getImportService();
346
- await importService.importPlaylist(source, url, name);
347
- }
348
- catch (error) {
349
- logger.error('WebServerManager', 'Import failed', {
350
- source,
351
- url,
352
- error: error instanceof Error ? error.message : String(error),
353
- });
354
- }
355
- }
356
- /**
357
- * Handle search request from web client
358
- */
359
- async handleSearchRequest(query, searchType) {
360
- logger.info('WebServerManager', 'Search request from client', {
361
- query,
362
- searchType,
363
- });
364
- try {
365
- const searchService = getSearchService();
366
- const response = await searchService.search(query, { type: searchType });
367
- const streamingService = getWebStreamingService();
368
- streamingService.broadcast({
369
- type: 'search-results',
370
- results: response.results,
371
- });
372
- }
373
- catch (error) {
374
- logger.error('WebServerManager', 'Search failed', {
375
- query,
376
- searchType,
377
- error: error instanceof Error ? error.message : String(error),
378
- });
379
- }
380
- }
381
- /**
382
- * Handle config update from web client
383
- */
384
- handleConfigUpdate(config) {
385
- logger.info('WebServerManager', 'Config update from client', { config });
386
- try {
387
- const configService = getConfigService();
388
- // Apply each config key
389
- for (const [key, value] of Object.entries(config)) {
390
- configService.set(key, value);
391
- }
392
- // Broadcast updated config to all clients
393
- const streamingService = getWebStreamingService();
394
- streamingService.broadcast({
395
- type: 'config-update',
396
- config,
397
- });
398
- }
399
- catch (error) {
400
- logger.error('WebServerManager', 'Config update failed', {
401
- config,
402
- error: error instanceof Error ? error.message : String(error),
403
- });
404
- }
405
- }
406
- /**
407
- * Update player state (call this when player state changes)
408
- * This is called by PlayerProvider in normal mode to sync state
409
- */
410
- updateState(state) {
411
- if (!this.isRunning)
412
- return;
413
- // Update internal state to stay in sync
414
- this.internalState = { ...state };
415
- const streamingService = getWebStreamingService();
416
- streamingService.onStateChange(state);
417
- }
418
- /**
419
- * Broadcast current state to all connected clients
420
- */
421
- broadcastState() {
422
- if (!this.isRunning)
423
- return;
424
- const streamingService = getWebStreamingService();
425
- streamingService.onStateChange(this.internalState);
426
- }
427
- /**
428
- * Get current internal state
429
- */
430
- getState() {
431
- return { ...this.internalState };
432
- }
433
- /**
434
- * Set internal state directly (for sync from external sources)
435
- */
436
- setState(state) {
437
- this.internalState = { ...this.internalState, ...state };
438
- this.broadcastState();
439
- }
440
- /**
441
- * Set up graceful shutdown hooks
442
- */
443
- setupShutdownHooks() {
444
- const shutdown = async () => {
445
- await this.stop();
446
- };
447
- process.on('beforeExit', shutdown);
448
- process.on('SIGINT', shutdown);
449
- process.on('SIGTERM', shutdown);
450
- this.cleanupHooks.push(() => {
451
- process.off('beforeExit', shutdown);
452
- process.off('SIGINT', shutdown);
453
- process.off('SIGTERM', shutdown);
454
- });
455
- }
456
- /**
457
- * Check if server is running
458
- */
459
- isServerRunning() {
460
- return this.isRunning;
461
- }
462
- /**
463
- * Get server URL
464
- */
465
- getServerUrl() {
466
- const wsServer = getWebSocketServer();
467
- return wsServer.getServerUrl();
468
- }
469
- /**
470
- * Get server statistics
471
- */
472
- getStats() {
473
- if (!this.isRunning) {
474
- return { running: false };
475
- }
476
- const streamingService = getWebStreamingService();
477
- const stats = streamingService.getStats();
478
- return {
479
- running: true,
480
- url: this.getServerUrl(),
481
- clients: stats.clients,
482
- };
483
- }
484
- /**
485
- * Update configuration
486
- */
487
- updateConfig(config) {
488
- this.config = { ...this.config, ...config };
489
- const configService = getConfigService();
490
- configService.set('webServer', this.config);
491
- }
492
- /**
493
- * Get current configuration
494
- */
495
- getConfig() {
496
- return { ...this.config };
497
- }
498
- }
499
- // Singleton instance
500
- let webServerManagerInstance = null;
501
- export function getWebServerManager() {
502
- if (!webServerManagerInstance) {
503
- webServerManagerInstance = new WebServerManager();
504
- }
505
- return webServerManagerInstance;
506
- }