mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-15 12:21:47 +00:00
feat(synced-lyrics): Better-Lyrics Styling for Synced-Lyrics (#2554)
Co-authored-by: JellyBrick <shlee1503@naver.com>
This commit is contained in:
@ -725,6 +725,10 @@
|
|||||||
"line-effect": {
|
"line-effect": {
|
||||||
"label": "Line effect",
|
"label": "Line effect",
|
||||||
"submenu": {
|
"submenu": {
|
||||||
|
"fancy": {
|
||||||
|
"label": "Fancy",
|
||||||
|
"tooltip": "Use large, app-like effects on the current line"
|
||||||
|
},
|
||||||
"focus": {
|
"focus": {
|
||||||
"label": "Focus",
|
"label": "Focus",
|
||||||
"tooltip": "Make only the current line white"
|
"tooltip": "Make only the current line white"
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import type { SyncedLyricsPluginConfig } from './types';
|
|||||||
export default createPlugin({
|
export default createPlugin({
|
||||||
name: () => t('plugins.synced-lyrics.name'),
|
name: () => t('plugins.synced-lyrics.name'),
|
||||||
description: () => t('plugins.synced-lyrics.description'),
|
description: () => t('plugins.synced-lyrics.description'),
|
||||||
authors: ['Non0reo', 'ArjixWasTaken'],
|
authors: ['Non0reo', 'ArjixWasTaken', 'KimJammer'],
|
||||||
restartNeeded: true,
|
restartNeeded: true,
|
||||||
addedVersion: '3.5.X',
|
addedVersion: '3.5.X',
|
||||||
config: {
|
config: {
|
||||||
@ -19,8 +19,8 @@ export default createPlugin({
|
|||||||
showLyricsEvenIfInexact: true,
|
showLyricsEvenIfInexact: true,
|
||||||
showTimeCodes: false,
|
showTimeCodes: false,
|
||||||
defaultTextString: '♪',
|
defaultTextString: '♪',
|
||||||
lineEffect: 'scale',
|
lineEffect: 'fancy',
|
||||||
} as SyncedLyricsPluginConfig,
|
} satisfies SyncedLyricsPluginConfig,
|
||||||
|
|
||||||
menu,
|
menu,
|
||||||
renderer,
|
renderer,
|
||||||
|
|||||||
@ -5,9 +5,9 @@ import { t } from '@/i18n';
|
|||||||
import type { MenuContext } from '@/types/contexts';
|
import type { MenuContext } from '@/types/contexts';
|
||||||
import type { SyncedLyricsPluginConfig } from './types';
|
import type { SyncedLyricsPluginConfig } from './types';
|
||||||
|
|
||||||
export const menu = async (ctx: MenuContext<SyncedLyricsPluginConfig>): Promise<
|
export const menu = async (
|
||||||
MenuItemConstructorOptions[]
|
ctx: MenuContext<SyncedLyricsPluginConfig>,
|
||||||
> => {
|
): Promise<MenuItemConstructorOptions[]> => {
|
||||||
const config = await ctx.getConfig();
|
const config = await ctx.getConfig();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@ -27,6 +27,21 @@ export const menu = async (ctx: MenuContext<SyncedLyricsPluginConfig>): Promise<
|
|||||||
toolTip: t('plugins.synced-lyrics.menu.line-effect.tooltip'),
|
toolTip: t('plugins.synced-lyrics.menu.line-effect.tooltip'),
|
||||||
type: 'submenu',
|
type: 'submenu',
|
||||||
submenu: [
|
submenu: [
|
||||||
|
{
|
||||||
|
label: t(
|
||||||
|
'plugins.synced-lyrics.menu.line-effect.submenu.fancy.label',
|
||||||
|
),
|
||||||
|
toolTip: t(
|
||||||
|
'plugins.synced-lyrics.menu.line-effect.submenu.fancy.tooltip',
|
||||||
|
),
|
||||||
|
type: 'radio',
|
||||||
|
checked: config.lineEffect === 'fancy',
|
||||||
|
click() {
|
||||||
|
ctx.setConfig({
|
||||||
|
lineEffect: 'fancy',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: t(
|
label: t(
|
||||||
'plugins.synced-lyrics.menu.line-effect.submenu.scale.label',
|
'plugins.synced-lyrics.menu.line-effect.submenu.scale.label',
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { createEffect, createMemo } from 'solid-js';
|
import { createEffect, createMemo, For } from 'solid-js';
|
||||||
|
|
||||||
import { currentTime } from './LyricsContainer';
|
import { currentTime } from './LyricsContainer';
|
||||||
|
|
||||||
@ -32,7 +32,16 @@ export const SyncedLine = ({ line }: SyncedLineProps) => {
|
|||||||
return config()?.defaultTextString ?? '';
|
return config()?.defaultTextString ?? '';
|
||||||
});
|
});
|
||||||
|
|
||||||
// prettier-ignore
|
if (!text()) {
|
||||||
|
return (
|
||||||
|
<yt-formatted-string
|
||||||
|
text={{
|
||||||
|
runs: [{ text: '' }],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
@ -41,14 +50,33 @@ export const SyncedLine = ({ line }: SyncedLineProps) => {
|
|||||||
_ytAPI?.seekTo(line.timeInMs / 1000);
|
_ytAPI?.seekTo(line.timeInMs / 1000);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<yt-formatted-string
|
<div class="text-lyrics description ytmusic-description-shelf-renderer">
|
||||||
class="text-lyrics description ytmusic-description-shelf-renderer"
|
<yt-formatted-string
|
||||||
text={{
|
text={{
|
||||||
runs: [
|
runs: [{ text: config()?.showTimeCodes ? `[${line.time}] ` : '' }],
|
||||||
{ text: config()?.showTimeCodes ? `[${line.time}]` : '' },
|
}}
|
||||||
{ text: text() }],
|
/>
|
||||||
}}
|
|
||||||
/>
|
<For each={text().split(' ')}>
|
||||||
|
{(word, index) => {
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
'transition-delay': `${index() * 0.05}s`,
|
||||||
|
'animation-delay': `${index() * 0.05}s`,
|
||||||
|
'--lyrics-duration:': `${line.duration / 1000}s;`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<yt-formatted-string
|
||||||
|
text={{
|
||||||
|
runs: [{ text: `${word} ` }],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -17,35 +17,85 @@ createEffect(() => {
|
|||||||
|
|
||||||
// Set the line effect
|
// Set the line effect
|
||||||
switch (config()?.lineEffect) {
|
switch (config()?.lineEffect) {
|
||||||
case 'scale':
|
case 'fancy':
|
||||||
|
root.style.setProperty('--lyrics-font-size', '3rem');
|
||||||
|
root.style.setProperty('--lyrics-line-height', '1.333');
|
||||||
|
root.style.setProperty('--lyrics-width', '100%');
|
||||||
|
root.style.setProperty('--lyrics-padding', '2rem');
|
||||||
root.style.setProperty(
|
root.style.setProperty(
|
||||||
'--previous-lyrics',
|
'--lyrics-animations',
|
||||||
'var(--ytmusic-text-primary)',
|
'lyrics-glow var(--lyrics-glow-duration) forwards, lyrics-wobble var(--lyrics-wobble-duration) forwards',
|
||||||
);
|
);
|
||||||
root.style.setProperty('--current-lyrics', 'var(--ytmusic-text-primary)');
|
|
||||||
root.style.setProperty('--size-lyrics', '1.2');
|
root.style.setProperty('--lyrics-inactive-font-weight', '700');
|
||||||
root.style.setProperty('--offset-lyrics', '0');
|
root.style.setProperty('--lyrics-inactive-opacity', '0.33');
|
||||||
root.style.setProperty('--lyric-width', '83%');
|
root.style.setProperty('--lyrics-inactive-scale', '0.95');
|
||||||
|
root.style.setProperty('--lyrics-inactive-offset', '0');
|
||||||
|
|
||||||
|
root.style.setProperty('--lyrics-active-font-weight', '700');
|
||||||
|
root.style.setProperty('--lyrics-active-opacity', '1');
|
||||||
|
root.style.setProperty('--lyrics-active-scale', '1');
|
||||||
|
root.style.setProperty('--lyrics-active-offset', '0');
|
||||||
|
break;
|
||||||
|
case 'scale':
|
||||||
|
root.style.setProperty('--lyrics-font-size', '1.4rem');
|
||||||
|
root.style.setProperty(
|
||||||
|
'--lyrics-line-height',
|
||||||
|
'var(--ytmusic-body-line-height)',
|
||||||
|
);
|
||||||
|
root.style.setProperty('--lyrics-width', '83%');
|
||||||
|
root.style.setProperty('--lyrics-padding', '0');
|
||||||
|
root.style.setProperty('--lyrics-animations', 'none');
|
||||||
|
|
||||||
|
root.style.setProperty('--lyrics-inactive-font-weight', '400');
|
||||||
|
root.style.setProperty('--lyrics-inactive-opacity', '0.33');
|
||||||
|
root.style.setProperty('--lyrics-inactive-scale', '1');
|
||||||
|
root.style.setProperty('--lyrics-inactive-offset', '0');
|
||||||
|
|
||||||
|
root.style.setProperty('--lyrics-active-font-weight', '700');
|
||||||
|
root.style.setProperty('--lyrics-active-opacity', '1');
|
||||||
|
root.style.setProperty('--lyrics-active-scale', '1.2');
|
||||||
|
root.style.setProperty('--lyrics-active-offset', '0');
|
||||||
break;
|
break;
|
||||||
case 'offset':
|
case 'offset':
|
||||||
|
root.style.setProperty('--lyrics-font-size', '1.4rem');
|
||||||
root.style.setProperty(
|
root.style.setProperty(
|
||||||
'--previous-lyrics',
|
'--lyrics-line-height',
|
||||||
'var(--ytmusic-text-primary)',
|
'var(--ytmusic-body-line-height)',
|
||||||
);
|
);
|
||||||
root.style.setProperty('--current-lyrics', 'var(--ytmusic-text-primary)');
|
root.style.setProperty('--lyrics-width', '100%');
|
||||||
root.style.setProperty('--size-lyrics', '1');
|
root.style.setProperty('--lyrics-padding', '0');
|
||||||
root.style.setProperty('--offset-lyrics', '5%');
|
root.style.setProperty('--lyrics-animations', 'none');
|
||||||
root.style.setProperty('--lyric-width', '100%');
|
|
||||||
|
root.style.setProperty('--lyrics-inactive-font-weight', '400');
|
||||||
|
root.style.setProperty('--lyrics-inactive-opacity', '0.33');
|
||||||
|
root.style.setProperty('--lyrics-inactive-scale', '1');
|
||||||
|
root.style.setProperty('--lyrics-inactive-offset', '0');
|
||||||
|
|
||||||
|
root.style.setProperty('--lyrics-active-font-weight', '700');
|
||||||
|
root.style.setProperty('--lyrics-active-opacity', '1');
|
||||||
|
root.style.setProperty('--lyrics-active-scale', '1');
|
||||||
|
root.style.setProperty('--lyrics-active-offset', '5%');
|
||||||
break;
|
break;
|
||||||
case 'focus':
|
case 'focus':
|
||||||
|
root.style.setProperty('--lyrics-font-size', '1.4rem');
|
||||||
root.style.setProperty(
|
root.style.setProperty(
|
||||||
'--previous-lyrics',
|
'--lyrics-line-height',
|
||||||
'var(--ytmusic-text-secondary)',
|
'var(--ytmusic-body-line-height)',
|
||||||
);
|
);
|
||||||
root.style.setProperty('--current-lyrics', 'var(--ytmusic-text-primary)');
|
root.style.setProperty('--lyrics-width', '100%');
|
||||||
root.style.setProperty('--size-lyrics', '1');
|
root.style.setProperty('--lyrics-padding', '0');
|
||||||
root.style.setProperty('--offset-lyrics', '0');
|
root.style.setProperty('--lyrics-animations', 'none');
|
||||||
root.style.setProperty('--lyric-width', '100%');
|
|
||||||
|
root.style.setProperty('--lyrics-inactive-font-weight', '400');
|
||||||
|
root.style.setProperty('--lyrics-inactive-opacity', '0.33');
|
||||||
|
root.style.setProperty('--lyrics-inactive-scale', '1');
|
||||||
|
root.style.setProperty('--lyrics-inactive-offset', '0');
|
||||||
|
|
||||||
|
root.style.setProperty('--lyrics-active-font-weight', '700');
|
||||||
|
root.style.setProperty('--lyrics-active-opacity', '1');
|
||||||
|
root.style.setProperty('--lyrics-active-scale', '1');
|
||||||
|
root.style.setProperty('--lyrics-active-offset', '0');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -8,18 +8,40 @@
|
|||||||
display: block !important;
|
display: block !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* :root {
|
/* Variables are overridden by selected line effect */
|
||||||
--ytmusic-text-primary: #fff;
|
|
||||||
--ytmusic-text-secondary: #aaa;
|
|
||||||
} */
|
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
|
/* Layout */
|
||||||
--global-margin: 0.7rem;
|
--global-margin: 0.7rem;
|
||||||
--previous-lyrics: var(--ytmusic-text-primary);
|
--lyrics-padding: 0;
|
||||||
--current-lyrics: var(--ytmusic-text-primary);
|
|
||||||
--upcoming-lyrics: var(--ytmusic-text-secondary);
|
/* Typography */
|
||||||
--size-lyrics: 1.2em;
|
--lyrics-font-family: Satoshi, Avenir, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell,
|
||||||
--offset-lyrics: 1em;
|
Open Sans, Helvetica Neue, sans-serif;
|
||||||
|
--lyrics-font-size: 1.4rem;
|
||||||
|
--lyrics-line-height: var(--ytmusic-body-line-height);
|
||||||
|
--lyrics-width: 100%;
|
||||||
|
|
||||||
|
/* Inactive Lyrics */
|
||||||
|
--lyrics-inactive-font-weight: 400;
|
||||||
|
--lyrics-inactive-opacity: 0.33;
|
||||||
|
--lyrics-inactive-scale: 1;
|
||||||
|
--lyrics-inactive-offset: 0;
|
||||||
|
|
||||||
|
/* Active Lyrics */
|
||||||
|
--lyrics-active-font-weight: 700;
|
||||||
|
--lyrics-active-opacity: 1;
|
||||||
|
--lyrics-active-scale: 1;
|
||||||
|
--lyrics-active-offset: 0;
|
||||||
|
|
||||||
|
/* Animations */
|
||||||
|
--lyrics-animations: lyrics-glow var(--lyrics-glow-duration) forwards, lyrics-wobble var(--lyrics-wobble-duration) forwards;
|
||||||
|
--lyrics-scale-duration: 0.166s;
|
||||||
|
--lyrics-opacity-transition: 0.33s;
|
||||||
|
--lyrics-glow-duration: var(--lyrics-duration, 2s);
|
||||||
|
--lyrics-wobble-duration: calc(var(--lyrics-duration, 2s) / 2);
|
||||||
|
|
||||||
|
/* Colors */
|
||||||
|
--glow-color: rgba(255, 255, 255, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.lyric-container {
|
.lyric-container {
|
||||||
@ -32,7 +54,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.synced-line {
|
.synced-line {
|
||||||
width: var(--lyric-width, 100%);
|
width: var(--lyrics-width, 100%);
|
||||||
|
|
||||||
& > .text-lyrics {
|
& > .text-lyrics {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@ -43,8 +65,7 @@
|
|||||||
display: block;
|
display: block;
|
||||||
justify-content: left;
|
justify-content: left;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
margin: 0.5rem 0;
|
margin: 0.5rem 20px 0.5rem 0;
|
||||||
margin-right: 20px;
|
|
||||||
transition: all 0.3s ease-in-out;
|
transition: all 0.3s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,35 +75,46 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.text-lyrics {
|
.text-lyrics {
|
||||||
|
font-family: var(--lyrics-font-family) !important;
|
||||||
|
font-size: var(--lyrics-font-size) !important;
|
||||||
|
font-weight: var(--lyrics-inactive-font-weight) !important;
|
||||||
|
line-height: var(--lyrics-line-height) !important;
|
||||||
|
padding-top: var(--lyrics-padding);
|
||||||
|
padding-bottom: var(--lyrics-padding);
|
||||||
|
scale: var(--lyrics-inactive-scale);
|
||||||
|
translate: var(--lyrics-inactive-offset);
|
||||||
|
transition:
|
||||||
|
scale var(--lyrics-scale-duration),
|
||||||
|
translate 0.3s ease-in-out;
|
||||||
|
|
||||||
display: block;
|
display: block;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
margin: var(--global-margin) 0;
|
margin: var(--global-margin) 0;
|
||||||
transition:
|
|
||||||
scale 0.3s ease-in-out,
|
|
||||||
translate 0.3s ease-in-out,
|
|
||||||
color 0.1s ease-in-out;
|
|
||||||
transform-origin: 0 50%;
|
transform-origin: 0 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.text-lyrics > span {
|
.text-lyrics > span {
|
||||||
margin-inline: 0.1em;
|
display: inline-block;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
opacity: var(--lyrics-inactive-opacity);
|
||||||
|
transition: opacity var(--lyrics-opacity-transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
.previous > .text-lyrics {
|
.previous > .text-lyrics {
|
||||||
color: var(--previous-lyrics);
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.current > .text-lyrics {
|
.current > .text-lyrics {
|
||||||
color: var(--current-lyrics);
|
font-weight: var(--lyrics-active-font-weight) !important;
|
||||||
font-weight: bold;
|
scale: var(--lyrics-active-scale);
|
||||||
scale: var(--size-lyrics);
|
translate: var(--lyrics-active-offset);
|
||||||
translate: var(--offset-lyrics) 0;
|
}
|
||||||
|
|
||||||
|
.current > .text-lyrics > span {
|
||||||
|
opacity: var(--lyrics-active-opacity);
|
||||||
|
animation: var(--lyrics-animations);
|
||||||
}
|
}
|
||||||
|
|
||||||
.upcoming > .text-lyrics {
|
.upcoming > .text-lyrics {
|
||||||
color: var(--upcoming-lyrics);
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.lyrics-renderer {
|
.lyrics-renderer {
|
||||||
@ -162,3 +194,28 @@
|
|||||||
|
|
||||||
transition: top 325ms ease-in-out;
|
transition: top 325ms ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Animations */
|
||||||
|
@keyframes lyrics-wobble {
|
||||||
|
from {
|
||||||
|
transform: translateY(0px);
|
||||||
|
}
|
||||||
|
33.33% {
|
||||||
|
transform: translateY(1.75px);
|
||||||
|
}
|
||||||
|
66.66% {
|
||||||
|
transform: translateY(-1.75px);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translateY(0px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes lyrics-glow {
|
||||||
|
0% {
|
||||||
|
text-shadow: 0 0 1.5rem var(--glow-color);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
text-shadow: 0 0 0 var(--glow-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -20,7 +20,7 @@ export type LineLyrics = {
|
|||||||
status: LineLyricsStatus;
|
status: LineLyricsStatus;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type LineEffect = 'scale' | 'offset' | 'focus';
|
export type LineEffect = 'fancy' | 'scale' | 'offset' | 'focus';
|
||||||
|
|
||||||
export interface LyricResult {
|
export interface LyricResult {
|
||||||
title: string;
|
title: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user