mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-12 11:01:45 +00:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fa160b2e90 | |||
| 308ac38e6b | |||
| a62cafb601 | |||
| bf9e3b5f48 | |||
| 3c6b3aeff0 | |||
| 37181a7b5e | |||
| 0b363d6487 | |||
| e9398adac3 | |||
| 6901713036 | |||
| 1d5b2997bd | |||
| 572a023aaa | |||
| 9187f1e240 | |||
| df13d7d0f3 | |||
| 85228fd7d2 | |||
| 17ba071057 | |||
| d7df4d7d10 | |||
| 7aa970cebc | |||
| f08f003cf4 | |||
| 9f99eded9e | |||
| c512f13009 | |||
| b475f780ff | |||
| 2294102006 | |||
| d69a07d025 | |||
| 4f4995c20c | |||
| b6894dca29 | |||
| 73f14e581d | |||
| 2f2e64af4a |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -117,7 +117,7 @@ jobs:
|
|||||||
if: ${{ env.VERSION_HASH == '' }}
|
if: ${{ env.VERSION_HASH == '' }}
|
||||||
uses: irongut/EditRelease@v1.2.0
|
uses: irongut/EditRelease@v1.2.0
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GH_TOKEN }}
|
||||||
id: ${{ steps.get_draft_release.outputs.id }}
|
id: ${{ steps.get_draft_release.outputs.id }}
|
||||||
draft: false
|
draft: false
|
||||||
prerelease: false
|
prerelease: false
|
||||||
|
|||||||
20
.github/workflows/winget-cla.yml
vendored
Normal file
20
.github/workflows/winget-cla.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
name: Submit CLA to Winget PR
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
pr_url:
|
||||||
|
description: "Specific PR URL"
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
comment:
|
||||||
|
name: Comment to PR
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Submit CLA to Windows Package Manager Community Repository Pull Request
|
||||||
|
run: gh pr comment $PR_URL --body "@microsoft-github-policy-service agree"
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.WINGET_ACC_TOKEN }}
|
||||||
|
PR_URL: ${{ inputs.pr_url }}
|
||||||
2
.github/workflows/winget-submission.yml
vendored
2
.github/workflows/winget-submission.yml
vendored
@ -19,7 +19,7 @@ jobs:
|
|||||||
uses: vedantmgoyal2009/winget-releaser@v2
|
uses: vedantmgoyal2009/winget-releaser@v2
|
||||||
with:
|
with:
|
||||||
identifier: th-ch.YouTubeMusic
|
identifier: th-ch.YouTubeMusic
|
||||||
installers-regex: '^YouTube-Music-Setup-[\d\.]+\.exe$'
|
installers-regex: '^YouTube-Music-Web-Setup-[\d\.]+\.exe$'
|
||||||
version: ${{ inputs.tag_name || github.event.release.tag_name }}
|
version: ${{ inputs.tag_name || github.event.release.tag_name }}
|
||||||
release-tag: ${{ inputs.tag_name || github.event.release.tag_name }}
|
release-tag: ${{ inputs.tag_name || github.event.release.tag_name }}
|
||||||
token: ${{ secrets.WINGET_ACC_TOKEN }}
|
token: ${{ secrets.WINGET_ACC_TOKEN }}
|
||||||
|
|||||||
25
changelog.md
25
changelog.md
@ -2,8 +2,33 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
|
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
|
||||||
|
|
||||||
|
#### [v2.0.4](https://github.com/th-ch/youtube-music/compare/v2.0.3...v2.0.4)
|
||||||
|
|
||||||
|
- hotfix(adblocker): fix `ipcRenderer.sendSync() with ...` [`#1301`](https://github.com/th-ch/youtube-music/pull/1301)
|
||||||
|
- fix(downloader): Korean filename is broken on non-macOS devices [`#1297`](https://github.com/th-ch/youtube-music/pull/1297)
|
||||||
|
- chore(deps): bump deps [`b6894dc`](https://github.com/th-ch/youtube-music/commit/b6894dca2974c63fa2945d3a4995665d11eb2a78)
|
||||||
|
- fix: bump dependencies [`7aa970c`](https://github.com/th-ch/youtube-music/commit/7aa970cebc8e1407ff6937b402ba303e14c73efd)
|
||||||
|
- fix(downloader): private playlist download [`1d5b299`](https://github.com/th-ch/youtube-music/commit/1d5b2997bd0c72c1c007c57b145509e4a8f77fef)
|
||||||
|
|
||||||
|
#### [v2.0.3](https://github.com/th-ch/youtube-music/compare/v2.0.2...v2.0.3)
|
||||||
|
|
||||||
|
> 10 October 2023
|
||||||
|
|
||||||
|
- feat(discord): add `Hide GitHub link Button` [`#1293`](https://github.com/th-ch/youtube-music/pull/1293)
|
||||||
|
- feat(deps): bundle `youtubei.js` (temporary solution) [`#1292`](https://github.com/th-ch/youtube-music/pull/1292)
|
||||||
|
- fix(mpris): fixed an issue where MPRIS information was incorrect [`#1291`](https://github.com/th-ch/youtube-music/pull/1291)
|
||||||
|
- fix(discord): fixed an issue where `timeChanged` was not being applied to Discord activities [`#1290`](https://github.com/th-ch/youtube-music/pull/1290)
|
||||||
|
- Fix: typo in README [`#1286`](https://github.com/th-ch/youtube-music/pull/1286)
|
||||||
|
- fix: chore(deps): update dependency @jellybrick/mpris-service to 2.1.4 (fix #971) [`#971`](https://github.com/th-ch/youtube-music/issues/971)
|
||||||
|
- chore(deps): Bump `@cliqz/adblocker-electron` to 1.26.8 (fix #1269) [`#1269`](https://github.com/th-ch/youtube-music/issues/1269)
|
||||||
|
- fix: missing icons taskbar-mediacontrol [`fbf4b3b`](https://github.com/th-ch/youtube-music/commit/fbf4b3b8b5e39c61975e67efc990c45f62de76d8)
|
||||||
|
- remove: migration scripts [`52ba2dc`](https://github.com/th-ch/youtube-music/commit/52ba2dc9ffd8e235251d1279686f55e33b3fa3bb)
|
||||||
|
- feat: add migration script [`926b9fb`](https://github.com/th-ch/youtube-music/commit/926b9fb5e6db69b69935ec5d7be9a76a84e54ceb)
|
||||||
|
|
||||||
#### [v2.0.2](https://github.com/th-ch/youtube-music/compare/v2.0.1...v2.0.2)
|
#### [v2.0.2](https://github.com/th-ch/youtube-music/compare/v2.0.1...v2.0.2)
|
||||||
|
|
||||||
|
> 8 October 2023
|
||||||
|
|
||||||
- fix: discord-rpc [`#1278`](https://github.com/th-ch/youtube-music/pull/1278)
|
- fix: discord-rpc [`#1278`](https://github.com/th-ch/youtube-music/pull/1278)
|
||||||
- Bump version to 2.0.2 [`b5dbfaf`](https://github.com/th-ch/youtube-music/commit/b5dbfaf68691a546d72f5c1818fd3a44802eb0fa)
|
- Bump version to 2.0.2 [`b5dbfaf`](https://github.com/th-ch/youtube-music/commit/b5dbfaf68691a546d72f5c1818fd3a44802eb0fa)
|
||||||
- Merge pull request #1272 from th-ch/feat/resolves-1265 [`6b7fd5b`](https://github.com/th-ch/youtube-music/commit/6b7fd5ba630888de08004105179c059c6d93e028)
|
- Merge pull request #1272 from th-ch/feat/resolves-1265 [`6b7fd5b`](https://github.com/th-ch/youtube-music/commit/6b7fd5ba630888de08004105179c059c6d93e028)
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import { blockers } from '../plugins/adblocker/blocker-types';
|
import { blockers } from '../plugins/adblocker/blocker-types';
|
||||||
|
|
||||||
|
import { DefaultPresetList } from '../plugins/downloader/types';
|
||||||
|
|
||||||
export interface WindowSizeConfig {
|
export interface WindowSizeConfig {
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
@ -111,14 +113,19 @@ const defaultConfig = {
|
|||||||
},
|
},
|
||||||
'downloader': {
|
'downloader': {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
ffmpegArgs: ['-b:a', '256k'], // E.g. ["-b:a", "192k"] for an audio bitrate of 192kb/s
|
|
||||||
downloadFolder: undefined as string | undefined, // Custom download folder (absolute path)
|
downloadFolder: undefined as string | undefined, // Custom download folder (absolute path)
|
||||||
preset: 'mp3',
|
selectedPreset: 'mp3 (256kbps)', // Selected preset
|
||||||
|
customPresetSetting: DefaultPresetList['mp3 (256kbps)'], // Presets
|
||||||
skipExisting: false,
|
skipExisting: false,
|
||||||
playlistMaxItems: undefined as number | undefined,
|
playlistMaxItems: undefined as number | undefined,
|
||||||
},
|
},
|
||||||
'exponential-volume': {},
|
'exponential-volume': {},
|
||||||
'in-app-menu': {},
|
'in-app-menu': {
|
||||||
|
/**
|
||||||
|
* true in Windows, false in Linux and macOS (see youtube-music/config/store.ts)
|
||||||
|
*/
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
'last-fm': {
|
'last-fm': {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
token: undefined as string | undefined, // Token used for authentication
|
token: undefined as string | undefined, // Token used for authentication
|
||||||
|
|||||||
@ -1,8 +1,18 @@
|
|||||||
import Store from 'electron-store';
|
import Store from 'electron-store';
|
||||||
import Conf from 'conf';
|
import Conf from 'conf';
|
||||||
|
import is from 'electron-is';
|
||||||
|
|
||||||
import defaults from './defaults';
|
import defaults from './defaults';
|
||||||
|
|
||||||
|
import { DefaultPresetList, type Preset } from '../plugins/downloader/types';
|
||||||
|
|
||||||
|
const getDefaults = () => {
|
||||||
|
if (is.windows()) {
|
||||||
|
defaults.plugins['in-app-menu'].enabled = true;
|
||||||
|
}
|
||||||
|
return defaults;
|
||||||
|
};
|
||||||
|
|
||||||
const setDefaultPluginOptions = (store: Conf<Record<string, unknown>>, plugin: keyof typeof defaults.plugins) => {
|
const setDefaultPluginOptions = (store: Conf<Record<string, unknown>>, plugin: keyof typeof defaults.plugins) => {
|
||||||
if (!store.get(`plugins.${plugin}`)) {
|
if (!store.get(`plugins.${plugin}`)) {
|
||||||
store.set(`plugins.${plugin}`, defaults.plugins[plugin]);
|
store.set(`plugins.${plugin}`, defaults.plugins[plugin]);
|
||||||
@ -10,6 +20,26 @@ const setDefaultPluginOptions = (store: Conf<Record<string, unknown>>, plugin: k
|
|||||||
};
|
};
|
||||||
|
|
||||||
const migrations = {
|
const migrations = {
|
||||||
|
'>=2.1.0'(store: Conf<Record<string, unknown>>) {
|
||||||
|
const originalPreset = store.get('plugins.downloader.preset') as string | undefined;
|
||||||
|
if (originalPreset) {
|
||||||
|
if (originalPreset !== 'opus') {
|
||||||
|
store.set('plugins.downloader.selectedPreset', 'Custom');
|
||||||
|
store.set('plugins.downloader.customPresetSetting', {
|
||||||
|
extension: 'mp3',
|
||||||
|
ffmpegArgs: store.get('plugins.downloader.ffmpegArgs') as string[] ?? DefaultPresetList['mp3 (256kbps)'].ffmpegArgs,
|
||||||
|
} satisfies Preset);
|
||||||
|
} else {
|
||||||
|
store.set('plugins.downloader.selectedPreset', 'Source');
|
||||||
|
store.set('plugins.downloader.customPresetSetting', {
|
||||||
|
extension: null,
|
||||||
|
ffmpegArgs: store.get('plugins.downloader.ffmpegArgs') as string[] ?? [],
|
||||||
|
} satisfies Preset);
|
||||||
|
}
|
||||||
|
store.delete('plugins.downloader.preset');
|
||||||
|
store.delete('plugins.downloader.ffmpegArgs');
|
||||||
|
}
|
||||||
|
},
|
||||||
'>=1.20.0'(store: Conf<Record<string, unknown>>) {
|
'>=1.20.0'(store: Conf<Record<string, unknown>>) {
|
||||||
setDefaultPluginOptions(store, 'visualizer');
|
setDefaultPluginOptions(store, 'visualizer');
|
||||||
|
|
||||||
@ -118,7 +148,7 @@ const migrations = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default new Store({
|
export default new Store({
|
||||||
defaults,
|
defaults: getDefaults(),
|
||||||
clearInvalidConfig: false,
|
clearInvalidConfig: false,
|
||||||
migrations,
|
migrations,
|
||||||
});
|
});
|
||||||
|
|||||||
37
index.ts
37
index.ts
@ -1,16 +1,14 @@
|
|||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
|
|
||||||
import { BrowserWindow, app, screen, globalShortcut, session, shell, dialog, ipcMain } from 'electron';
|
import { BrowserWindow, app, screen, globalShortcut, session, shell, dialog, ipcMain } from 'electron';
|
||||||
import enhanceWebRequest from 'electron-better-web-request';
|
import enhanceWebRequest, { BetterSession } from '@jellybrick/electron-better-web-request';
|
||||||
import is from 'electron-is';
|
import is from 'electron-is';
|
||||||
import unhandled from 'electron-unhandled';
|
import unhandled from 'electron-unhandled';
|
||||||
import { autoUpdater } from 'electron-updater';
|
import { autoUpdater } from 'electron-updater';
|
||||||
import electronDebug from 'electron-debug';
|
import electronDebug from 'electron-debug';
|
||||||
|
|
||||||
import { BetterWebRequest } from 'electron-better-web-request/lib/electron-better-web-request';
|
|
||||||
|
|
||||||
import config from './config';
|
import config from './config';
|
||||||
import { setApplicationMenu } from './menu';
|
import { refreshMenu, setApplicationMenu } from './menu';
|
||||||
import { fileExists, injectCSS, injectCSSAsFile } from './plugins/utils';
|
import { fileExists, injectCSS, injectCSSAsFile } from './plugins/utils';
|
||||||
import { isTesting } from './utils/testing';
|
import { isTesting } from './utils/testing';
|
||||||
import { setUpTray } from './tray';
|
import { setUpTray } from './tray';
|
||||||
@ -144,7 +142,7 @@ if (is.windows()) {
|
|||||||
|
|
||||||
ipcMain.handle('get-main-plugin-names', () => Object.keys(mainPlugins));
|
ipcMain.handle('get-main-plugin-names', () => Object.keys(mainPlugins));
|
||||||
|
|
||||||
function loadPlugins(win: BrowserWindow) {
|
async function loadPlugins(win: BrowserWindow) {
|
||||||
injectCSS(win.webContents, youtubeMusicCSS);
|
injectCSS(win.webContents, youtubeMusicCSS);
|
||||||
// Load user CSS
|
// Load user CSS
|
||||||
const themes: string[] = config.get('options.themes');
|
const themes: string[] = config.get('options.themes');
|
||||||
@ -175,7 +173,7 @@ function loadPlugins(win: BrowserWindow) {
|
|||||||
console.log('Loaded plugin - ' + plugin);
|
console.log('Loaded plugin - ' + plugin);
|
||||||
const handler = mainPlugins[plugin as keyof typeof mainPlugins];
|
const handler = mainPlugins[plugin as keyof typeof mainPlugins];
|
||||||
if (handler) {
|
if (handler) {
|
||||||
handler(win, options as never);
|
await handler(win, options as never);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -184,7 +182,7 @@ function loadPlugins(win: BrowserWindow) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMainWindow() {
|
async function createMainWindow() {
|
||||||
const windowSize = config.get('window-size');
|
const windowSize = config.get('window-size');
|
||||||
const windowMaximized = config.get('window-maximized');
|
const windowMaximized = config.get('window-maximized');
|
||||||
const windowPosition: Electron.Point = config.get('window-position');
|
const windowPosition: Electron.Point = config.get('window-position');
|
||||||
@ -223,7 +221,7 @@ function createMainWindow() {
|
|||||||
: 'default'),
|
: 'default'),
|
||||||
autoHideMenuBar: config.get('options.hideMenu'),
|
autoHideMenuBar: config.get('options.hideMenu'),
|
||||||
});
|
});
|
||||||
loadPlugins(win);
|
await loadPlugins(win);
|
||||||
|
|
||||||
if (windowPosition) {
|
if (windowPosition) {
|
||||||
const { x: windowX, y: windowY } = windowPosition;
|
const { x: windowX, y: windowY } = windowPosition;
|
||||||
@ -258,7 +256,6 @@ function createMainWindow() {
|
|||||||
const urlToLoad = config.get('options.resumeOnStart')
|
const urlToLoad = config.get('options.resumeOnStart')
|
||||||
? config.get('url')
|
? config.get('url')
|
||||||
: config.defaultConfig.url;
|
: config.defaultConfig.url;
|
||||||
win.webContents.loadURL(urlToLoad);
|
|
||||||
win.on('closed', onClosed);
|
win.on('closed', onClosed);
|
||||||
|
|
||||||
type PiPOptions = typeof config.defaultConfig.plugins['picture-in-picture'];
|
type PiPOptions = typeof config.defaultConfig.plugins['picture-in-picture'];
|
||||||
@ -338,6 +335,8 @@ function createMainWindow() {
|
|||||||
|
|
||||||
removeContentSecurityPolicy();
|
removeContentSecurityPolicy();
|
||||||
|
|
||||||
|
win.webContents.loadURL(urlToLoad);
|
||||||
|
|
||||||
return win;
|
return win;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,7 +393,7 @@ app.once('browser-window-created', (event, win) => {
|
|||||||
console.log(log);
|
console.log(log);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(config.plugins.isEnabled('in-app-menu') && errorCode === -3)) { // -3 is a false positive with in-app-menu
|
if (errorCode !== -3) { // -3 is a false positive
|
||||||
win.webContents.send('log', log);
|
win.webContents.send('log', log);
|
||||||
win.webContents.loadFile(path.join(__dirname, 'error.html'));
|
win.webContents.loadFile(path.join(__dirname, 'error.html'));
|
||||||
}
|
}
|
||||||
@ -414,17 +413,17 @@ app.on('window-all-closed', () => {
|
|||||||
globalShortcut.unregisterAll();
|
globalShortcut.unregisterAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
app.on('activate', () => {
|
app.on('activate', async () => {
|
||||||
// On OS X it's common to re-create a window in the app when the
|
// On OS X it's common to re-create a window in the app when the
|
||||||
// dock icon is clicked and there are no other windows open.
|
// dock icon is clicked and there are no other windows open.
|
||||||
if (mainWindow === null) {
|
if (mainWindow === null) {
|
||||||
mainWindow = createMainWindow();
|
mainWindow = await createMainWindow();
|
||||||
} else if (!mainWindow.isVisible()) {
|
} else if (!mainWindow.isVisible()) {
|
||||||
mainWindow.show();
|
mainWindow.show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.on('ready', () => {
|
app.on('ready', async () => {
|
||||||
if (config.get('options.autoResetAppCache')) {
|
if (config.get('options.autoResetAppCache')) {
|
||||||
// Clear cache after 20s
|
// Clear cache after 20s
|
||||||
const clearCacheTimeout = setTimeout(() => {
|
const clearCacheTimeout = setTimeout(() => {
|
||||||
@ -469,8 +468,9 @@ app.on('ready', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mainWindow = createMainWindow();
|
mainWindow = await createMainWindow();
|
||||||
setApplicationMenu(mainWindow);
|
setApplicationMenu(mainWindow);
|
||||||
|
refreshMenu(mainWindow);
|
||||||
setUpTray(app, mainWindow);
|
setUpTray(app, mainWindow);
|
||||||
|
|
||||||
setupProtocolHandler(mainWindow);
|
setupProtocolHandler(mainWindow);
|
||||||
@ -602,8 +602,6 @@ function showUnresponsiveDialog(win: BrowserWindow, details: Electron.RenderProc
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// HACK: electron-better-web-request's typing is wrong
|
|
||||||
type BetterSession = Omit<Electron.Session, 'webRequest'> & { webRequest: BetterWebRequest & Electron.WebRequest };
|
|
||||||
function removeContentSecurityPolicy(
|
function removeContentSecurityPolicy(
|
||||||
betterSession: BetterSession = session.defaultSession as BetterSession,
|
betterSession: BetterSession = session.defaultSession as BetterSession,
|
||||||
) {
|
) {
|
||||||
@ -623,11 +621,10 @@ function removeContentSecurityPolicy(
|
|||||||
callback({ cancel: false, responseHeaders: details.responseHeaders });
|
callback({ cancel: false, responseHeaders: details.responseHeaders });
|
||||||
});
|
});
|
||||||
|
|
||||||
type ResolverListener = { apply: () => Promise<Record<string, unknown>>; context: unknown };
|
|
||||||
// When multiple listeners are defined, apply them all
|
// When multiple listeners are defined, apply them all
|
||||||
betterSession.webRequest.setResolver('onHeadersReceived', async (listeners: ResolverListener[]) => {
|
betterSession.webRequest.setResolver('onHeadersReceived', async (listeners) => {
|
||||||
return listeners.reduce<Promise<Record<string, unknown>>>(
|
return listeners.reduce(
|
||||||
async (accumulator: Promise<Record<string, unknown>>, listener: ResolverListener) => {
|
async (accumulator, listener) => {
|
||||||
const acc = await accumulator;
|
const acc = await accumulator;
|
||||||
if (acc.cancel) {
|
if (acc.cancel) {
|
||||||
return acc;
|
return acc;
|
||||||
|
|||||||
20
menu.ts
20
menu.ts
@ -62,13 +62,15 @@ const pluginEnabledMenu = (plugin: string, label = '', hasSubmenu = false, refre
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const refreshMenu = (win: BrowserWindow) => {
|
||||||
|
setApplicationMenu(win);
|
||||||
|
if (inAppMenuActive) {
|
||||||
|
win.webContents.send('refreshMenu');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const mainMenuTemplate = (win: BrowserWindow): MenuTemplate => {
|
export const mainMenuTemplate = (win: BrowserWindow): MenuTemplate => {
|
||||||
const refreshMenu = () => {
|
const innerRefreshMenu = () => refreshMenu(win);
|
||||||
setApplicationMenu(win);
|
|
||||||
if (inAppMenuActive) {
|
|
||||||
win.webContents.send('refreshMenu');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@ -84,15 +86,15 @@ export const mainMenuTemplate = (win: BrowserWindow): MenuTemplate => {
|
|||||||
const getPluginMenu = pluginMenus[pluginName as keyof typeof pluginMenus];
|
const getPluginMenu = pluginMenus[pluginName as keyof typeof pluginMenus];
|
||||||
|
|
||||||
if (!config.plugins.isEnabled(pluginName)) {
|
if (!config.plugins.isEnabled(pluginName)) {
|
||||||
return pluginEnabledMenu(pluginName, pluginLabel, true, refreshMenu);
|
return pluginEnabledMenu(pluginName, pluginLabel, true, innerRefreshMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
label: pluginLabel,
|
label: pluginLabel,
|
||||||
submenu: [
|
submenu: [
|
||||||
pluginEnabledMenu(pluginName, 'Enabled', true, refreshMenu),
|
pluginEnabledMenu(pluginName, 'Enabled', true, innerRefreshMenu),
|
||||||
{ type: 'separator' },
|
{ type: 'separator' },
|
||||||
...getPluginMenu(win, config.plugins.getOptions(pluginName), refreshMenu),
|
...getPluginMenu(win, config.plugins.getOptions(pluginName), innerRefreshMenu),
|
||||||
],
|
],
|
||||||
} satisfies Electron.MenuItemConstructorOptions;
|
} satisfies Electron.MenuItemConstructorOptions;
|
||||||
}
|
}
|
||||||
|
|||||||
408
package-lock.json
generated
408
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "youtube-music",
|
"name": "youtube-music",
|
||||||
"version": "2.0.3",
|
"version": "2.1.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "youtube-music",
|
"name": "youtube-music",
|
||||||
"version": "2.0.3",
|
"version": "2.1.0",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -14,14 +14,14 @@
|
|||||||
"@ffmpeg.wasm/core-mt": "0.12.0",
|
"@ffmpeg.wasm/core-mt": "0.12.0",
|
||||||
"@ffmpeg.wasm/main": "0.12.0",
|
"@ffmpeg.wasm/main": "0.12.0",
|
||||||
"@foobar404/wave": "2.0.4",
|
"@foobar404/wave": "2.0.4",
|
||||||
|
"@jellybrick/electron-better-web-request": "1.0.4",
|
||||||
"@jellybrick/mpris-service": "2.1.4",
|
"@jellybrick/mpris-service": "2.1.4",
|
||||||
"@xhayper/discord-rpc": "1.0.23",
|
"@xhayper/discord-rpc": "1.0.23",
|
||||||
"async-mutex": "0.4.0",
|
"async-mutex": "0.4.0",
|
||||||
"butterchurn": "2.6.7",
|
"butterchurn": "3.0.0-beta.4",
|
||||||
"butterchurn-presets": "2.4.7",
|
"butterchurn-presets": "3.0.0-beta.4",
|
||||||
"conf": "10.2.0",
|
"conf": "10.2.0",
|
||||||
"custom-electron-prompt": "1.5.7",
|
"custom-electron-prompt": "1.5.7",
|
||||||
"electron-better-web-request": "1.0.1",
|
|
||||||
"electron-debug": "3.2.0",
|
"electron-debug": "3.2.0",
|
||||||
"electron-is": "3.0.0",
|
"electron-is": "3.0.0",
|
||||||
"electron-localshortcut": "3.2.1",
|
"electron-localshortcut": "3.2.1",
|
||||||
@ -35,14 +35,14 @@
|
|||||||
"keyboardevent-from-electron-accelerator": "2.0.0",
|
"keyboardevent-from-electron-accelerator": "2.0.0",
|
||||||
"keyboardevents-areequal": "0.2.2",
|
"keyboardevents-areequal": "0.2.2",
|
||||||
"node-id3": "0.2.6",
|
"node-id3": "0.2.6",
|
||||||
"simple-youtube-age-restriction-bypass": "git+https://github.com/MiepHD/Simple-YouTube-Age-Restriction-Bypass.git#v2.5.5",
|
"simple-youtube-age-restriction-bypass": "git+https://github.com/organization/Simple-YouTube-Age-Restriction-Bypass.git#v2.5.8",
|
||||||
"vudio": "2.1.1",
|
"vudio": "2.1.1",
|
||||||
"x11": "2.3.0",
|
"x11": "2.3.0",
|
||||||
"youtubei.js": "6.4.1",
|
"youtubei.js": "6.4.1",
|
||||||
"ytpl": "2.3.0"
|
"ytpl": "2.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "1.38.1",
|
"@playwright/test": "1.39.0",
|
||||||
"@rollup/plugin-commonjs": "25.0.5",
|
"@rollup/plugin-commonjs": "25.0.5",
|
||||||
"@rollup/plugin-image": "3.0.3",
|
"@rollup/plugin-image": "3.0.3",
|
||||||
"@rollup/plugin-json": "6.0.1",
|
"@rollup/plugin-json": "6.0.1",
|
||||||
@ -54,21 +54,21 @@
|
|||||||
"@types/electron-localshortcut": "3.1.1",
|
"@types/electron-localshortcut": "3.1.1",
|
||||||
"@types/howler": "2.2.9",
|
"@types/howler": "2.2.9",
|
||||||
"@types/html-to-text": "9.0.2",
|
"@types/html-to-text": "9.0.2",
|
||||||
"@typescript-eslint/eslint-plugin": "6.7.4",
|
"@typescript-eslint/eslint-plugin": "6.7.5",
|
||||||
"auto-changelog": "2.4.0",
|
"auto-changelog": "2.4.0",
|
||||||
"del-cli": "5.1.0",
|
"del-cli": "5.1.0",
|
||||||
"electron": "27.0.0-beta.9",
|
"electron": "27.0.0",
|
||||||
"electron-builder": "24.6.4",
|
"electron-builder": "24.6.4",
|
||||||
"electron-devtools-installer": "3.2.0",
|
"electron-devtools-installer": "3.2.0",
|
||||||
"eslint": "8.51.0",
|
"eslint": "8.51.0",
|
||||||
"eslint-plugin-import": "2.28.1",
|
"eslint-plugin-import": "2.28.1",
|
||||||
"eslint-plugin-prettier": "5.0.0",
|
"eslint-plugin-prettier": "5.0.1",
|
||||||
"node-gyp": "9.4.0",
|
"node-gyp": "9.4.0",
|
||||||
"patch-package": "8.0.0",
|
"patch-package": "8.0.0",
|
||||||
"playwright": "1.38.1",
|
"playwright": "1.39.0",
|
||||||
"rollup": "4.0.2",
|
"rollup": "4.0.2",
|
||||||
"rollup-plugin-copy": "3.5.0",
|
"rollup-plugin-copy": "3.5.0",
|
||||||
"rollup-plugin-import-css": "3.3.4",
|
"rollup-plugin-import-css": "3.3.5",
|
||||||
"rollup-plugin-string": "3.0.0",
|
"rollup-plugin-string": "3.0.0",
|
||||||
"typescript": "5.2.2"
|
"typescript": "5.2.2"
|
||||||
},
|
},
|
||||||
@ -85,6 +85,11 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@assemblyscript/loader": {
|
||||||
|
"version": "0.17.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.17.14.tgz",
|
||||||
|
"integrity": "sha512-+PVTOfla/0XMLRTQLJFPg4u40XcdTfon6GGea70hBGi8Pd7ZymIXyVUR+vK8wt5Jb4MVKTKPIz43Myyebw5mZA=="
|
||||||
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
"version": "7.22.13",
|
"version": "7.22.13",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
|
||||||
@ -264,9 +269,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/runtime": {
|
"node_modules/@babel/runtime": {
|
||||||
"version": "7.23.1",
|
"version": "7.23.2",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.1.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz",
|
||||||
"integrity": "sha512-hC2v6p8ZSI/W0HUzh3V8C5g+NwSKzKPtJwSpTjwl0o297GP9+ZLQSkdvHz46CM3LqyoXxq+5G9komY+eSqSO0g==",
|
"integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"regenerator-runtime": "^0.14.0"
|
"regenerator-runtime": "^0.14.0"
|
||||||
},
|
},
|
||||||
@ -882,6 +887,27 @@
|
|||||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@jellybrick/electron-better-web-request": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@jellybrick/electron-better-web-request/-/electron-better-web-request-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-vL2lv7Gz8BWgCpwXb3ha17oaEmJqG5ZLdVWssAkA/0PGPMCWH2lLWq7vDymyTswmZ+zKpfOdzwTomvMqn9nElg==",
|
||||||
|
"dependencies": {
|
||||||
|
"browser-extension-url-match": "^1.0.0",
|
||||||
|
"uuid": "^9.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@jellybrick/electron-better-web-request/node_modules/uuid": {
|
||||||
|
"version": "9.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
|
||||||
|
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
|
||||||
|
"funding": [
|
||||||
|
"https://github.com/sponsors/broofa",
|
||||||
|
"https://github.com/sponsors/ctavan"
|
||||||
|
],
|
||||||
|
"bin": {
|
||||||
|
"uuid": "dist/bin/uuid"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@jellybrick/mpris-service": {
|
"node_modules/@jellybrick/mpris-service": {
|
||||||
"version": "2.1.4",
|
"version": "2.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@jellybrick/mpris-service/-/mpris-service-2.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@jellybrick/mpris-service/-/mpris-service-2.1.4.tgz",
|
||||||
@ -1137,12 +1163,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@playwright/test": {
|
"node_modules/@playwright/test": {
|
||||||
"version": "1.38.1",
|
"version": "1.39.0",
|
||||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.38.1.tgz",
|
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.39.0.tgz",
|
||||||
"integrity": "sha512-NqRp8XMwj3AK+zKLbZShl0r/9wKgzqI/527bkptKXomtuo+dOjU9NdMASQ8DNC9z9zLOMbG53T4eihYr3XR+BQ==",
|
"integrity": "sha512-3u1iFqgzl7zr004bGPYiN/5EZpRUSFddQBra8Rqll5N0/vfpqlP9I9EXqAoGacuAbX6c9Ulg/Cjqglp5VkK6UQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"playwright": "1.38.1"
|
"playwright": "1.39.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright": "cli.js"
|
"playwright": "cli.js"
|
||||||
@ -1774,16 +1800,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "6.7.4",
|
"version": "6.7.5",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.5.tgz",
|
||||||
"integrity": "sha512-DAbgDXwtX+pDkAHwiGhqP3zWUGpW49B7eqmgpPtg+BKJXwdct79ut9+ifqOFPJGClGKSHXn2PTBatCnldJRUoA==",
|
"integrity": "sha512-JhtAwTRhOUcP96D0Y6KYnwig/MRQbOoLGXTON2+LlyB/N35SP9j1boai2zzwXb7ypKELXMx3DVk9UTaEq1vHEw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.5.1",
|
"@eslint-community/regexpp": "^4.5.1",
|
||||||
"@typescript-eslint/scope-manager": "6.7.4",
|
"@typescript-eslint/scope-manager": "6.7.5",
|
||||||
"@typescript-eslint/type-utils": "6.7.4",
|
"@typescript-eslint/type-utils": "6.7.5",
|
||||||
"@typescript-eslint/utils": "6.7.4",
|
"@typescript-eslint/utils": "6.7.5",
|
||||||
"@typescript-eslint/visitor-keys": "6.7.4",
|
"@typescript-eslint/visitor-keys": "6.7.5",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"graphemer": "^1.4.0",
|
"graphemer": "^1.4.0",
|
||||||
"ignore": "^5.2.4",
|
"ignore": "^5.2.4",
|
||||||
@ -1808,6 +1834,53 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": {
|
||||||
|
"version": "6.7.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.5.tgz",
|
||||||
|
"integrity": "sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "6.7.5",
|
||||||
|
"@typescript-eslint/visitor-keys": "6.7.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": {
|
||||||
|
"version": "6.7.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.5.tgz",
|
||||||
|
"integrity": "sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": {
|
||||||
|
"version": "6.7.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz",
|
||||||
|
"integrity": "sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "6.7.5",
|
||||||
|
"eslint-visitor-keys": "^3.4.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "6.7.4",
|
"version": "6.7.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.4.tgz",
|
||||||
@ -1842,6 +1915,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.4.tgz",
|
||||||
"integrity": "sha512-SdGqSLUPTXAXi7c3Ob7peAGVnmMoGzZ361VswK2Mqf8UOYcODiYvs8rs5ILqEdfvX1lE7wEZbLyELCW+Yrql1A==",
|
"integrity": "sha512-SdGqSLUPTXAXi7c3Ob7peAGVnmMoGzZ361VswK2Mqf8UOYcODiYvs8rs5ILqEdfvX1lE7wEZbLyELCW+Yrql1A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "6.7.4",
|
"@typescript-eslint/types": "6.7.4",
|
||||||
"@typescript-eslint/visitor-keys": "6.7.4"
|
"@typescript-eslint/visitor-keys": "6.7.4"
|
||||||
@ -1855,13 +1929,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "6.7.4",
|
"version": "6.7.5",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.5.tgz",
|
||||||
"integrity": "sha512-n+g3zi1QzpcAdHFP9KQF+rEFxMb2KxtnJGID3teA/nxKHOVi3ylKovaqEzGBbVY2pBttU6z85gp0D00ufLzViQ==",
|
"integrity": "sha512-Gs0qos5wqxnQrvpYv+pf3XfcRXW6jiAn9zE/K+DlmYf6FcpxeNYN0AIETaPR7rHO4K2UY+D0CIbDP9Ut0U4m1g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/typescript-estree": "6.7.4",
|
"@typescript-eslint/typescript-estree": "6.7.5",
|
||||||
"@typescript-eslint/utils": "6.7.4",
|
"@typescript-eslint/utils": "6.7.5",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"ts-api-utils": "^1.0.1"
|
"ts-api-utils": "^1.0.1"
|
||||||
},
|
},
|
||||||
@ -1881,11 +1955,69 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": {
|
||||||
|
"version": "6.7.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.5.tgz",
|
||||||
|
"integrity": "sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": {
|
||||||
|
"version": "6.7.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.5.tgz",
|
||||||
|
"integrity": "sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "6.7.5",
|
||||||
|
"@typescript-eslint/visitor-keys": "6.7.5",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"globby": "^11.1.0",
|
||||||
|
"is-glob": "^4.0.3",
|
||||||
|
"semver": "^7.5.4",
|
||||||
|
"ts-api-utils": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"typescript": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": {
|
||||||
|
"version": "6.7.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz",
|
||||||
|
"integrity": "sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "6.7.5",
|
||||||
|
"eslint-visitor-keys": "^3.4.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "6.7.4",
|
"version": "6.7.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.4.tgz",
|
||||||
"integrity": "sha512-o9XWK2FLW6eSS/0r/tgjAGsYasLAnOWg7hvZ/dGYSSNjCh+49k5ocPN8OmG5aZcSJ8pclSOyVKP2x03Sj+RrCA==",
|
"integrity": "sha512-o9XWK2FLW6eSS/0r/tgjAGsYasLAnOWg7hvZ/dGYSSNjCh+49k5ocPN8OmG5aZcSJ8pclSOyVKP2x03Sj+RrCA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^16.0.0 || >=18.0.0"
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
},
|
},
|
||||||
@ -1899,6 +2031,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.4.tgz",
|
||||||
"integrity": "sha512-ty8b5qHKatlNYd9vmpHooQz3Vki3gG+3PchmtsA4TgrZBKWHNjWfkQid7K7xQogBqqc7/BhGazxMD5vr6Ha+iQ==",
|
"integrity": "sha512-ty8b5qHKatlNYd9vmpHooQz3Vki3gG+3PchmtsA4TgrZBKWHNjWfkQid7K7xQogBqqc7/BhGazxMD5vr6Ha+iQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "6.7.4",
|
"@typescript-eslint/types": "6.7.4",
|
||||||
"@typescript-eslint/visitor-keys": "6.7.4",
|
"@typescript-eslint/visitor-keys": "6.7.4",
|
||||||
@ -1922,17 +2055,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/utils": {
|
"node_modules/@typescript-eslint/utils": {
|
||||||
"version": "6.7.4",
|
"version": "6.7.5",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.5.tgz",
|
||||||
"integrity": "sha512-PRQAs+HUn85Qdk+khAxsVV+oULy3VkbH3hQ8hxLRJXWBEd7iI+GbQxH5SEUSH7kbEoTp6oT1bOwyga24ELALTA==",
|
"integrity": "sha512-pfRRrH20thJbzPPlPc4j0UNGvH1PjPlhlCMq4Yx7EGjV7lvEeGX0U6MJYe8+SyFutWgSHsdbJ3BXzZccYggezA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.4.0",
|
"@eslint-community/eslint-utils": "^4.4.0",
|
||||||
"@types/json-schema": "^7.0.12",
|
"@types/json-schema": "^7.0.12",
|
||||||
"@types/semver": "^7.5.0",
|
"@types/semver": "^7.5.0",
|
||||||
"@typescript-eslint/scope-manager": "6.7.4",
|
"@typescript-eslint/scope-manager": "6.7.5",
|
||||||
"@typescript-eslint/types": "6.7.4",
|
"@typescript-eslint/types": "6.7.5",
|
||||||
"@typescript-eslint/typescript-estree": "6.7.4",
|
"@typescript-eslint/typescript-estree": "6.7.5",
|
||||||
"semver": "^7.5.4"
|
"semver": "^7.5.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@ -1946,11 +2079,86 @@
|
|||||||
"eslint": "^7.0.0 || ^8.0.0"
|
"eslint": "^7.0.0 || ^8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": {
|
||||||
|
"version": "6.7.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.5.tgz",
|
||||||
|
"integrity": "sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "6.7.5",
|
||||||
|
"@typescript-eslint/visitor-keys": "6.7.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": {
|
||||||
|
"version": "6.7.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.5.tgz",
|
||||||
|
"integrity": "sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": {
|
||||||
|
"version": "6.7.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.5.tgz",
|
||||||
|
"integrity": "sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "6.7.5",
|
||||||
|
"@typescript-eslint/visitor-keys": "6.7.5",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"globby": "^11.1.0",
|
||||||
|
"is-glob": "^4.0.3",
|
||||||
|
"semver": "^7.5.4",
|
||||||
|
"ts-api-utils": "^1.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"typescript": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": {
|
||||||
|
"version": "6.7.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz",
|
||||||
|
"integrity": "sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/types": "6.7.5",
|
||||||
|
"eslint-visitor-keys": "^3.4.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^16.0.0 || >=18.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "6.7.4",
|
"version": "6.7.4",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.4.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.4.tgz",
|
||||||
"integrity": "sha512-pOW37DUhlTZbvph50x5zZCkFn3xzwkGtNoJHzIM3svpiSkJzwOYr/kVBaXmf+RAQiUDs1AHEZVNPg6UJCJpwRA==",
|
"integrity": "sha512-pOW37DUhlTZbvph50x5zZCkFn3xzwkGtNoJHzIM3svpiSkJzwOYr/kVBaXmf+RAQiUDs1AHEZVNPg6UJCJpwRA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "6.7.4",
|
"@typescript-eslint/types": "6.7.4",
|
||||||
"eslint-visitor-keys": "^3.4.1"
|
"eslint-visitor-keys": "^3.4.1"
|
||||||
@ -2543,20 +2751,6 @@
|
|||||||
"proxy-from-env": "^1.1.0"
|
"proxy-from-env": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/babel-runtime": {
|
|
||||||
"version": "6.26.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
|
|
||||||
"integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==",
|
|
||||||
"dependencies": {
|
|
||||||
"core-js": "^2.4.0",
|
|
||||||
"regenerator-runtime": "^0.11.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/babel-runtime/node_modules/regenerator-runtime": {
|
|
||||||
"version": "0.11.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
|
|
||||||
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
|
|
||||||
},
|
|
||||||
"node_modules/balanced-match": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
@ -2656,6 +2850,14 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/browser-extension-url-match": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/browser-extension-url-match/-/browser-extension-url-match-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-LfIs9SYgPjYksjxkgOVYZhxMIroR56isQB3YHTAmzunWuT9qrH6Fxt7TD9/s9MoKo7GP37JZbLlZhL9vwQAk3w==",
|
||||||
|
"dependencies": {
|
||||||
|
"fancy-regex": "^0.5.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/buffer": {
|
"node_modules/buffer": {
|
||||||
"version": "5.7.1",
|
"version": "5.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
|
||||||
@ -2805,22 +3007,22 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/butterchurn": {
|
"node_modules/butterchurn": {
|
||||||
"version": "2.6.7",
|
"version": "3.0.0-beta.4",
|
||||||
"resolved": "https://registry.npmjs.org/butterchurn/-/butterchurn-2.6.7.tgz",
|
"resolved": "https://registry.npmjs.org/butterchurn/-/butterchurn-3.0.0-beta.4.tgz",
|
||||||
"integrity": "sha512-BJiRA8L0L2+84uoG2SSfkp0kclBuN+vQKf217pK7pMlwEO2ZEg3MtO2/o+l8Qpr8Nbejg8tmL1ZHD1jmhiaaqg==",
|
"integrity": "sha512-hiY1ktHYHQ8MT65nnZi7GjrgZZ6sl/ipT5rBqEfaYJd90L4SvOtB6lVxtKadtzAyJo2TQJc4gJfEca4cpZo0DA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.0.0",
|
"@assemblyscript/loader": "^0.17.11",
|
||||||
"ecma-proposal-math-extensions": "0.0.2"
|
"@babel/runtime": "^7.11.2",
|
||||||
|
"ecma-proposal-math-extensions": "0.0.2",
|
||||||
|
"eel-wasm": "^0.0.15"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/butterchurn-presets": {
|
"node_modules/butterchurn-presets": {
|
||||||
"version": "2.4.7",
|
"version": "3.0.0-beta.4",
|
||||||
"resolved": "https://registry.npmjs.org/butterchurn-presets/-/butterchurn-presets-2.4.7.tgz",
|
"resolved": "https://registry.npmjs.org/butterchurn-presets/-/butterchurn-presets-3.0.0-beta.4.tgz",
|
||||||
"integrity": "sha512-4MdM8ripz/VfH1BCldrIKdAc/1ryJFBDvqlyow6Ivo1frwj0H3duzvSMFC7/wIjAjxb1QpwVHVqGqS9uAFKhpg==",
|
"integrity": "sha512-TbQLUPvGOYMZAtWKoCmBtludh9aQZ6NaMGQU4lvPeadBPy3Du3yNmwBjlTMLP5c5mRWElxQPjTL1PtR7FZK3OQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"babel-runtime": "^6.26.0",
|
"@babel/runtime": "^7.12.5"
|
||||||
"ecma-proposal-math-extensions": "0.0.2",
|
|
||||||
"lodash": "^4.17.4"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/cacache": {
|
"node_modules/cacache": {
|
||||||
@ -3263,13 +3465,6 @@
|
|||||||
"integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
|
"integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
|
||||||
"devOptional": true
|
"devOptional": true
|
||||||
},
|
},
|
||||||
"node_modules/core-js": {
|
|
||||||
"version": "2.6.12",
|
|
||||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
|
|
||||||
"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==",
|
|
||||||
"deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.",
|
|
||||||
"hasInstallScript": true
|
|
||||||
},
|
|
||||||
"node_modules/core-util-is": {
|
"node_modules/core-util-is": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||||
@ -3849,6 +4044,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ecma-proposal-math-extensions/-/ecma-proposal-math-extensions-0.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/ecma-proposal-math-extensions/-/ecma-proposal-math-extensions-0.0.2.tgz",
|
||||||
"integrity": "sha512-80BnDp2Fn7RxXlEr5HHZblniY4aQ97MOAicdWWpSo0vkQiISSE9wLR4SqxKsu4gCtXFBIPPzy8JMhay4NWRg/Q=="
|
"integrity": "sha512-80BnDp2Fn7RxXlEr5HHZblniY4aQ97MOAicdWWpSo0vkQiISSE9wLR4SqxKsu4gCtXFBIPPzy8JMhay4NWRg/Q=="
|
||||||
},
|
},
|
||||||
|
"node_modules/eel-wasm": {
|
||||||
|
"version": "0.0.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/eel-wasm/-/eel-wasm-0.0.15.tgz",
|
||||||
|
"integrity": "sha512-FSTWf6lwGn7Zc3QiV+KxWTznIqq4j9eST/aXmyN/cC39+1Arqs13YOMosHQ7tqUt+OjQmG79Vd41f9gu+w1lvA=="
|
||||||
|
},
|
||||||
"node_modules/ejs": {
|
"node_modules/ejs": {
|
||||||
"version": "3.1.9",
|
"version": "3.1.9",
|
||||||
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz",
|
"resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz",
|
||||||
@ -3865,9 +4065,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/electron": {
|
"node_modules/electron": {
|
||||||
"version": "27.0.0-beta.9",
|
"version": "27.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/electron/-/electron-27.0.0-beta.9.tgz",
|
"resolved": "https://registry.npmjs.org/electron/-/electron-27.0.0.tgz",
|
||||||
"integrity": "sha512-4h78B843eYU2oh2yMjrwYtl5aVMiFdpurIwtoZvXpfTwyuKiEOQaylmLbi4+sPg1rCmqW/VLv9hfVlOqHDNj/Q==",
|
"integrity": "sha512-mr3Zoy82l8XKK/TgguE5FeNeHZ9KHXIGIpUMjbjZWIREfAv+X2Q3vdX6RG0Pmi1K23AFAxANXQezIHBA2Eypwg==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@electron/get": "^2.0.0",
|
"@electron/get": "^2.0.0",
|
||||||
@ -3881,15 +4081,6 @@
|
|||||||
"node": ">= 12.20.55"
|
"node": ">= 12.20.55"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/electron-better-web-request": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/electron-better-web-request/-/electron-better-web-request-1.0.1.tgz",
|
|
||||||
"integrity": "sha512-euwLeL82k6fbVODfH5Uz9c4BN047/XyYKfsZcaFhdWfqx05JPu2J0xE7nciJ/1Bb0sTClU1FDLW5H2zQWBB5Gw==",
|
|
||||||
"dependencies": {
|
|
||||||
"url-match-patterns": "^0.2.0",
|
|
||||||
"uuid": "^3.3.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/electron-builder": {
|
"node_modules/electron-builder": {
|
||||||
"version": "24.6.4",
|
"version": "24.6.4",
|
||||||
"resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-24.6.4.tgz",
|
"resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-24.6.4.tgz",
|
||||||
@ -4557,9 +4748,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-plugin-prettier": {
|
"node_modules/eslint-plugin-prettier": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz",
|
||||||
"integrity": "sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==",
|
"integrity": "sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"prettier-linter-helpers": "^1.0.0",
|
"prettier-linter-helpers": "^1.0.0",
|
||||||
@ -4808,6 +4999,11 @@
|
|||||||
],
|
],
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
"node_modules/fancy-regex": {
|
||||||
|
"version": "0.5.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/fancy-regex/-/fancy-regex-0.5.4.tgz",
|
||||||
|
"integrity": "sha512-O6qfjtMnrPRs+3XOavCxGQDFaMS9K1vEsQMhPowqx2P/h1fDCvK5RUyeWeyDusMH2FkSHAsRE3IbSBMMg53fmw=="
|
||||||
|
},
|
||||||
"node_modules/fast-average-color": {
|
"node_modules/fast-average-color": {
|
||||||
"version": "9.4.0",
|
"version": "9.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/fast-average-color/-/fast-average-color-9.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/fast-average-color/-/fast-average-color-9.4.0.tgz",
|
||||||
@ -6587,7 +6783,8 @@
|
|||||||
"node_modules/lodash": {
|
"node_modules/lodash": {
|
||||||
"version": "4.17.21",
|
"version": "4.17.21",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/lodash.debounce": {
|
"node_modules/lodash.debounce": {
|
||||||
"version": "4.0.8",
|
"version": "4.0.8",
|
||||||
@ -7863,12 +8060,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/playwright": {
|
"node_modules/playwright": {
|
||||||
"version": "1.38.1",
|
"version": "1.39.0",
|
||||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.38.1.tgz",
|
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.39.0.tgz",
|
||||||
"integrity": "sha512-oRMSJmZrOu1FP5iu3UrCx8JEFRIMxLDM0c/3o4bpzU5Tz97BypefWf7TuTNPWeCe279TPal5RtPPZ+9lW/Qkow==",
|
"integrity": "sha512-naE5QT11uC/Oiq0BwZ50gDmy8c8WLPRTEWuSSFVG2egBka/1qMoSqYQcROMT9zLwJ86oPofcTH2jBY/5wWOgIw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"playwright-core": "1.38.1"
|
"playwright-core": "1.39.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright": "cli.js"
|
"playwright": "cli.js"
|
||||||
@ -7881,9 +8078,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/playwright-core": {
|
"node_modules/playwright-core": {
|
||||||
"version": "1.38.1",
|
"version": "1.39.0",
|
||||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.38.1.tgz",
|
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.39.0.tgz",
|
||||||
"integrity": "sha512-tQqNFUKa3OfMf4b2jQ7aGLB8o9bS3bOY0yMEtldtC2+spf8QXG9zvXLTXUeRsoNuxEYMgLYR+NXfAa1rjKRcrg==",
|
"integrity": "sha512-+k4pdZgs1qiM+OUkSjx96YiKsXsmb59evFoqv8SKO067qBA+Z2s/dCzJij/ZhdQcs2zlTAgRKfeiiLm8PQ2qvw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright-core": "cli.js"
|
"playwright-core": "cli.js"
|
||||||
@ -8377,9 +8574,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup-plugin-import-css": {
|
"node_modules/rollup-plugin-import-css": {
|
||||||
"version": "3.3.4",
|
"version": "3.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/rollup-plugin-import-css/-/rollup-plugin-import-css-3.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/rollup-plugin-import-css/-/rollup-plugin-import-css-3.3.5.tgz",
|
||||||
"integrity": "sha512-w5p1Dd1CavAht/P82zB3WX2RVy7O47MlJGSmgrWXTBPAkWHTbOBh/nUPz94IczCD0HLxpuT4AhF24cix7CpZWA==",
|
"integrity": "sha512-wSfzveEzvUDlVevo70kmVD5Mk785UN55NG4C7VVnrmdE0qZ8apcVVFajyCPfFYSNxq5YkccOcrGUT2T/2HnEcQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rollup/pluginutils": "^5.0.4"
|
"@rollup/pluginutils": "^5.0.4"
|
||||||
@ -8388,7 +8585,7 @@
|
|||||||
"node": ">=16"
|
"node": ">=16"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"rollup": "^2.x.x || ^3.x.x"
|
"rollup": "^2.x.x || ^3.x.x || ^4.x.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup-plugin-string": {
|
"node_modules/rollup-plugin-string": {
|
||||||
@ -8744,7 +8941,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/simple-youtube-age-restriction-bypass": {
|
"node_modules/simple-youtube-age-restriction-bypass": {
|
||||||
"version": "2.5.9",
|
"version": "2.5.9",
|
||||||
"resolved": "git+ssh://git@github.com/MiepHD/Simple-YouTube-Age-Restriction-Bypass.git#79b9456c290df42f35f081413e18dc336d340724",
|
"resolved": "git+ssh://git@github.com/organization/Simple-YouTube-Age-Restriction-Bypass.git#816a882c68fcfe6cdd9410a6877b88093ed15b28",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"account-proxy"
|
"account-proxy"
|
||||||
@ -9601,14 +9798,6 @@
|
|||||||
"punycode": "^2.1.0"
|
"punycode": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/url-match-patterns": {
|
|
||||||
"version": "0.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/url-match-patterns/-/url-match-patterns-0.2.0.tgz",
|
|
||||||
"integrity": "sha512-vtaWyxq+CyrQP4/dapGddkSGwGypQOD2qjHcsqp9ahsjRWzGtjqm+ANxApH46OfWQfpkL6cuyPwsm80386jdjQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"lodash": "^4.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/usocket": {
|
"node_modules/usocket": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/usocket/-/usocket-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/usocket/-/usocket-0.3.0.tgz",
|
||||||
@ -9633,15 +9822,6 @@
|
|||||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||||
"devOptional": true
|
"devOptional": true
|
||||||
},
|
},
|
||||||
"node_modules/uuid": {
|
|
||||||
"version": "3.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
|
||||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
|
||||||
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
|
|
||||||
"bin": {
|
|
||||||
"uuid": "bin/uuid"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/validate-npm-package-license": {
|
"node_modules/validate-npm-package-license": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
|
||||||
|
|||||||
31
package.json
31
package.json
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "youtube-music",
|
"name": "youtube-music",
|
||||||
"productName": "YouTube Music",
|
"productName": "YouTube Music",
|
||||||
"version": "2.0.3",
|
"version": "2.1.0",
|
||||||
"description": "YouTube Music Desktop App - including custom plugins",
|
"description": "YouTube Music Desktop App - including custom plugins",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -21,8 +21,6 @@
|
|||||||
"!node_modules",
|
"!node_modules",
|
||||||
"node_modules/custom-electron-prompt/**",
|
"node_modules/custom-electron-prompt/**",
|
||||||
"node_modules/@cliqz/adblocker-electron-preload/**",
|
"node_modules/@cliqz/adblocker-electron-preload/**",
|
||||||
"node_modules/@cliqz/adblocker-content/**",
|
|
||||||
"node_modules/@cliqz/adblocker-extended-selectors/**",
|
|
||||||
"node_modules/@ffmpeg.wasm/core-mt/**",
|
"node_modules/@ffmpeg.wasm/core-mt/**",
|
||||||
"!node_modules/**/*.map",
|
"!node_modules/**/*.map",
|
||||||
"!node_modules/**/*.ts"
|
"!node_modules/**/*.ts"
|
||||||
@ -96,8 +94,7 @@
|
|||||||
"build": "npm run rollup:preload && npm run rollup:main",
|
"build": "npm run rollup:preload && npm run rollup:main",
|
||||||
"start": "npm run build && electron ./dist/index.js",
|
"start": "npm run build && electron ./dist/index.js",
|
||||||
"start:debug": "ELECTRON_ENABLE_LOGGING=1 npm run start",
|
"start:debug": "ELECTRON_ENABLE_LOGGING=1 npm run start",
|
||||||
"generate:package": "node utils/generate-package-json.js",
|
"postinstall": "patch-package",
|
||||||
"postinstall": "patch-package && npm run plugins && npm run clean",
|
|
||||||
"clean": "del-cli dist && del-cli pack",
|
"clean": "del-cli dist && del-cli pack",
|
||||||
"dist": "npm run clean && npm run build && electron-builder --win --mac --linux -p never",
|
"dist": "npm run clean && npm run build && electron-builder --win --mac --linux -p never",
|
||||||
"dist:linux": "npm run clean && npm run build && electron-builder --linux -p never",
|
"dist:linux": "npm run clean && npm run build && electron-builder --linux -p never",
|
||||||
@ -107,8 +104,6 @@
|
|||||||
"dist:win:x64": "npm run clean && npm run build && electron-builder --win nsis-web:x64 -p never",
|
"dist:win:x64": "npm run clean && npm run build && electron-builder --win nsis-web:x64 -p never",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"changelog": "auto-changelog",
|
"changelog": "auto-changelog",
|
||||||
"plugins": "npm run plugin:bypass-age-restrictions",
|
|
||||||
"plugin:bypass-age-restrictions": "del-cli node_modules/simple-youtube-age-restriction-bypass/package.json && npm run generate:package simple-youtube-age-restriction-bypass",
|
|
||||||
"release:linux": "npm run clean && npm run build && electron-builder --linux -p always -c.snap.publish=github",
|
"release:linux": "npm run clean && npm run build && electron-builder --linux -p always -c.snap.publish=github",
|
||||||
"release:mac": "npm run clean && npm run build && electron-builder --mac -p always",
|
"release:mac": "npm run clean && npm run build && electron-builder --mac -p always",
|
||||||
"release:win": "npm run clean && npm run build && electron-builder --win -p always",
|
"release:win": "npm run clean && npm run build && electron-builder --win -p always",
|
||||||
@ -122,14 +117,14 @@
|
|||||||
"@ffmpeg.wasm/core-mt": "0.12.0",
|
"@ffmpeg.wasm/core-mt": "0.12.0",
|
||||||
"@ffmpeg.wasm/main": "0.12.0",
|
"@ffmpeg.wasm/main": "0.12.0",
|
||||||
"@foobar404/wave": "2.0.4",
|
"@foobar404/wave": "2.0.4",
|
||||||
|
"@jellybrick/electron-better-web-request": "1.0.4",
|
||||||
"@jellybrick/mpris-service": "2.1.4",
|
"@jellybrick/mpris-service": "2.1.4",
|
||||||
"@xhayper/discord-rpc": "1.0.23",
|
"@xhayper/discord-rpc": "1.0.23",
|
||||||
"async-mutex": "0.4.0",
|
"async-mutex": "0.4.0",
|
||||||
"butterchurn": "2.6.7",
|
"butterchurn": "3.0.0-beta.4",
|
||||||
"butterchurn-presets": "2.4.7",
|
"butterchurn-presets": "3.0.0-beta.4",
|
||||||
"conf": "10.2.0",
|
"conf": "10.2.0",
|
||||||
"custom-electron-prompt": "1.5.7",
|
"custom-electron-prompt": "1.5.7",
|
||||||
"electron-better-web-request": "1.0.1",
|
|
||||||
"electron-debug": "3.2.0",
|
"electron-debug": "3.2.0",
|
||||||
"electron-is": "3.0.0",
|
"electron-is": "3.0.0",
|
||||||
"electron-localshortcut": "3.2.1",
|
"electron-localshortcut": "3.2.1",
|
||||||
@ -143,7 +138,7 @@
|
|||||||
"keyboardevent-from-electron-accelerator": "2.0.0",
|
"keyboardevent-from-electron-accelerator": "2.0.0",
|
||||||
"keyboardevents-areequal": "0.2.2",
|
"keyboardevents-areequal": "0.2.2",
|
||||||
"node-id3": "0.2.6",
|
"node-id3": "0.2.6",
|
||||||
"simple-youtube-age-restriction-bypass": "git+https://github.com/MiepHD/Simple-YouTube-Age-Restriction-Bypass.git#v2.5.5",
|
"simple-youtube-age-restriction-bypass": "git+https://github.com/organization/Simple-YouTube-Age-Restriction-Bypass.git#v2.5.8",
|
||||||
"vudio": "2.1.1",
|
"vudio": "2.1.1",
|
||||||
"x11": "2.3.0",
|
"x11": "2.3.0",
|
||||||
"youtubei.js": "6.4.1",
|
"youtubei.js": "6.4.1",
|
||||||
@ -155,10 +150,10 @@
|
|||||||
"xml2js": "0.6.2",
|
"xml2js": "0.6.2",
|
||||||
"node-fetch": "2.7.0",
|
"node-fetch": "2.7.0",
|
||||||
"@electron/universal": "1.4.2",
|
"@electron/universal": "1.4.2",
|
||||||
"electron": "27.0.0-beta.9"
|
"@babel/runtime": "7.23.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "1.38.1",
|
"@playwright/test": "1.39.0",
|
||||||
"@rollup/plugin-commonjs": "25.0.5",
|
"@rollup/plugin-commonjs": "25.0.5",
|
||||||
"@rollup/plugin-image": "3.0.3",
|
"@rollup/plugin-image": "3.0.3",
|
||||||
"@rollup/plugin-json": "6.0.1",
|
"@rollup/plugin-json": "6.0.1",
|
||||||
@ -170,21 +165,21 @@
|
|||||||
"@types/electron-localshortcut": "3.1.1",
|
"@types/electron-localshortcut": "3.1.1",
|
||||||
"@types/howler": "2.2.9",
|
"@types/howler": "2.2.9",
|
||||||
"@types/html-to-text": "9.0.2",
|
"@types/html-to-text": "9.0.2",
|
||||||
"@typescript-eslint/eslint-plugin": "6.7.4",
|
"@typescript-eslint/eslint-plugin": "6.7.5",
|
||||||
"auto-changelog": "2.4.0",
|
"auto-changelog": "2.4.0",
|
||||||
"del-cli": "5.1.0",
|
"del-cli": "5.1.0",
|
||||||
"electron": "27.0.0-beta.9",
|
"electron": "27.0.0",
|
||||||
"electron-builder": "24.6.4",
|
"electron-builder": "24.6.4",
|
||||||
"electron-devtools-installer": "3.2.0",
|
"electron-devtools-installer": "3.2.0",
|
||||||
"eslint": "8.51.0",
|
"eslint": "8.51.0",
|
||||||
"eslint-plugin-import": "2.28.1",
|
"eslint-plugin-import": "2.28.1",
|
||||||
"eslint-plugin-prettier": "5.0.0",
|
"eslint-plugin-prettier": "5.0.1",
|
||||||
"node-gyp": "9.4.0",
|
"node-gyp": "9.4.0",
|
||||||
"patch-package": "8.0.0",
|
"patch-package": "8.0.0",
|
||||||
"playwright": "1.38.1",
|
"playwright": "1.39.0",
|
||||||
"rollup": "4.0.2",
|
"rollup": "4.0.2",
|
||||||
"rollup-plugin-copy": "3.5.0",
|
"rollup-plugin-copy": "3.5.0",
|
||||||
"rollup-plugin-import-css": "3.3.4",
|
"rollup-plugin-import-css": "3.3.5",
|
||||||
"rollup-plugin-string": "3.0.0",
|
"rollup-plugin-string": "3.0.0",
|
||||||
"typescript": "5.2.2"
|
"typescript": "5.2.2"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -8,8 +8,8 @@ import type { ConfigType } from '../../config/dynamic';
|
|||||||
type AdBlockOptions = ConfigType<'adblocker'>;
|
type AdBlockOptions = ConfigType<'adblocker'>;
|
||||||
|
|
||||||
export default async (win: BrowserWindow, options: AdBlockOptions) => {
|
export default async (win: BrowserWindow, options: AdBlockOptions) => {
|
||||||
if (await shouldUseBlocklists()) {
|
if (shouldUseBlocklists()) {
|
||||||
loadAdBlockerEngine(
|
await loadAdBlockerEngine(
|
||||||
win.webContents.session,
|
win.webContents.session,
|
||||||
options.cache,
|
options.cache,
|
||||||
options.additionalBlockLists,
|
options.additionalBlockLists,
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import path from 'node:path';
|
|||||||
import fs, { promises } from 'node:fs';
|
import fs, { promises } from 'node:fs';
|
||||||
|
|
||||||
import { ElectronBlocker } from '@cliqz/adblocker-electron';
|
import { ElectronBlocker } from '@cliqz/adblocker-electron';
|
||||||
import { app } from 'electron';
|
import { app, net } from 'electron';
|
||||||
|
|
||||||
const SOURCES = [
|
const SOURCES = [
|
||||||
'https://raw.githubusercontent.com/kbinani/adblock-youtube-ads/master/signed.txt',
|
'https://raw.githubusercontent.com/kbinani/adblock-youtube-ads/master/signed.txt',
|
||||||
@ -17,7 +17,7 @@ const SOURCES = [
|
|||||||
'https://secure.fanboy.co.nz/fanboy-annoyance_ubo.txt',
|
'https://secure.fanboy.co.nz/fanboy-annoyance_ubo.txt',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const loadAdBlockerEngine = (
|
export const loadAdBlockerEngine = async (
|
||||||
session: Electron.Session | undefined = undefined,
|
session: Electron.Session | undefined = undefined,
|
||||||
cache = true,
|
cache = true,
|
||||||
additionalBlockLists = [],
|
additionalBlockLists = [],
|
||||||
@ -49,25 +49,24 @@ export const loadAdBlockerEngine = (
|
|||||||
...additionalBlockLists,
|
...additionalBlockLists,
|
||||||
];
|
];
|
||||||
|
|
||||||
ElectronBlocker.fromLists(
|
try {
|
||||||
fetch,
|
const blocker = await ElectronBlocker.fromLists(
|
||||||
lists,
|
(url: string) => net.fetch(url),
|
||||||
{
|
lists,
|
||||||
// When generating the engine for caching, do not load network filters
|
{
|
||||||
// So that enhancing the session works as expected
|
// When generating the engine for caching, do not load network filters
|
||||||
// Allowing to define multiple webRequest listeners
|
// So that enhancing the session works as expected
|
||||||
loadNetworkFilters: session !== undefined,
|
// Allowing to define multiple webRequest listeners
|
||||||
},
|
loadNetworkFilters: session !== undefined,
|
||||||
cachingOptions,
|
},
|
||||||
)
|
cachingOptions,
|
||||||
.then((blocker) => {
|
);
|
||||||
if (session) {
|
if (session) {
|
||||||
blocker.enableBlockingInSession(session);
|
blocker.enableBlockingInSession(session);
|
||||||
} else {
|
}
|
||||||
console.log('Successfully generated adBlocker engine.');
|
} catch (error) {
|
||||||
}
|
console.log('Error loading adBlocker engine', error);
|
||||||
})
|
}
|
||||||
.catch((error) => console.log('Error loading adBlocker engine', error));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default { loadAdBlockerEngine };
|
export default { loadAdBlockerEngine };
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { PluginConfig } from '../../config/dynamic';
|
|||||||
|
|
||||||
const config = new PluginConfig('adblocker', { enableFront: true });
|
const config = new PluginConfig('adblocker', { enableFront: true });
|
||||||
|
|
||||||
export const shouldUseBlocklists = async () => await config.get('blocker') !== blockers.InPlayer;
|
export const shouldUseBlocklists = () => config.get('blocker') !== blockers.InPlayer;
|
||||||
|
|
||||||
export default Object.assign(config, {
|
export default Object.assign(config, {
|
||||||
shouldUseBlocklists,
|
shouldUseBlocklists,
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
export default () => {
|
export default async () => {
|
||||||
const path = '@cliqz/adblocker-electron-preload'; // prevent require hoisting
|
await import('@cliqz/adblocker-electron-preload');
|
||||||
require(path);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
import config from './config';
|
import config, { shouldUseBlocklists } from './config';
|
||||||
import inject from './inject';
|
import inject from './inject';
|
||||||
import injectCliqzPreload from './inject-cliqz-preload';
|
import injectCliqzPreload from './inject-cliqz-preload';
|
||||||
|
|
||||||
import { blockers } from './blocker-types';
|
import { blockers } from './blocker-types';
|
||||||
|
|
||||||
export default async () => {
|
export default async () => {
|
||||||
if (await config.shouldUseBlocklists()) {
|
if (shouldUseBlocklists()) {
|
||||||
// Preload adblocker to inject scripts/styles
|
// Preload adblocker to inject scripts/styles
|
||||||
injectCliqzPreload();
|
await injectCliqzPreload();
|
||||||
// eslint-disable-next-line @typescript-eslint/await-thenable
|
// eslint-disable-next-line @typescript-eslint/await-thenable
|
||||||
} else if ((await config.get('blocker')) === blockers.InPlayer) {
|
} else if ((config.get('blocker')) === blockers.InPlayer) {
|
||||||
inject();
|
inject();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
export default () => {
|
export default async () => {
|
||||||
// See https://github.com/zerodytrash/Simple-YouTube-Age-Restriction-Bypass#userscript
|
// See https://github.com/zerodytrash/Simple-YouTube-Age-Restriction-Bypass#userscript
|
||||||
require('simple-youtube-age-restriction-bypass/dist/Simple-YouTube-Age-Restriction-Bypass.user.js');
|
await import('simple-youtube-age-restriction-bypass');
|
||||||
};
|
};
|
||||||
|
|||||||
4
plugins/bypass-age-restrictions/simple-youtube-age-restriction-bypass.d.ts
vendored
Normal file
4
plugins/bypass-age-restrictions/simple-youtube-age-restriction-bypass.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
declare module 'simple-youtube-age-restriction-bypass' {
|
||||||
|
const nothing: never;
|
||||||
|
export default nothing;
|
||||||
|
}
|
||||||
@ -3,26 +3,16 @@ import { join } from 'node:path';
|
|||||||
import { randomBytes } from 'node:crypto';
|
import { randomBytes } from 'node:crypto';
|
||||||
|
|
||||||
import { app, BrowserWindow, dialog, ipcMain, net } from 'electron';
|
import { app, BrowserWindow, dialog, ipcMain, net } from 'electron';
|
||||||
import { ClientType, Innertube, UniversalCache, Utils } from 'youtubei.js';
|
import { ClientType, Innertube, UniversalCache, Utils, YTNodes } from 'youtubei.js';
|
||||||
import is from 'electron-is';
|
import is from 'electron-is';
|
||||||
import ytpl from 'ytpl';
|
|
||||||
// REPLACE with youtubei getplaylist https://github.com/LuanRT/YouTube.js#getplaylistid
|
|
||||||
import filenamify from 'filenamify';
|
import filenamify from 'filenamify';
|
||||||
import { Mutex } from 'async-mutex';
|
import { Mutex } from 'async-mutex';
|
||||||
import { createFFmpeg } from '@ffmpeg.wasm/main';
|
import { createFFmpeg } from '@ffmpeg.wasm/main';
|
||||||
|
|
||||||
import NodeID3, { TagConstants } from 'node-id3';
|
import NodeID3, { TagConstants } from 'node-id3';
|
||||||
|
|
||||||
import PlayerErrorMessage from 'youtubei.js/dist/src/parser/classes/PlayerErrorMessage';
|
import { cropMaxWidth, getFolder, sendFeedback as sendFeedback_, setBadge } from './utils';
|
||||||
import { FormatOptions } from 'youtubei.js/dist/src/types/FormatUtils';
|
|
||||||
|
|
||||||
import TrackInfo from 'youtubei.js/dist/src/parser/ytmusic/TrackInfo';
|
|
||||||
|
|
||||||
import { VideoInfo } from 'youtubei.js/dist/src/parser/youtube';
|
|
||||||
|
|
||||||
import { cropMaxWidth, getFolder, presets, sendFeedback as sendFeedback_, setBadge } from './utils';
|
|
||||||
|
|
||||||
import config from './config';
|
import config from './config';
|
||||||
|
import { YoutubeFormatList, type Preset, DefaultPresetList } from './types';
|
||||||
|
|
||||||
import style from './style.css';
|
import style from './style.css';
|
||||||
|
|
||||||
@ -32,8 +22,13 @@ import { cleanupName, getImage, SongInfo } from '../../providers/song-info';
|
|||||||
import { injectCSS } from '../utils';
|
import { injectCSS } from '../utils';
|
||||||
import { cache } from '../../providers/decorators';
|
import { cache } from '../../providers/decorators';
|
||||||
|
|
||||||
import type { GetPlayerResponse } from '../../types/get-player-response';
|
import type { FormatOptions } from 'youtubei.js/dist/src/types/FormatUtils';
|
||||||
|
import type PlayerErrorMessage from 'youtubei.js/dist/src/parser/classes/PlayerErrorMessage';
|
||||||
|
import type { Playlist } from 'youtubei.js/dist/src/parser/ytmusic';
|
||||||
|
import type { VideoInfo } from 'youtubei.js/dist/src/parser/youtube';
|
||||||
|
import type TrackInfo from 'youtubei.js/dist/src/parser/ytmusic/TrackInfo';
|
||||||
|
|
||||||
|
import type { GetPlayerResponse } from '../../types/get-player-response';
|
||||||
|
|
||||||
type CustomSongInfo = SongInfo & { trackId?: string };
|
type CustomSongInfo = SongInfo & { trackId?: string };
|
||||||
|
|
||||||
@ -69,16 +64,19 @@ const sendError = (error: Error, source?: string) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getCookieFromWindow = async (win: BrowserWindow) => {
|
||||||
|
return (await win.webContents.session.cookies.get({ url: 'https://music.youtube.com' })).map((it) =>
|
||||||
|
it.name + '=' + it.value + ';'
|
||||||
|
).join('');
|
||||||
|
};
|
||||||
|
|
||||||
export default async (win_: BrowserWindow) => {
|
export default async (win_: BrowserWindow) => {
|
||||||
win = win_;
|
win = win_;
|
||||||
injectCSS(win.webContents, style);
|
injectCSS(win.webContents, style);
|
||||||
|
|
||||||
const cookie = (await win.webContents.session.cookies.get({ url: 'https://music.youtube.com' })).map((it) =>
|
|
||||||
it.name + '=' + it.value + ';'
|
|
||||||
).join('');
|
|
||||||
yt = await Innertube.create({
|
yt = await Innertube.create({
|
||||||
cache: new UniversalCache(false),
|
cache: new UniversalCache(false),
|
||||||
cookie,
|
cookie: await getCookieFromWindow(win),
|
||||||
generate_session_locally: true,
|
generate_session_locally: true,
|
||||||
fetch: async (input: RequestInfo | URL, init?: RequestInit) => {
|
fetch: async (input: RequestInfo | URL, init?: RequestInit) => {
|
||||||
const url =
|
const url =
|
||||||
@ -118,6 +116,7 @@ export async function downloadSong(
|
|||||||
let resolvedName;
|
let resolvedName;
|
||||||
try {
|
try {
|
||||||
await downloadSongUnsafe(
|
await downloadSongUnsafe(
|
||||||
|
false,
|
||||||
url,
|
url,
|
||||||
(name: string) => resolvedName = name,
|
(name: string) => resolvedName = name,
|
||||||
playlistFolder,
|
playlistFolder,
|
||||||
@ -129,8 +128,31 @@ export async function downloadSong(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function downloadSongFromId(
|
||||||
|
id: string,
|
||||||
|
playlistFolder: string | undefined = undefined,
|
||||||
|
trackId: string | undefined = undefined,
|
||||||
|
increasePlaylistProgress: (value: number) => void = () => {
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
let resolvedName;
|
||||||
|
try {
|
||||||
|
await downloadSongUnsafe(
|
||||||
|
true,
|
||||||
|
id,
|
||||||
|
(name: string) => resolvedName = name,
|
||||||
|
playlistFolder,
|
||||||
|
trackId,
|
||||||
|
increasePlaylistProgress,
|
||||||
|
);
|
||||||
|
} catch (error: unknown) {
|
||||||
|
sendError(error as Error, resolvedName || id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function downloadSongUnsafe(
|
async function downloadSongUnsafe(
|
||||||
url: string,
|
isId: boolean,
|
||||||
|
idOrUrl: string,
|
||||||
setName: (name: string) => void,
|
setName: (name: string) => void,
|
||||||
playlistFolder: string | undefined = undefined,
|
playlistFolder: string | undefined = undefined,
|
||||||
trackId: string | undefined = undefined,
|
trackId: string | undefined = undefined,
|
||||||
@ -147,8 +169,13 @@ async function downloadSongUnsafe(
|
|||||||
|
|
||||||
sendFeedback('Downloading...', 2);
|
sendFeedback('Downloading...', 2);
|
||||||
|
|
||||||
const id = getVideoId(url);
|
let id: string | null;
|
||||||
if (typeof id !== 'string') throw new Error('Video not found');
|
if (isId) {
|
||||||
|
id = idOrUrl;
|
||||||
|
} else {
|
||||||
|
id = getVideoId(idOrUrl);
|
||||||
|
if (typeof id !== 'string') throw new Error('Video not found');
|
||||||
|
}
|
||||||
|
|
||||||
let info: TrackInfo | VideoInfo = await yt.music.getInfo(id);
|
let info: TrackInfo | VideoInfo = await yt.music.getInfo(id);
|
||||||
|
|
||||||
@ -193,21 +220,14 @@ async function downloadSongUnsafe(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const preset = config.get('preset') ?? 'mp3';
|
const selectedPreset = config.get('selectedPreset') ?? 'mp3 (256kbps)';
|
||||||
let presetSetting: { extension: string; ffmpegArgs: string[] } | null = null;
|
let presetSetting: Preset;
|
||||||
if (preset === 'opus') {
|
if (selectedPreset === 'Custom') {
|
||||||
presetSetting = presets[preset];
|
presetSetting = config.get('customPresetSetting') ?? DefaultPresetList['Custom'];
|
||||||
}
|
} else if (selectedPreset === 'Source') {
|
||||||
|
presetSetting = DefaultPresetList['Source'];
|
||||||
const filename = filenamify(`${name}.${presetSetting?.extension ?? 'mp3'}`, {
|
} else {
|
||||||
replacement: '_',
|
presetSetting = DefaultPresetList['mp3 (256kbps)'];
|
||||||
maxLength: 255,
|
|
||||||
});
|
|
||||||
const filePath = join(dir, filename);
|
|
||||||
|
|
||||||
if (config.get('skipExisting') && existsSync(filePath)) {
|
|
||||||
sendFeedback(null, -1);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const downloadOptions: FormatOptions = {
|
const downloadOptions: FormatOptions = {
|
||||||
@ -217,6 +237,28 @@ async function downloadSongUnsafe(
|
|||||||
};
|
};
|
||||||
|
|
||||||
const format = info.chooseFormat(downloadOptions);
|
const format = info.chooseFormat(downloadOptions);
|
||||||
|
|
||||||
|
let targetFileExtension: string;
|
||||||
|
if (!presetSetting?.extension) {
|
||||||
|
targetFileExtension = YoutubeFormatList.find((it) => it.itag === format.itag)?.container ?? 'mp3';
|
||||||
|
} else {
|
||||||
|
targetFileExtension = presetSetting?.extension ?? 'mp3';
|
||||||
|
}
|
||||||
|
|
||||||
|
let filename = filenamify(`${name}.${targetFileExtension}`, {
|
||||||
|
replacement: '_',
|
||||||
|
maxLength: 255,
|
||||||
|
});
|
||||||
|
if (!is.macOS()) {
|
||||||
|
filename = filename.normalize('NFC');
|
||||||
|
}
|
||||||
|
const filePath = join(dir, filename);
|
||||||
|
|
||||||
|
if (config.get('skipExisting') && existsSync(filePath)) {
|
||||||
|
sendFeedback(null, -1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const stream = await info.download(downloadOptions);
|
const stream = await info.download(downloadOptions);
|
||||||
|
|
||||||
console.info(
|
console.info(
|
||||||
@ -229,39 +271,20 @@ async function downloadSongUnsafe(
|
|||||||
mkdirSync(dir);
|
mkdirSync(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ffmpegArgs = config.get('ffmpegArgs');
|
const fileBuffer = await iterableStreamToTargetFile(
|
||||||
|
iterableStream,
|
||||||
|
targetFileExtension,
|
||||||
|
metadata,
|
||||||
|
presetSetting?.ffmpegArgs ?? [],
|
||||||
|
format.content_length ?? 0,
|
||||||
|
sendFeedback,
|
||||||
|
increasePlaylistProgress,
|
||||||
|
);
|
||||||
|
|
||||||
if (presetSetting && presetSetting?.extension !== 'mp3') {
|
if (fileBuffer) {
|
||||||
const file = createWriteStream(filePath);
|
if (targetFileExtension !== 'mp3') {
|
||||||
let downloaded = 0;
|
createWriteStream(filePath).write(fileBuffer);
|
||||||
const total: number = format.content_length ?? 1;
|
} else {
|
||||||
|
|
||||||
for await (const chunk of iterableStream) {
|
|
||||||
downloaded += chunk.length;
|
|
||||||
const ratio = downloaded / total;
|
|
||||||
const progress = Math.floor(ratio * 100);
|
|
||||||
sendFeedback(`Download: ${progress}%`, ratio);
|
|
||||||
increasePlaylistProgress(ratio);
|
|
||||||
file.write(chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
await ffmpegWriteTags(
|
|
||||||
filePath,
|
|
||||||
metadata,
|
|
||||||
presetSetting.ffmpegArgs,
|
|
||||||
ffmpegArgs,
|
|
||||||
);
|
|
||||||
sendFeedback(null, -1);
|
|
||||||
} else {
|
|
||||||
const fileBuffer = await iterableStreamToMP3(
|
|
||||||
iterableStream,
|
|
||||||
metadata,
|
|
||||||
ffmpegArgs,
|
|
||||||
format.content_length ?? 0,
|
|
||||||
sendFeedback,
|
|
||||||
increasePlaylistProgress,
|
|
||||||
);
|
|
||||||
if (fileBuffer) {
|
|
||||||
const buffer = await writeID3(Buffer.from(fileBuffer), metadata, sendFeedback);
|
const buffer = await writeID3(Buffer.from(fileBuffer), metadata, sendFeedback);
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
writeFileSync(filePath, buffer);
|
writeFileSync(filePath, buffer);
|
||||||
@ -273,10 +296,11 @@ async function downloadSongUnsafe(
|
|||||||
console.info(`Done: "${filePath}"`);
|
console.info(`Done: "${filePath}"`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function iterableStreamToMP3(
|
async function iterableStreamToTargetFile(
|
||||||
stream: AsyncGenerator<Uint8Array, void>,
|
stream: AsyncGenerator<Uint8Array, void>,
|
||||||
|
extension: string,
|
||||||
metadata: CustomSongInfo,
|
metadata: CustomSongInfo,
|
||||||
ffmpegArgs: string[],
|
presetFfmpegArgs: string[],
|
||||||
contentLength: number,
|
contentLength: number,
|
||||||
sendFeedback: (str: string, value?: number) => void,
|
sendFeedback: (str: string, value?: number) => void,
|
||||||
increasePlaylistProgress: (value: number) => void = () => {
|
increasePlaylistProgress: (value: number) => void = () => {
|
||||||
@ -316,13 +340,14 @@ async function iterableStreamToMP3(
|
|||||||
increasePlaylistProgress(0.15 + (ratio * 0.85));
|
increasePlaylistProgress(0.15 + (ratio * 0.85));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const safeVideoNameWithExtension = `${safeVideoName}.${extension}`;
|
||||||
try {
|
try {
|
||||||
await ffmpeg.run(
|
await ffmpeg.run(
|
||||||
'-i',
|
'-i',
|
||||||
safeVideoName,
|
safeVideoName,
|
||||||
...ffmpegArgs,
|
...presetFfmpegArgs,
|
||||||
...getFFmpegMetadataArgs(metadata),
|
...getFFmpegMetadataArgs(metadata),
|
||||||
`${safeVideoName}.mp3`,
|
safeVideoNameWithExtension,
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
ffmpeg.FS('unlink', safeVideoName);
|
ffmpeg.FS('unlink', safeVideoName);
|
||||||
@ -331,9 +356,9 @@ async function iterableStreamToMP3(
|
|||||||
sendFeedback('Saving…');
|
sendFeedback('Saving…');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return ffmpeg.FS('readFile', `${safeVideoName}.mp3`);
|
return ffmpeg.FS('readFile', safeVideoNameWithExtension);
|
||||||
} finally {
|
} finally {
|
||||||
ffmpeg.FS('unlink', `${safeVideoName}.mp3`);
|
ffmpeg.FS('unlink', safeVideoNameWithExtension);
|
||||||
}
|
}
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
sendError(error as Error, safeVideoName);
|
sendError(error as Error, safeVideoName);
|
||||||
@ -414,11 +439,9 @@ export async function downloadPlaylist(givenUrl?: string | URL) {
|
|||||||
|
|
||||||
console.log(`trying to get playlist ID: '${playlistId}'`);
|
console.log(`trying to get playlist ID: '${playlistId}'`);
|
||||||
sendFeedback('Getting playlist info…');
|
sendFeedback('Getting playlist info…');
|
||||||
let playlist: ytpl.Result;
|
let playlist: Playlist;
|
||||||
try {
|
try {
|
||||||
playlist = await ytpl(playlistId, {
|
playlist = await yt.music.getPlaylist(playlistId);
|
||||||
limit: config.get('playlistMaxItems') || Number.POSITIVE_INFINITY,
|
|
||||||
});
|
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
sendError(
|
sendError(
|
||||||
Error(`Error getting playlist info: make sure it isn't a private or "Mixed for you" playlist\n\n${String(error)}`),
|
Error(`Error getting playlist info: make sure it isn't a private or "Mixed for you" playlist\n\n${String(error)}`),
|
||||||
@ -426,22 +449,27 @@ export async function downloadPlaylist(givenUrl?: string | URL) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (playlist.items.length === 0) {
|
if (!playlist || !playlist.items || playlist.items.length === 0) {
|
||||||
sendError(new Error('Playlist is empty'));
|
sendError(new Error('Playlist is empty'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (playlist.items.length === 1) {
|
const items = playlist.items!.as(YTNodes.MusicResponsiveListItem);
|
||||||
|
if (items.length === 1) {
|
||||||
sendFeedback('Playlist has only one item, downloading it directly');
|
sendFeedback('Playlist has only one item, downloading it directly');
|
||||||
await downloadSong(playlist.items[0].url);
|
await downloadSongFromId(items.at(0)!.id!);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isAlbum = playlist.title.startsWith('Album - ');
|
let playlistTitle = playlist.header?.title?.text ?? '';
|
||||||
|
const isAlbum = playlistTitle?.startsWith('Album - ');
|
||||||
if (isAlbum) {
|
if (isAlbum) {
|
||||||
playlist.title = playlist.title.slice(8);
|
playlistTitle = playlistTitle.slice(8);
|
||||||
}
|
}
|
||||||
|
|
||||||
const safePlaylistTitle = filenamify(playlist.title, { replacement: ' ' });
|
let safePlaylistTitle = filenamify(playlistTitle, { replacement: ' ' });
|
||||||
|
if (!is.macOS()) {
|
||||||
|
safePlaylistTitle = safePlaylistTitle.normalize('NFC');
|
||||||
|
}
|
||||||
|
|
||||||
const folder = getFolder(config.get('downloadFolder') ?? '');
|
const folder = getFolder(config.get('downloadFolder') ?? '');
|
||||||
const playlistFolder = join(folder, safePlaylistTitle);
|
const playlistFolder = join(folder, safePlaylistTitle);
|
||||||
@ -458,47 +486,47 @@ export async function downloadPlaylist(givenUrl?: string | URL) {
|
|||||||
type: 'info',
|
type: 'info',
|
||||||
buttons: ['OK'],
|
buttons: ['OK'],
|
||||||
title: 'Started Download',
|
title: 'Started Download',
|
||||||
message: `Downloading Playlist "${playlist.title}"`,
|
message: `Downloading Playlist "${playlistTitle}"`,
|
||||||
detail: `(${playlist.items.length} songs)`,
|
detail: `(${items.length} songs)`,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (is.dev()) {
|
if (is.dev()) {
|
||||||
console.log(
|
console.log(
|
||||||
`Downloading playlist "${playlist.title}" - ${playlist.items.length} songs (${playlistId})`,
|
`Downloading playlist "${playlistTitle}" - ${items.length} songs (${playlistId})`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
win.setProgressBar(2); // Starts with indefinite bar
|
win.setProgressBar(2); // Starts with indefinite bar
|
||||||
|
|
||||||
setBadge(playlist.items.length);
|
setBadge(items.length);
|
||||||
|
|
||||||
let counter = 1;
|
let counter = 1;
|
||||||
|
|
||||||
const progressStep = 1 / playlist.items.length;
|
const progressStep = 1 / items.length;
|
||||||
|
|
||||||
const increaseProgress = (itemPercentage: number) => {
|
const increaseProgress = (itemPercentage: number) => {
|
||||||
const currentProgress = (counter - 1) / (playlist.items.length ?? 1);
|
const currentProgress = (counter - 1) / (items.length ?? 1);
|
||||||
const newProgress = currentProgress + (progressStep * itemPercentage);
|
const newProgress = currentProgress + (progressStep * itemPercentage);
|
||||||
win.setProgressBar(newProgress);
|
win.setProgressBar(newProgress);
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (const song of playlist.items) {
|
for (const song of items) {
|
||||||
sendFeedback(`Downloading ${counter}/${playlist.items.length}...`);
|
sendFeedback(`Downloading ${counter}/${items.length}...`);
|
||||||
const trackId = isAlbum ? counter : undefined;
|
const trackId = isAlbum ? counter : undefined;
|
||||||
await downloadSong(
|
await downloadSongFromId(
|
||||||
song.url,
|
song.id!,
|
||||||
playlistFolder,
|
playlistFolder,
|
||||||
trackId?.toString(),
|
trackId?.toString(),
|
||||||
increaseProgress,
|
increaseProgress,
|
||||||
).catch((error) =>
|
).catch((error) =>
|
||||||
sendError(
|
sendError(
|
||||||
new Error(`Error downloading "${song.author.name} - ${song.title}":\n ${error}`)
|
new Error(`Error downloading "${song.author!.name} - ${song.title!}":\n ${error}`)
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
win.setProgressBar(counter / playlist.items.length);
|
win.setProgressBar(counter / items.length);
|
||||||
setBadge(playlist.items.length - counter);
|
setBadge(items.length - counter);
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
@ -510,29 +538,6 @@ export async function downloadPlaylist(givenUrl?: string | URL) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function ffmpegWriteTags(filePath: string, metadata: CustomSongInfo, presetFFmpegArgs: string[] = [], ffmpegArgs: string[] = []) {
|
|
||||||
const releaseFFmpegMutex = await ffmpegMutex.acquire();
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (!ffmpeg.isLoaded()) {
|
|
||||||
await ffmpeg.load();
|
|
||||||
}
|
|
||||||
|
|
||||||
await ffmpeg.run(
|
|
||||||
'-i',
|
|
||||||
filePath,
|
|
||||||
...getFFmpegMetadataArgs(metadata),
|
|
||||||
...presetFFmpegArgs,
|
|
||||||
...ffmpegArgs,
|
|
||||||
filePath,
|
|
||||||
);
|
|
||||||
} catch (error: unknown) {
|
|
||||||
sendError(error as Error);
|
|
||||||
} finally {
|
|
||||||
releaseFFmpegMutex();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFFmpegMetadataArgs(metadata: CustomSongInfo) {
|
function getFFmpegMetadataArgs(metadata: CustomSongInfo) {
|
||||||
if (!metadata) {
|
if (!metadata) {
|
||||||
return [];
|
return [];
|
||||||
|
|||||||
@ -47,7 +47,7 @@ const menuObserver = new MutationObserver(() => {
|
|||||||
(global as any).download = () => {
|
(global as any).download = () => {
|
||||||
let videoUrl = getSongMenu()
|
let videoUrl = getSongMenu()
|
||||||
// Selector of first button which is always "Start Radio"
|
// Selector of first button which is always "Start Radio"
|
||||||
?.querySelector('ytmusic-menu-navigation-item-renderer[tabindex="0"] #navigation-endpoint')
|
?.querySelector('ytmusic-menu-navigation-item-renderer[tabindex="-1"] #navigation-endpoint')
|
||||||
?.getAttribute('href');
|
?.getAttribute('href');
|
||||||
if (videoUrl) {
|
if (videoUrl) {
|
||||||
if (videoUrl.startsWith('watch?')) {
|
if (videoUrl.startsWith('watch?')) {
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import { dialog } from 'electron';
|
import { dialog } from 'electron';
|
||||||
|
|
||||||
import { downloadPlaylist } from './back';
|
import { downloadPlaylist } from './back';
|
||||||
import { defaultMenuDownloadLabel, getFolder, presets } from './utils';
|
import { defaultMenuDownloadLabel, getFolder } from './utils';
|
||||||
|
import { DefaultPresetList } from './types';
|
||||||
import config from './config';
|
import config from './config';
|
||||||
|
|
||||||
import { MenuTemplate } from '../../menu';
|
import { MenuTemplate } from '../../menu';
|
||||||
@ -25,12 +26,12 @@ export default (): MenuTemplate => [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Presets',
|
label: 'Presets',
|
||||||
submenu: Object.keys(presets).map((preset) => ({
|
submenu: Object.keys(DefaultPresetList).map((preset) => ({
|
||||||
label: preset,
|
label: preset,
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
checked: config.get('preset') === preset,
|
checked: config.get('selectedPreset') === preset,
|
||||||
click() {
|
click() {
|
||||||
config.set('preset', preset);
|
config.set('selectedPreset', preset);
|
||||||
},
|
},
|
||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
|
|||||||
116
plugins/downloader/types.ts
Normal file
116
plugins/downloader/types.ts
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
export interface Preset {
|
||||||
|
extension?: string | null;
|
||||||
|
ffmpegArgs: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Presets for FFmpeg
|
||||||
|
export const DefaultPresetList: Record<string, Preset> = {
|
||||||
|
'mp3 (256kbps)': {
|
||||||
|
extension: 'mp3',
|
||||||
|
ffmpegArgs: ['-b:a', '256k'],
|
||||||
|
},
|
||||||
|
'Source': {
|
||||||
|
extension: undefined,
|
||||||
|
ffmpegArgs: ['-acodec', 'copy'],
|
||||||
|
},
|
||||||
|
'Custom': {
|
||||||
|
extension: null,
|
||||||
|
ffmpegArgs: [],
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface YouTubeFormat {
|
||||||
|
itag: number;
|
||||||
|
container: string;
|
||||||
|
content: string;
|
||||||
|
resolution: string;
|
||||||
|
bitrate: string;
|
||||||
|
range: string;
|
||||||
|
vrOr3D: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// converted from https://gist.github.com/sidneys/7095afe4da4ae58694d128b1034e01e2#file-youtube_format_code_itag_list-md
|
||||||
|
export const YoutubeFormatList: YouTubeFormat[] = [
|
||||||
|
{ itag: 5, container: 'flv', content: 'audio/video', resolution: '240p', bitrate: '-', range: '-', vrOr3D: '-' },
|
||||||
|
{ itag: 6, container: 'flv', content: 'audio/video', resolution: '270p', bitrate: '-', range: '-', vrOr3D: '-' },
|
||||||
|
{ itag: 17, container: '3gp', content: 'audio/video', resolution: '144p', bitrate: '-', range: '-', vrOr3D: '-' },
|
||||||
|
{ itag: 18, container: 'mp4', content: 'audio/video', resolution: '360p', bitrate: '-', range: '-', vrOr3D: '-' },
|
||||||
|
{ itag: 22, container: 'mp4', content: 'audio/video', resolution: '720p', bitrate: '-', range: '-', vrOr3D: '-' },
|
||||||
|
{ itag: 34, container: 'flv', content: 'audio/video', resolution: '360p', bitrate: '-', range: '-', vrOr3D: '-' },
|
||||||
|
{ itag: 35, container: 'flv', content: 'audio/video', resolution: '480p', bitrate: '-', range: '-', vrOr3D: '-' },
|
||||||
|
{ itag: 36, container: '3gp', content: 'audio/video', resolution: '180p', bitrate: '-', range: '-', vrOr3D: '-' },
|
||||||
|
{ itag: 37, container: 'mp4', content: 'audio/video', resolution: '1080p', bitrate: '-', range: '-', vrOr3D: '-' },
|
||||||
|
{ itag: 38, container: 'mp4', content: 'audio/video', resolution: '3072p', bitrate: '-', range: '-', vrOr3D: '-' },
|
||||||
|
{ itag: 43, container: 'webm', content: 'audio/video', resolution: '360p', bitrate: '-', range: '-', vrOr3D: '-' },
|
||||||
|
{ itag: 44, container: 'webm', content: 'audio/video', resolution: '480p', bitrate: '-', range: '-', vrOr3D: '-' },
|
||||||
|
{ itag: 45, container: 'webm', content: 'audio/video', resolution: '720p', bitrate: '-', range: '-', vrOr3D: '-' },
|
||||||
|
{ itag: 46, container: 'webm', content: 'audio/video', resolution: '1080p', bitrate: '-', range: '-', vrOr3D: '-' },
|
||||||
|
{ itag: 82, container: 'mp4', content: 'audio/video', resolution: '360p', bitrate: '-', range: '-', vrOr3D: '3D' },
|
||||||
|
{ itag: 83, container: 'mp4', content: 'audio/video', resolution: '480p', bitrate: '-', range: '-', vrOr3D: '3D' },
|
||||||
|
{ itag: 84, container: 'mp4', content: 'audio/video', resolution: '720p', bitrate: '-', range: '-', vrOr3D: '3D' },
|
||||||
|
{ itag: 85, container: 'mp4', content: 'audio/video', resolution: '1080p', bitrate: '-', range: '-', vrOr3D: '3D' },
|
||||||
|
{ itag: 91, container: 'hls', content: 'audio/video', resolution: '144p', bitrate: '-', range: '-', vrOr3D: '3D' },
|
||||||
|
{ itag: 92, container: 'hls', content: 'audio/video', resolution: '240p', bitrate: '-', range: '-', vrOr3D: '3D' },
|
||||||
|
{ itag: 93, container: 'hls', content: 'audio/video', resolution: '360p', bitrate: '-', range: '-', vrOr3D: '3D' },
|
||||||
|
{ itag: 94, container: 'hls', content: 'audio/video', resolution: '480p', bitrate: '-', range: '-', vrOr3D: '3D' },
|
||||||
|
{ itag: 95, container: 'hls', content: 'audio/video', resolution: '720p', bitrate: '-', range: '-', vrOr3D: '3D' },
|
||||||
|
{ itag: 96, container: 'hls', content: 'audio/video', resolution: '1080p', bitrate: '-', range: '-', vrOr3D: '-' },
|
||||||
|
{ itag: 100, container: 'webm', content: 'audio/video', resolution: '360p', bitrate: '-', range: '-', vrOr3D: '3D' },
|
||||||
|
{ itag: 101, container: 'webm', content: 'audio/video', resolution: '480p', bitrate: '-', range: '-', vrOr3D: '3D' },
|
||||||
|
{ itag: 102, container: 'webm', content: 'audio/video', resolution: '720p', bitrate: '-', range: '-', vrOr3D: '3D' },
|
||||||
|
{ itag: 132, container: 'hls', content: 'audio/video', resolution: '240p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 133, container: 'mp4', content: 'video', resolution: '240p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 134, container: 'mp4', content: 'video', resolution: '360p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 135, container: 'mp4', content: 'video', resolution: '480p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 136, container: 'mp4', content: 'video', resolution: '720p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 137, container: 'mp4', content: 'video', resolution: '1080p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 138, container: 'mp4', content: 'video', resolution: '2160p60', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 139, container: 'm4a', content: 'audio', resolution: '-', bitrate: '48k', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 140, container: 'm4a', content: 'audio', resolution: '-', bitrate: '128k', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 141, container: 'm4a', content: 'audio', resolution: '-', bitrate: '256k', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 151, container: 'hls', content: 'audio/video', resolution: '72p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 160, container: 'mp4', content: 'video', resolution: '144p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 167, container: 'webm', content: 'video', resolution: '360p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 168, container: 'webm', content: 'video', resolution: '480p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 169, container: 'webm', content: 'video', resolution: '1080p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 171, container: 'webm', content: 'audio', resolution: '-', bitrate: '128k', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 218, container: 'webm', content: 'video', resolution: '480p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 219, container: 'webm', content: 'video', resolution: '144p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 242, container: 'webm', content: 'video', resolution: '240p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 243, container: 'webm', content: 'video', resolution: '360p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 244, container: 'webm', content: 'video', resolution: '480p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 245, container: 'webm', content: 'video', resolution: '480p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 246, container: 'webm', content: 'video', resolution: '480p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 247, container: 'webm', content: 'video', resolution: '720p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 248, container: 'webm', content: 'video', resolution: '1080p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 249, container: 'webm', content: 'audio', resolution: '-', bitrate: '50k', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 250, container: 'webm', content: 'audio', resolution: '-', bitrate: '70k', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 251, container: 'webm', content: 'audio', resolution: '-', bitrate: '160k', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 264, container: 'mp4', content: 'video', resolution: '1440p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 266, container: 'mp4', content: 'video', resolution: '2160p60', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 271, container: 'webm', content: 'video', resolution: '1440p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 272, container: 'webm', content: 'video', resolution: '4320p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 278, container: 'webm', content: 'video', resolution: '144p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 298, container: 'mp4', content: 'video', resolution: '720p60', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 299, container: 'mp4', content: 'video', resolution: '1080p60', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 302, container: 'webm', content: 'video', resolution: '720p60', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 303, container: 'webm', content: 'video', resolution: '1080p60', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 308, container: 'webm', content: 'video', resolution: '1440p60', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 313, container: 'webm', content: 'video', resolution: '2160p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 315, container: 'webm', content: 'video', resolution: '2160p60', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 330, container: 'webm', content: 'video', resolution: '144p60', bitrate: '-', range: 'hdr', vrOr3D: '' },
|
||||||
|
{ itag: 331, container: 'webm', content: 'video', resolution: '240p60', bitrate: '-', range: 'hdr', vrOr3D: '' },
|
||||||
|
{ itag: 332, container: 'webm', content: 'video', resolution: '360p60', bitrate: '-', range: 'hdr', vrOr3D: '' },
|
||||||
|
{ itag: 333, container: 'webm', content: 'video', resolution: '480p60', bitrate: '-', range: 'hdr', vrOr3D: '' },
|
||||||
|
{ itag: 334, container: 'webm', content: 'video', resolution: '720p60', bitrate: '-', range: 'hdr', vrOr3D: '' },
|
||||||
|
{ itag: 335, container: 'webm', content: 'video', resolution: '1080p60', bitrate: '-', range: 'hdr', vrOr3D: '' },
|
||||||
|
{ itag: 336, container: 'webm', content: 'video', resolution: '1440p60', bitrate: '-', range: 'hdr', vrOr3D: '' },
|
||||||
|
{ itag: 337, container: 'webm', content: 'video', resolution: '2160p60', bitrate: '-', range: 'hdr', vrOr3D: '' },
|
||||||
|
{ itag: 272, container: 'webm', content: 'video', resolution: '2880p/4320p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 399, container: 'mp4', content: 'video', resolution: '1080p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 400, container: 'mp4', content: 'video', resolution: '1440p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 401, container: 'mp4', content: 'video', resolution: '2160p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 402, container: 'mp4', content: 'video', resolution: '2880p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 571, container: 'mp4', content: 'video', resolution: '3840p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
{ itag: 702, container: 'mp4', content: 'video', resolution: '3840p', bitrate: '-', range: '-', vrOr3D: '' },
|
||||||
|
];
|
||||||
@ -10,7 +10,7 @@ export const sendFeedback = (win: BrowserWindow, message?: unknown) => {
|
|||||||
|
|
||||||
export const cropMaxWidth = (image: Electron.NativeImage) => {
|
export const cropMaxWidth = (image: Electron.NativeImage) => {
|
||||||
const imageSize = image.getSize();
|
const imageSize = image.getSize();
|
||||||
// Standart youtube artwork width with margins from both sides is 280 + 720 + 280
|
// Standart YouTube artwork width with margins from both sides is 280 + 720 + 280
|
||||||
if (imageSize.width === 1280 && imageSize.height === 720) {
|
if (imageSize.width === 1280 && imageSize.height === 720) {
|
||||||
return image.crop({
|
return image.crop({
|
||||||
x: 280,
|
x: 280,
|
||||||
@ -23,15 +23,6 @@ export const cropMaxWidth = (image: Electron.NativeImage) => {
|
|||||||
return image;
|
return image;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Presets for FFmpeg
|
|
||||||
export const presets = {
|
|
||||||
'None (defaults to mp3)': undefined,
|
|
||||||
'opus': {
|
|
||||||
extension: 'opus',
|
|
||||||
ffmpegArgs: ['-acodec', 'libopus'],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const setBadge = (n: number) => {
|
export const setBadge = (n: number) => {
|
||||||
if (is.linux() || is.macOS()) {
|
if (is.linux() || is.macOS()) {
|
||||||
app.setBadgeCount(n);
|
app.setBadgeCount(n);
|
||||||
|
|||||||
@ -61,5 +61,7 @@ export default (win: BrowserWindow) => {
|
|||||||
ipcMain.handle('window-close', () => win.close());
|
ipcMain.handle('window-close', () => win.close());
|
||||||
ipcMain.handle('window-minimize', () => win.minimize());
|
ipcMain.handle('window-minimize', () => win.minimize());
|
||||||
ipcMain.handle('window-maximize', () => win.maximize());
|
ipcMain.handle('window-maximize', () => win.maximize());
|
||||||
|
win.on('maximize', () => win.webContents.send('window-maximize'));
|
||||||
ipcMain.handle('window-unmaximize', () => win.unmaximize());
|
ipcMain.handle('window-unmaximize', () => win.unmaximize());
|
||||||
|
win.on('unmaximize', () => win.webContents.send('window-unmaximize'));
|
||||||
};
|
};
|
||||||
|
|||||||
@ -22,6 +22,7 @@ export default async () => {
|
|||||||
let hideMenu = config.get('options.hideMenu');
|
let hideMenu = config.get('options.hideMenu');
|
||||||
const titleBar = document.createElement('title-bar');
|
const titleBar = document.createElement('title-bar');
|
||||||
const navBar = document.querySelector<HTMLDivElement>('#nav-bar-background');
|
const navBar = document.querySelector<HTMLDivElement>('#nav-bar-background');
|
||||||
|
let maximizeButton: HTMLButtonElement;
|
||||||
if (isMacOS) titleBar.style.setProperty('--offset-left', '70px');
|
if (isMacOS) titleBar.style.setProperty('--offset-left', '70px');
|
||||||
|
|
||||||
logo.classList.add('title-bar-icon');
|
logo.classList.add('title-bar-icon');
|
||||||
@ -55,7 +56,7 @@ export default async () => {
|
|||||||
minimizeButton.appendChild(minimize);
|
minimizeButton.appendChild(minimize);
|
||||||
minimizeButton.onclick = () => ipcRenderer.invoke('window-minimize');
|
minimizeButton.onclick = () => ipcRenderer.invoke('window-minimize');
|
||||||
|
|
||||||
const maximizeButton = document.createElement('button');
|
maximizeButton = document.createElement('button');
|
||||||
if (await ipcRenderer.invoke('window-is-maximized')) {
|
if (await ipcRenderer.invoke('window-is-maximized')) {
|
||||||
maximizeButton.classList.add('window-control');
|
maximizeButton.classList.add('window-control');
|
||||||
maximizeButton.appendChild(unmaximize);
|
maximizeButton.appendChild(unmaximize);
|
||||||
@ -135,8 +136,14 @@ export default async () => {
|
|||||||
|
|
||||||
document.title = 'Youtube Music';
|
document.title = 'Youtube Music';
|
||||||
|
|
||||||
ipcRenderer.on('refreshMenu', () => {
|
ipcRenderer.on('refreshMenu', () => updateMenu());
|
||||||
updateMenu();
|
ipcRenderer.on('window-maximize', () => {
|
||||||
|
maximizeButton.removeChild(maximizeButton.firstChild!);
|
||||||
|
maximizeButton.appendChild(unmaximize);
|
||||||
|
});
|
||||||
|
ipcRenderer.on('window-unmaximize', () => {
|
||||||
|
maximizeButton.removeChild(maximizeButton.firstChild!);
|
||||||
|
maximizeButton.appendChild(maximize);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isEnabled('picture-in-picture')) {
|
if (isEnabled('picture-in-picture')) {
|
||||||
|
|||||||
4
plugins/visualizer/butterchurn.d.ts
vendored
4
plugins/visualizer/butterchurn.d.ts
vendored
@ -49,5 +49,7 @@ declare module 'butterchurn' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
declare module 'butterchurn-presets' {
|
declare module 'butterchurn-presets' {
|
||||||
export function getPresets(): Record<string, unknown>;
|
const presets: Record<string, unknown>;
|
||||||
|
|
||||||
|
export default presets;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,8 +5,6 @@ import { Visualizer } from './visualizer';
|
|||||||
|
|
||||||
import { ConfigType } from '../../../config/dynamic';
|
import { ConfigType } from '../../../config/dynamic';
|
||||||
|
|
||||||
const presets = ButterchurnPresets.getPresets();
|
|
||||||
|
|
||||||
class ButterchurnVisualizer extends Visualizer<Butterchurn> {
|
class ButterchurnVisualizer extends Visualizer<Butterchurn> {
|
||||||
name = 'butterchurn';
|
name = 'butterchurn';
|
||||||
|
|
||||||
@ -41,7 +39,7 @@ class ButterchurnVisualizer extends Visualizer<Butterchurn> {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const preset = presets[options.butterchurn.preset];
|
const preset = ButterchurnPresets[options.butterchurn.preset];
|
||||||
this.visualizer.loadPreset(preset, options.butterchurn.blendTimeInSeconds);
|
this.visualizer.loadPreset(preset, options.butterchurn.blendTimeInSeconds);
|
||||||
|
|
||||||
this.visualizer.connectAudio(audioNode);
|
this.visualizer.connectAudio(audioNode);
|
||||||
|
|||||||
@ -187,7 +187,7 @@ function onApiLoaded() {
|
|||||||
// Remove upgrade button
|
// Remove upgrade button
|
||||||
if (config.get('options.removeUpgradeButton')) {
|
if (config.get('options.removeUpgradeButton')) {
|
||||||
const styles = document.createElement('style');
|
const styles = document.createElement('style');
|
||||||
styles.innerHTML = `ytmusic-guide-section-renderer #items ytmusic-guide-entry-renderer:last-child {
|
styles.innerHTML = `ytmusic-guide-section-renderer #items ytmusic-guide-entry-renderer:nth-child(4) {
|
||||||
display: none;
|
display: none;
|
||||||
}`;
|
}`;
|
||||||
document.head.appendChild(styles);
|
document.head.appendChild(styles);
|
||||||
|
|||||||
@ -178,7 +178,7 @@ Some predefined themes are available in https://github.com/kerichdev/themes-for-
|
|||||||
```bash
|
```bash
|
||||||
git clone https://github.com/th-ch/youtube-music
|
git clone https://github.com/th-ch/youtube-music
|
||||||
cd youtube-music
|
cd youtube-music
|
||||||
npm
|
npm ci
|
||||||
npm run start
|
npm run start
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -269,9 +269,9 @@ export default () => {
|
|||||||
2. Run `npm i` to install dependencies
|
2. Run `npm i` to install dependencies
|
||||||
3. Run `npm run build:OS`
|
3. Run `npm run build:OS`
|
||||||
|
|
||||||
- `npm run build:win` - Windows
|
- `npm run dist:win` - Windows
|
||||||
- `npm run build:linux` - Linux
|
- `npm run dist:linux` - Linux
|
||||||
- `npm run build:mac` - MacOS
|
- `npm run dist:mac` - MacOS
|
||||||
|
|
||||||
Builds the app for macOS, Linux, and Windows,
|
Builds the app for macOS, Linux, and Windows,
|
||||||
using [electron-builder](https://github.com/electron-userland/electron-builder).
|
using [electron-builder](https://github.com/electron-userland/electron-builder).
|
||||||
|
|||||||
@ -1,42 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
const { existsSync, writeFile } = require('node:fs');
|
|
||||||
const { join } = require('node:path');
|
|
||||||
const { promisify } = require('node:util');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a fake package.json for given packages that don't have any.
|
|
||||||
* Allows electron-builder to resolve them
|
|
||||||
*/
|
|
||||||
|
|
||||||
const generatePackageJson = async (packageName) => {
|
|
||||||
const packageFolder = join('node_modules', packageName);
|
|
||||||
if (!existsSync(packageFolder)) {
|
|
||||||
console.log(
|
|
||||||
`${packageName} module not found, exiting…`,
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const filepath = join(packageFolder, 'package.json');
|
|
||||||
if (!existsSync(filepath)) {
|
|
||||||
console.log(
|
|
||||||
`No package.json found for ${packageName} module, generating one…`,
|
|
||||||
);
|
|
||||||
let pkg = {
|
|
||||||
name: packageName,
|
|
||||||
version: '0.0.0',
|
|
||||||
description: '-',
|
|
||||||
repository: { type: 'git', url: '-' },
|
|
||||||
readme: '-',
|
|
||||||
};
|
|
||||||
const writeFileAsync = promisify(writeFile);
|
|
||||||
await writeFileAsync(filepath, JSON.stringify(pkg, null, 2));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (require.main === module) {
|
|
||||||
process.argv.slice(2).forEach(async (packageName) => {
|
|
||||||
await generatePackageJson(packageName);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user