feat(transparent-player): new plugin for Acrylic, Mica or Tabbed effects (#3529)

Co-authored-by: JellyBrick <shlee1503@naver.com>
This commit is contained in:
FrostyBiscuit
2025-09-06 02:00:39 +02:00
committed by GitHub
parent 789a30312b
commit 895210cbb6
9 changed files with 309 additions and 21 deletions

View File

@ -31,7 +31,7 @@ export default createPlugin<
alpha?: number,
ratioMultiply?: number,
): string;
updateColor(): void;
updateColor(alpha: number): void;
},
{
enabled: boolean;
@ -143,7 +143,16 @@ export default createPlugin<
document.documentElement.style.setProperty(DARK_COLOR_KEY, '0, 0, 0');
}
this.updateColor();
let alpha: number | null = null;
if (await window.mainConfig.plugins.isEnabled('transparent-player')) {
const value: unknown = window.mainConfig.get(
'plugins.transparent-player.opacity',
);
if (typeof value === 'number' && value >= 0 && value <= 1) {
alpha = value;
}
}
this.updateColor(alpha ?? 1);
});
},
onConfigChange(config) {
@ -163,7 +172,7 @@ export default createPlugin<
}
return `color-mix(in srgb, ${color} ${originalRatio}, ${keyColor} ${colorRatio})`;
},
updateColor() {
updateColor(alpha: number) {
const variableMap = {
'--ytmusic-color-black1': '#212121',
'--ytmusic-color-black2': '#181818',
@ -202,19 +211,20 @@ export default createPlugin<
Object.entries(variableMap).map(([variable, color]) => {
document.documentElement.style.setProperty(
variable,
this.getMixedColor(color, COLOR_KEY),
this.getMixedColor(color, COLOR_KEY, alpha),
'important',
);
});
document.body.style.setProperty(
'background',
this.getMixedColor('#030303', COLOR_KEY),
this.getMixedColor('rgba(3, 3, 3)', DARK_COLOR_KEY, alpha),
'important',
);
document.documentElement.style.setProperty(
'--ytmusic-background',
this.getMixedColor('#030303', DARK_COLOR_KEY),
// #030303
this.getMixedColor('rgba(3, 3, 3)', DARK_COLOR_KEY, alpha),
'important',
);
},

View File

@ -329,6 +329,7 @@ export const TitleBar = (props: TitleBarProps) => {
data-macos={props.isMacOS}
data-show={mouseY() < 32}
data-ytmd-main-panel={true}
id={'ytmd-title-bar-main-panel'}
>
<IconButton
onClick={() => setCollapsed(!collapsed())}

View File

@ -0,0 +1,112 @@
import { t } from '@/i18n';
import { createPlugin } from '@/utils';
import { Platform } from '@/types/plugins';
import { MaterialType, type TransparentPlayerConfig } from './types';
import style from './style.css?inline';
import type { BrowserWindow } from 'electron';
const defaultConfig: TransparentPlayerConfig = {
enabled: false,
opacity: 0.5,
type: MaterialType.ACRYLIC,
};
const opacityList = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1];
const typeList = Object.values(MaterialType);
export default createPlugin({
name: () => t('plugins.transparent-player.name'),
description: () => t('plugins.transparent-player.description'),
addedVersion: '3.10.x',
restartNeeded: true,
platform: Platform.Windows,
config: defaultConfig,
stylesheets: [style],
async menu({ getConfig, setConfig }) {
const config = await getConfig();
return [
{
label: t('plugins.transparent-player.menu.opacity.label'),
submenu: opacityList.map((opacity) => ({
label: t('plugins.transparent-player.menu.opacity.submenu.percent', {
opacity: opacity * 100,
}),
type: 'radio',
checked: config.opacity === opacity,
click() {
setConfig({ opacity });
},
})),
},
{
label: t('plugins.transparent-player.menu.type.label'),
submenu: typeList.map((type) => ({
label: t(`plugins.transparent-player.menu.type.submenu.${type}`),
type: 'radio',
checked: config.type === type,
click() {
setConfig({ type });
},
})),
},
];
},
backend: {
mainWindow: null as BrowserWindow | null,
async start({ window, getConfig }) {
this.mainWindow = window;
const config = await getConfig();
window.setBackgroundMaterial?.(config.type);
window.setBackgroundColor?.(`rgba(0, 0, 0, ${config.opacity})`);
},
onConfigChange(newConfig) {
this.mainWindow?.setBackgroundMaterial?.(newConfig.type);
},
stop({ window }) {
window.setBackgroundMaterial?.('none');
},
},
renderer: {
props: {
enabled: defaultConfig.enabled,
opacity: defaultConfig.opacity,
type: defaultConfig.type,
} as TransparentPlayerConfig,
async start({ getConfig }) {
const config = await getConfig();
this.props = config;
if (config.enabled) {
document.body.classList.add('transparent-background-color');
document.body.classList.add('transparent-player-backdrop-filter');
if (!(await window.mainConfig.plugins.isEnabled('album-color-theme'))) {
document.body.classList.add('transparent-player');
}
this.applyVariables();
}
},
onConfigChange(newConfig) {
this.props = newConfig;
this.applyVariables();
},
stop() {
document.body.classList.remove('transparent-background-color');
document.body.classList.remove('transparent-player-backdrop-filter');
document.body.classList.remove('transparent-player');
document.documentElement.style.removeProperty(
'--ytmd-transparent-player-opacity',
);
},
applyVariables(this: { props: TransparentPlayerConfig }) {
const { opacity } = this.props;
document.documentElement.style.setProperty(
'--ytmd-transparent-player-opacity',
opacity.toString(),
);
},
},
});

View File

@ -0,0 +1,106 @@
:root {
--ytmd-transparent-player-transparency-color: #111;
--ytmd-transparent-player-transparent-background: rgb(
from var(--ytmd-transparent-player-transparency-color) r g b /
var(--ytmd-transparent-player-opacity, 0.5)
);
--ytmd-transparent-player-transparent-background-dark: rgb(
from var(--ytmd-transparent-player-transparency-color) r g b / 0.8
);
--ytmd-transparent-player-backdrop-blur: blur(20px);
}
body.transparent-background-color {
background-color: var(--ytmd-transparent-player-transparent-background) !important;
}
body.transparent-player-backdrop-filter {
#layout {
#nav-bar-background,
#player-bar-background {
backdrop-filter: var(--ytmd-transparent-player-backdrop-blur) !important;
}
}
#search-page {
#tabs {
&.stuck {
backdrop-filter: var(--ytmd-transparent-player-backdrop-blur) !important;
}
}
}
ytmusic-menu-popup-renderer {
backdrop-filter: var(--ytmd-transparent-player-backdrop-blur) !important;
}
#ytmd-title-bar-main-panel {
backdrop-filter: var(--ytmd-transparent-player-backdrop-blur) !important;
}
}
body.transparent-player {
ytmusic-app {
ytmusic-app-layout[player-page-open] {
#nav-bar-background.ytmusic-app-layout,
#player-bar-background.ytmusic-app-layout {
opacity: 0 !important;
}
}
#layout {
#nav-bar-background,
#player-bar-background {
background: var(--ytmd-transparent-player-transparent-background-dark) !important;
}
#mini-guide-background {
background: none !important;
border: 0 !important;
}
#guide {
#guide-wrapper {
background: none !important;
border: 0 !important;
}
}
ytmusic-player-bar {
background: none !important;
}
#player-page {
background: none !important;
}
#search-page {
#tabs {
&.stuck {
background: var(--ytmd-transparent-player-transparent-background) !important;
}
}
}
#browse-page {
#background {
display: none !important;
}
.background-gradient {
background: none !important;
}
}
}
}
/* Window Top Panel */
nav[data-ytmd-main-panel] {
background-color: transparent !important;
}
/* Video Toggle Plugin */
.av-toggle.ytmusic-av-toggle {
background-color: var(--ytmd-transparent-player-transparent-background);
}
}

View File

@ -0,0 +1,12 @@
export enum MaterialType {
MICA = 'mica',
ACRYLIC = 'acrylic',
TABBED = 'tabbed',
NONE = 'none',
}
export type TransparentPlayerConfig = {
enabled: boolean;
opacity: number;
type: MaterialType;
};