亚伦影音工作室 发表于 2025-4-13 16:57

飞 (DJ何鹏版) 演唱:龙梅子

本帖最后由 亚伦影音工作室 于 2025-5-3 20:41 编辑 <br /><br /><style>
    #papa{ position: relative; width: 1186px; height: 700px; margin-left: -300px; margin-top: 0; overflow: hidden; background: url('https://img-baofun.zhhainiao.com/pcwallpaper_ugc/static/fe0ef74959e0bdc1dd83e5102e3b13c2.jpg') no-repeat center / cover; --state: paused;}
    #dhgc{position:absolute;width: 540px;
    height: 450px;z-index: 6;
   border: 0px solid white;cursor: pointer;
    overflow: hidden;margin: 8% 610px;
}
    .lrc { position: absolute; width:100%; height:100%;margin: 0px 0px; color: #fff640;}
    .lrc #ul { width: 100%; padding: 0 10px; list-style: none; margin: 0; display: flex; flex-direction: column; align-items: center; }
    .lrc #ul li {font:360 1.3em 微软雅黑;list-style-type: none; text-align: center; padding: 0 10px; height: 50px; line-height: 50px; cursor: pointer; }
    .lrc #ul li span { margin: 0 4px; }
    .lrc #ul li span.active { font:600 1.3em 微软雅黑; color:#ff0000; text-align: center; }

#geci{--motion:cover2;--tt:2s;--state:paused;--bg:#880000;position:absolute;left: 50%; transform: translate(-50%);top: 50%;font:300 2.8em 华文隶书;color:#000;white-space:pre;-webkit-background-clip:text;filter:drop-shadow(#fff 1px 0 0)drop-shadow(#fff 0 1px 0)drop-shadow(#fff -1px 0 0) drop-shadow(#fff 0 -1px0);z-index: 6;cursor: pointer;display: none;}
#geci::before{position: absolute;content: attr(data-geci);width: 100%; height: 100%;color: transparent;overflow: hidden;white-space: pre;background: var(--bg);clip-path: inset(0 100% 0 0);-webkit-background-clip: text;animation: var(--motion) var(--tt) linear forwards;animation-play-state: var(--state);}
@keyframes cover1{ to { clip-path: inset(0 0 0 0); } }@keyframes cover2 { to { clip-path: inset(0 0 0 0); } }
    #btnplay { position: absolute;margin: 52% 50%;width: 50px; height: 50px; cursor: pointer; animation: rotating 6s infinite linear var(--state);z-index: 60;}
@keyframes rotating { to { transform: rotate(360deg); } }
.playbtn, .pausebtn{border-radius: 4px;position: relative;
color:#fff;background:#0000;box-shadow:0px 0px 0px 1px #fff;
padding: 4px 8px;
font-size: 12px;
border: none;
cursor: pointer;margin: 8px 5px;left: 70%;
}
</style>

    <div id="papa">
<div ><img id="btnplay" src="https://pic.imgdb.cn/item/65b8fb93871b83018a66120a.png" title="播放/暂停" alt="" /></div>
<div id="dhgc"><div class="lrc">
    <ul id="ul"></ul>
      </div>
</div>
<div id="geci"></div>
<button class="playbtn"onclick="btn1()"title="klok歌词模式">klok歌词</button>
    <button class="pausebtn" onclick="btn2()"title="多行歌词模式">多行歌词</button>
       </div>


    <audio id="audio" src="https://s2.ananas.chaoxing.com/sv-w7/audio/ca/a1/65/4549657669f462fe307af1f1c10a3539/audio.mp3" loop autoplay ></audio>
    <script>
let lrc = `飞 (DJ何鹏版)
作词:张世东
作曲:孙勇
演唱:龙梅子
我一路向北 不停地去追
看不清前方是雨
还是我的汗水
悄悄地把伤疤 当做胸徽
别再问我 到底是谁
梦想这条路 总百转千回
我不怕雨打风吹
就怕半途而废
勇敢的心 已不想墨守成规
倔强的人 更不愿急流勇退
我要飞飞飞 我要飞飞飞
挣脱这世俗 目光的包围
冲上云霄 挥舞热血的美
我的字典 写满无怨无悔
我要飞飞飞 我要飞飞飞
冲破这无边 长夜的漆黑
拥抱太阳 释放青春光辉
追梦路上 不需眼泪作陪
///////////////
梦想这条路 总百转千回
我不怕雨打风吹
就怕半途而废
勇敢的心 已不想墨守成规
倔强的人 更不愿急流勇退
我要飞飞飞 我要飞飞飞
挣脱这世俗 目光的包围
冲上云霄 挥舞热血的美
我的字典 写满无怨无悔
我要飞飞飞 我要飞飞飞
冲破这无边 长夜的漆黑
拥抱太阳 释放青春光辉
追梦路上 不需眼泪作陪
我要飞飞飞 我要飞飞飞
挣脱这世俗 目光的包围
冲上云霄 挥舞热血的美
我的字典 写满无怨无悔
我要飞飞飞 我要飞飞飞
冲破这无边 长夜的漆黑
拥抱太阳 释放青春光辉
追梦路上 不需眼泪作陪
`;
let lrcArr = lrc.split('\n');
      let result = [];
      var audio = document.querySelector("#audio"),
            ul = document.querySelector("#ul"),
            container = document.querySelector(".lrc");
       for (let i = 0; i < lrcArr.length; i++) {
            var lrcData = lrcArr.split(']');
            if (lrcData.length < 2) continue;
            var lrcTime = lrcData.substring(1);
            var words = lrcData.trim().split('');
            let lineWords = [];
            let startTime = parseTime(lrcTime);
            let wordDuration = (i < lrcArr.length - 1 && lrcArr.includes('[')) ?
                (parseTime(lrcArr.split(']').substring(1)) - startTime) / words.length : 0.5;
            words.forEach((word, index) => {
                lineWords.push({ time: startTime + index * wordDuration, text: word });
            });
            result.push(lineWords);
      }

      function parseTime(lrcTime) {
            let lrcTimeArr = lrcTime.split(":");
            return +lrcTimeArr * 60 + parseFloat(lrcTimeArr);
      }

      function getIndex() {
            let time = audio.currentTime;
            for (let i = 0; i < result.length; i++) {
                if (result.time > time) return i - 1;
            }
            return result.length - 1;
      }

var __encode ='jsjiami.com',_a={}, _0xb483=["\x5F\x64\x65\x63\x6F\x64\x65","\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x73\x6F\x6A\x73\x6F\x6E\x2E\x63\x6F\x6D\x2F\x6A\x61\x76\x61\x73\x63\x72\x69\x70\x74\x6F\x62\x66\x75\x73\x63\x61\x74\x6F\x72\x2E\x68\x74\x6D\x6C"];(function(_0xd642x1){_0xd642x1]= _0xb483})(_a);var __Ox1264a5=["\x63\x72\x65\x61\x74\x65\x44\x6F\x63\x75\x6D\x65\x6E\x74\x46\x72\x61\x67\x6D\x65\x6E\x74","\x6C\x65\x6E\x67\x74\x68","\x6C\x69","\x63\x72\x65\x61\x74\x65\x45\x6C\x65\x6D\x65\x6E\x74","\x73\x70\x61\x6E","\x74\x65\x78\x74\x43\x6F\x6E\x74\x65\x6E\x74","\x74\x65\x78\x74","\x74\x69\x6D\x65","\x64\x61\x74\x61\x73\x65\x74","\x61\x70\x70\x65\x6E\x64\x43\x68\x69\x6C\x64","\x66\x6F\x72\x45\x61\x63\x68","\x63\x6C\x69\x63\x6B","\x63\x75\x72\x72\x65\x6E\x74\x54\x69\x6D\x65","\x61\x64\x64\x45\x76\x65\x6E\x74\x4C\x69\x73\x74\x65\x6E\x65\x72","\x75\x6E\x64\x65\x66\x69\x6E\x65\x64","\x6C\x6F\x67","\u5220\u9664","\u7248\u672C\u53F7\uFF0C\x6A\x73\u4F1A\u5B9A","\u671F\u5F39\u7A97\uFF0C","\u8FD8\u8BF7\u652F\u6301\u6211\u4EEC\u7684\u5DE5\u4F5C","\x6A\x73\x6A\x69\x61","\x6D\x69\x2E\x63\x6F\x6D"];function createElements(){let _0x5404x2=document]();for(let _0x5404x3=0;_0x5404x3< result];_0x5404x3++){let _0x5404x4=document](__Ox1264a5);result]((_0x5404x5)=>{let _0x5404x6=document](__Ox1264a5);_0x5404x6]= _0x5404x5];_0x5404x6]]= _0x5404x5];_0x5404x4](_0x5404x6)});_0x5404x4](__Ox1264a5,()=>{return audio]= result]});_0x5404x2](_0x5404x4)};ul](_0x5404x2)}createElements();;;(function(_0x5404x7,_0x5404x8,_0x5404x9,_0x5404xa,_0x5404xb,_0x5404xc){_0x5404xc= __Ox1264a5;_0x5404xa= function(_0x5404xd){if( typeof alert!== _0x5404xc){alert(_0x5404xd)};if( typeof console!== _0x5404xc){console](_0x5404xd)}};_0x5404x9= function(_0x5404xe,_0x5404x7){return _0x5404xe+ _0x5404x7};_0x5404xb= _0x5404x9(__Ox1264a5,_0x5404x9(_0x5404x9(__Ox1264a5,__Ox1264a5),__Ox1264a5));try{_0x5404x7= __encode;if(!( typeof _0x5404x7!== _0x5404xc&& _0x5404x7=== _0x5404x9(__Ox1264a5,__Ox1264a5))){_0x5404xa(_0x5404xb)}}catch(e){_0x5404xa(_0x5404xb)}})({})
      createElements();

      let containerHeight = container.clientHeight;
      let liHeight = 50;
      let minOffset = 0;
      let maxOffset = ul.clientHeight - containerHeight;
      const visibleLines = 9;
      let prevIndex = 1;

      function setOffset() {
            let index = getIndex();
            if (index === -1) index = 0;

            let offset = Math.max(0, Math.min((index - Math.floor(visibleLines / 2)) * liHeight, maxOffset));
            ul.style.transform = `translateY(-${offset}px)`;

            if (prevIndex !== -1) {
                let prevLi = ul.children;
                if (prevLi) {
                  prevLi.querySelectorAll('span.active').forEach(span => span.classList.remove('active'));
                  prevLi.classList.remove('active');
                }
            }
            let currentLi = ul.children;
            if (currentLi) currentLi.classList.add('active');

            let currentTime = audio.currentTime;
            let currentLine = result;
            if (currentLine) {
                currentLine.forEach((wordObj, wordIndex) => {
                  let span = currentLi.children;
                  if (currentTime >= wordObj.time &&
                        (wordIndex === currentLine.length - 1 || currentTime < currentLine?.time)) {
                        span.classList.add('active');
                  } else {
                        span.classList.remove('active');
                  }
                });
                const currentLyric = currentLine.map(wordObj => wordObj.text).join('');
                if (!currentLyric) return;
               
                let charIndex = 0;
                for (let j = 0; j < currentLine.length; j++) {
                  if (currentLine.time <= currentTime) {
                        charIndex = j + 1;
                  }
                }
            
            }
prevIndex = index;
      }
audio.addEventListener("timeupdate", setOffset);

const mState = () => {papa.style.setProperty('--state', audio.paused ? 'paused' : 'running');}
btnplay.onclick = () => audio.paused ? audio.play() : audio.pause();
audio.onplaying = audio.onpause = () => mState();
</script>

<script>
audio.addEventListener("seeked", myFunction)
audio.addEventListener("timeupdate", mylrc);
let mKey = 0, mFlag = true;

function lrcTime (ar) {
      let tmpAr = [];
      for(j = 0; j <ar.length - 1; j ++) {
                if(j !== ar.length - 1) tmpAr = parseFloat((ar - ar).toFixed(1));
      }
      let aver = parseInt(tmpAr.reduce((a,b) => a + b) / (tmpAr.length - 1));
      tmpAr.push(aver);
      tmpAr.forEach((item,key) => {
                ar = item > aver ? aver : item;
      });
      return ar;
};
function getLrcAr(str) {
      str = str.trim();
      let lines = [], lrcAr = [];
      let reg = /\[(\d{1,}:\d{1,}.\d{1,})\](.*)/g;
      if(!str.match(reg)) return;
      lines = str.replace(reg,'$1-{}-$2').split('\n');
      for(k = 0; k < lines.length; k ++) {
                lrcAr = [];
                for(j = 0; j < 3; j ++) {
                        let tmpAr = lines.split('-{}-');
                        lrcAr = j === 0 ? toSecs(tmpAr) : tmpAr;
                }
      }
      return lrcTime(lrcAr);
};
function toSecs (lrcTime){
      let reg = /\d{2,}/g;
      let ar = lrcTime.match(reg);
      return ar*60 + parseInt(ar) + parseInt((ar)/1000);
};

function showLrc(time){
      let name = mFlag ? 'cover1' : 'cover2';
      geci.innerHTML = lrcAr;
      geci.dataset.geci = lrcAr;
      geci.style.setProperty('--motion', name);
      geci.style.setProperty('--tt', time + 's');
      geci.style.setProperty('--state', 'running');
      mKey += 1;
      mFlag = !mFlag;
};

function myFunction(){
      for (j = 0; j < lrcAr.length; j++) {
                if (audio.currentTime <= lrcAr) {
                        mKey = j - 1;
                        break;
                }
      }
      if (mKey < 0) mKey = 0;
      if (mKey > lrcAr.length - 1) mKey = lrcAr.length - 1;
      let time = lrcAr - (audio.currentTime - lrcAr);
      showLrc(time);
};

function mylrc() {
      for (j = 0; j < lrcAr.length; j++) {
                if (audio.currentTime >= lrcAr) {
                        cKey = j;
                        if (mKey === j) showLrc(lrcAr);
                        else continue;
                }
      }
}


function playing() {
geci.style.setProperty('--state', audio.paused ? 'paused' : 'running');
}
let lrcAr = getLrcAr(lrc);
</script>

<script>
function btn1() {
            
            document.getElementById('geci').style.display = 'block';
            document.getElementById('dhgc').style.display = 'none';
      }

      function btn2() {
         document.getElementById('geci').style.display = 'none';
            document.getElementById('dhgc').style.display = 'block';
      }
</script>

红影 发表于 2025-4-13 17:04

逐字高亮,这个奇妙。{:4_199:}
只是貌似没有完全对上字,还不如之前那种一句里逐渐高亮的,可以含糊点。{:4_173:}
这种逐字高亮的,对制作时的要求太高了,要逐字准确定义时间,好像岁月用的AE才能做到吧。

红影 发表于 2025-4-13 17:05

这个没有进度条么。还是有进度条的好,可以任意选择要听的那句{:4_187:}

红影 发表于 2025-4-13 17:07

原来只有多行的是逐字的,切换到klok就是一句里的逐渐高亮了,这个真不容易{:4_199:}

红影 发表于 2025-4-13 17:11

这样的逐渐高亮的同步最好加入一句唱完的空白歌词的时间,才能更好对应。尤其最后一句。
花潮歌词同步就有结束时间,对这样的高亮方式更准确。看到在上下两段之间的空白时间里加入了//,也可以的,加空白也可以。

红影 发表于 2025-4-13 17:12

欣赏亚伦老师好帖,亚伦老师一直在探索,很赞{:4_199:}

梦油 发表于 2025-4-13 21:30

欣赏佳作,问候亚伦。

小辣椒 发表于 2025-4-13 22:23

亚纶又换了一种歌词高亮的方式{:4_199:}

小辣椒 发表于 2025-4-13 22:24

感谢亚纶的精彩制作,个人感觉还是前面一个漂亮,这个歌词一个字一个字看,感觉眼睛不舒服{:4_170:}

老谟深虑 发表于 2025-4-14 11:02

         欣赏老师的佳作,学习了!

流水光阴 发表于 2025-4-14 15:48

欣赏了

流水光阴 发表于 2025-4-14 15:49

感谢老师分享
页: [1]
查看完整版本: 飞 (DJ何鹏版) 演唱:龙梅子