Compare commits

...

6 Commits

Author SHA1 Message Date
8d9a819346 chore(deps): update dependency vite to v7.2.9 2025-12-01 07:26:47 +00:00
127f56905c fix(album-color-theme): improve theming consistency across UI elements (#4109)
Co-authored-by: 최민우 <chaeminu0711@gmail.com>
2025-12-01 16:25:14 +09:00
8d448c667f chore(i18n): Translated using Weblate (Urdu)
Currently translated at 25.0% (114 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/ur/
2025-11-29 08:01:53 +01:00
e00f33eb2d chore(i18n): Translated using Weblate (Slovak)
Currently translated at 84.4% (385 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/sk/
2025-11-29 08:01:52 +01:00
8100804ced chore(i18n): Translated using Weblate (Hebrew)
Currently translated at 46.9% (214 of 456 strings)

Translation: pear-devs/pear-desktop/i18n
Translate-URL: https://hosted.weblate.org/projects/youtube-music/i18n/he/
2025-11-28 06:02:01 +01:00
4fba3ffd92 fix(downloader): update youtubei.js and remove player_id (#4069) 2025-11-26 21:20:58 +02:00
10 changed files with 331 additions and 359 deletions

View File

@ -45,7 +45,7 @@
},
"pnpm": {
"overrides": {
"vite": "npm:rolldown-vite@7.1.8",
"vite": "npm:rolldown-vite@7.2.9",
"node-gyp": "11.4.2",
"xml2js": "0.6.2",
"node-fetch": "3.3.2",
@ -134,7 +134,7 @@
"virtua": "0.42.3",
"vudio": "2.1.1",
"x11": "2.3.0",
"youtubei.js": "15.0.1",
"youtubei.js": "^16.0.1",
"zod": "4.1.5"
},
"devDependencies": {
@ -173,7 +173,7 @@
"typescript": "5.9.2",
"typescript-eslint": "8.43.0",
"utf-8-validate": "6.0.5",
"vite": "npm:rolldown-vite@7.1.8",
"vite": "npm:rolldown-vite@7.2.9",
"vite-plugin-inspect": "11.3.3",
"vite-plugin-resolve": "2.5.2",
"vite-plugin-solid": "2.11.8",

491
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -237,7 +237,8 @@
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"enable-seekbar": "Enable seekbar theming"
},
"name": "Album Color Theme"
},

View File

@ -150,6 +150,11 @@
"visual-tweaks": {
"label": "תיקונים חזותיים",
"submenu": {
"custom-window-title": {
"prompt": {
"placeholder": "לדוגמה: שולחן כתיבה אגסי"
}
},
"like-buttons": {
"default": "ברירת מחדל",
"force-show": "הפעל בכוח",
@ -201,8 +206,8 @@
"restart": "הפעל מחדש",
"show": "הראה חלון",
"tooltip": {
"default": "יוטיוב מיוזיק",
"with-song-info": "יוטיוב מיוזיק: {{artist}} - {{title}}"
"default": "שולחן כתיבה אגסי",
"with-song-info": "שולחן כתיב אגסי: {{יוצר}} - {{כותרת}}"
}
}
},
@ -212,7 +217,7 @@
"name": "הגבר מהירות פרסומת"
},
"adblocker": {
"description": "חסום את כל המודעות והמעקב מחוץ לקופסה",
"description": "חסום את כל המודעות והמעקבים",
"menu": {
"blocker": "חוסם"
},
@ -244,6 +249,7 @@
}
},
"buffer": {
"label": "חוצץ",
"submenu": {
"buffer": "{{buffer}}"
}
@ -380,6 +386,11 @@
},
"templates": {
"title": "פתח בחירת כתוביות"
},
"toast": {
"caption-changed": "תרגום שונה ל {{שפה}}",
"caption-disabled": "תרגום בוטל",
"no-captions": "אין תרגום זמין לשיר הזה"
}
},
"compact-sidebar": {
@ -391,9 +402,11 @@
"menu": {
"advanced": "מתקדם"
},
"name": "התפיידות צלב[בית]",
"prompt": {
"options": {
"multi-input": {
"fade-in-duration": "תתפייד בזמן[מילישניות]",
"fade-scaling": {
"linear": "לינארי",
"logarithmic": "לוגריתמי"

View File

@ -237,7 +237,8 @@
"submenu": {
"percent": "{{ratio}}%"
}
}
},
"enable-seekbar": "재생바 색조 변경 활성화"
},
"name": "앨범 컬러 기반 테마"
},

View File

@ -462,7 +462,7 @@
"label": "Text stavu",
"submenu": {
"artist": "Aktuálne si prehráva {artist}",
"pear-desktop": "Aktuálne prehráva Pear Desktop",
"pear-desktop": "Počúva Pear Desktop",
"title": "Aktuálne si prehráva {song title}"
}
}

View File

@ -151,7 +151,9 @@
"label": "بصری تبدیلیاں",
"submenu": {
"custom-window-title": {
"label": "اپنی مرضی کا ونڈو عنوان",
"prompt": {
"label": "اپنی مرضی کا ونڈو عنوان درج کریں: (بند کرنے کے لیے خالی چھوڑ دیں)",
"placeholder": "مثال: پیئر ڈیسک ٹاپ"
}
},
@ -219,7 +221,8 @@
"description": "شروغ سے تمام اشتہارات اور ٹریکنگ بلاک کردیں",
"menu": {
"blocker": "بلاکر"
}
},
"name": "ایڈ بلاکر"
}
}
}

View File

@ -10,41 +10,32 @@ const COLOR_KEY = '--ytmusic-album-color';
const DARK_COLOR_KEY = '--ytmusic-album-color-dark';
const RATIO_KEY = '--ytmusic-album-color-ratio';
export default createPlugin<
unknown,
unknown,
{
color?: ColorInstance;
darkColor?: ColorInstance;
type Config = {
enabled: boolean;
ratio: number;
enableSeekbar: boolean;
};
playerPage: HTMLElement | null;
navBarBackground: HTMLElement | null;
ytmusicPlayerBar: HTMLElement | null;
playerBarBackground: HTMLElement | null;
sidebarBig: HTMLElement | null;
sidebarSmall: HTMLElement | null;
ytmusicAppLayout: HTMLElement | null;
type Renderer = {
getMixedColor(
color: string,
key: string,
alpha?: number,
ratioMultiply?: number,
): string;
updateColor(alpha: number): void;
onConfigChange(newConfig: Config): void;
};
getMixedColor(
color: string,
key: string,
alpha?: number,
ratioMultiply?: number,
): string;
updateColor(alpha: number): void;
},
{
enabled: boolean;
ratio: number;
}
>({
export default createPlugin({
name: () => t('plugins.album-color-theme.name'),
description: () => t('plugins.album-color-theme.description'),
restartNeeded: false,
config: {
enabled: false,
ratio: 0.5,
},
enableSeekbar: true,
} satisfies Config as Config,
stylesheets: [style],
menu: async ({ getConfig, setConfig }) => {
const ratioList = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1];
@ -68,18 +59,28 @@ export default createPlugin<
},
})),
},
{
label: t('plugins.album-color-theme.menu.enable-seekbar'),
type: 'checkbox',
checked: config.enableSeekbar,
click(item) {
setConfig({ enableSeekbar: item.checked });
},
},
];
},
renderer: {
playerPage: null,
navBarBackground: null,
ytmusicPlayerBar: null,
playerBarBackground: null,
sidebarBig: null,
sidebarSmall: null,
ytmusicAppLayout: null,
playerPage: null as HTMLElement | null,
navBarBackground: null as HTMLElement | null,
ytmusicPlayerBar: null as HTMLElement | null,
playerBarBackground: null as HTMLElement | null,
sidebarBig: null as HTMLElement | null,
sidebarSmall: null as HTMLElement | null,
ytmusicAppLayout: null as HTMLElement | null,
color: null as ColorInstance | null,
darkColor: null as ColorInstance | null,
async start({ getConfig }) {
start() {
this.playerPage = document.querySelector<HTMLElement>('#player-page');
this.navBarBackground = document.querySelector<HTMLElement>(
'#nav-bar-background',
@ -94,14 +95,11 @@ export default createPlugin<
'#mini-guide-background',
);
this.ytmusicAppLayout = document.querySelector<HTMLElement>('#layout');
const config = await getConfig();
document.documentElement.style.setProperty(
RATIO_KEY,
`${~~(config.ratio * 100)}%`,
);
},
onPlayerApiReady(playerApi) {
async onPlayerApiReady(playerApi, { getConfig }) {
const config = await getConfig();
(this as Renderer).onConfigChange(config);
const fastAverageColor = new FastAverageColor();
document.addEventListener('videodatachange', async (event) => {
@ -152,7 +150,7 @@ export default createPlugin<
alpha = value;
}
}
this.updateColor(alpha ?? 1);
(this as Renderer).updateColor(alpha ?? 1);
});
},
onConfigChange(config) {
@ -160,8 +158,15 @@ export default createPlugin<
RATIO_KEY,
`${~~(config.ratio * 100)}%`,
);
if (config.enableSeekbar) document.body.classList.add('seekbar-theme');
else document.body.classList.remove('seekbar-theme');
},
getMixedColor(color: string, key: string, alpha = 1, ratioMultiply) {
getMixedColor(
color: string,
key: string,
alpha = 1,
ratioMultiply?: number,
) {
const keyColor = `rgba(var(${key}), ${alpha})`;
let colorRatio = `var(${RATIO_KEY}, 50%)`;
@ -207,26 +212,39 @@ export default createPlugin<
'--yt-spec-black-pure-alpha-80': 'rgba(0,0,0,0.8)',
'--yt-spec-black-1-alpha-98': 'rgba(40,40,40,0.98)',
'--yt-spec-black-1-alpha-95': 'rgba(40,40,40,0.95)',
'--paper-toast-background-color': '#323232',
'--ytmusic-search-background': '#030303',
'--paper-slider-knob-color': '#f03',
'--paper-dialog-background-color': '#212121',
'--paper-progress-active-color-1': '#f03',
'--paper-progress-active-color-2': '#ff2791',
'--yt-spec-inverted-background': '#f3f3f3',
'background': 'rgba(3, 3, 3)',
'--ytmusic-background': 'rgba(3, 3, 3)',
};
const colorKeyMap: Record<string, string> = {
'background': DARK_COLOR_KEY,
'--ytmusic-background': DARK_COLOR_KEY,
};
const ratioMap: Record<string, number> = {
'--paper-progress-active-color-1': 1.75,
'--paper-progress-active-color-2': 1.75,
'--yt-spec-inverted-background': 1.75,
};
const getMixedColor = (this as Renderer).getMixedColor.bind(this);
Object.entries(variableMap).map(([variable, color]) => {
const key = colorKeyMap[variable] ?? COLOR_KEY;
const ratio = ratioMap[variable] ?? undefined;
document.documentElement.style.setProperty(
variable,
this.getMixedColor(color, COLOR_KEY, alpha),
getMixedColor(color, key, alpha, ratio),
'important',
);
});
document.body.style.setProperty(
'background',
this.getMixedColor('rgba(3, 3, 3)', DARK_COLOR_KEY, alpha),
'important',
);
document.documentElement.style.setProperty(
'--ytmusic-background',
// #030303
this.getMixedColor('rgba(3, 3, 3)', DARK_COLOR_KEY, alpha),
'important',
);
},
},
});

View File

@ -81,3 +81,14 @@ ytmusic-browse-response[has-background]:not([disable-gradient]) .background-grad
#background.immersive-background.style-scope.ytmusic-browse-response {
opacity: 0.6;
}
ytmusic-search-box[is-bauhaus-sidenav-enabled] {
--ytmusic-search-background: var(--ytmusic-color-black3) !important;
}
.seekbar-theme #progress-bar.ytmusic-player-bar {
--paper-slider-active-color: linear-gradient(to right, var(--paper-progress-active-color-1) 80%, var(--paper-progress-active-color-2) 100%) !important;
--paper-slider-knob-color: var(--paper-progress-active-color-1) !important;
--paper-slider-knob-start-color: var(--paper-progress-active-color-2) !important;
}

View File

@ -8,6 +8,7 @@ import {
UniversalCache,
Utils,
YTNodes,
Platform,
} from '\u0079\u006f\u0075\u0074\u0075\u0062\u0065i.js';
import is from 'electron-is';
import filenamify from 'filenamify';
@ -57,6 +58,22 @@ const ffmpeg = lazy(async () =>
);
const ffmpegMutex = new Mutex();
Platform.shim.eval = async (data: Types.BuildScriptResult, env: Record<string, Types.VMPrimative>) => {
const properties = [];
if(env.n) {
properties.push(`n: exportedVars.nFunction("${env.n}")`)
}
if (env.sig) {
properties.push(`sig: exportedVars.sigFunction("${env.sig}")`)
}
const code = `${data.output}\nreturn { ${properties.join(', ')} }`;
return new Function(code)();
}
let yt: Innertube;
let win: BrowserWindow;
let playingUrl: string;
@ -131,7 +148,6 @@ export const onMainLoad = async ({
yt = await Innertube.create({
cache: new UniversalCache(false),
player_id: '0004de42',
cookie: await getCookieFromWindow(win),
generate_session_locally: true,
fetch: getNetFetchAsFetch(),