mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-09 17:51:46 +00:00
fix: apply fix from eslint
This commit is contained in:
@ -2,6 +2,7 @@
|
||||
|
||||
import eslint from '@eslint/js';
|
||||
import prettier from 'eslint-plugin-prettier/recommended';
|
||||
import solid from 'eslint-plugin-solid/configs/recommended';
|
||||
import stylistic from '@stylistic/eslint-plugin-js';
|
||||
import tsEslint from 'typescript-eslint';
|
||||
|
||||
@ -12,6 +13,7 @@ export default tsEslint.config(
|
||||
tsEslint.configs.eslintRecommended,
|
||||
...tsEslint.configs.recommendedTypeChecked,
|
||||
prettier,
|
||||
solid,
|
||||
{ ignores: ['dist', 'node_modules', '*.config.*js', '*.test.*js'] },
|
||||
{
|
||||
plugins: {
|
||||
|
||||
@ -163,6 +163,7 @@
|
||||
"eslint-import-resolver-typescript": "4.4.4",
|
||||
"eslint-plugin-import": "2.32.0",
|
||||
"eslint-plugin-prettier": "5.5.1",
|
||||
"eslint-plugin-solid": "0.14.5",
|
||||
"glob": "11.0.3",
|
||||
"node-gyp": "11.2.0",
|
||||
"playwright": "1.53.2",
|
||||
|
||||
59
pnpm-lock.yaml
generated
59
pnpm-lock.yaml
generated
@ -329,6 +329,9 @@ importers:
|
||||
eslint-plugin-prettier:
|
||||
specifier: 5.5.1
|
||||
version: 5.5.1(@types/eslint@9.6.1)(eslint-config-prettier@10.1.5(eslint@9.30.1))(eslint@9.30.1)(prettier@3.5.2)
|
||||
eslint-plugin-solid:
|
||||
specifier: 0.14.5
|
||||
version: 0.14.5(eslint@9.30.1)(typescript@5.8.3)
|
||||
glob:
|
||||
specifier: 11.0.3
|
||||
version: 11.0.3
|
||||
@ -2501,6 +2504,13 @@ packages:
|
||||
eslint-config-prettier:
|
||||
optional: true
|
||||
|
||||
eslint-plugin-solid@0.14.5:
|
||||
resolution: {integrity: sha512-nfuYK09ah5aJG/oEN6P1qziy1zLgW4PDWe75VNPi4CEFYk1x2AEqwFeQfEPR7gNn0F2jOeqKhx2E+5oNCOBYWQ==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
peerDependencies:
|
||||
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0
|
||||
typescript: '>=4.8.4'
|
||||
|
||||
eslint-scope@8.4.0:
|
||||
resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
@ -2882,6 +2892,10 @@ packages:
|
||||
html-entities@2.3.3:
|
||||
resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==}
|
||||
|
||||
html-tags@3.3.1:
|
||||
resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
html-to-text@9.0.5:
|
||||
resolution: {integrity: sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==}
|
||||
engines: {node: '>=14'}
|
||||
@ -2982,6 +2996,9 @@ packages:
|
||||
ini@1.3.8:
|
||||
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
|
||||
|
||||
inline-style-parser@0.2.4:
|
||||
resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==}
|
||||
|
||||
internal-slot@1.1.0:
|
||||
resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -3066,6 +3083,10 @@ packages:
|
||||
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
is-html@2.0.0:
|
||||
resolution: {integrity: sha512-S+OpgB5i7wzIue/YSE5hg0e5ZYfG3hhpNh9KGl6ayJ38p7ED6wxQLd1TV91xHpcTvw90KMJ9EwN3F/iNflHBVg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
is-inside-container@1.0.0:
|
||||
resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==}
|
||||
engines: {node: '>=14.16'}
|
||||
@ -3265,6 +3286,9 @@ packages:
|
||||
jszip@3.10.1:
|
||||
resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==}
|
||||
|
||||
kebab-case@1.0.2:
|
||||
resolution: {integrity: sha512-7n6wXq4gNgBELfDCpzKc+mRrZFs7D+wgfF5WRFLNAr4DA/qtr9Js8uOAVAfHhuLMfAcQ0pRKqbpjx+TcJVdE1Q==}
|
||||
|
||||
keyboardevent-from-electron-accelerator@2.0.0:
|
||||
resolution: {integrity: sha512-iQcmNA0M4ETMNi0kG/q0h/43wZk7rMeKYrXP7sqKIJbHkTU8Koowgzv+ieR/vWJbOwxx5nDC3UnudZ0aLSu4VA==}
|
||||
|
||||
@ -3274,6 +3298,9 @@ packages:
|
||||
keyv@4.5.4:
|
||||
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
||||
|
||||
known-css-properties@0.30.0:
|
||||
resolution: {integrity: sha512-VSWXYUnsPu9+WYKkfmJyLKtIvaRJi1kXUqVmBACORXZQxT5oZDsoZ2vQP+bQFDnWtpI/4eq3MLoRMjI2fnLzTQ==}
|
||||
|
||||
kuromoji@0.1.2:
|
||||
resolution: {integrity: sha512-V0dUf+C2LpcPEXhoHLMAop/bOht16Dyr+mDiIE39yX3vqau7p80De/koFqpiTcL1zzdZlc3xuHZ8u5gjYRfFaQ==}
|
||||
|
||||
@ -4443,6 +4470,9 @@ packages:
|
||||
stubborn-fs@1.2.5:
|
||||
resolution: {integrity: sha512-H2N9c26eXjzL/S/K+i/RHHcFanE74dptvvjM8iwzwbVcWY/zjBbgRqF3K0DY4+OD+uTTASTBvDoxPDaPN02D7g==}
|
||||
|
||||
style-to-object@1.0.9:
|
||||
resolution: {integrity: sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==}
|
||||
|
||||
sumchecker@3.0.1:
|
||||
resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==}
|
||||
engines: {node: '>= 8.0'}
|
||||
@ -7374,6 +7404,19 @@ snapshots:
|
||||
'@types/eslint': 9.6.1
|
||||
eslint-config-prettier: 10.1.5(eslint@9.30.1)
|
||||
|
||||
eslint-plugin-solid@0.14.5(eslint@9.30.1)(typescript@5.8.3):
|
||||
dependencies:
|
||||
'@typescript-eslint/utils': 8.36.0(eslint@9.30.1)(typescript@5.8.3)
|
||||
eslint: 9.30.1
|
||||
estraverse: 5.3.0
|
||||
is-html: 2.0.0
|
||||
kebab-case: 1.0.2
|
||||
known-css-properties: 0.30.0
|
||||
style-to-object: 1.0.9
|
||||
typescript: 5.8.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-scope@8.4.0:
|
||||
dependencies:
|
||||
esrecurse: 4.3.0
|
||||
@ -7828,6 +7871,8 @@ snapshots:
|
||||
|
||||
html-entities@2.3.3: {}
|
||||
|
||||
html-tags@3.3.1: {}
|
||||
|
||||
html-to-text@9.0.5:
|
||||
dependencies:
|
||||
'@selderee/plugin-htmlparser2': 0.11.0
|
||||
@ -7937,6 +7982,8 @@ snapshots:
|
||||
|
||||
ini@1.3.8: {}
|
||||
|
||||
inline-style-parser@0.2.4: {}
|
||||
|
||||
internal-slot@1.1.0:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
@ -8026,6 +8073,10 @@ snapshots:
|
||||
dependencies:
|
||||
is-extglob: 2.1.1
|
||||
|
||||
is-html@2.0.0:
|
||||
dependencies:
|
||||
html-tags: 3.3.1
|
||||
|
||||
is-inside-container@1.0.0:
|
||||
dependencies:
|
||||
is-docker: 3.0.0
|
||||
@ -8221,6 +8272,8 @@ snapshots:
|
||||
readable-stream: 2.3.8
|
||||
setimmediate: 1.0.5
|
||||
|
||||
kebab-case@1.0.2: {}
|
||||
|
||||
keyboardevent-from-electron-accelerator@2.0.0: {}
|
||||
|
||||
keyboardevents-areequal@0.2.2: {}
|
||||
@ -8229,6 +8282,8 @@ snapshots:
|
||||
dependencies:
|
||||
json-buffer: 3.0.1
|
||||
|
||||
known-css-properties@0.30.0: {}
|
||||
|
||||
kuromoji@0.1.2(patch_hash=4a948f1ea45c61779fa371feb020253ccf7a24e1f7c6b2e250b3ce53d86216d4):
|
||||
dependencies:
|
||||
async: 2.6.4
|
||||
@ -9415,6 +9470,10 @@ snapshots:
|
||||
|
||||
stubborn-fs@1.2.5: {}
|
||||
|
||||
style-to-object@1.0.9:
|
||||
dependencies:
|
||||
inline-style-parser: 0.2.4
|
||||
|
||||
sumchecker@3.0.1:
|
||||
dependencies:
|
||||
debug: 4.4.1
|
||||
|
||||
@ -76,7 +76,7 @@ export default createPlugin({
|
||||
async onPlayerApiReady(_, { getConfig }) {
|
||||
const config = await getConfig();
|
||||
if (config.blocker === blockers.AdSpeedup) {
|
||||
await loadAdSpeedup();
|
||||
loadAdSpeedup();
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@ -12,7 +12,7 @@ export const DislikeButton = (props: DislikeButtonProps) => (
|
||||
class="like-menu yt-spec-button-shape-next yt-spec-button-shape-next--text yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m yt-spec-button-shape-next--icon-button"
|
||||
aria-pressed="false"
|
||||
aria-label="Dislike all"
|
||||
onClick={props.onClick}
|
||||
onClick={(e) => props.onClick?.(e)}
|
||||
>
|
||||
<div
|
||||
class="yt-spec-button-shape-next__icon"
|
||||
@ -34,7 +34,7 @@ export const DislikeButton = (props: DislikeButtonProps) => (
|
||||
}}
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div style="width: 24px; height: 24px">
|
||||
<div style={{ 'width': '24px', 'height': '24px' }}>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
@ -50,7 +50,7 @@ export const DislikeButton = (props: DislikeButtonProps) => (
|
||||
<path
|
||||
d="M18,4h3v10h-3V4z M5.23,14h4.23l-1.52,4.94C7.62,19.97,8.46,21,9.62,21c0.58,0,1.14-0.24,1.52-0.65L17,14V4H6.57 C5.5,4,4.59,4.67,4.38,5.61l-1.34,6C2.77,12.85,3.82,14,5.23,14z"
|
||||
class="style-scope yt-icon"
|
||||
></path>
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
@ -76,7 +76,7 @@ export const DislikeButton = (props: DislikeButtonProps) => (
|
||||
<path
|
||||
d="M18,4h3v10h-3V4z M5.23,14h4.23l-1.52,4.94C7.62,19.97,8.46,21,9.62,21c0.58,0,1.14-0.24,1.52-0.65L17,14V4H6.57 C5.5,4,4.59,4.67,4.38,5.61l-1.34,6C2.77,12.85,3.82,14,5.23,14z"
|
||||
class="style-scope yt-icon"
|
||||
></path>
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
@ -90,8 +90,8 @@ export const DislikeButton = (props: DislikeButtonProps) => (
|
||||
class="yt-spec-touch-feedback-shape yt-spec-touch-feedback-shape--touch-response"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="yt-spec-touch-feedback-shape__stroke"></div>
|
||||
<div class="yt-spec-touch-feedback-shape__fill"></div>
|
||||
<div class="yt-spec-touch-feedback-shape__stroke" />
|
||||
<div class="yt-spec-touch-feedback-shape__fill" />
|
||||
</div>
|
||||
</yt-touch-feedback-shape>
|
||||
</button>
|
||||
|
||||
@ -12,7 +12,7 @@ export const LikeButton = (props: LikeButtonProps) => (
|
||||
class="like-menu yt-spec-button-shape-next yt-spec-button-shape-next--text yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m yt-spec-button-shape-next--icon-button"
|
||||
aria-pressed="false"
|
||||
aria-label="Like all"
|
||||
onClick={props.onClick}
|
||||
onClick={(e) => props.onClick?.(e)}
|
||||
>
|
||||
<div
|
||||
class="yt-spec-button-shape-next__icon"
|
||||
@ -34,7 +34,7 @@ export const LikeButton = (props: LikeButtonProps) => (
|
||||
}}
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div style="width: 24px; height: 24px">
|
||||
<div style={{ 'width': '24px', 'height': '24px' }}>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
@ -50,12 +50,12 @@ export const LikeButton = (props: LikeButtonProps) => (
|
||||
<path
|
||||
d="M3,11h3v10H3V11z M18.77,11h-4.23l1.52-4.94C16.38,5.03,15.54,4,14.38,4c-0.58,0-1.14,0.24-1.52,0.65L7,11v10h10.43 c1.06,0,1.98-0.67,2.19-1.61l1.34-6C21.23,12.15,20.18,11,18.77,11z"
|
||||
class="style-scope yt-icon"
|
||||
></path>
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div style="width: 24px; height: 24px">
|
||||
<div style={{ 'width': '24px', 'height': '24px' }}>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
@ -71,18 +71,18 @@ export const LikeButton = (props: LikeButtonProps) => (
|
||||
<path
|
||||
d="M3,11h3v10H3V11z M18.77,11h-4.23l1.52-4.94C16.38,5.03,15.54,4,14.38,4c-0.58,0-1.14,0.24-1.52,0.65L7,11v10h10.43 c1.06,0,1.98-0.67,2.19-1.61l1.34-6C21.23,12.15,20.18,11,18.77,11z"
|
||||
class="style-scope yt-icon"
|
||||
></path>
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<yt-touch-feedback-shape style="border-radius: inherit">
|
||||
<yt-touch-feedback-shape style={{ 'border-radius': 'inherit' }}>
|
||||
<div
|
||||
class="yt-spec-touch-feedback-shape yt-spec-touch-feedback-shape--touch-response"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="yt-spec-touch-feedback-shape__stroke"></div>
|
||||
<div class="yt-spec-touch-feedback-shape__fill"></div>
|
||||
<div class="yt-spec-touch-feedback-shape__stroke" />
|
||||
<div class="yt-spec-touch-feedback-shape__fill" />
|
||||
</div>
|
||||
</yt-touch-feedback-shape>
|
||||
</button>
|
||||
|
||||
@ -12,7 +12,7 @@ export const UnDislikeButton = (props: UnDislikeButtonProps) => (
|
||||
class="like-menu yt-spec-button-shape-next yt-spec-button-shape-next--text yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m yt-spec-button-shape-next--icon-button"
|
||||
aria-pressed="false"
|
||||
aria-label="Undislike all"
|
||||
onClick={props.onClick}
|
||||
onClick={(e) => props.onClick?.(e)}
|
||||
>
|
||||
<div
|
||||
class="yt-spec-button-shape-next__icon"
|
||||
@ -55,7 +55,7 @@ export const UnDislikeButton = (props: UnDislikeButtonProps) => (
|
||||
<path
|
||||
d="M17,4h-1H6.57C5.5,4,4.59,4.67,4.38,5.61l-1.34,6C2.77,12.85,3.82,14,5.23,14h4.23l-1.52,4.94C7.62,19.97,8.46,21,9.62,21 c0.58,0,1.14-0.24,1.52-0.65L17,14h4V4H17z M10.4,19.67C10.21,19.88,9.92,20,9.62,20c-0.26,0-0.5-0.11-0.63-0.3 c-0.07-0.1-0.15-0.26-0.09-0.47l1.52-4.94l0.4-1.29H9.46H5.23c-0.41,0-0.8-0.17-1.03-0.46c-0.12-0.15-0.25-0.4-0.18-0.72l1.34-6 C5.46,5.35,5.97,5,6.57,5H16v8.61L10.4,19.67z M20,13h-3V5h3V13z"
|
||||
class="style-scope yt-icon"
|
||||
></path>
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
@ -81,7 +81,7 @@ export const UnDislikeButton = (props: UnDislikeButtonProps) => (
|
||||
<path
|
||||
d="M17,4h-1H6.57C5.5,4,4.59,4.67,4.38,5.61l-1.34,6C2.77,12.85,3.82,14,5.23,14h4.23l-1.52,4.94C7.62,19.97,8.46,21,9.62,21 c0.58,0,1.14-0.24,1.52-0.65L17,14h4V4H17z M10.4,19.67C10.21,19.88,9.92,20,9.62,20c-0.26,0-0.5-0.11-0.63-0.3 c-0.07-0.1-0.15-0.26-0.09-0.47l1.52-4.94l0.4-1.29H9.46H5.23c-0.41,0-0.8-0.17-1.03-0.46c-0.12-0.15-0.25-0.4-0.18-0.72l1.34-6 C5.46,5.35,5.97,5,6.57,5H16v8.61L10.4,19.67z M20,13h-3V5h3V13z"
|
||||
class="style-scope yt-icon"
|
||||
></path>
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
@ -95,8 +95,8 @@ export const UnDislikeButton = (props: UnDislikeButtonProps) => (
|
||||
class="yt-spec-touch-feedback-shape yt-spec-touch-feedback-shape--touch-response"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="yt-spec-touch-feedback-shape__stroke"></div>
|
||||
<div class="yt-spec-touch-feedback-shape__fill"></div>
|
||||
<div class="yt-spec-touch-feedback-shape__stroke" />
|
||||
<div class="yt-spec-touch-feedback-shape__fill" />
|
||||
</div>
|
||||
</yt-touch-feedback-shape>
|
||||
</button>
|
||||
|
||||
@ -12,7 +12,7 @@ export const UnLikeButton = (props: UnLikeButtonProps) => (
|
||||
class="like-menu yt-spec-button-shape-next yt-spec-button-shape-next--text yt-spec-button-shape-next--mono yt-spec-button-shape-next--size-m yt-spec-button-shape-next--icon-button"
|
||||
aria-pressed="false"
|
||||
aria-label="Unlike all"
|
||||
onClick={props.onClick}
|
||||
onClick={(e) => props.onClick?.(e)}
|
||||
>
|
||||
<div
|
||||
class="yt-spec-button-shape-next__icon"
|
||||
@ -55,7 +55,7 @@ export const UnLikeButton = (props: UnLikeButtonProps) => (
|
||||
<path
|
||||
d="M18.77,11h-4.23l1.52-4.94C16.38,5.03,15.54,4,14.38,4c-0.58,0-1.14,0.24-1.52,0.65L7,11H3v10h4h1h9.43 c1.06,0,1.98-0.67,2.19-1.61l1.34-6C21.23,12.15,20.18,11,18.77,11z M7,20H4v-8h3V20z M19.98,13.17l-1.34,6 C18.54,19.65,18.03,20,17.43,20H8v-8.61l5.6-6.06C13.79,5.12,14.08,5,14.38,5c0.26,0,0.5,0.11,0.63,0.3 c0.07,0.1,0.15,0.26,0.09,0.47l-1.52,4.94L13.18,12h1.35h4.23c0.41,0,0.8,0.17,1.03,0.46C19.92,12.61,20.05,12.86,19.98,13.17z"
|
||||
class="style-scope yt-icon"
|
||||
></path>
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
@ -81,7 +81,7 @@ export const UnLikeButton = (props: UnLikeButtonProps) => (
|
||||
<path
|
||||
d="M18.77,11h-4.23l1.52-4.94C16.38,5.03,15.54,4,14.38,4c-0.58,0-1.14,0.24-1.52,0.65L7,11H3v10h4h1h9.43 c1.06,0,1.98-0.67,2.19-1.61l1.34-6C21.23,12.15,20.18,11,18.77,11z M7,20H4v-8h3V20z M19.98,13.17l-1.34,6 C18.54,19.65,18.03,20,17.43,20H8v-8.61l5.6-6.06C13.79,5.12,14.08,5,14.38,5c0.26,0,0.5,0.11,0.63,0.3 c0.07,0.1,0.15,0.26,0.09,0.47l-1.52,4.94L13.18,12h1.35h4.23c0.41,0,0.8,0.17,1.03,0.46C19.92,12.61,20.05,12.86,19.98,13.17z"
|
||||
class="style-scope yt-icon"
|
||||
></path>
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
@ -95,8 +95,8 @@ export const UnLikeButton = (props: UnLikeButtonProps) => (
|
||||
class="yt-spec-touch-feedback-shape yt-spec-touch-feedback-shape--touch-response"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="yt-spec-touch-feedback-shape__stroke"></div>
|
||||
<div class="yt-spec-touch-feedback-shape__fill"></div>
|
||||
<div class="yt-spec-touch-feedback-shape__stroke" />
|
||||
<div class="yt-spec-touch-feedback-shape__fill" />
|
||||
</div>
|
||||
</yt-touch-feedback-shape>
|
||||
</button>
|
||||
|
||||
@ -120,7 +120,8 @@ export const backend = createBackend<BackendType, APIServerConfig>({
|
||||
info: {
|
||||
version: '1.0.0',
|
||||
title: 'Youtube Music API Server',
|
||||
description: 'Note: You need to get an access token using the `/auth/{id}` endpoint first to call any API endpoints under `/api`.',
|
||||
description:
|
||||
'Note: You need to get an access token using the `/auth/{id}` endpoint first to call any API endpoints under `/api`.',
|
||||
},
|
||||
security: [
|
||||
{
|
||||
|
||||
@ -12,7 +12,7 @@ export const CaptionsSettingButton = (props: CaptionsSettingsButtonProps) => (
|
||||
role={'button'}
|
||||
tabindex={0}
|
||||
title={props.label}
|
||||
on:click={props.onClick}
|
||||
on:click={(e) => props.onClick(e)}
|
||||
>
|
||||
<span class="yt-icon-shape style-scope yt-icon yt-spec-icon-shape">
|
||||
<div
|
||||
@ -26,14 +26,19 @@ export const CaptionsSettingButton = (props: CaptionsSettingsButtonProps) => (
|
||||
<svg
|
||||
class="style-scope yt-icon"
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
style="pointer-events: none; display: block; width: 100%; height: 100%"
|
||||
style={{
|
||||
'pointer-events': 'none',
|
||||
'display': 'block',
|
||||
'width': '100%',
|
||||
'height': '100%',
|
||||
}}
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<g class="style-scope yt-icon">
|
||||
<path
|
||||
class="style-scope yt-icon"
|
||||
d="M20 4H4c-1.103 0-2 .897-2 2v12c0 1.103.897 2 2 2h16c1.103 0 2-.897 2-2V6c0-1.103-.897-2-2-2zm-9 6H8v4h3v2H8c-1.103 0-2-.897-2-2v-4c0-1.103.897-2 2-2h3v2zm7 0h-3v4h3v2h-3c-1.103 0-2-.897-2-2v-4c0-1.103.897-2 2-2h3v2z"
|
||||
></path>
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
@ -39,7 +39,10 @@ import type { GetPlayerResponse } from '@/types/get-player-response';
|
||||
import type { FormatOptions } from 'node_modules/youtubei.js/dist/src/types';
|
||||
import type { VideoInfo } from 'node_modules/youtubei.js/dist/src/parser/youtube';
|
||||
import type { PlayerErrorMessage } from 'node_modules/youtubei.js/dist/src/parser/nodes';
|
||||
import type { TrackInfo, Playlist } from 'node_modules/youtubei.js/dist/src/parser/ytmusic';
|
||||
import type {
|
||||
TrackInfo,
|
||||
Playlist,
|
||||
} from 'node_modules/youtubei.js/dist/src/parser/ytmusic';
|
||||
|
||||
type CustomSongInfo = SongInfo & { trackId?: string };
|
||||
|
||||
|
||||
@ -38,7 +38,7 @@ export const onMenu = async ({
|
||||
...deepmerge(
|
||||
defaultConfig.downloadOnFinish,
|
||||
config.downloadOnFinish,
|
||||
)!,
|
||||
),
|
||||
enabled: item.checked,
|
||||
},
|
||||
});
|
||||
@ -62,7 +62,7 @@ export const onMenu = async ({
|
||||
...deepmerge(
|
||||
defaultConfig.downloadOnFinish,
|
||||
config.downloadOnFinish,
|
||||
)!,
|
||||
),
|
||||
folder: result[0],
|
||||
},
|
||||
});
|
||||
@ -87,7 +87,7 @@ export const onMenu = async ({
|
||||
...deepmerge(
|
||||
defaultConfig.downloadOnFinish,
|
||||
config.downloadOnFinish,
|
||||
)!,
|
||||
),
|
||||
mode: 'seconds',
|
||||
},
|
||||
});
|
||||
@ -105,7 +105,7 @@ export const onMenu = async ({
|
||||
...deepmerge(
|
||||
defaultConfig.downloadOnFinish,
|
||||
config.downloadOnFinish,
|
||||
)!,
|
||||
),
|
||||
mode: 'percent',
|
||||
},
|
||||
});
|
||||
@ -168,7 +168,7 @@ export const onMenu = async ({
|
||||
...deepmerge(
|
||||
defaultConfig.downloadOnFinish,
|
||||
config.downloadOnFinish,
|
||||
)!,
|
||||
),
|
||||
seconds: Number(res[0]),
|
||||
percent: Number(res[1]),
|
||||
},
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { createSignal, JSX, Show, splitProps } from 'solid-js';
|
||||
import { mergeProps, Portal } from 'solid-js/web';
|
||||
import { createSignal, JSX, Show, splitProps, mergeProps } from 'solid-js';
|
||||
import { Portal } from 'solid-js/web';
|
||||
import { css } from 'solid-styled-components';
|
||||
import { Transition } from 'solid-transition-group';
|
||||
import {
|
||||
|
||||
@ -6,7 +6,7 @@ export interface BackButtonProps {
|
||||
export const BackButton = (props: BackButtonProps) => (
|
||||
<div
|
||||
class="style-scope ytmusic-pivot-bar-renderer navigation-item"
|
||||
onClick={props.onClick}
|
||||
onClick={(e) => props.onClick?.(e)}
|
||||
role="tab"
|
||||
tab-id="FEmusic_back"
|
||||
>
|
||||
@ -33,7 +33,7 @@ export const BackButton = (props: BackButtonProps) => (
|
||||
viewBox="0 0 492 492"
|
||||
>
|
||||
<g class="style-scope iron-icon">
|
||||
<path d="M109.3 265.2l218.9 218.9c5.1 5.1 11.8 7.9 19 7.9s14-2.8 19-7.9l16.1-16.1c10.5-10.5 10.5-27.6 0-38.1L198.6 246.1 382.7 62c5.1-5.1 7.9-11.8 7.9-19 0-7.2-2.8-14-7.9-19L366.5 7.9c-5.1-5.1-11.8-7.9-19-7.9-7.2 0-14 2.8-19 7.9L109.3 227c-5.1 5.1-7.9 11.9-7.8 19.1 0 7.2 2.8 14 7.8 19.1z"></path>
|
||||
<path d="M109.3 265.2l218.9 218.9c5.1 5.1 11.8 7.9 19 7.9s14-2.8 19-7.9l16.1-16.1c10.5-10.5 10.5-27.6 0-38.1L198.6 246.1 382.7 62c5.1-5.1 7.9-11.8 7.9-19 0-7.2-2.8-14-7.9-19L366.5 7.9c-5.1-5.1-11.8-7.9-19-7.9-7.2 0-14 2.8-19 7.9L109.3 227c-5.1 5.1-7.9 11.9-7.8 19.1 0 7.2 2.8 14 7.8 19.1z" />
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
@ -6,7 +6,7 @@ export interface ForwardButtonProps {
|
||||
export const ForwardButton = (props: ForwardButtonProps) => (
|
||||
<div
|
||||
class="style-scope ytmusic-pivot-bar-renderer navigation-item"
|
||||
onClick={props.onClick}
|
||||
onClick={(e) => props.onClick?.(e)}
|
||||
role="tab"
|
||||
tab-id="FEmusic_next"
|
||||
>
|
||||
@ -37,7 +37,7 @@ export const ForwardButton = (props: ForwardButtonProps) => (
|
||||
d="M382.7,226.8L163.7,7.9c-5.1-5.1-11.8-7.9-19-7.9s-14,2.8-19,7.9L109.5,24c-10.5,10.5-10.5,27.6,0,38.1
|
||||
l183.9,183.9L109.3,430c-5.1,5.1-7.9,11.8-7.9,19c0,7.2,2.8,14,7.9,19l16.1,16.1c5.1,5.1,11.8,7.9,19,7.9s14-2.8,19-7.9L382.7,265
|
||||
c5.1-5.1,7.9-11.9,7.8-19.1C390.5,238.7,387.8,231.9,382.7,226.8z"
|
||||
></path>
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
@ -23,4 +23,4 @@ export default createPlugin({
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@ -8,7 +8,7 @@ export const PictureInPictureButton = (props: PictureInPictureButtonProps) => (
|
||||
class="yt-simple-endpoint style-scope ytmusic-menu-navigation-item-renderer"
|
||||
id="navigation-endpoint"
|
||||
tabindex={-1}
|
||||
onClick={props.onClick}
|
||||
onClick={(e) => props.onClick?.(e)}
|
||||
>
|
||||
<div class="icon ytmd-menu-item style-scope ytmusic-menu-navigation-item-renderer">
|
||||
<svg
|
||||
|
||||
@ -26,13 +26,13 @@ export const PlaybackSpeedSlider = (props: PlaybackSpeedSliderProps) => (
|
||||
aria-valuenow={props.speed}
|
||||
class="volume-slider style-scope ytmusic-player-bar on-hover"
|
||||
dir="ltr"
|
||||
on:immediate-value-changed={props.onImmediateValueChanged}
|
||||
onWheel={props.onWheel}
|
||||
on:immediate-value-changed={(e) => props.onImmediateValueChanged?.(e)}
|
||||
onWheel={(e) => props.onWheel?.(e)}
|
||||
max="2"
|
||||
min="0"
|
||||
role="slider"
|
||||
step="0.125"
|
||||
style="display: inherit !important"
|
||||
style={{ 'display': 'inherit !important' }}
|
||||
tabindex="0"
|
||||
title={props.title}
|
||||
value={props.speed}
|
||||
@ -48,7 +48,7 @@ export const PlaybackSpeedSlider = (props: PlaybackSpeedSliderProps) => (
|
||||
class="style-scope tp-yt-paper-slider"
|
||||
id="sliderBar"
|
||||
role="progressbar"
|
||||
style="touch-action: none"
|
||||
style={{ 'touch-action': 'none' }}
|
||||
value="1"
|
||||
>
|
||||
<div
|
||||
@ -59,12 +59,12 @@ export const PlaybackSpeedSlider = (props: PlaybackSpeedSliderProps) => (
|
||||
class="style-scope tp-yt-paper-progress"
|
||||
hidden={true}
|
||||
id="secondaryProgress"
|
||||
style="transform: scaleX(0)"
|
||||
style={{ 'transform': 'scaleX(0)' }}
|
||||
/>
|
||||
<div
|
||||
class="style-scope tp-yt-paper-progress"
|
||||
id="primaryProgress"
|
||||
style="transform: scaleX(0.5)"
|
||||
style={{ 'transform': 'scaleX(0.5)' }}
|
||||
/>
|
||||
</div>
|
||||
</tp-yt-paper-progress>
|
||||
@ -72,7 +72,7 @@ export const PlaybackSpeedSlider = (props: PlaybackSpeedSliderProps) => (
|
||||
<div
|
||||
class="slider-knob style-scope tp-yt-paper-slider"
|
||||
id="sliderKnob"
|
||||
style="left: 50%; touch-action: none"
|
||||
style={{ 'left': '50%', 'touch-action': 'none' }}
|
||||
>
|
||||
<input
|
||||
class="slider-knob-inner style-scope tp-yt-paper-slider"
|
||||
|
||||
@ -12,7 +12,7 @@ export const QualitySettingButton = (props: QualitySettingButtonProps) => (
|
||||
role={'button'}
|
||||
tabindex={0}
|
||||
title={props.label}
|
||||
on:click={props.onClick}
|
||||
on:click={(e) => props.onClick(e)}
|
||||
>
|
||||
<span class="yt-icon-shape style-scope yt-icon yt-spec-icon-shape">
|
||||
<div
|
||||
@ -26,14 +26,19 @@ export const QualitySettingButton = (props: QualitySettingButtonProps) => (
|
||||
<svg
|
||||
class="style-scope yt-icon"
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
style="pointer-events: none; display: block; width: 100%; height: 100%"
|
||||
style={{
|
||||
'pointer-events': 'none',
|
||||
'display': 'block',
|
||||
'width': '100%',
|
||||
'height': '100%',
|
||||
}}
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<g class="style-scope yt-icon">
|
||||
<path
|
||||
class="style-scope yt-icon"
|
||||
d="M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2.1-1.65c.2-.15.25-.42.13-.64l-2-3.46c-.12-.22-.4-.3-.6-.22l-2.5 1c-.52-.4-1.08-.73-1.7-.98l-.37-2.65c-.06-.24-.27-.42-.5-.42h-4c-.27 0-.48.18-.5.42l-.4 2.65c-.6.25-1.17.6-1.7.98l-2.48-1c-.23-.1-.5 0-.6.22l-2 3.46c-.14.22-.08.5.1.64l2.12 1.65c-.04.32-.07.65-.07.98s.02.66.06.98l-2.1 1.65c-.2.15-.25.42-.13.64l2 3.46c.12.22.4.3.6.22l2.5-1c.52.4 1.08.73 1.7.98l.37 2.65c.04.24.25.42.5.42h4c.25 0 .46-.18.5-.42l.37-2.65c.6-.25 1.17-.6 1.7-.98l2.48 1c.23.1.5 0 .6-.22l2-3.46c.13-.22.08-.5-.1-.64l-2.12-1.65zM12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z"
|
||||
></path>
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
import { createBackend } from '@/utils';
|
||||
import { net } from 'electron';
|
||||
|
||||
import { createBackend } from '@/utils';
|
||||
|
||||
const handlers = {
|
||||
// Note: This will only be used for Forbidden headers, e.g. User-Agent, Authority, Cookie, etc.
|
||||
// See: https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_request_header
|
||||
async fetch(
|
||||
url: string,
|
||||
init: RequestInit
|
||||
init: RequestInit,
|
||||
): Promise<[number, string, Record<string, string>]> {
|
||||
const res = await net.fetch(url, init);
|
||||
return [
|
||||
@ -19,7 +20,9 @@ const handlers = {
|
||||
|
||||
export const backend = createBackend({
|
||||
start(ctx) {
|
||||
ctx.ipc.handle('synced-lyrics:fetch', handlers.fetch);
|
||||
ctx.ipc.handle('synced-lyrics:fetch', (url: string, init: RequestInit) =>
|
||||
handlers.fetch(url, init),
|
||||
);
|
||||
},
|
||||
stop(ctx) {
|
||||
ctx.ipc.removeHandler('synced-lyrics:fetch');
|
||||
|
||||
@ -17,7 +17,6 @@ export class LRCLib implements LyricProvider {
|
||||
songDuration,
|
||||
tags,
|
||||
}: SearchSongInfo): Promise<LyricResult | null> {
|
||||
|
||||
let query = new URLSearchParams({
|
||||
artist_name: artist,
|
||||
track_name: title,
|
||||
@ -59,7 +58,7 @@ export class LRCLib implements LyricProvider {
|
||||
if (!Array.isArray(data)) {
|
||||
throw new Error(`Expected an array, instead got ${typeof data}`);
|
||||
}
|
||||
|
||||
|
||||
// If still no results, try with the original title as fallback
|
||||
if (data.length === 0 && alternativeTitle) {
|
||||
query = new URLSearchParams({ q: title });
|
||||
@ -98,15 +97,15 @@ export class LRCLib implements LyricProvider {
|
||||
}
|
||||
}
|
||||
|
||||
let ratio = Math.max(
|
||||
...permutations.map(([x, y]) => jaroWinkler(x, y)),
|
||||
);
|
||||
let ratio = Math.max(...permutations.map(([x, y]) => jaroWinkler(x, y)));
|
||||
|
||||
// If direct artist match is below threshold and we have tags, try matching with tags
|
||||
if (ratio <= 0.9 && tags && tags.length > 0) {
|
||||
// Filter out the artist from tags to avoid duplicate comparisons
|
||||
const filteredTags = tags.filter(tag => tag.toLowerCase() !== artist.toLowerCase());
|
||||
|
||||
const filteredTags = tags.filter(
|
||||
(tag) => tag.toLowerCase() !== artist.toLowerCase(),
|
||||
);
|
||||
|
||||
const tagPermutations = [];
|
||||
// Compare each tag with each item artist
|
||||
for (const tag of filteredTags) {
|
||||
@ -114,19 +113,19 @@ export class LRCLib implements LyricProvider {
|
||||
tagPermutations.push([tag.toLowerCase(), itemArtist.toLowerCase()]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Compare each item artist with each tag
|
||||
for (const itemArtist of itemArtists) {
|
||||
for (const tag of filteredTags) {
|
||||
tagPermutations.push([itemArtist.toLowerCase(), tag.toLowerCase()]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (tagPermutations.length > 0) {
|
||||
const tagRatio = Math.max(
|
||||
...tagPermutations.map(([x, y]) => jaroWinkler(x, y)),
|
||||
);
|
||||
|
||||
|
||||
// Use the best match ratio between direct artist match and tag match
|
||||
ratio = Math.max(ratio, tagRatio);
|
||||
}
|
||||
|
||||
@ -37,10 +37,13 @@ type LyricsStore = {
|
||||
};
|
||||
|
||||
const initialData = () =>
|
||||
providerNames.reduce((acc, name) => {
|
||||
acc[name] = { state: 'fetching', data: null, error: null };
|
||||
return acc;
|
||||
}, {} as LyricsStore['lyrics']);
|
||||
providerNames.reduce(
|
||||
(acc, name) => {
|
||||
acc[name] = { state: 'fetching', data: null, error: null };
|
||||
return acc;
|
||||
},
|
||||
{} as LyricsStore['lyrics'],
|
||||
);
|
||||
|
||||
export const [lyricsStore, setLyricsStore] = createStore<LyricsStore>({
|
||||
provider: providerNames[0],
|
||||
|
||||
@ -10,11 +10,13 @@ interface PlainLyricsProps {
|
||||
export const PlainLyrics = (props: PlainLyricsProps) => {
|
||||
const [romanization, setRomanization] = createSignal('');
|
||||
|
||||
createEffect(async () => {
|
||||
createEffect(() => {
|
||||
if (!config()?.romanization) return;
|
||||
|
||||
const input = canonicalize(props.line);
|
||||
setRomanization(canonicalize(await romanize(input)));
|
||||
romanize(input).then((result) => {
|
||||
setRomanization(canonicalize(result));
|
||||
});
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
import { createEffect, createMemo, For, Show, createSignal } from 'solid-js';
|
||||
|
||||
import { VirtualizerHandle } from 'virtua/solid';
|
||||
|
||||
import { LineLyrics } from '@/plugins/synced-lyrics/types';
|
||||
|
||||
import { config } from '../renderer';
|
||||
import { _ytAPI } from '..';
|
||||
|
||||
import { canonicalize, romanize, simplifyUnicode } from '../utils';
|
||||
|
||||
import { VirtualizerHandle } from 'virtua/solid';
|
||||
import { LineLyrics } from '@/plugins/synced-lyrics/types';
|
||||
|
||||
interface SyncedLineProps {
|
||||
scroller: VirtualizerHandle;
|
||||
index: number;
|
||||
@ -27,80 +28,57 @@ export const SyncedLine = (props: SyncedLineProps) => {
|
||||
|
||||
const [romanization, setRomanization] = createSignal('');
|
||||
|
||||
createEffect(async () => {
|
||||
createEffect(() => {
|
||||
if (!config()?.romanization) return;
|
||||
|
||||
const input = canonicalize(text());
|
||||
setRomanization(canonicalize(await romanize(input)));
|
||||
romanize(input).then((result) => {
|
||||
setRomanization(canonicalize(result));
|
||||
});
|
||||
});
|
||||
|
||||
if (!text()) {
|
||||
return (
|
||||
<yt-formatted-string
|
||||
text={{
|
||||
runs: [{ text: '' }],
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
class={`synced-line ${props.status}`}
|
||||
onClick={() => {
|
||||
_ytAPI?.seekTo((props.line.timeInMs + 10) / 1000);
|
||||
}}
|
||||
>
|
||||
<div dir="auto" class="description ytmusic-description-shelf-renderer">
|
||||
<Show
|
||||
when={text()}
|
||||
fallback={
|
||||
<yt-formatted-string
|
||||
text={{
|
||||
runs: [
|
||||
{ text: config()?.showTimeCodes ? `[${props.line.time}] ` : '' },
|
||||
],
|
||||
runs: [{ text: '' }],
|
||||
}}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div
|
||||
class={`synced-line ${props.status}`}
|
||||
onClick={() => {
|
||||
_ytAPI?.seekTo((props.line.timeInMs + 10) / 1000);
|
||||
}}
|
||||
>
|
||||
<div dir="auto" class="description ytmusic-description-shelf-renderer">
|
||||
<yt-formatted-string
|
||||
text={{
|
||||
runs: [
|
||||
{
|
||||
text: config()?.showTimeCodes ? `[${props.line.time}] ` : '',
|
||||
},
|
||||
],
|
||||
}}
|
||||
/>
|
||||
|
||||
<div
|
||||
class="text-lyrics"
|
||||
ref={(div: HTMLDivElement) => {
|
||||
// TODO: Investigate the animation, even though the duration is properly set, all lines have the same animation duration
|
||||
div.style.setProperty(
|
||||
'--lyrics-duration',
|
||||
`${props.line.duration / 1000}s`,
|
||||
'important',
|
||||
);
|
||||
}}
|
||||
style={{ 'display': 'flex', 'flex-direction': 'column' }}
|
||||
>
|
||||
<span>
|
||||
<For each={text().split(' ')}>
|
||||
{(word, index) => {
|
||||
return (
|
||||
<span
|
||||
style={{
|
||||
'transition-delay': `${index() * 0.05}s`,
|
||||
'animation-delay': `${index() * 0.05}s`,
|
||||
}}
|
||||
>
|
||||
<yt-formatted-string
|
||||
text={{
|
||||
runs: [{ text: `${word} ` }],
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}}
|
||||
</For>
|
||||
</span>
|
||||
|
||||
<Show
|
||||
when={
|
||||
config()?.romanization &&
|
||||
simplifyUnicode(text()) !== simplifyUnicode(romanization())
|
||||
}
|
||||
<div
|
||||
class="text-lyrics"
|
||||
ref={(div: HTMLDivElement) => {
|
||||
// TODO: Investigate the animation, even though the duration is properly set, all lines have the same animation duration
|
||||
div.style.setProperty(
|
||||
'--lyrics-duration',
|
||||
`${props.line.duration / 1000}s`,
|
||||
'important',
|
||||
);
|
||||
}}
|
||||
style={{ 'display': 'flex', 'flex-direction': 'column' }}
|
||||
>
|
||||
<span class="romaji">
|
||||
<For each={romanization().split(' ')}>
|
||||
<span>
|
||||
<For each={text().split(' ')}>
|
||||
{(word, index) => {
|
||||
return (
|
||||
<span
|
||||
@ -119,9 +97,37 @@ export const SyncedLine = (props: SyncedLineProps) => {
|
||||
}}
|
||||
</For>
|
||||
</span>
|
||||
</Show>
|
||||
|
||||
<Show
|
||||
when={
|
||||
config()?.romanization &&
|
||||
simplifyUnicode(text()) !== simplifyUnicode(romanization())
|
||||
}
|
||||
>
|
||||
<span class="romaji">
|
||||
<For each={romanization().split(' ')}>
|
||||
{(word, index) => {
|
||||
return (
|
||||
<span
|
||||
style={{
|
||||
'transition-delay': `${index() * 0.05}s`,
|
||||
'animation-delay': `${index() * 0.05}s`,
|
||||
}}
|
||||
>
|
||||
<yt-formatted-string
|
||||
text={{
|
||||
runs: [{ text: `${word} ` }],
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}}
|
||||
</For>
|
||||
</span>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
|
||||
@ -14,7 +14,7 @@ import type { SyncedLyricsPluginConfig } from '../types';
|
||||
export let _ytAPI: YoutubePlayer | null = null;
|
||||
export let netFetch: (
|
||||
url: string,
|
||||
init?: RequestInit
|
||||
init?: RequestInit,
|
||||
) => Promise<[number, string, Record<string, string>]>;
|
||||
|
||||
export const renderer = createRenderer<
|
||||
@ -56,7 +56,7 @@ export const renderer = createRenderer<
|
||||
if (!this.updateTimestampInterval) {
|
||||
this.updateTimestampInterval = setInterval(
|
||||
() => setCurrentTime((_ytAPI?.getCurrentTime() ?? 0) * 1000),
|
||||
100
|
||||
100,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -10,11 +10,11 @@ import pinyin from 'tiny-pinyin';
|
||||
|
||||
import { lazy } from 'lazy-var';
|
||||
|
||||
import { detect } from 'tinyld';
|
||||
|
||||
import { waitForElement } from '@/utils/wait-for-element';
|
||||
import { LyricsRenderer, setIsVisible } from './renderer';
|
||||
|
||||
import { detect } from 'tinyld';
|
||||
|
||||
export const selectors = {
|
||||
head: '#tabsContent > .tab-header:nth-of-type(2)',
|
||||
body: {
|
||||
|
||||
@ -183,7 +183,7 @@ export default createPlugin({
|
||||
setVideoState(target.checked);
|
||||
}}
|
||||
songButtonText={t('plugins.video-toggle.templates.button-song')}
|
||||
videoButtonText={t('plugins.video-toggle.templates.button-video',)}
|
||||
videoButtonText={t('plugins.video-toggle.templates.button-video')}
|
||||
/>
|
||||
</Show>
|
||||
),
|
||||
|
||||
@ -9,8 +9,8 @@ export const VideoSwitchButton = (props: VideoSwitchButtonProps) => (
|
||||
<div
|
||||
class="video-switch-button"
|
||||
data-video-button-text={props.videoButtonText}
|
||||
on:click={props.onClick}
|
||||
onChange={props.onChange}
|
||||
on:click={(e) => props.onClick?.(e)}
|
||||
onChange={(e) => props.onChange?.(e)}
|
||||
>
|
||||
<input
|
||||
checked={true}
|
||||
@ -18,7 +18,10 @@ export const VideoSwitchButton = (props: VideoSwitchButtonProps) => (
|
||||
class="video-switch-button-checkbox"
|
||||
type="checkbox"
|
||||
/>
|
||||
<label class="video-switch-button-label" for="video-toggle-video-switch-button-checkbox">
|
||||
<label
|
||||
class="video-switch-button-label"
|
||||
for="video-toggle-video-switch-button-checkbox"
|
||||
>
|
||||
<span class="video-switch-button-label-span">{props.songButtonText}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
1436
src/types/icons.ts
1436
src/types/icons.ts
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user