diff --git a/resources/cider-ui/index.js b/resources/cider-ui/index.js index d5f3b06c..7abef56a 100644 --- a/resources/cider-ui/index.js +++ b/resources/cider-ui/index.js @@ -7,11 +7,6 @@ Vue.component('sidebar-library-item', { methods: {} }); -Vue.component('lyrics-view', { - template: '#lyrics-view', - props: ["time", "lyrics", "translation"], - methods: {} -}); // This is going to suck to code var CiderContextMenu = { @@ -194,12 +189,14 @@ const app = new Vue({ details: {} }, mxmtoken: "", + playerReady: false, lyricon: false, currentTrackID: '', currentTrackIDBG: '', lyrics: [], currentLyricsLine: 0, lyriccurrenttime: 0, + richlyrics: [], lyricsMediaItem: {}, lyricsDebug: { current: 0, @@ -291,72 +288,21 @@ const app = new Vue({ } MusicKit.getInstance().videoContainerElement = document.getElementById("apple-music-video-player") + + + this.mk.addEventListener(MusicKit.Events.playbackTimeDidChange, (a) => { this.currentSongInfo = a self.playerLCD.playbackDuration = (self.mk.currentPlaybackTime) - self.lyriccurrenttime = app.mk.currentPlaybackTime; - - if (self.lyricon) app.getActiveLyric(); - // animated dot like AM - bad perf - if (self.lyricon && self.drawertest) { - let currentLine = document.querySelector(`.lyric-line.active`) - if (currentLine && currentLine.getElementsByClassName('lyricWaiting').length > 0) { - let duration = currentLine.getAttribute("end") - currentLine.getAttribute("start"); - let u = (self.lyriccurrenttime - currentLine.getAttribute("start")) / duration; - if (u < 0.25 && !currentLine.classList.contains('mode1')) { - try { - currentLine.classList.add('mode1'); - currentLine.classList.remove('mode3'); - currentLine.classList.remove('mode2'); - } catch (e) { - } - currentLine.getElementsByClassName('WaitingDot1')[0].style.animation = `dotOpacity ${0.25 * duration}s cubic-bezier(0.42, 0, 0.58, 1) forwards`; - currentLine.getElementsByClassName('WaitingDot2')[0].style.animation = ``; - currentLine.getElementsByClassName('WaitingDot3')[0].style.animation = ``; - currentLine.getElementsByClassName('WaitingDot2')[0].style.opacity = 0.25; - currentLine.getElementsByClassName('WaitingDot3')[0].style.opacity = 0.25; - - } else if (u >= 0.25 && u < 0.5 && !currentLine.classList.contains('mode2')) { - try { - currentLine.classList.add('mode2'); - currentLine.classList.remove('mode1'); - currentLine.classList.remove('mode3'); - } catch (e) { - } - currentLine.getElementsByClassName('WaitingDot2')[0].style.animation = `dotOpacity ${0.25 * duration}s cubic-bezier(0.42, 0, 0.58, 1) forwards`; - currentLine.getElementsByClassName('WaitingDot1')[0].style.animation = ``; - currentLine.getElementsByClassName('WaitingDot3')[0].style.animation = ``; - currentLine.getElementsByClassName('WaitingDot1')[0].style.opacity = 1; - currentLine.getElementsByClassName('WaitingDot3')[0].style.opacity = 0.25; - } else if (u >= 0.5 && u < 0.75 && !currentLine.classList.contains('mode3')) { - try { - currentLine.classList.add('mode3'); - currentLine.classList.remove('mode1'); - currentLine.classList.remove('mode2'); - } catch (e) { - } - currentLine.getElementsByClassName('WaitingDot3')[0].style.animation = `dotOpacity ${0.25 * duration}s cubic-bezier(0.42, 0, 0.58, 1) forwards`; - currentLine.getElementsByClassName('WaitingDot1')[0].style.animation = ``; - currentLine.getElementsByClassName('WaitingDot2')[0].style.animation = ``; - currentLine.getElementsByClassName('WaitingDot1')[0].style.opacity = 1; - currentLine.getElementsByClassName('WaitingDot2')[0].style.opacity = 1; - } else if (u >= 0.75 && currentLine.classList.contains('mode3')) { - try { - currentLine.classList.remove('mode1'); - currentLine.classList.remove('mode2'); - currentLine.classList.remove('mode3'); - } catch (e) { - } - currentLine.getElementsByClassName('WaitingDot1')[0].style.animation = ``; - currentLine.getElementsByClassName('WaitingDot2')[0].style.animation = ``; - currentLine.getElementsByClassName('WaitingDot1')[0].style.opacity = 1; - currentLine.getElementsByClassName('WaitingDot2')[0].style.opacity = 1; - - } - + if (!self.playerReady){ + self.playerReady = true + document.getElementById("apple-music-player").addEventListener('timeupdate', function () { + self.lyriccurrenttime = this.currentTime; } + ) } + // animated dot like AM - bad perf }) this.mk.addEventListener(MusicKit.Events.nowPlayingItemDidChange, (a) => { @@ -380,6 +326,7 @@ const app = new Vue({ } self.chrome.artworkReady = false self.lyrics = [] + self.richlyrics = [] app.getNowPlayingArtwork(42); app.getNowPlayingArtworkBG(32); app.loadLyrics() @@ -1263,6 +1210,7 @@ const app = new Vue({ const artist = encodeURIComponent((this.mk.nowPlayingItem != null) ? this.mk.nowPlayingItem.artistName ?? '' : ''); const time = encodeURIComponent((this.mk.nowPlayingItem != null) ? (Math.round((this.mk.nowPlayingItem.attributes["durationInMillis"] ?? -1000) / 1000) ?? -1) : -1); var lrcfile = ""; + var richsync = []; const lang = "en" // translation language function revisedRandId() { return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(2, 10); @@ -1315,7 +1263,7 @@ const app = new Vue({ function getMXMSubs(track, artist, token, lang, time) { var usertoken = encodeURIComponent(token); var timecustom = (!time || (time && time < 0)) ? '' : `&f_subtitle_length=${time}&q_duration=${time}&f_subtitle_length_max_deviation=40`; - var url = "https://apic-desktop.musixmatch.com/ws/1.1/macro.subtitles.get?format=json&namespace=lyrics_richsynched&subtitle_format=lrc&q_artist=" + artist + "&q_track=" + track + "&usertoken=" + usertoken + timecustom + "&app_id=web-desktop-app-v1.0&t=" + revisedRandId(); + var url = "https://apic-desktop.musixmatch.com/ws/1.1/macro.subtitles.get?format=json&namespace=lyrics_richsynched&optional_calls=track.richsync&subtitle_format=lrc&q_artist=" + artist + "&q_track=" + track + "&usertoken=" + usertoken + timecustom + "&app_id=web-desktop-app-v1.0&t=" + revisedRandId(); var req = new XMLHttpRequest(); req.overrideMimeType("application/json"); req.open('GET', url, true); @@ -1331,33 +1279,55 @@ const app = new Vue({ if (jsonResponse["message"]["body"]["macro_calls"]["matcher.track.get"]["message"]["header"]["status_code"] == 200 && jsonResponse["message"]["body"]["macro_calls"]["track.subtitles.get"]["message"]["header"]["status_code"] == 200) { id = jsonResponse["message"]["body"]["macro_calls"]["matcher.track.get"]["message"]["body"]["track"]["track_id"] ?? ''; lrcfile = jsonResponse["message"]["body"]["macro_calls"]["track.subtitles.get"]["message"]["body"]["subtitle_list"][0]["subtitle"]["subtitle_body"]; + + try{ + lrcrich = jsonResponse["message"]["body"]["macro_calls"]["track.richsync.get"]["message"]["body"]["richsync"]["richsync_body"]; + richsync = JSON.parse(lrcrich); + app.richlyrics = richsync; + } catch(_){} } if (lrcfile == "") { app.loadAMLyrics() } else { - // process lrcfile to json here - app.lyricsMediaItem = lrcfile - let u = app.lyricsMediaItem.split(/[\r\n]/); - let preLrc = [] - for (var i = u.length - 1; i >= 0; i--) { - let xline = (/(\[[0-9.:\[\]]*\])+(.*)/).exec(u[i]) - let end = (preLrc.length > 0) ? ((preLrc[preLrc.length - 1].startTime) ?? 99999) : 99999 - preLrc.push({ - startTime: app.toMS(xline[1].substring(1, xline[1].length - 2)) ?? 0, - endTime: end, - line: xline[2], - translation: '' - }) - } - if (preLrc.length > 0) - preLrc.push({ + if (richsync == [] || richsync.length == 0 ){ + console.log("ok"); + // process lrcfile to json here + app.lyricsMediaItem = lrcfile + let u = app.lyricsMediaItem.split(/[\r\n]/); + let preLrc = [] + for (var i = u.length - 1; i >= 0; i--) { + let xline = (/(\[[0-9.:\[\]]*\])+(.*)/).exec(u[i]) + let end = (preLrc.length > 0) ? ((preLrc[preLrc.length - 1].startTime) ?? 99999) : 99999 + preLrc.push({ + startTime: app.toMS(xline[1].substring(1, xline[1].length - 2)) ?? 0, + endTime: end, + line: xline[2], + translation: '' + }) + } + if (preLrc.length > 0) + preLrc.push({ + startTime: 0, + endTime: preLrc[preLrc.length - 1].startTime, + line: "lrcInstrumental", + translation: '' + }); + app.lyrics = preLrc.reverse(); + } else { + preLrc = richsync.map(function (item){ return { startTime: item.ts, + endTime: item.te, + line: item.x, + translation: ''}}) + if (preLrc.length > 0) + preLrc.unshift({ startTime: 0, - endTime: preLrc[preLrc.length - 1].startTime, + endTime: preLrc[0].startTime, line: "lrcInstrumental", translation: '' }); - app.lyrics = preLrc.reverse(); + app.lyrics = preLrc; + } if (lrcfile != null && lrcfile != '') { // load translation getMXMTrans(id, lang, token); @@ -1397,7 +1367,7 @@ const app = new Vue({ for (var i = 0; i < u.length - 1; i++) { preTrans[i] = "" for (var trans_line of translation_list) { - if (u[i].line == " " + trans_line["translation"]["matched_line"]) { + if (u[i].line == " " + trans_line["translation"]["matched_line"] || u[i].line == trans_line["translation"]["matched_line"]) { u[i].translation = trans_line["translation"]["description"]; break; } @@ -1483,31 +1453,6 @@ const app = new Vue({ getCurrentTime() { return parseFloat(this.hmsToSecondsOnly(this.parseTime(this.mk.nowPlayingItem.attributes.durationInMillis - app.mk.currentPlaybackTimeRemaining * 1000))); }, - getActiveLyric() { - const delayfix = 0.5 - const prevLine = app.currentLyricsLine; - for (var i = 0; i < app.lyrics.length; i++) { - if (this.lyriccurrenttime + delayfix >= app.lyrics[i].startTime && this.lyriccurrenttime + delayfix <= app.lyrics[i].endTime) { - if (app.currentLyricsLine != i) { - app.currentLyricsLine = i; - if (app.lyricon && document.querySelector(`.lyric-line[line-index="${i}"]`)) { - document.querySelector(`.lyric-line[line-index="${prevLine}"]`).classList.remove("active"); - document.querySelector(`.lyric-line[line-index="${i}"]`).classList.add("active"); - if (checkIfScrollIsStatic) { - document.querySelector(`.lyric-line[line-index="${i}"]`).scrollIntoView({ - behavior: "smooth", - block: "center" - }) - } - } - } else if (app.currentLyricsLine == 0) { - if (document.querySelector(`.lyric-line[line-index="0"]`) && !document.querySelector(`.lyric-line[line-index="0"]`).classList.contains("active")) - document.querySelector(`.lyric-line[line-index="0"]`).classList.add("active"); - } - break; - } - } - }, seekTo(time) { this.mk.seekToTime(time); }, @@ -1717,7 +1662,7 @@ const app = new Vue({ } try { - if (this.mk.nowPlayingItem && this.mk.nowPlayingItem.id != this.currentTrackID && document.querySelector('.bg-artwork')) { + if (this.mk.nowPlayingItem && this.mk.nowPlayingItem.id && this.mk.nowPlayingItem.id != this.currentTrackID && document.querySelector('.bg-artwork')) { if (document.querySelector('.bg-artwork')) { clearInterval(bginterval); } @@ -1733,7 +1678,8 @@ const app = new Vue({ try { clearInterval(bginterval); } catch (err) { console.log(err) } } } catch (e) { - this.setLibraryArtBG() + if (this.mk.nowPlayingItem && this.mk.nowPlayingItem.id && document.querySelector('.bg-artwork')){ + this.setLibraryArtBG()} } }, 200) }, @@ -1741,7 +1687,7 @@ const app = new Vue({ let interval = setInterval(() => { try { - if (this.mk.nowPlayingItem && this.mk.nowPlayingItem.id != this.currentTrackIDBG && document.querySelector('.app-playback-controls .artwork')) { + if (this.mk.nowPlayingItem && this.mk.nowPlayingItem.id && this.mk.nowPlayingItem.id != this.currentTrackIDBG && document.querySelector('.app-playback-controls .artwork')) { this.currentTrackIDBG = this.mk.nowPlayingItem.id; if (document.querySelector('.app-playback-controls .artwork') != null) { clearInterval(interval); @@ -1757,30 +1703,30 @@ const app = new Vue({ try { clearInterval(interval); } catch (err) { console.log(err) } } } catch (e) { - console.log(e); - this.setLibraryArt() + if (this.mk.nowPlayingItem && this.mk.nowPlayingItem.id && document.querySelector('.app-playback-controls .artwork')){ + this.setLibraryArt()} } }, 200) }, - async setLibraryArt() { - const data = await this.mk.api.library.song(this.mk.nowPlayingItem.id) try { + const data = await this.mk.api.library.song(this.mk.nowPlayingItem.id) + if (data != null && data !== "") { document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', 'url("' + (data["attributes"]["artwork"]["url"]).toString() + '")'); } else { - document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("https://beta.music.apple.com/assets/product/MissingArtworkMusic.svg")`); + document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("")`); } } catch (e) { - document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("https://beta.music.apple.com/assets/product/MissingArtworkMusic.svg")`); } }, async setLibraryArtBG() { - const data = await this.mk.api.library.song(this.mk.nowPlayingItem.id) try { + const data = await this.mk.api.library.song(this.mk.nowPlayingItem.id) + if (data != null && data !== "") { document.querySelector('.bg-artwork').src = (data["attributes"]["artwork"]["url"]).toString(); } diff --git a/resources/cider-ui/style.less b/resources/cider-ui/style.less index 32fbe7f3..6018bbdb 100644 --- a/resources/cider-ui/style.less +++ b/resources/cider-ui/style.less @@ -1366,6 +1366,14 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { margin-right: 0px; } +.lyric-line.active .verse{ + opacity: 0.6; +} + +.lyric-line.active .verse.verse-active{ + opacity: 1; +} + .lyric-line:hover { cursor: pointer; } diff --git a/resources/cider-ui/views/components/karaoke-in.ejs b/resources/cider-ui/views/components/karaoke-in.ejs new file mode 100644 index 00000000..23427996 --- /dev/null +++ b/resources/cider-ui/views/components/karaoke-in.ejs @@ -0,0 +1,20 @@ + \ No newline at end of file diff --git a/resources/cider-ui/views/components/lyrics-view.ejs b/resources/cider-ui/views/components/lyrics-view.ejs new file mode 100644 index 00000000..08a1e8c6 --- /dev/null +++ b/resources/cider-ui/views/components/lyrics-view.ejs @@ -0,0 +1,164 @@ + + \ No newline at end of file diff --git a/resources/cider-ui/views/main.ejs b/resources/cider-ui/views/main.ejs index ebf26982..9e950199 100644 --- a/resources/cider-ui/views/main.ejs +++ b/resources/cider-ui/views/main.ejs @@ -374,8 +374,7 @@
- - +
@@ -490,37 +489,9 @@ <%- include('components/mediaitem-mvview-sp') %> <%- include('components/animatedartwork-view') %> - - +<%- include('components/lyrics-view') %> +