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