@uimaxbai/am-lyrics 1.0.6 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -24
- package/demo/index.html +2 -2
- package/dist/src/AmLyrics.d.ts.map +1 -1
- package/dist/src/am-lyrics.js +34 -28
- package/dist/src/am-lyrics.js.map +1 -1
- package/dist/src/react.js +34 -28
- package/dist/src/react.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/AmLyrics.ts +10 -3
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
This webcomponent follows the [open-wc](https://github.com/open-wc/open-wc) recommendation.
|
|
6
6
|
|
|
7
|
+
This web component utilises the [lyricsplus](https://github.com/ibratabian17/YouLyPlus) API to fetch lyrics and the animations are heavily inspired by [YouLy+](https://github.com/ibratabian17/YouLyPlus).
|
|
8
|
+
|
|
7
9
|
## Installation
|
|
8
10
|
|
|
9
11
|
```bash
|
|
@@ -37,23 +39,23 @@ Or, just use the CDN.
|
|
|
37
39
|
|
|
38
40
|
## Properties & Attributes
|
|
39
41
|
|
|
40
|
-
| Property/Attribute
|
|
41
|
-
|
|
42
|
-
| `query`
|
|
43
|
-
| `music-id`
|
|
44
|
-
| `isrc`
|
|
45
|
-
| `song-title`
|
|
46
|
-
| `song-artist`
|
|
47
|
-
| `song-album`
|
|
48
|
-
| `song-duration`
|
|
49
|
-
| `current-time`
|
|
50
|
-
| `duration`
|
|
51
|
-
| `highlight-color`
|
|
52
|
-
| `hover-background-color` | `string`
|
|
53
|
-
| ~~`hide-source-footer`~~ | `boolean` | `false`
|
|
54
|
-
| `font-family`
|
|
55
|
-
| `autoscroll`
|
|
56
|
-
| `interpolate`
|
|
42
|
+
| Property/Attribute | Type | Default | Description |
|
|
43
|
+
| ------------------------ | --------- | ----------- | ---------------------------------------------------------------------------------------------- |
|
|
44
|
+
| `query` | `string` | `undefined` | Search phrase that resolves metadata via LyricsPlus catalog (falls back to Apple Music search) |
|
|
45
|
+
| `music-id` | `string` | `undefined` | Specific Apple Music song ID (served through the backup Apple endpoint) |
|
|
46
|
+
| `isrc` | `string` | `undefined` | ISRC code to verify correct song match |
|
|
47
|
+
| `song-title` | `string` | `undefined` | Preferred title for LyricsPlus (primary) provider |
|
|
48
|
+
| `song-artist` | `string` | `undefined` | Preferred artist name for LyricsPlus provider |
|
|
49
|
+
| `song-album` | `string` | `undefined` | Optional album name passed to LyricsPlus provider |
|
|
50
|
+
| `song-duration` | `number` | `undefined` | Optional song duration in milliseconds sent to LyricsPlus |
|
|
51
|
+
| `current-time` | `number` | `0` | Current playback time in milliseconds |
|
|
52
|
+
| `duration` | `number` | `undefined` | Playback timer duration in milliseconds. **Set to `-1` to reset/stop playback** |
|
|
53
|
+
| `highlight-color` | `string` | `"#000"` | Color for highlighted/active lyrics |
|
|
54
|
+
| `hover-background-color` | `string` | `"#f0f0f0"` | Background color on line hover |
|
|
55
|
+
| ~~`hide-source-footer`~~ | `boolean` | `false` | Hide/show the source attribution footer |
|
|
56
|
+
| `font-family` | `string` | `undefined` | Custom font family for lyrics |
|
|
57
|
+
| `autoscroll` | `boolean` | `true` | Enable automatic scrolling to active lyrics |
|
|
58
|
+
| `interpolate` | `boolean` | `true` | Enable smooth word-by-word highlighting animation |
|
|
57
59
|
|
|
58
60
|
## CSS Custom Properties (CSS Variables)
|
|
59
61
|
|
|
@@ -63,10 +65,10 @@ You can customize the appearance using CSS custom properties:
|
|
|
63
65
|
am-lyrics {
|
|
64
66
|
/* Highlight color for active lyrics */
|
|
65
67
|
--am-lyrics-highlight-color: #007aff;
|
|
66
|
-
|
|
68
|
+
|
|
67
69
|
/* Hover background color (fallback) */
|
|
68
70
|
--hover-background-color: #f5f5f5;
|
|
69
|
-
|
|
71
|
+
|
|
70
72
|
/* Alternative highlight color (fallback) */
|
|
71
73
|
--highlight-color: #000;
|
|
72
74
|
}
|
|
@@ -74,7 +76,6 @@ am-lyrics {
|
|
|
74
76
|
|
|
75
77
|
**Note**: The CSS variables take precedent over the set properties above.
|
|
76
78
|
|
|
77
|
-
|
|
78
79
|
## Lyrics providers
|
|
79
80
|
|
|
80
81
|
The component now only uses the LyricsPlus (KPoe) API that powers [YouLyPlus](https://github.com/ibratabian17/YouLyPlus).
|
|
@@ -82,8 +83,7 @@ The component now only uses the LyricsPlus (KPoe) API that powers [YouLyPlus](ht
|
|
|
82
83
|
1. Provide `song-title` and `song-artist` (plus optional `song-album`/`song-duration`) to request word-synced lyrics from LyricsPlus. A standalone `query` such as `"Bad Habit - Steve Lacy"` also works—the component looks up the metadata through LyricsPlus' `/v1/songlist/search` endpoint.
|
|
83
84
|
2. If LyricsPlus cannot serve lyrics or metadata is missing, the component automatically falls back to the legacy Apple Music endpoint using the best available identifiers (`query`, `music-id`, `isrc`). Requests that rely solely on `music-id` are handled exclusively by this backup service because LyricsPlus does not support Apple IDs.
|
|
84
85
|
|
|
85
|
-
The footer shows the active provider (e.g. “LyricsPlus (KPoe)” or “Apple Music”) so you always know which service responded. Supplying both metadata
|
|
86
|
-
|
|
86
|
+
The footer shows the active provider (e.g. “LyricsPlus (KPoe)” or “Apple Music”) so you always know which service responded. Supplying both metadata _and_ a `query` gives the best results because the query remains available for the Apple Music backup.
|
|
87
87
|
|
|
88
88
|
## Events
|
|
89
89
|
|
|
@@ -92,7 +92,7 @@ The footer shows the active provider (e.g. “LyricsPlus (KPoe)” or “Apple M
|
|
|
92
92
|
Fired when a user clicks on a lyrics line.
|
|
93
93
|
|
|
94
94
|
```javascript
|
|
95
|
-
amLyrics.addEventListener('line-click',
|
|
95
|
+
amLyrics.addEventListener('line-click', event => {
|
|
96
96
|
console.log('Seek to:', event.detail.timestamp); // timestamp in milliseconds
|
|
97
97
|
});
|
|
98
98
|
```
|
|
@@ -295,7 +295,7 @@ You can synchronize the lyrics with an HTML `<audio>` element.
|
|
|
295
295
|
});
|
|
296
296
|
|
|
297
297
|
// Seek audio when a lyric line is clicked
|
|
298
|
-
amLyrics.addEventListener('line-click',
|
|
298
|
+
amLyrics.addEventListener('line-click', e => {
|
|
299
299
|
// The event detail contains the timestamp in milliseconds
|
|
300
300
|
audioPlayer.currentTime = e.detail.timestamp / 1000;
|
|
301
301
|
audioPlayer.play();
|
package/demo/index.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AmLyrics.d.ts","sourceRoot":"","sources":["../../src/AmLyrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAE,MAAM,KAAK,CAAC;AA6E5C,qBAAa,QAAS,SAAQ,UAAU;IACtC,MAAM,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"AmLyrics.d.ts","sourceRoot":"","sources":["../../src/AmLyrics.ts"],"names":[],"mappings":"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"}
|
package/dist/src/am-lyrics.js
CHANGED
|
@@ -32,32 +32,32 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
32
32
|
* Copyright 2019 Google LLC
|
|
33
33
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
34
34
|
*/
|
|
35
|
-
const t$1=globalThis,e$4=t$1.ShadowRoot&&(void 0===t$1.ShadyCSS||t$1.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,s$2=Symbol(),o$4=new WeakMap;let n$3 = class n{constructor(t,e,o){if(this._$cssResult$=true,o!==s$2)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e;}get styleSheet(){let t=this.o;const s=this.t;if(e$4&&void 0===t){const e=void 0!==s&&1===s.length;e&&(t=o$4.get(s)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),e&&o$4.set(s,t));}return t}toString(){return this.cssText}};const r$4=t=>new n$3("string"==typeof t?t:t+"",void 0,s$2),i$3=(t,...e)=>{const o=1===t.length?t[0]:e.reduce((
|
|
35
|
+
const t$1=globalThis,e$4=t$1.ShadowRoot&&(void 0===t$1.ShadyCSS||t$1.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,s$2=Symbol(),o$4=new WeakMap;let n$3 = class n{constructor(t,e,o){if(this._$cssResult$=true,o!==s$2)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e;}get styleSheet(){let t=this.o;const s=this.t;if(e$4&&void 0===t){const e=void 0!==s&&1===s.length;e&&(t=o$4.get(s)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),e&&o$4.set(s,t));}return t}toString(){return this.cssText}};const r$4=t=>new n$3("string"==typeof t?t:t+"",void 0,s$2),i$3=(t,...e)=>{const o=1===t.length?t[0]:e.reduce((e,s,o)=>e+(t=>{if(true===t._$cssResult$)return t.cssText;if("number"==typeof t)return t;throw Error("Value passed to 'css' function must be a 'css' function result: "+t+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(s)+t[o+1],t[0]);return new n$3(o,t,s$2)},S$1=(s,o)=>{if(e$4)s.adoptedStyleSheets=o.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(const e of o){const o=document.createElement("style"),n=t$1.litNonce;void 0!==n&&o.setAttribute("nonce",n),o.textContent=e.cssText,s.appendChild(o);}},c$2=e$4?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e="";for(const s of t.cssRules)e+=s.cssText;return r$4(e)})(t):t;
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* @license
|
|
39
39
|
* Copyright 2017 Google LLC
|
|
40
40
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
41
|
-
*/const{is:i$2,defineProperty:e$3,getOwnPropertyDescriptor:h$1,getOwnPropertyNames:r$3,getOwnPropertySymbols:o$3,getPrototypeOf:n$2}=Object,a$1=globalThis,c$1=a$1.trustedTypes,l$1=c$1?c$1.emptyScript:"",p$1=a$1.reactiveElementPolyfillSupport,d$1=(t,s)=>t,u$1={toAttribute(t,s){switch(s){case Boolean:t=t?l$1:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t);}return t},fromAttribute(t,s){let i=t;switch(s){case Boolean:i=null!==t;break;case Number:i=null===t?null:Number(t);break;case Object:case Array:try{i=JSON.parse(t);}catch(t){i=null;}}return i}},f$1=(t,s)=>!i$2(t,s),b={attribute:true,type:String,converter:u$1,reflect:false,useDefault:false,hasChanged:f$1};Symbol.metadata??=Symbol("metadata"),a$1.litPropertyMetadata??=new WeakMap;let y$1 = class y extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t);}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,s=b){if(s.state&&(s.attribute=false),this._$Ei(),this.prototype.hasOwnProperty(t)&&((s=Object.create(s)).wrapped=true),this.elementProperties.set(t,s),!s.noAccessor){const i=Symbol(),h=this.getPropertyDescriptor(t,i,s);void 0!==h&&e$3(this.prototype,t,h);}}static getPropertyDescriptor(t,s,i){const{get:e,set:r}=h$1(this.prototype,t)??{get(){return this[s]},set(t){this[s]=t;}};return {get:e,set(s){const h=e?.call(this);r?.call(this,s),this.requestUpdate(t,h,i);},configurable:true,enumerable:true}}static getPropertyOptions(t){return this.elementProperties.get(t)??b}static _$Ei(){if(this.hasOwnProperty(d$1("elementProperties")))return;const t=n$2(this);t.finalize(),void 0!==t.l&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties);}static finalize(){if(this.hasOwnProperty(d$1("finalized")))return;if(this.finalized=true,this._$Ei(),this.hasOwnProperty(d$1("properties"))){const t=this.properties,s=[...r$3(t),...o$3(t)];for(const i of s)this.createProperty(i,t[i]);}const t=this[Symbol.metadata];if(null!==t){const s=litPropertyMetadata.get(t);if(void 0!==s)for(const[t,i]of s)this.elementProperties.set(t,i);}this._$Eh=new Map;for(const[t,s]of this.elementProperties){const i=this._$Eu(t,s);void 0!==i&&this._$Eh.set(i,t);}this.elementStyles=this.finalizeStyles(this.styles);}static finalizeStyles(s){const i=[];if(Array.isArray(s)){const e=new Set(s.flat(1/0).reverse());for(const s of e)i.unshift(c$2(s));}else void 0!==s&&i.push(c$2(s));return i}static _$Eu(t,s){const i=s.attribute;return false===i?void 0:"string"==typeof i?i:"string"==typeof t?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=false,this.hasUpdated=false,this._$Em=null,this._$Ev();}_$Ev(){this._$ES=new Promise(
|
|
41
|
+
*/const{is:i$2,defineProperty:e$3,getOwnPropertyDescriptor:h$1,getOwnPropertyNames:r$3,getOwnPropertySymbols:o$3,getPrototypeOf:n$2}=Object,a$1=globalThis,c$1=a$1.trustedTypes,l$1=c$1?c$1.emptyScript:"",p$1=a$1.reactiveElementPolyfillSupport,d$1=(t,s)=>t,u$1={toAttribute(t,s){switch(s){case Boolean:t=t?l$1:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t);}return t},fromAttribute(t,s){let i=t;switch(s){case Boolean:i=null!==t;break;case Number:i=null===t?null:Number(t);break;case Object:case Array:try{i=JSON.parse(t);}catch(t){i=null;}}return i}},f$1=(t,s)=>!i$2(t,s),b$1={attribute:true,type:String,converter:u$1,reflect:false,useDefault:false,hasChanged:f$1};Symbol.metadata??=Symbol("metadata"),a$1.litPropertyMetadata??=new WeakMap;let y$1 = class y extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t);}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,s=b$1){if(s.state&&(s.attribute=false),this._$Ei(),this.prototype.hasOwnProperty(t)&&((s=Object.create(s)).wrapped=true),this.elementProperties.set(t,s),!s.noAccessor){const i=Symbol(),h=this.getPropertyDescriptor(t,i,s);void 0!==h&&e$3(this.prototype,t,h);}}static getPropertyDescriptor(t,s,i){const{get:e,set:r}=h$1(this.prototype,t)??{get(){return this[s]},set(t){this[s]=t;}};return {get:e,set(s){const h=e?.call(this);r?.call(this,s),this.requestUpdate(t,h,i);},configurable:true,enumerable:true}}static getPropertyOptions(t){return this.elementProperties.get(t)??b$1}static _$Ei(){if(this.hasOwnProperty(d$1("elementProperties")))return;const t=n$2(this);t.finalize(),void 0!==t.l&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties);}static finalize(){if(this.hasOwnProperty(d$1("finalized")))return;if(this.finalized=true,this._$Ei(),this.hasOwnProperty(d$1("properties"))){const t=this.properties,s=[...r$3(t),...o$3(t)];for(const i of s)this.createProperty(i,t[i]);}const t=this[Symbol.metadata];if(null!==t){const s=litPropertyMetadata.get(t);if(void 0!==s)for(const[t,i]of s)this.elementProperties.set(t,i);}this._$Eh=new Map;for(const[t,s]of this.elementProperties){const i=this._$Eu(t,s);void 0!==i&&this._$Eh.set(i,t);}this.elementStyles=this.finalizeStyles(this.styles);}static finalizeStyles(s){const i=[];if(Array.isArray(s)){const e=new Set(s.flat(1/0).reverse());for(const s of e)i.unshift(c$2(s));}else void 0!==s&&i.push(c$2(s));return i}static _$Eu(t,s){const i=s.attribute;return false===i?void 0:"string"==typeof i?i:"string"==typeof t?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=false,this.hasUpdated=false,this._$Em=null,this._$Ev();}_$Ev(){this._$ES=new Promise(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this));}addController(t){(this._$EO??=new Set).add(t),void 0!==this.renderRoot&&this.isConnected&&t.hostConnected?.();}removeController(t){this._$EO?.delete(t);}_$E_(){const t=new Map,s=this.constructor.elementProperties;for(const i of s.keys())this.hasOwnProperty(i)&&(t.set(i,this[i]),delete this[i]);t.size>0&&(this._$Ep=t);}createRenderRoot(){const t=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return S$1(t,this.constructor.elementStyles),t}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(true),this._$EO?.forEach(t=>t.hostConnected?.());}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.());}attributeChangedCallback(t,s,i){this._$AK(t,i);}_$ET(t,s){const i=this.constructor.elementProperties.get(t),e=this.constructor._$Eu(t,i);if(void 0!==e&&true===i.reflect){const h=(void 0!==i.converter?.toAttribute?i.converter:u$1).toAttribute(s,i.type);this._$Em=t,null==h?this.removeAttribute(e):this.setAttribute(e,h),this._$Em=null;}}_$AK(t,s){const i=this.constructor,e=i._$Eh.get(t);if(void 0!==e&&this._$Em!==e){const t=i.getPropertyOptions(e),h="function"==typeof t.converter?{fromAttribute:t.converter}:void 0!==t.converter?.fromAttribute?t.converter:u$1;this._$Em=e;const r=h.fromAttribute(s,t.type);this[e]=r??this._$Ej?.get(e)??r,this._$Em=null;}}requestUpdate(t,s,i,e=false,h){if(void 0!==t){const r=this.constructor;if(false===e&&(h=this[t]),i??=r.getPropertyOptions(t),!((i.hasChanged??f$1)(h,s)||i.useDefault&&i.reflect&&h===this._$Ej?.get(t)&&!this.hasAttribute(r._$Eu(t,i))))return;this.C(t,s,i);} false===this.isUpdatePending&&(this._$ES=this._$EP());}C(t,s,{useDefault:i,reflect:e,wrapped:h},r){i&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,r??s??this[t]),true!==h||void 0!==r)||(this._$AL.has(t)||(this.hasUpdated||i||(s=void 0),this._$AL.set(t,s)),true===e&&this._$Em!==t&&(this._$Eq??=new Set).add(t));}async _$EP(){this.isUpdatePending=true;try{await this._$ES;}catch(t){Promise.reject(t);}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[t,s]of this._$Ep)this[t]=s;this._$Ep=void 0;}const t=this.constructor.elementProperties;if(t.size>0)for(const[s,i]of t){const{wrapped:t}=i,e=this[s];true!==t||this._$AL.has(s)||void 0===e||this.C(s,void 0,i,e);}}let t=false;const s=this._$AL;try{t=this.shouldUpdate(s),t?(this.willUpdate(s),this._$EO?.forEach(t=>t.hostUpdate?.()),this.update(s)):this._$EM();}catch(s){throw t=false,this._$EM(),s}t&&this._$AE(s);}willUpdate(t){}_$AE(t){this._$EO?.forEach(t=>t.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=true,this.firstUpdated(t)),this.updated(t);}_$EM(){this._$AL=new Map,this.isUpdatePending=false;}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return true}update(t){this._$Eq&&=this._$Eq.forEach(t=>this._$ET(t,this[t])),this._$EM();}updated(t){}firstUpdated(t){}};y$1.elementStyles=[],y$1.shadowRootOptions={mode:"open"},y$1[d$1("elementProperties")]=new Map,y$1[d$1("finalized")]=new Map,p$1?.({ReactiveElement:y$1}),(a$1.reactiveElementVersions??=[]).push("2.1.2");
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
44
|
* @license
|
|
45
45
|
* Copyright 2017 Google LLC
|
|
46
46
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
47
47
|
*/
|
|
48
|
-
const t=globalThis,i$1=t
|
|
48
|
+
const t=globalThis,i$1=t=>t,s$1=t.trustedTypes,e$2=s$1?s$1.createPolicy("lit-html",{createHTML:t=>t}):void 0,h="$lit$",o$2=`lit$${Math.random().toFixed(9).slice(2)}$`,n$1="?"+o$2,r$2=`<${n$1}>`,l=document,c=()=>l.createComment(""),a=t=>null===t||"object"!=typeof t&&"function"!=typeof t,u=Array.isArray,d=t=>u(t)||"function"==typeof t?.[Symbol.iterator],f="[ \t\n\f\r]",v=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,_=/-->/g,m=/>/g,p=RegExp(`>|${f}(?:([^\\s"'>=/]+)(${f}*=${f}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),g=/'/g,$=/"/g,y=/^(?:script|style|textarea|title)$/i,x=t=>(i,...s)=>({_$litType$:t,strings:i,values:s}),b=x(1),E=Symbol.for("lit-noChange"),A=Symbol.for("lit-nothing"),C=new WeakMap,P=l.createTreeWalker(l,129);function V(t,i){if(!u(t)||!t.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==e$2?e$2.createHTML(i):i}const N=(t,i)=>{const s=t.length-1,e=[];let n,l=2===i?"<svg>":3===i?"<math>":"",c=v;for(let i=0;i<s;i++){const s=t[i];let a,u,d=-1,f=0;for(;f<s.length&&(c.lastIndex=f,u=c.exec(s),null!==u);)f=c.lastIndex,c===v?"!--"===u[1]?c=_:void 0!==u[1]?c=m:void 0!==u[2]?(y.test(u[2])&&(n=RegExp("</"+u[2],"g")),c=p):void 0!==u[3]&&(c=p):c===p?">"===u[0]?(c=n??v,d=-1):void 0===u[1]?d=-2:(d=c.lastIndex-u[2].length,a=u[1],c=void 0===u[3]?p:'"'===u[3]?$:g):c===$||c===g?c=p:c===_||c===m?c=v:(c=p,n=void 0);const x=c===p&&t[i+1].startsWith("/>")?" ":"";l+=c===v?s+r$2:d>=0?(e.push(a),s.slice(0,d)+h+s.slice(d)+o$2+x):s+o$2+(-2===d?i:x);}return [V(t,l+(t[s]||"<?>")+(2===i?"</svg>":3===i?"</math>":"")),e]};class S{constructor({strings:t,_$litType$:i},e){let r;this.parts=[];let l=0,a=0;const u=t.length-1,d=this.parts,[f,v]=N(t,i);if(this.el=S.createElement(f,e),P.currentNode=this.el.content,2===i||3===i){const t=this.el.content.firstChild;t.replaceWith(...t.childNodes);}for(;null!==(r=P.nextNode())&&d.length<u;){if(1===r.nodeType){if(r.hasAttributes())for(const t of r.getAttributeNames())if(t.endsWith(h)){const i=v[a++],s=r.getAttribute(t).split(o$2),e=/([.?@])?(.*)/.exec(i);d.push({type:1,index:l,name:e[2],strings:s,ctor:"."===e[1]?I:"?"===e[1]?L:"@"===e[1]?z:H}),r.removeAttribute(t);}else t.startsWith(o$2)&&(d.push({type:6,index:l}),r.removeAttribute(t));if(y.test(r.tagName)){const t=r.textContent.split(o$2),i=t.length-1;if(i>0){r.textContent=s$1?s$1.emptyScript:"";for(let s=0;s<i;s++)r.append(t[s],c()),P.nextNode(),d.push({type:2,index:++l});r.append(t[i],c());}}}else if(8===r.nodeType)if(r.data===n$1)d.push({type:2,index:l});else {let t=-1;for(;-1!==(t=r.data.indexOf(o$2,t+1));)d.push({type:7,index:l}),t+=o$2.length-1;}l++;}}static createElement(t,i){const s=l.createElement("template");return s.innerHTML=t,s}}function M(t,i,s=t,e){if(i===E)return i;let h=void 0!==e?s._$Co?.[e]:s._$Cl;const o=a(i)?void 0:i._$litDirective$;return h?.constructor!==o&&(h?._$AO?.(false),void 0===o?h=void 0:(h=new o(t),h._$AT(t,s,e)),void 0!==e?(s._$Co??=[])[e]=h:s._$Cl=h),void 0!==h&&(i=M(t,h._$AS(t,i.values),h,e)),i}class R{constructor(t,i){this._$AV=[],this._$AN=void 0,this._$AD=t,this._$AM=i;}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(t){const{el:{content:i},parts:s}=this._$AD,e=(t?.creationScope??l).importNode(i,true);P.currentNode=e;let h=P.nextNode(),o=0,n=0,r=s[0];for(;void 0!==r;){if(o===r.index){let i;2===r.type?i=new k(h,h.nextSibling,this,t):1===r.type?i=new r.ctor(h,r.name,r.strings,this,t):6===r.type&&(i=new Z(h,this,t)),this._$AV.push(i),r=s[++n];}o!==r?.index&&(h=P.nextNode(),o++);}return P.currentNode=l,e}p(t){let i=0;for(const s of this._$AV) void 0!==s&&(void 0!==s.strings?(s._$AI(t,s,i),i+=s.strings.length-2):s._$AI(t[i])),i++;}}class k{get _$AU(){return this._$AM?._$AU??this._$Cv}constructor(t,i,s,e){this.type=2,this._$AH=A,this._$AN=void 0,this._$AA=t,this._$AB=i,this._$AM=s,this.options=e,this._$Cv=e?.isConnected??true;}get parentNode(){let t=this._$AA.parentNode;const i=this._$AM;return void 0!==i&&11===t?.nodeType&&(t=i.parentNode),t}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(t,i=this){t=M(this,t,i),a(t)?t===A||null==t||""===t?(this._$AH!==A&&this._$AR(),this._$AH=A):t!==this._$AH&&t!==E&&this._(t):void 0!==t._$litType$?this.$(t):void 0!==t.nodeType?this.T(t):d(t)?this.k(t):this._(t);}O(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}T(t){this._$AH!==t&&(this._$AR(),this._$AH=this.O(t));}_(t){this._$AH!==A&&a(this._$AH)?this._$AA.nextSibling.data=t:this.T(l.createTextNode(t)),this._$AH=t;}$(t){const{values:i,_$litType$:s}=t,e="number"==typeof s?this._$AC(t):(void 0===s.el&&(s.el=S.createElement(V(s.h,s.h[0]),this.options)),s);if(this._$AH?._$AD===e)this._$AH.p(i);else {const t=new R(e,this),s=t.u(this.options);t.p(i),this.T(s),this._$AH=t;}}_$AC(t){let i=C.get(t.strings);return void 0===i&&C.set(t.strings,i=new S(t)),i}k(t){u(this._$AH)||(this._$AH=[],this._$AR());const i=this._$AH;let s,e=0;for(const h of t)e===i.length?i.push(s=new k(this.O(c()),this.O(c()),this,this.options)):s=i[e],s._$AI(h),e++;e<i.length&&(this._$AR(s&&s._$AB.nextSibling,e),i.length=e);}_$AR(t=this._$AA.nextSibling,s){for(this._$AP?.(false,true,s);t!==this._$AB;){const s=i$1(t).nextSibling;i$1(t).remove(),t=s;}}setConnected(t){ void 0===this._$AM&&(this._$Cv=t,this._$AP?.(t));}}class H{get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}constructor(t,i,s,e,h){this.type=1,this._$AH=A,this._$AN=void 0,this.element=t,this.name=i,this._$AM=e,this.options=h,s.length>2||""!==s[0]||""!==s[1]?(this._$AH=Array(s.length-1).fill(new String),this.strings=s):this._$AH=A;}_$AI(t,i=this,s,e){const h=this.strings;let o=false;if(void 0===h)t=M(this,t,i,0),o=!a(t)||t!==this._$AH&&t!==E,o&&(this._$AH=t);else {const e=t;let n,r;for(t=h[0],n=0;n<h.length-1;n++)r=M(this,e[s+n],i,n),r===E&&(r=this._$AH[n]),o||=!a(r)||r!==this._$AH[n],r===A?t=A:t!==A&&(t+=(r??"")+h[n+1]),this._$AH[n]=r;}o&&!e&&this.j(t);}j(t){t===A?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,t??"");}}class I extends H{constructor(){super(...arguments),this.type=3;}j(t){this.element[this.name]=t===A?void 0:t;}}class L extends H{constructor(){super(...arguments),this.type=4;}j(t){this.element.toggleAttribute(this.name,!!t&&t!==A);}}class z extends H{constructor(t,i,s,e,h){super(t,i,s,e,h),this.type=5;}_$AI(t,i=this){if((t=M(this,t,i,0)??A)===E)return;const s=this._$AH,e=t===A&&s!==A||t.capture!==s.capture||t.once!==s.once||t.passive!==s.passive,h=t!==A&&(s===A||e);e&&this.element.removeEventListener(this.name,this,s),h&&this.element.addEventListener(this.name,this,t),this._$AH=t;}handleEvent(t){"function"==typeof this._$AH?this._$AH.call(this.options?.host??this.element,t):this._$AH.handleEvent(t);}}class Z{constructor(t,i,s){this.element=t,this.type=6,this._$AN=void 0,this._$AM=i,this.options=s;}get _$AU(){return this._$AM._$AU}_$AI(t){M(this,t);}}const B=t.litHtmlPolyfillSupport;B?.(S,k),(t.litHtmlVersions??=[]).push("3.3.2");const D=(t,i,s)=>{const e=s?.renderBefore??i;let h=e._$litPart$;if(void 0===h){const t=s?.renderBefore??null;e._$litPart$=h=new k(i.insertBefore(c(),t),t,void 0,s??{});}return h._$AI(t),h};
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* @license
|
|
52
52
|
* Copyright 2017 Google LLC
|
|
53
53
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
54
|
-
*/const s=globalThis;class i extends y$1{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0;}createRenderRoot(){const t=super.createRenderRoot();return this.renderOptions.renderBefore??=t.firstChild,t}update(t){const r=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=
|
|
54
|
+
*/const s=globalThis;class i extends y$1{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0;}createRenderRoot(){const t=super.createRenderRoot();return this.renderOptions.renderBefore??=t.firstChild,t}update(t){const r=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=D(r,this.renderRoot,this.renderOptions);}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(true);}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(false);}render(){return E}}i._$litElement$=true,i["finalized"]=true,s.litElementHydrateSupport?.({LitElement:i});const o$1=s.litElementPolyfillSupport;o$1?.({LitElement:i});(s.litElementVersions??=[]).push("4.2.2");
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
57
|
* @license
|
|
58
58
|
* Copyright 2017 Google LLC
|
|
59
59
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
60
|
-
*/const o={attribute:true,type:String,converter:u$1,reflect:false,hasChanged:f$1},r$1=(t=o,e,r)=>{const{kind:n,metadata:i}=r;let s=globalThis.litPropertyMetadata.get(i);if(void 0===s&&globalThis.litPropertyMetadata.set(i,s=new Map),"setter"===n&&((t=Object.create(t)).wrapped=true),s.set(r.name,t),"accessor"===n){const{name:o}=r;return {set(r){const n=e.get.call(this);e.set.call(this,r),this.requestUpdate(o,n,t);},init(e){return void 0!==e&&this.C(o,void 0,t,e),e}}}if("setter"===n){const{name:o}=r;return function(r){const n=this[o];e.call(this,r),this.requestUpdate(o,n,t);}}throw Error("Unsupported decorator location: "+n)};function n(t){return (e,o)=>"object"==typeof o?r$1(t,e,o):((t,e,o)=>{const r=e.hasOwnProperty(o);return e.constructor.createProperty(o,t),r?Object.getOwnPropertyDescriptor(e,o):void 0})(t,e,o)}
|
|
60
|
+
*/const o={attribute:true,type:String,converter:u$1,reflect:false,hasChanged:f$1},r$1=(t=o,e,r)=>{const{kind:n,metadata:i}=r;let s=globalThis.litPropertyMetadata.get(i);if(void 0===s&&globalThis.litPropertyMetadata.set(i,s=new Map),"setter"===n&&((t=Object.create(t)).wrapped=true),s.set(r.name,t),"accessor"===n){const{name:o}=r;return {set(r){const n=e.get.call(this);e.set.call(this,r),this.requestUpdate(o,n,t,true,r);},init(e){return void 0!==e&&this.C(o,void 0,t,e),e}}}if("setter"===n){const{name:o}=r;return function(r){const n=this[o];e.call(this,r),this.requestUpdate(o,n,t,true,r);}}throw Error("Unsupported decorator location: "+n)};function n(t){return (e,o)=>"object"==typeof o?r$1(t,e,o):((t,e,o)=>{const r=e.hasOwnProperty(o);return e.constructor.createProperty(o,t),r?Object.getOwnPropertyDescriptor(e,o):void 0})(t,e,o)}
|
|
61
61
|
|
|
62
62
|
/**
|
|
63
63
|
* @license
|
|
@@ -310,7 +310,7 @@ class GoogleService {
|
|
|
310
310
|
}
|
|
311
311
|
}
|
|
312
312
|
|
|
313
|
-
const VERSION = '1.0.
|
|
313
|
+
const VERSION = '1.0.7';
|
|
314
314
|
const INSTRUMENTAL_THRESHOLD_MS = 7000; // Show dots for gaps >= 7s
|
|
315
315
|
const KPOE_SERVERS = [
|
|
316
316
|
'https://lyricsplus.binimum.org',
|
|
@@ -801,6 +801,8 @@ class AmLyrics extends i {
|
|
|
801
801
|
});
|
|
802
802
|
}
|
|
803
803
|
}
|
|
804
|
+
// Extract translation from KPoe API if available
|
|
805
|
+
const translationText = entry.translation?.text;
|
|
804
806
|
const lineResult = {
|
|
805
807
|
text: mainSyllables,
|
|
806
808
|
background: backgroundSyllables.length > 0,
|
|
@@ -815,6 +817,7 @@ class AmLyrics extends i {
|
|
|
815
817
|
alignment,
|
|
816
818
|
songPart: entry.element?.songPart,
|
|
817
819
|
romanizedText: romanizedTextFromPayload,
|
|
820
|
+
translation: translationText,
|
|
818
821
|
};
|
|
819
822
|
lines.push(lineResult);
|
|
820
823
|
}
|
|
@@ -969,7 +972,6 @@ class AmLyrics extends i {
|
|
|
969
972
|
}
|
|
970
973
|
}
|
|
971
974
|
// Pre-scroll: scroll to upcoming line ~0.5s before it starts
|
|
972
|
-
// This provides the "anticipatory scroll" requested by the user.
|
|
973
975
|
if (this.autoScroll &&
|
|
974
976
|
!this.isUserScrolling &&
|
|
975
977
|
!this.isClickSeeking &&
|
|
@@ -2183,7 +2185,7 @@ class AmLyrics extends i {
|
|
|
2183
2185
|
const renderContent = () => {
|
|
2184
2186
|
if (this.isLoading) {
|
|
2185
2187
|
// Render stylized skeleton lines
|
|
2186
|
-
return
|
|
2188
|
+
return b `
|
|
2187
2189
|
<div class="skeleton-line"></div>
|
|
2188
2190
|
<div class="skeleton-line"></div>
|
|
2189
2191
|
<div class="skeleton-line"></div>
|
|
@@ -2194,7 +2196,7 @@ class AmLyrics extends i {
|
|
|
2194
2196
|
`;
|
|
2195
2197
|
}
|
|
2196
2198
|
if (!this.lyrics || this.lyrics.length === 0) {
|
|
2197
|
-
return
|
|
2199
|
+
return b `<div class="no-lyrics">No lyrics found.</div>`;
|
|
2198
2200
|
}
|
|
2199
2201
|
// Build a lookup map of ALL gaps so they are always in the DOM
|
|
2200
2202
|
const allGaps = this.findAllInstrumentalGaps();
|
|
@@ -2209,7 +2211,7 @@ class AmLyrics extends i {
|
|
|
2209
2211
|
const hasBackground = line.backgroundText && line.backgroundText.length > 0;
|
|
2210
2212
|
// Create background vocals container (with romanization support)
|
|
2211
2213
|
const backgroundVocalElement = hasBackground
|
|
2212
|
-
?
|
|
2214
|
+
? b `<p class="background-vocal-container">
|
|
2213
2215
|
${line.backgroundText.map((syllable, syllableIndex) => {
|
|
2214
2216
|
const startTimeMs = syllable.timestamp;
|
|
2215
2217
|
const endTimeMs = syllable.endtime;
|
|
@@ -2217,7 +2219,7 @@ class AmLyrics extends i {
|
|
|
2217
2219
|
const bgRomanizedText = this.showRomanization &&
|
|
2218
2220
|
syllable.romanizedText &&
|
|
2219
2221
|
syllable.romanizedText.trim() !== syllable.text.trim()
|
|
2220
|
-
?
|
|
2222
|
+
? b `<span
|
|
2221
2223
|
class="lyrics-syllable transliteration ${syllable.lineSynced
|
|
2222
2224
|
? 'line-synced'
|
|
2223
2225
|
: ''}"
|
|
@@ -2229,7 +2231,7 @@ class AmLyrics extends i {
|
|
|
2229
2231
|
>${syllable.romanizedText}</span
|
|
2230
2232
|
>`
|
|
2231
2233
|
: '';
|
|
2232
|
-
return
|
|
2234
|
+
return b `<span class="lyrics-word">
|
|
2233
2235
|
<span class="lyrics-syllable-wrap">
|
|
2234
2236
|
<span
|
|
2235
2237
|
class="lyrics-syllable ${syllable.lineSynced
|
|
@@ -2264,7 +2266,7 @@ class AmLyrics extends i {
|
|
|
2264
2266
|
}
|
|
2265
2267
|
}
|
|
2266
2268
|
// Create main vocals using YouLyPlus syllable structure
|
|
2267
|
-
const mainVocalElement =
|
|
2269
|
+
const mainVocalElement = b `<p class="main-vocal-container">
|
|
2268
2270
|
${wordGroups.map(group => {
|
|
2269
2271
|
// Compute combined text and timing for the whole word group
|
|
2270
2272
|
const groupText = group.map(s => s.text).join('');
|
|
@@ -2297,7 +2299,7 @@ class AmLyrics extends i {
|
|
|
2297
2299
|
const romanizedText = this.showRomanization &&
|
|
2298
2300
|
syllable.romanizedText &&
|
|
2299
2301
|
syllable.romanizedText.trim() !== syllable.text.trim()
|
|
2300
|
-
?
|
|
2302
|
+
? b `<span
|
|
2301
2303
|
class="lyrics-syllable transliteration ${syllable.lineSynced
|
|
2302
2304
|
? 'line-synced'
|
|
2303
2305
|
: ''}"
|
|
@@ -2311,7 +2313,7 @@ class AmLyrics extends i {
|
|
|
2311
2313
|
: '';
|
|
2312
2314
|
// For growable words, wrap each character in a span with YouLyPlus applyGrowthStyles
|
|
2313
2315
|
const syllableContent = isGrowable
|
|
2314
|
-
?
|
|
2316
|
+
? b `${text.split('').map((char, charIndex) => {
|
|
2315
2317
|
if (char === ' ') {
|
|
2316
2318
|
return ' ';
|
|
2317
2319
|
}
|
|
@@ -2351,7 +2353,7 @@ class AmLyrics extends i {
|
|
|
2351
2353
|
const position = (charIndex + 0.5) / numChars;
|
|
2352
2354
|
const horizontalOffset = (position - 0.5) * 2 * ((charMaxScale - 1.0) * 25);
|
|
2353
2355
|
// MOVED TO DATA ATTRIBUTES and removed style attribute to avoid Lit conflict
|
|
2354
|
-
return
|
|
2356
|
+
return b `<span
|
|
2355
2357
|
class="char"
|
|
2356
2358
|
data-char-index="${charIndex}"
|
|
2357
2359
|
data-syllable-char-index="${charIndex}"
|
|
@@ -2365,7 +2367,7 @@ class AmLyrics extends i {
|
|
|
2365
2367
|
>`;
|
|
2366
2368
|
})}`
|
|
2367
2369
|
: text;
|
|
2368
|
-
return
|
|
2370
|
+
return b `<span
|
|
2369
2371
|
class="lyrics-word ${isGrowable ? 'growable' : ''}"
|
|
2370
2372
|
>
|
|
2371
2373
|
<span class="lyrics-syllable-wrap">
|
|
@@ -2385,10 +2387,10 @@ class AmLyrics extends i {
|
|
|
2385
2387
|
</span>`;
|
|
2386
2388
|
}
|
|
2387
2389
|
// Multi-syllable group (part=true): render all syllables inside one lyrics-word
|
|
2388
|
-
return
|
|
2390
|
+
return b `<span
|
|
2389
2391
|
class="lyrics-word ${isGrowable ? 'growable' : ''} allow-break"
|
|
2390
2392
|
>
|
|
2391
|
-
${group.map((syllable, sylIdx) =>
|
|
2393
|
+
${group.map((syllable, sylIdx) => b `
|
|
2392
2394
|
<span class="lyrics-syllable-wrap">
|
|
2393
2395
|
<span
|
|
2394
2396
|
class="lyrics-syllable ${groupLineSynced
|
|
@@ -2404,7 +2406,7 @@ class AmLyrics extends i {
|
|
|
2404
2406
|
${this.showRomanization &&
|
|
2405
2407
|
syllable.romanizedText &&
|
|
2406
2408
|
syllable.romanizedText.trim() !== syllable.text.trim()
|
|
2407
|
-
?
|
|
2409
|
+
? b `<span
|
|
2408
2410
|
class="lyrics-syllable transliteration ${groupLineSynced
|
|
2409
2411
|
? 'line-synced'
|
|
2410
2412
|
: ''}"
|
|
@@ -2431,7 +2433,7 @@ class AmLyrics extends i {
|
|
|
2431
2433
|
const translationElement = this.showTranslation &&
|
|
2432
2434
|
line.translation &&
|
|
2433
2435
|
line.translation.trim() !== fullLineText
|
|
2434
|
-
?
|
|
2436
|
+
? b `<div class="lyrics-translation-container">
|
|
2435
2437
|
${line.translation}
|
|
2436
2438
|
</div>`
|
|
2437
2439
|
: '';
|
|
@@ -2441,7 +2443,7 @@ class AmLyrics extends i {
|
|
|
2441
2443
|
line.romanizedText &&
|
|
2442
2444
|
!line.text.some(s => s.romanizedText) &&
|
|
2443
2445
|
line.romanizedText.trim() !== fullLineText
|
|
2444
|
-
?
|
|
2446
|
+
? b `<div class="lyrics-romanization-container">
|
|
2445
2447
|
${line.romanizedText}
|
|
2446
2448
|
</div>`
|
|
2447
2449
|
: '';
|
|
@@ -2452,7 +2454,7 @@ class AmLyrics extends i {
|
|
|
2452
2454
|
// Calculate dot timing for fill-up animation (3 dots)
|
|
2453
2455
|
const dotDuration = (gapForLine.gapEnd - gapForLine.gapStart) / 3;
|
|
2454
2456
|
// Gap starts without 'active' — _onTimeChanged toggles it imperatively
|
|
2455
|
-
maybeInstrumentalBlock =
|
|
2457
|
+
maybeInstrumentalBlock = b `<div
|
|
2456
2458
|
id="gap-${lineIndex}"
|
|
2457
2459
|
class="lyrics-line lyrics-gap"
|
|
2458
2460
|
data-start-time="${gapForLine.gapStart}"
|
|
@@ -2496,7 +2498,7 @@ class AmLyrics extends i {
|
|
|
2496
2498
|
</div>
|
|
2497
2499
|
</div>`;
|
|
2498
2500
|
}
|
|
2499
|
-
return
|
|
2501
|
+
return b `
|
|
2500
2502
|
${maybeInstrumentalBlock}
|
|
2501
2503
|
<div
|
|
2502
2504
|
id="${lineId}"
|
|
@@ -2521,14 +2523,14 @@ class AmLyrics extends i {
|
|
|
2521
2523
|
`;
|
|
2522
2524
|
});
|
|
2523
2525
|
};
|
|
2524
|
-
return
|
|
2526
|
+
return b `
|
|
2525
2527
|
<div
|
|
2526
2528
|
class="lyrics-container blur-inactive-enabled ${this.isUserScrolling
|
|
2527
2529
|
? 'user-scrolling'
|
|
2528
2530
|
: ''}"
|
|
2529
2531
|
>
|
|
2530
2532
|
${!this.isLoading && this.lyrics && this.lyrics.length > 0
|
|
2531
|
-
?
|
|
2533
|
+
? b `
|
|
2532
2534
|
<div class="lyrics-header">
|
|
2533
2535
|
<div class="header-controls">
|
|
2534
2536
|
<button
|
|
@@ -2627,7 +2629,7 @@ class AmLyrics extends i {
|
|
|
2627
2629
|
: ''}
|
|
2628
2630
|
${renderContent()}
|
|
2629
2631
|
${!this.isLoading
|
|
2630
|
-
?
|
|
2632
|
+
? b `
|
|
2631
2633
|
<footer class="lyrics-footer">
|
|
2632
2634
|
<div class="footer-content">
|
|
2633
2635
|
<span class="source-info">Source: ${sourceLabel}</span>
|
|
@@ -3173,8 +3175,12 @@ AmLyrics.styles = i$3 `
|
|
|
3173
3175
|
|
|
3174
3176
|
/* Line-synced lyrics should fade in instantly/quickly instead of wiping */
|
|
3175
3177
|
.lyrics-syllable.line-synced {
|
|
3176
|
-
animation: fade-in-line 0.2s ease-out forwards !important;
|
|
3177
3178
|
background: transparent !important;
|
|
3179
|
+
color: var(--lyplus-text-secondary) !important;
|
|
3180
|
+
}
|
|
3181
|
+
|
|
3182
|
+
.lyrics-line.active .lyrics-syllable.line-synced {
|
|
3183
|
+
animation: fade-in-line 0.2s ease-out forwards !important;
|
|
3178
3184
|
color: var(--lyplus-text-primary) !important;
|
|
3179
3185
|
}
|
|
3180
3186
|
|