@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.
- package/CHANGELOG.md +2 -0
- package/dist/cli.js.map +3 -3
- package/dist/youtube-music-cli +0 -0
- package/package.json +1 -1
- package/dist/eslint.config.js +0 -55
- package/dist/package.json +0 -120
- package/dist/scripts/build-cli.js +0 -46
- package/dist/source/app.js +0 -17
- package/dist/source/cli.js +0 -504
- package/dist/source/components/common/ErrorBoundary.js +0 -22
- package/dist/source/components/common/Help.js +0 -18
- package/dist/source/components/common/ShortcutsBar.js +0 -89
- package/dist/source/components/config/ConfigLayout.js +0 -84
- package/dist/source/components/config/KeybindingsLayout.js +0 -107
- package/dist/source/components/export/ExportLayout.js +0 -111
- package/dist/source/components/import/ImportLayout.js +0 -119
- package/dist/source/components/import/ImportProgress.js +0 -73
- package/dist/source/components/layouts/ExploreLayout.js +0 -72
- package/dist/source/components/layouts/HistoryLayout.js +0 -37
- package/dist/source/components/layouts/LyricsLayout.js +0 -89
- package/dist/source/components/layouts/MainLayout.js +0 -190
- package/dist/source/components/layouts/MiniPlayerLayout.js +0 -20
- package/dist/source/components/layouts/PlayerLayout.js +0 -9
- package/dist/source/components/layouts/PluginsLayout.js +0 -77
- package/dist/source/components/layouts/SearchLayout.js +0 -193
- package/dist/source/components/layouts/TrendingLayout.js +0 -59
- package/dist/source/components/player/NowPlaying.js +0 -45
- package/dist/source/components/player/PlayerControls.js +0 -83
- package/dist/source/components/player/ProgressBar.js +0 -19
- package/dist/source/components/player/QueueList.js +0 -36
- package/dist/source/components/player/Suggestions.js +0 -50
- package/dist/source/components/playlist/PlaylistList.js +0 -138
- package/dist/source/components/plugins/PluginInstallDialog.js +0 -41
- package/dist/source/components/plugins/PluginsAvailable.js +0 -55
- package/dist/source/components/plugins/PluginsList.js +0 -18
- package/dist/source/components/search/SearchBar.js +0 -55
- package/dist/source/components/search/SearchHistory.js +0 -35
- package/dist/source/components/search/SearchResults.js +0 -280
- package/dist/source/components/settings/Settings.js +0 -211
- package/dist/source/components/theme/ThemeSwitcher.js +0 -11
- package/dist/source/config/themes.config.js +0 -123
- package/dist/source/contexts/theme.context.js +0 -29
- package/dist/source/hooks/useKeyboard.js +0 -188
- package/dist/source/hooks/useKeyboardBlocker.js +0 -45
- package/dist/source/hooks/useNavigation.js +0 -5
- package/dist/source/hooks/usePlayer.js +0 -43
- package/dist/source/hooks/usePlaylist.js +0 -65
- package/dist/source/hooks/useSearch.js +0 -76
- package/dist/source/hooks/useSleepTimer.js +0 -48
- package/dist/source/hooks/useTerminalSize.js +0 -24
- package/dist/source/hooks/useTheme.js +0 -5
- package/dist/source/hooks/useYouTubeMusic.js +0 -112
- package/dist/source/main.js +0 -127
- package/dist/source/services/cache/cache.service.js +0 -67
- package/dist/source/services/completions/completions.service.js +0 -313
- package/dist/source/services/config/config.service.js +0 -191
- package/dist/source/services/discord/discord-rpc.service.js +0 -95
- package/dist/source/services/download/download.service.js +0 -350
- package/dist/source/services/export/export.service.js +0 -131
- package/dist/source/services/history/history.service.js +0 -83
- package/dist/source/services/import/import.service.js +0 -272
- package/dist/source/services/import/spotify.service.js +0 -171
- package/dist/source/services/import/track-matcher.service.js +0 -271
- package/dist/source/services/import/youtube-import.service.js +0 -84
- package/dist/source/services/logger/logger.service.js +0 -52
- package/dist/source/services/lyrics/lyrics.service.js +0 -93
- package/dist/source/services/mpris/mpris.service.js +0 -78
- package/dist/source/services/notification/notification.service.js +0 -57
- package/dist/source/services/player/dependency-check.service.js +0 -140
- package/dist/source/services/player/player.service.js +0 -478
- package/dist/source/services/player-state/player-state.service.js +0 -123
- package/dist/source/services/plugin/plugin-audio-api.js +0 -36
- package/dist/source/services/plugin/plugin-context.js +0 -256
- package/dist/source/services/plugin/plugin-hooks.service.js +0 -135
- package/dist/source/services/plugin/plugin-installer.service.js +0 -248
- package/dist/source/services/plugin/plugin-loader.service.js +0 -161
- package/dist/source/services/plugin/plugin-permissions.service.js +0 -194
- package/dist/source/services/plugin/plugin-registry.service.js +0 -215
- package/dist/source/services/plugin/plugin-ui-api.js +0 -46
- package/dist/source/services/plugin/plugin-updater.service.js +0 -206
- package/dist/source/services/scrobbling/scrobbling.service.js +0 -115
- package/dist/source/services/sleep-timer/sleep-timer.service.js +0 -45
- package/dist/source/services/version-check/version-check.service.js +0 -121
- package/dist/source/services/web/static-file.service.js +0 -185
- package/dist/source/services/web/web-server-manager.js +0 -507
- package/dist/source/services/web/web-streaming.service.js +0 -292
- package/dist/source/services/web/websocket.server.js +0 -267
- package/dist/source/services/youtube-music/api.js +0 -649
- package/dist/source/services/youtube-music/search.service.js +0 -38
- package/dist/source/stores/history.store.js +0 -64
- package/dist/source/stores/navigation.store.js +0 -90
- package/dist/source/stores/player.store.js +0 -789
- package/dist/source/stores/plugins.store.js +0 -177
- package/dist/source/types/actions.js +0 -1
- package/dist/source/types/cli.types.js +0 -1
- package/dist/source/types/config.types.js +0 -1
- package/dist/source/types/history.types.js +0 -1
- package/dist/source/types/import.types.js +0 -2
- package/dist/source/types/keyboard.types.js +0 -1
- package/dist/source/types/navigation.types.js +0 -1
- package/dist/source/types/player.types.js +0 -1
- package/dist/source/types/playlist.types.js +0 -1
- package/dist/source/types/plugin.types.js +0 -1
- package/dist/source/types/theme.types.js +0 -1
- package/dist/source/types/web.types.js +0 -2
- package/dist/source/types/youtube-music.types.js +0 -1
- package/dist/source/types/youtubei.types.js +0 -3
- package/dist/source/utils/constants.js +0 -135
- package/dist/source/utils/format.js +0 -24
- package/dist/source/utils/icons.js +0 -28
- package/dist/source/utils/search-filters.js +0 -100
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
// Version check service for npm registry updates
|
|
2
|
-
import { APP_NAME, APP_VERSION } from "../../utils/constants.js";
|
|
3
|
-
import { logger } from "../logger/logger.service.js";
|
|
4
|
-
class VersionCheckService {
|
|
5
|
-
static instance;
|
|
6
|
-
NPM_REGISTRY_URL = 'https://registry.npmjs.org';
|
|
7
|
-
CHECK_INTERVAL = 24 * 60 * 60 * 1000; // 24 hours in milliseconds
|
|
8
|
-
constructor() { }
|
|
9
|
-
static getInstance() {
|
|
10
|
-
if (!VersionCheckService.instance) {
|
|
11
|
-
VersionCheckService.instance = new VersionCheckService();
|
|
12
|
-
}
|
|
13
|
-
return VersionCheckService.instance;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Compare two semantic version strings
|
|
17
|
-
* Returns: 1 if a > b, -1 if a < b, 0 if equal
|
|
18
|
-
*/
|
|
19
|
-
compareVersions(a, b) {
|
|
20
|
-
const parseVersion = (v) => {
|
|
21
|
-
// Remove 'v' prefix if present and split by non-numeric chars
|
|
22
|
-
const clean = v.replace(/^v/i, '');
|
|
23
|
-
return clean.split(/[.-]/).map(part => {
|
|
24
|
-
const num = parseInt(part, 10);
|
|
25
|
-
return Number.isNaN(num) ? 0 : num;
|
|
26
|
-
});
|
|
27
|
-
};
|
|
28
|
-
const partsA = parseVersion(a);
|
|
29
|
-
const partsB = parseVersion(b);
|
|
30
|
-
const maxLength = Math.max(partsA.length, partsB.length);
|
|
31
|
-
for (let i = 0; i < maxLength; i++) {
|
|
32
|
-
const partA = partsA[i] ?? 0;
|
|
33
|
-
const partB = partsB[i] ?? 0;
|
|
34
|
-
if (partA > partB)
|
|
35
|
-
return 1;
|
|
36
|
-
if (partA < partB)
|
|
37
|
-
return -1;
|
|
38
|
-
}
|
|
39
|
-
return 0;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Check if a version check should be performed (once per 24 hours)
|
|
43
|
-
*/
|
|
44
|
-
shouldCheck(lastCheck) {
|
|
45
|
-
if (!lastCheck)
|
|
46
|
-
return true;
|
|
47
|
-
try {
|
|
48
|
-
const lastCheckDate = new Date(lastCheck);
|
|
49
|
-
const now = new Date();
|
|
50
|
-
const diff = now.getTime() - lastCheckDate.getTime();
|
|
51
|
-
return diff >= this.CHECK_INTERVAL;
|
|
52
|
-
}
|
|
53
|
-
catch {
|
|
54
|
-
return true;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Mark that a version check has been performed
|
|
59
|
-
* Returns the timestamp string to store
|
|
60
|
-
*/
|
|
61
|
-
markChecked() {
|
|
62
|
-
return new Date().toISOString();
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Check npm registry for available updates
|
|
66
|
-
*/
|
|
67
|
-
async checkForUpdates(currentVersion = APP_VERSION) {
|
|
68
|
-
try {
|
|
69
|
-
logger.debug('VersionCheckService', 'Checking for updates', {
|
|
70
|
-
package: APP_NAME,
|
|
71
|
-
currentVersion,
|
|
72
|
-
});
|
|
73
|
-
const url = `${this.NPM_REGISTRY_URL}/${APP_NAME}`;
|
|
74
|
-
const response = await fetch(url, {
|
|
75
|
-
signal: AbortSignal.timeout(5000), // 5 second timeout
|
|
76
|
-
});
|
|
77
|
-
if (!response.ok) {
|
|
78
|
-
logger.warn('VersionCheckService', 'Failed to fetch package info', {
|
|
79
|
-
status: response.status,
|
|
80
|
-
});
|
|
81
|
-
return {
|
|
82
|
-
hasUpdate: false,
|
|
83
|
-
currentVersion,
|
|
84
|
-
latestVersion: currentVersion,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
const data = (await response.json());
|
|
88
|
-
const latestVersion = data['dist-tags']?.latest;
|
|
89
|
-
if (!latestVersion) {
|
|
90
|
-
logger.warn('VersionCheckService', 'No latest version found in response');
|
|
91
|
-
return {
|
|
92
|
-
hasUpdate: false,
|
|
93
|
-
currentVersion,
|
|
94
|
-
latestVersion: currentVersion,
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
const hasUpdate = this.compareVersions(latestVersion, currentVersion) > 0;
|
|
98
|
-
logger.info('VersionCheckService', 'Version check complete', {
|
|
99
|
-
currentVersion,
|
|
100
|
-
latestVersion,
|
|
101
|
-
hasUpdate,
|
|
102
|
-
});
|
|
103
|
-
return {
|
|
104
|
-
hasUpdate,
|
|
105
|
-
currentVersion,
|
|
106
|
-
latestVersion,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
catch (error) {
|
|
110
|
-
logger.error('VersionCheckService', 'Error checking for updates', {
|
|
111
|
-
error: error instanceof Error ? error.message : String(error),
|
|
112
|
-
});
|
|
113
|
-
return {
|
|
114
|
-
hasUpdate: false,
|
|
115
|
-
currentVersion,
|
|
116
|
-
latestVersion: currentVersion,
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
export const getVersionCheckService = () => VersionCheckService.getInstance();
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
// Static file serving service for web UI
|
|
2
|
-
import { readFile } from 'node:fs/promises';
|
|
3
|
-
import { existsSync } from 'node:fs';
|
|
4
|
-
import { extname, join, dirname, normalize, resolve, sep } from 'node:path';
|
|
5
|
-
import { fileURLToPath } from 'node:url';
|
|
6
|
-
import { logger } from "../logger/logger.service.js";
|
|
7
|
-
const MIME_TYPES = {
|
|
8
|
-
'.html': 'text/html',
|
|
9
|
-
'.css': 'text/css',
|
|
10
|
-
'.js': 'text/javascript',
|
|
11
|
-
'.json': 'application/json',
|
|
12
|
-
'.png': 'image/png',
|
|
13
|
-
'.jpg': 'image/jpeg',
|
|
14
|
-
'.jpeg': 'image/jpeg',
|
|
15
|
-
'.gif': 'image/gif',
|
|
16
|
-
'.svg': 'image/svg+xml',
|
|
17
|
-
'.ico': 'image/x-icon',
|
|
18
|
-
'.woff': 'font/woff',
|
|
19
|
-
'.woff2': 'font/woff2',
|
|
20
|
-
'.ttf': 'font/ttf',
|
|
21
|
-
'.eot': 'application/vnd.ms-fontobject',
|
|
22
|
-
};
|
|
23
|
-
class StaticFileService {
|
|
24
|
-
webDistDir;
|
|
25
|
-
indexHtml = null;
|
|
26
|
-
indexHtmlLoaded = false;
|
|
27
|
-
constructor() {
|
|
28
|
-
// Web UI is built to dist/web/ relative to the project root
|
|
29
|
-
// Get the directory of the current file
|
|
30
|
-
const currentFile = fileURLToPath(import.meta.url);
|
|
31
|
-
const currentDir = dirname(currentFile);
|
|
32
|
-
// Detect if running from dist/ or source/
|
|
33
|
-
// dist/source/services/web -> need to go up 4 levels to reach project root
|
|
34
|
-
// source/services/web -> need to go up 3 levels to reach project root
|
|
35
|
-
const isDist = currentFile.includes('/dist/') || currentFile.includes('\\dist\\');
|
|
36
|
-
let projectRoot;
|
|
37
|
-
if (isDist) {
|
|
38
|
-
// dist/source/services/web -> services/web -> services -> source -> dist -> project root
|
|
39
|
-
projectRoot = join(currentDir, '..', '..', '..', '..');
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
// source/services/web -> services/web -> services -> source -> project root
|
|
43
|
-
projectRoot = join(currentDir, '..', '..', '..');
|
|
44
|
-
}
|
|
45
|
-
this.webDistDir = join(projectRoot, 'dist', 'web');
|
|
46
|
-
logger.debug('StaticFileService', 'Path resolved', {
|
|
47
|
-
webDistDir: this.webDistDir,
|
|
48
|
-
exists: existsSync(this.webDistDir),
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Get MIME type for a file extension
|
|
53
|
-
*/
|
|
54
|
-
getMimeType(filePath) {
|
|
55
|
-
const ext = extname(filePath).toLowerCase();
|
|
56
|
-
return MIME_TYPES[ext] || 'application/octet-stream';
|
|
57
|
-
}
|
|
58
|
-
resolveSafeFilePath(urlPath) {
|
|
59
|
-
let decodedPath;
|
|
60
|
-
try {
|
|
61
|
-
decodedPath = decodeURIComponent(urlPath);
|
|
62
|
-
}
|
|
63
|
-
catch {
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
const relativePath = normalize(decodedPath).replace(/^[\\/]+/, '');
|
|
67
|
-
const rootPath = resolve(this.webDistDir);
|
|
68
|
-
const resolvedPath = resolve(rootPath, relativePath);
|
|
69
|
-
const rootPrefix = rootPath.endsWith(sep) ? rootPath : `${rootPath}${sep}`;
|
|
70
|
-
if (resolvedPath !== rootPath && !resolvedPath.startsWith(rootPrefix)) {
|
|
71
|
-
return null;
|
|
72
|
-
}
|
|
73
|
-
return resolvedPath;
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Load index.html into memory
|
|
77
|
-
*/
|
|
78
|
-
async loadIndexHtml() {
|
|
79
|
-
if (this.indexHtmlLoaded)
|
|
80
|
-
return;
|
|
81
|
-
const indexPath = join(this.webDistDir, 'index.html');
|
|
82
|
-
try {
|
|
83
|
-
const buffer = await readFile(indexPath);
|
|
84
|
-
this.indexHtml = buffer.toString('utf-8');
|
|
85
|
-
this.indexHtmlLoaded = true;
|
|
86
|
-
logger.info('StaticFileService', 'index.html loaded');
|
|
87
|
-
}
|
|
88
|
-
catch (error) {
|
|
89
|
-
logger.error('StaticFileService', 'Failed to load index.html', {
|
|
90
|
-
indexPath,
|
|
91
|
-
error: error instanceof Error ? error.message : String(error),
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Serve a static file
|
|
97
|
-
*/
|
|
98
|
-
async serve(url, _req, res) {
|
|
99
|
-
// Remove query string
|
|
100
|
-
const urlPath = url.split('?')[0] ?? '/';
|
|
101
|
-
// Serve index.html for SPA routes
|
|
102
|
-
if (urlPath === '/' || !urlPath.includes('.')) {
|
|
103
|
-
// Ensure index.html is loaded
|
|
104
|
-
if (!this.indexHtmlLoaded) {
|
|
105
|
-
await this.loadIndexHtml();
|
|
106
|
-
}
|
|
107
|
-
if (this.indexHtml) {
|
|
108
|
-
res.writeHead(200, {
|
|
109
|
-
'Content-Type': 'text/html',
|
|
110
|
-
'Cache-Control': 'public, max-age=3600',
|
|
111
|
-
});
|
|
112
|
-
res.end(this.indexHtml);
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
// Web UI not built, serve a simple message
|
|
116
|
-
res.writeHead(503, { 'Content-Type': 'text/html' });
|
|
117
|
-
res.end(`
|
|
118
|
-
<!DOCTYPE html>
|
|
119
|
-
<html>
|
|
120
|
-
<head><title>Web UI Not Built</title></head>
|
|
121
|
-
<body>
|
|
122
|
-
<h1>Web UI Not Built</h1>
|
|
123
|
-
<p>Run <code>bun run build:web</code> to build the web UI.</p>
|
|
124
|
-
</body>
|
|
125
|
-
</html>
|
|
126
|
-
`);
|
|
127
|
-
}
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
// Serve static files
|
|
131
|
-
const filePath = this.resolveSafeFilePath(urlPath);
|
|
132
|
-
if (!filePath) {
|
|
133
|
-
res.writeHead(400, { 'Content-Type': 'text/plain' });
|
|
134
|
-
res.end('Bad Request');
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
try {
|
|
138
|
-
// Check if file exists
|
|
139
|
-
if (!existsSync(filePath)) {
|
|
140
|
-
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
141
|
-
res.end('Not Found');
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
// Read and serve file
|
|
145
|
-
const content = await readFile(filePath);
|
|
146
|
-
const mimeType = this.getMimeType(filePath);
|
|
147
|
-
res.writeHead(200, {
|
|
148
|
-
'Content-Type': mimeType,
|
|
149
|
-
'Cache-Control': 'public, max-age=86400', // 1 day
|
|
150
|
-
});
|
|
151
|
-
res.end(content);
|
|
152
|
-
}
|
|
153
|
-
catch (error) {
|
|
154
|
-
logger.error('StaticFileService', 'Failed to serve file', {
|
|
155
|
-
filePath,
|
|
156
|
-
error: error instanceof Error ? error.message : String(error),
|
|
157
|
-
});
|
|
158
|
-
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
|
159
|
-
res.end('Internal Server Error');
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Check if web UI is built
|
|
164
|
-
*/
|
|
165
|
-
isWebUiBuilt() {
|
|
166
|
-
const indexPath = join(this.webDistDir, 'index.html');
|
|
167
|
-
return existsSync(indexPath);
|
|
168
|
-
}
|
|
169
|
-
/**
|
|
170
|
-
* Clear cached index.html (useful for development)
|
|
171
|
-
*/
|
|
172
|
-
clearCache() {
|
|
173
|
-
this.indexHtml = null;
|
|
174
|
-
this.indexHtmlLoaded = false;
|
|
175
|
-
logger.debug('StaticFileService', 'Cache cleared');
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
// Singleton instance
|
|
179
|
-
let staticFileServiceInstance = null;
|
|
180
|
-
export function getStaticFileService() {
|
|
181
|
-
if (!staticFileServiceInstance) {
|
|
182
|
-
staticFileServiceInstance = new StaticFileService();
|
|
183
|
-
}
|
|
184
|
-
return staticFileServiceInstance;
|
|
185
|
-
}
|