亚伦影音工作室 发表于 2025-10-26 21:09

代码磁带—花潮论坛播放器

本帖最后由 亚伦影音工作室 于 2025-10-28 18:44 编辑 <br /><br /><style>
#papa {margin: 20px -320px;
width: 1286px;
height: 720px;
border: 0px solid gray;
background:radial-gradient(ellipse farthest-corner at center center, transparent 38%,#000 90%),url(https://pic1.imgdb.cn/item/67334a1bd29ded1a8c90061b.jpg),linear-gradient(135deg, #e56420, #c22525, #3d9c31, #000078);
overflow: hidden;
position: relative;
--state: running;
}

.k-container-body {margin: 180px 190px;
position: absolute;transform:rotatey(0deg);
background: linear-gradient(45deg,
                #000078, #000, #880000, #00aa00, #00aa7f, #111111, #00bb00, #ff0000);
border: 3px solid #d0d0d0;
border-radius: 15px;
width: 550px;
height: 320px;
perspective: 10000;
padding: 10px;overflow: hidden;
}
.k-container-body:before,
.k-container-body:after {
content: '';
position: absolute;
bottom: 20px;
height: 90px;
width: 35px;
border-radius: 10px;
z-index: -1;
}
.k-container-body:before {
border-left: 3px solid #d0d0d0;
left: -12px;
}
.k-container-body:after {
border-right: 3px solid #d0d0d0;
right: -12px;
}
.k-screw {
position: absolute;
display: inline-block;
border: 1px solid #d0d0d0;
border-radius: 50%;
width: 14px;
height: 14px;
}
.k-screw:before,
.k-screw:after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
transform-origin: center;
background-color: #d0d0d0;
height: 70%;
width: 2px;
}
.k-screw:before {
transform: translate(-50%, -50%) rotate(90deg);
}
.body .k-screw:after {
transform: translate(-50%, -50%) rotate(-90deg);
}
.k-screw.top-left {transform:rotateZ(12deg);
top: 7px;
left: 7px;
}
.k-screw.top-right {transform:rotateZ(-5deg);
top: 7px;
right: 7px;
}
.k-screw.bottom-left {transform:rotateZ(8deg);
bottom: 7px;
left: 7px;
}
.k-screw.bottom-right {transform:rotateZ(-10deg);
bottom: 7px;
right: 7px;
}
.k-centerreel {box-sizing: border-box;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border: 3px solid #d0d0d0;
border-radius: 45px;
width: 300px;
height: 90px;background: linear-gradient(45deg,
                #000078, #000, #ff0000, #ffd700, #00aa7f, #111111, #999999, #000080);
padding: 10px;
}
.k-centerreel .reel {
position: relative;
display: inline-block;
border: 2px solid #d0d0d0;
width: 65px;
height: 100%;
border-radius: 50%;
}
.k-centerreel .reel:before {
content: '';
display: inline-block;
width: 82%;
height: 82%;
border: 6px dashed #d0d0d0;
border-radius: 50%;
transform-origin: center;
animation: spin 3s linear infinite var(--state);
}
.k-centerreel .reel.left {
float: left;
}
.k-centerreel .reel.right {
float: right;
}
.k-centerreel .center-tape {
border: 2px solid #d0d0d0;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
height: 70%;
width: 100px;
border-radius: 10px;
overflow: hidden;
}
.k-centerreel .center-tape:before {
content: '';
border: 3px solid #d0d0d0;
border-radius: 50%;
width: 80px;
height: 80px;
position: absolute;
top: 50%;
transform: translateY(-50%);
left: -50%;
animation: shiftLeft 1.3s ease-in-out alternate infinite var(--state);
}
.k-centerreel .center-tape:after {
content: '';
border: 3px solid #d0d0d0;
border-radius: 50%;
width: 100px;
height: 100px;
position: absolute;
top: 50%;
transform: translateY(-50%);
right: -95%;
animation: shiftRight 1s ease-in-out alternate infinite var(--state);
}
.k-label {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border: 1px solid #d0d0d0;
top: 25%;
max-width: 400px;
width: 100%;
padding: 0px 20px;
overflow: hidden;
}
.k-label:before {
content: '';
position: absolute;
bottom: 1.85ex;
left: 0;
right: 0;
height: 2.5ex;
border-top: 1px dashed #d0d0d0;
border-bottom: 3px dashed #d0d0d0;
z-index: -1;
}

.k-chin {
position: absolute;
left: 10%;
bottom: -6px;
transform:perspective(1em) rotateX(3deg);
transform-origin: bottom center;
max-width: 450px;
width: 100%;
height: 80px;background: linear-gradient(45deg,
                #000078, #000, #ff0000, #ffd700, #00aa7f, #111111, #999999, #000080);
border-radius: 5px;
font-size: 60px;
   border: 2px solid #d0d0d0;
}

.k-chin:after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
top: 30%;
background: #555;
width: 10px;
height: 10px;
border-radius: 50%;
}
.k-chin .holes {transform:rotateX(-65deg);
position: absolute;
display: inline-block;
border: 3px solid #d0d0d0;
border-radius: 20%;
}
.k-chin .holes:nth-child(1) {
width: 15px;
height: 20px;
bottom: 15px;
left: 40px;
}
.k-chin .holes:nth-child(2) {
width: 10px;
height: 20px;
bottom: 30px;
left: 90px;
}
.k-chin .holes:nth-child(3) {
width: 10px;
height: 20px;
bottom: 30px;
right: 90px;
}
.k-chin .holes:nth-child(4) {
width: 15px;
height: 20px;
bottom: 15px;
right: 40px;
}

@keyframes spin {
0% {
    transform: rotate(0deg);
}
100% {
    transform: rotate(360deg);
}
}

@keyframes shiftLeft {
0% {
    left: -50%;
}
100% {
    left: -53%;
}
}

@keyframes shiftRight {
0% {
    right: -95%;
}
100% {
    right: -93%;
}
}
.lyrics{margin: 0;
            top: 22%;
            left: 50%;
    transform: translate(-50%, -50%);
            height: 100px; /**/
                 text-align: center;
            position: absolute;z-index: 1;
      }
            .lyric-line{
            width: 100%;
            position: relative;
            height: 60px;
            overflow: visible;
   font: 400 30px '仿宋', sans-serif;
            line-height: 60px;
         text-align: left;
            
            white-space: nowrap; /**/
            
      }

      .lyric-mask {
            position: absolute;
            top: 0;
            left: 0;
            width: 0;
            overflow: hidden;
      color: #eee;
            height: 100%;
            white-space: nowrap;
      }

      .lyric-original {
             color: #800000;
            white-space: nowrap;
            
      }
#player {
        position: absolute;z-index: 40;
        left:5%;
        bottom: 260px;
        width: 100px;
        height: 40px;
         opacity: 1;
        transition: .4s;
display: grid;
        place-items: center;
        --sp1: 0; --sp2: 1;
}
#player::before, #player::after {
        position: absolute;
        content: '';
        cursor: pointer;
        transition: .4s;
}
#player::before {width: 100%;height: 100%;background:url(https://pic1.imgdb.cn/item/68ff14983203f7be00a5fd1b.png)no-repeat center/cover;
        opacity: var(--sp1);}
#player::after {width: 100%;height: 100%;background:url(https://pic1.imgdb.cn/item/68ff14983203f7be00a5fd1c.png)no-repeat center/cover;
        opacity: var(--sp2);}
#tmsg {position: absolute;z-index: 1;
      font: normal 14px sans-serif;
      color: #eee;
         bottom: 95px;
      left:250px;}
#prog {position: absolute;z-index: 8;filter:invert(0%) hue-rotate(0deg);
      width: 444px;border-radius: 20px;
      height: 2px;
      cursor: pointer;
         bottom: 254px;
left:11%;}
</style>
<div id="papa">

        <div class="k-container-body">
                <span class="k-screw top-left"></span>
                <span class="k-screw top-right"></span>
                <span class="k-screw bottom-left"></span>
                <span class="k-screw bottom-right"></span>
                <div class="k-centerreel">
                        <div class="reel left"></div>
                        <div class="center-tape"></div>
                        <div class="reel right"></div>
                </div>
                <div class="k-label"></div>
                <div class="k-chin">
                        <span class="holes"></span>
                        <span class="holes"></span>
                        <span class="holes"></span>
                        <span class="holes"></span>
                </div>

<div class="lyrics" >
            <div class="lyric-line">
                  <div class="lyric-mask"></div>
                  <div class="lyric-original"></div>
                </div>
            </div>
<div id="player" title="暂停/播放" ></div>
<div id="tmsg">00:00‖00:00</div>
<progress id="prog"></progress>
</div>
</div>

<audio id="aud" src="https://www.dda5.com/plug/down.php?ac=mp3&amp;id=1b9b98de498049248cf4be5d87e409d8&amp;.mp3" loop autoplay></audio>
<script>
const kcenterreel = document.querySelector('.k-centerreel');
const kcontainerbody= document.querySelector('.k-container-body');
player.onclick = () => aud.paused ? aud.play() : aud.pause();
        mState = () => papa.style.setProperty('--state',aud.paused ? (player.style.setProperty('--sp1','1' ), player.style.setProperty('--sp2','0'),'paused') : (player.style.setProperty('--sp1','0'), player.style.setProperty('--sp2','1'),'running'));

aud.onplaying = aud.onpause = () => mState();
aud.ontimeupdate = () => prog.value=aud.currentTime/aud.duration;
prog.onclick = (e) => aud.currentTime=aud.duration*e.offsetX/prog.offsetWidth;
aud.addEventListener('timeupdate', () => {
            tmsg.innerText = toMin(aud.currentTime) + '‖' + toMin(aud.duration);
      });
      
      function toMin(val) {
            if (!val) return '00:00';
            val = Math.floor(val);
            let min = parseInt(val / 60);
            let sec = parseFloat(val % 60);
            if (min < 10) min = '0' + min;
            if (sec < 10) sec = '0' + sec;
            return min + ':' + sec;
      }
</script>

<script>
      // ksclrc
      const lrc = `假如世界没有你
词曲: 马健涛
编曲: 马健涛
混音: 马健涛
母带: 马健涛
出品: 亚伦影音工作室
假如这世界没有了你
我活着有什么意义
假如有一天找不到你
我哭的比谁都委屈
假如你厌倦了别离
我等着你的归期
假如生命中没有了你
我的心情不会美丽
假如这世界没有你
什么都提不起兴趣
假如有一天又见到了你
幸福的会把眼泪滴
假如你爱情不如意
我该不该靠近你
假如你生活不如意
欢迎回到我这里
假如你厌倦了别离
我等着你的归期
假如生命中没有了你
我的心情不会美丽
假如这世界没有你
什么都提不起兴趣
假如有一天又见到了你
幸福的会把眼泪滴
假如你爱情不如意
我该不该靠近你
假如你生活不如意
欢迎回到我这里
假如这世界没有你
什么都提不起兴趣
假如有一天又见到了你
幸福的会把眼泪滴
假如你爱情不如意
我该不该靠近你
假如你生活不如意
欢迎回到我这里
欢迎回到我这里

`;

      const lyrics = parseLyrics(lrc);
      const lyricMask = document.querySelector('.lyric-mask');
      const lyricOriginal = document.querySelector('.lyric-original');
      
      let currentIndex = -1;
      let currentLyric = null;
      
      //
      function parseLyrics(lrcText) {
            const lyrics = [];
            if (lrcText.includes('karaoke.add')) {
                const lineRegex = /karaoke\.add\('([^']+)', '([^']+)', '([^']+)', '([^']+)'\);/g;
                let match;
                while ((match = lineRegex.exec(lrcText)) !== null) {
                  const startTime = timeToMs(match);
                  const endTime = timeToMs(match);
                  const text = match.replace(/\[|\]/g, '').trim();
                  const durations = match.split(',').map(Number);
                  if (text) {
                        lyrics.push({startTime, endTime, text, durations});
                  }
                }
            }
            else if (lrcText.includes('[')) {
                const lines = lrcText.split('\n').filter(line => line.trim());
                lines.forEach((line, index) => {
                  const timeMatch = line.match(/\[(\d+:\d+\.\d+)\]/);
                  if (timeMatch) {
                        const timeStr = timeMatch;
                        const text = line.replace(/\[.*?\]/, '').trim();
                        if (text) {
                            const startTime = timeToMs(timeStr);
                            const nextLine = lines;
                            const nextTimeMatch = nextLine ? nextLine.match(/\[(\d+:\d+\.\d+)\]/) : null;
                            const endTime = nextTimeMatch ? timeToMs(nextTimeMatch) : startTime + 5000;
                            lyrics.push({
                              startTime,
                              endTime,
                              text,
                              durations: calculateCharDurations(text, startTime, endTime)
                            });
                        }
                  }
                });
            }
            return lyrics;
      }
      function calculateCharDurations(text, startTime, endTime) {
            const totalDuration = endTime - startTime;
            const charCount = text.length;
            const baseDur = Math.floor(totalDuration / charCount);
            const durations = new Array(charCount).fill(baseDur);
            const remainder = totalDuration % charCount;
            for (let i = 0; i < remainder; i++) {
                durations++;
            }
            return durations;
      }
      function timeToMs(timeStr) {
            const parts = timeStr.split(':');
            const minutes = parseInt(parts, 10);
            const secondsAndMs = parts.split('.');
            const seconds = parseInt(secondsAndMs, 10);
            const ms = parseInt(secondsAndMs || 0, 10);
            return minutes * 60 * 1000 + seconds * 1000 + ms;
      }
      function getCurrentLyricIndex(lyrics, currentTimeMs) {
            for (let i = 0; i < lyrics.length; i++) {
                if (currentTimeMs >= lyrics.startTime && currentTimeMs <= lyrics.endTime) {
                  return i;
                }
            }
            return -1;
      }
      function updateLyricDisplay(index) {
            if (index < 0 || index >= lyrics.length) return;
            currentIndex = index;
            currentLyric = lyrics;
            lyricOriginal.textContent = currentLyric.text;
            lyricMask.textContent = currentLyric.text;
            lyricMask.style.width = '0%';
      }
      function updateLyricMask(currentTimeMs) {
            if (!currentLyric) return;
            const lyricStartTime = currentLyric.startTime;
            const elapsed = currentTimeMs - lyricStartTime;
            const totalDuration = currentLyric.durations.reduce((sum, d) => sum + d, 0);
            let charIndex = 0;
            let accumulatedTime = 0;
            
            for (let i = 0; i < currentLyric.durations.length; i++) {
                accumulatedTime += currentLyric.durations;
                if (elapsed <= accumulatedTime) {
                  charIndex = i + 1;
                  break;
                }
            }
            
            if (elapsed >= totalDuration) {
                charIndex = currentLyric.text.length;
            }
            
            charIndex = Math.min(charIndex, currentLyric.text.length);
            
            const tempSpan = document.createElement('span');
            tempSpan.style.visibility = 'hidden';
            tempSpan.style.position = 'absolute';
            tempSpan.style.fontSize = '50px';
            tempSpan.style.fontWeight = '800';
            document.body.appendChild(tempSpan);
            
            const visibleText = currentLyric.text.substring(0, charIndex);
            tempSpan.textContent = visibleText;
            const width = tempSpan.offsetWidth;
            document.body.removeChild(tempSpan);
            
            lyricMask.style.width = `${width}px`;
      }
      
      //
      aud.addEventListener('timeupdate', () => {
            const currentTimeMs = aud.currentTime * 1000;
            const index = getCurrentLyricIndex(lyrics, currentTimeMs);
            
            if (index !== currentIndex) {
                updateLyricDisplay(index);
            }
            
            updateLyricMask(currentTimeMs);
      });
      updateLyricDisplay(0);
</script>

红影 发表于 2025-10-26 22:31

这磁带上面还带歌词的,这还是多彩的磁带呢。
欣赏亚伦老师精美制作{:4_199:}

杨帆 发表于 2025-10-26 22:38

好听好看,耳目一新,谢谢亚伦老师精彩分享{:4_180:}

梦油 发表于 2025-10-27 11:05

欣赏佳作,问候亚伦。

寒冬残荷 发表于 2025-10-27 13:17

欣赏!点赞!学习!

小辣椒 发表于 2025-10-27 22:11

用了小风论坛的LOGO

小辣椒 发表于 2025-10-27 22:12

这个是纯代码制作,亚纶也是越来越厉害了

小辣椒 发表于 2025-10-27 22:12

你这个分分钟可以套用一个

亦是金 发表于 2025-10-28 09:46

漂亮,好看!欣赏学习了!{:4_178:}

老谟深虑 发表于 2025-10-28 18:55

         老师好代码,点赞!
页: [1]
查看完整版本: 代码磁带—花潮论坛播放器