惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

云风的 BLOG
云风的 BLOG
Hacker News: Ask HN
Hacker News: Ask HN
C
CXSECURITY Database RSS Feed - CXSecurity.com
T
The Exploit Database - CXSecurity.com
The Hacker News
The Hacker News
Security Latest
Security Latest
Attack and Defense Labs
Attack and Defense Labs
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Scott Helme
Scott Helme
H
Heimdal Security Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
WordPress大学
WordPress大学
雷峰网
雷峰网
L
LangChain Blog
Y
Y Combinator Blog
I
Intezer
V
Vulnerabilities – Threatpost
Apple Machine Learning Research
Apple Machine Learning Research
The Last Watchdog
The Last Watchdog
Simon Willison's Weblog
Simon Willison's Weblog
W
WeLiveSecurity
P
Privacy International News Feed
V
Visual Studio Blog
T
The Blog of Author Tim Ferriss
A
About on SuperTechFans
AI
AI
博客园 - Franky
Hacker News - Newest:
Hacker News - Newest: "LLM"
Martin Fowler
Martin Fowler
K
Kaspersky official blog
U
Unit 42
S
Schneier on Security
Webroot Blog
Webroot Blog
Know Your Adversary
Know Your Adversary
T
Tor Project blog
aimingoo的专栏
aimingoo的专栏
Engineering at Meta
Engineering at Meta
G
GRAHAM CLULEY
美团技术团队
TaoSecurity Blog
TaoSecurity Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Google DeepMind News
Google DeepMind News
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Jina AI
Jina AI
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
人人都是产品经理
人人都是产品经理
P
Proofpoint News Feed
爱范儿
爱范儿
F
Fortinet All Blogs
有赞技术团队
有赞技术团队

耳朵的主人

张老师说:成功是成功之母 - 碎碎念 - 耳朵的主人 忙碌近况杂话篇,生活尽是折腾。 - 碎碎念 - 耳朵的主人 忙碌近况杂话篇,生活尽是折腾。 - 碎碎念 - 耳朵的主人 妈祖诞辰1066周年|善坛妈祖庙祭典 - 碎碎念 - 耳朵的主人 妈祖诞辰1066周年|善坛妈祖庙祭典 - 碎碎念 - 耳朵的主人 行将四十,时常在夜里失眠,也许是睡不着,也许是不想睡。 - 期刊 - 耳朵的主人 行将四十,时常在夜里失眠,也许是睡不着,也许是不想睡。 - 期刊 - 耳朵的主人 The Last Hour Ancient Sunlight – Draconian 选自《A Rose for the Apocalypse》专辑 - 单曲 The Last Hour Ancient Sunlight – Draconian 选自《A Rose for the Apocalypse》专辑 - 单曲 当下能抓住的就牢牢抓住,善良还是要带点锋芒。 - 碎碎念 - 耳朵的主人 当下能抓住的就牢牢抓住,善良还是要带点锋芒。 - 碎碎念 - 耳朵的主人 立冬虽已过,仍要小心蛇出没。 - 碎碎念 - 耳朵的主人 立冬虽已过,仍要小心蛇出没。 - 碎碎念 - 耳朵的主人 什么玩意儿?| 网站新增暗夜模式,AI搓出来的代码分享 - 碎碎念 - 耳朵的主人 什么玩意儿?| 网站新增暗夜模式,AI搓出来的代码分享 - 碎碎念 - 耳朵的主人 奶奶落寞的背影 - 碎碎念 - 耳朵的主人 奶奶落寞的背影 - 碎碎念 - 耳朵的主人 消失的一百块 - 碎碎念 - 耳朵的主人 消失的一百块 - 碎碎念 - 耳朵的主人 又是一年博饼时,迎中秋庆国庆•叙乡情促公益 - 碎碎念 - 耳朵的主人 又是一年博饼时,迎中秋庆国庆•叙乡情促公益 - 碎碎念 - 耳朵的主人 又没有车,为什么要等红灯,是不是傻。 - 碎碎念 - 耳朵的主人 又没有车,为什么要等红灯,是不是傻。 - 碎碎念 - 耳朵的主人 我们终有老的那一天。 - 碎碎念 - 耳朵的主人 我们终有老的那一天。 - 碎碎念 - 耳朵的主人 装修记:石材进度完成,接下来木作进场。 - 碎碎念 - 耳朵的主人 装修记:石材进度完成,接下来木作进场。 - 碎碎念 - 耳朵的主人 夜色属于孤独的盛宴,黑暗与光影交织,灵魂在低沉中沉淀。 - 期刊 - 耳朵的主人 夜色属于孤独的盛宴,黑暗与光影交织,灵魂在低沉中沉淀。 - 期刊 - 耳朵的主人 早知道当初… 呃,电台新版发布了。 - 碎碎念 - 耳朵的主人 我的浪迹地图 - 碎碎念 - 耳朵的主人 我的浪迹地图 - 碎碎念 - 耳朵的主人 回山里,窝两天。 - 碎碎念 - 耳朵的主人 回山里,窝两天。 - 碎碎念 - 耳朵的主人 哎呦,我的好大儿,不错哦。 - 碎碎念 - 耳朵的主人 哎呦,我的好大儿,不错哦。 - 碎碎念 - 耳朵的主人 欲望也好,得失也罢,不必太多计较,人生总该归于平静。 - 期刊 - 耳朵的主人 欲望也好,得失也罢,不必太多计较,人生总该归于平静。 - 期刊 - 耳朵的主人 哎呦,三八了。 - 碎碎念 - 耳朵的主人 哎呦,三八了。 - 碎碎念 - 耳朵的主人 稚子何仇画影谏 老父捧腹莞尔篇 - 碎碎念 - 耳朵的主人
早知道当初… 呃,电台新版发布了。 - 碎碎念 - 耳朵的主人
耳朵的主人²º²⁵ · 2025-06-05 · via 耳朵的主人

书到用时方恨少,早知道当初年少就不应该沉迷于QQ聊天泡妞,就应该多买几本技术类教程书籍多看看…

我不知道今天抽什么风,突然间就想把电台的PC端和H5端给完善一下,然后,我太自信了,呃,这完全是在我能力之外的工作啊!

从昨天AM10:42到现在AM3:40,几个小时我算算,呃,十六还是十七个小时,啊啊啊,我现在脑壳短路,算不明白了。中途就吃了晚饭半个小时,然后辅导娃儿作业一个小时,其余时间我就抱着电脑死命磕磕磕,我的老腰啊……

想法一大堆,但是奈何水平不够,总是碰到一大堆问题,借助Gemini才勉勉强强完成。

电台页面:https://www.edzbe.com/fm/top

去年搞了这个电台页面,用的还是七八九年前的jplayer播放器,直接用代码套来套去整出来的,但是这个播放器源码太老了,总是能遇到一大堆乱七八糟的问题,索性就用Jquery从新搞一个,前端后端的水平都有限,UI啥的也是这里找那里抄,唉。

电台切换页面也得弄一下,我个小破站,为什么要弄这么多歌曲分类,唉,我真的是服了自己。

这个页面抄的QQ音乐的界面,呃,老实交代了。

因为歌曲较多,每次加载json,如果全部加载的话,那网页就卡得不要不要的,设置了获取100首歌,每次刷新随机替换一批。

封装成桌面端了,下载地址:EdzbeFm_0.0.1_x64-setup.exe

H5版折腾了最长时间,还有个问题就是滑动歌曲列表的时候,悬浮的播放器没办法移到最底部,会遮挡到歌曲列表,这个我实在是搞不定,唉,就这样将就吧!

20250606补充,呃,说将就吧,浑身不得劲,唉,这该死的强迫症。

H5版播放器增加了响应式自适应,现在可以把悬浮的播放器根据页面滑动加载缩放到网页底部了,不会遮挡了,呃,果然,方法总比问题多,再坚持坚持就解决了。

H5手机版首页做了个电台的入口,按照喜怒哀乐四种情绪把电台分类给分开。

分享下电脑端和手机端的播放器源码吧,需要的自取。

电脑端:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8"/>
  <title>电脑版黑胶唱片音乐播放器</title>
  <style>
    @import url(https://fonts.googleapis.com/css?family=Raleway:400,300,700);
    *, *:before, *:after {
      box-sizing: border-box;
    }

    body {
      background-color: #fef29c;
     color: #515044;
     font-family: "Raleway", sans-serif;
      min-height: 100vh;
      display: flex;
      justify-content: center;
      align-items: center;
      margin: 0;
    }

    .music-player-container {
      -webkit-transform: translate(-50%, -50%);
      -moz-transform: translate(-50%, -50%);
      -ms-transform: translate(-50%, -50%);
      -o-transform: translate(-50%, -50%);
      transform: translate(-50%, -50%);
      display: inline-block;
      height: 370px;
      position: absolute;
      min-width: 460px;
      left: 50%;
      top: 50%;
    }
    .music-player-container:after {
      -webkit-filter: blur(8px);
      filter: blur(8px);
      background-color: rgba(0, 0, 0, 0.8);
      bottom: -2px;
      content: " ";
      display: block;
      height: 10px;
      left: 19px;
      position: absolute;
      transform: rotate(-3deg);
      width: 70%;
      z-index: 0;
    }

    .music-player {
      background-color: #fff;
     height: 370px;
      padding: 40px 250px 40px 40px;
      position: absolute;
      text-align: right;
      width: 460px;
      z-index: 3;
    }

    .player-content-container {
      -webkit-transform: translateY(-50%);
      -moz-transform: translateY(-50%);
      -ms-transform: translateY(-50%);
      -o-transform: translateY(-50%);
      transform: translateY(-50%);
      top: 50%;
      position: relative;
    }

    .artist-name {
      font-size: 24px;
      font-weight: 200;
      margin: 0 0 0.75em 0;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      max-width: 170px;
    }

    .album-title {
      font-weight: 200;
      font-size: 18px;
      margin: 0 0 1.75em 0;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      max-width: 170px;
    }

    .song-title {
      font-size: 28px;
      font-weight: normal;
      margin: 0 0 0.5em 0;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      max-width: 170px;
      cursor: pointer;
      transition: all 0.3s ease;
      position: relative;
      padding: 5px 0;
    }
   
    .song-title:hover {
      color: #878787;
   }
   
    .song-title::after {
      content: "点击打开链接";
      position: absolute;
      bottom: -20px;
      left: 0;
      font-size: 10px;
      opacity: 0;
      transition: opacity 0.3s ease;
      background: rgba(0,0,0,0.7);
      color: white;
      padding: 2px 5px;
      border-radius: 3px;
      white-space: nowrap;
    }
   
    .song-title:hover::after {
      opacity: 1;
    }

    .album {
      box-shadow: 3px 3px 15px rgba(0, 0, 0, 0.65);
      height: 315px;
      margin-left: 250px;
      margin-top: 27px;
      position: relative;
      width: 315px;
      z-index: 10;
    }

    .album-art {
      height: 315px;
      position: relative;
      width: 315px;
      z-index: 10;
      background-size: cover;
      background-position: center;
    }

    .vinyl {
      -webkit-animation: spin 2s linear infinite;
      -moz-animation: spin 2s linear infinite;
      animation: spin 2s linear infinite;
      -webkit-transition: all 500ms;
      -moz-transition: all 500ms;
      transition: all 500ms;
      background-position: center, center;
      background-size: cover, 40% auto;
      background-repeat: no-repeat;
      border-radius: 100%;
      box-shadow: 0 0 10px rgba(0, 0, 0, 0.8);
      height: 300px;
      left: 0;
      position: absolute;
      top: 5px;
      width: 300px;
      z-index: 5;
      will-change: transform, left;
      animation-play-state: paused; /* 初始状态为暂停 */
    }
    .is-playing .vinyl {
      left: 52%;
      animation-play-state: running; /* 播放时运行动画 */
    }

    .music-player-controls {
      text-align: center;
    }

    [class^=control-] {
      -webkit-filter: brightness(95%);
      filter: brightness(95%);
      border-radius: 100%;
      display: inline-block;
      height: 44px;
      margin: 0 3px;
      width: 44px;
    }
    [class^=control-]:hover {
      -webkit-filter: brightness(85%);
      filter: brightness(85%);
      cursor: pointer;
    }

    .control-play {
      background: transparent url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/83141/play.svg") center/cover no-repeat;
    }
    .is-playing .control-play {
      background: transparent url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/83141/pause.svg") center/cover no-repeat;
    }

    .control-forwards {
      background: transparent url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/83141/forwards.svg") center/cover no-repeat;
    }

    .control-back {
      background: transparent url("https://s3-us-west-2.amazonaws.com/s.cdpn.io/83141/backwards.svg") center/cover no-repeat;
    }

    @-webkit-keyframes spin {
      0% {
        -webkit-transform: rotate(0deg);
      }
      100% {
        -webkit-transform: rotate(360deg);
      }
    }
    @-moz-keyframes spin {
      0% {
        -moz-transform: rotate(0deg);
      }
      100% {
        -moz-transform: rotate(360deg);
      }
    }
    @keyframes spin {
      0% {
        -webkit-transform: rotate(0deg);
        -moz-transform: rotate(0deg);
        -ms-transform: rotate(0deg);
        -o-transform: rotate(0deg);
        transform: rotate(0deg);
      }
      100% {
        -webkit-transform: rotate(360deg);
        -moz-transform: rotate(360deg);
        -ms-transform: rotate(360deg);
        -o-transform: rotate(360deg);
        transform: rotate(360deg);
      }
    }
   
    /* 播放控制面板 */
    .player-controls {
      margin-top: 20px;
      display: flex;
      flex-direction: column;
      align-items: center;
    }
   
    .progress-container {
      width: 200px;
      height: 4px;
      background: #d3d3d3;
     border-radius: 2px;
      margin-bottom: 8px;
      cursor: pointer;
      position: relative;
    }
   
    .progress-bar {
      height: 100%;
      background: #515044;
     border-radius: 2px;
      transition: width 0.1s linear;
    }
   
    .time-display {
      font-size: 14px;
      color: #666;
     width: 100%;
      display: flex;
      justify-content: space-between;
    }
   
    .volume-container {
      display: flex;
      align-items: center;
      margin-top: 10px;
      width: 200px;
    }
   
    .volume-icon {
      margin-right: 10px;
      width: 20px;
      text-align: center;
    }
   
    .volume-slider {
      flex: 1;
      height: 4px;
      background: #d3d3d3;
     border-radius: 2px;
      cursor: pointer;
      position: relative;
    }
   
    .volume-level {
      height: 100%;
      background: #515044;
     border-radius: 2px;
    }
   
    .playlist-btn {
      background: none;
      border: none;
      color: #515044;
     cursor: pointer;
      font-size: 14px;
      margin-top: 15px;
      text-decoration: underline;
      padding: 5px 10px;
      border-radius: 4px;
      transition: all 0.3s ease;
    }
   
    .playlist-btn:hover {
      background: rgba(52, 152, 219, 0.1);
    }
   
    /* 播放列表样式 */
    .playlist-container {
      position: fixed;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background: rgba(0,0,0,0.7);
      display: flex;
      justify-content: center;
      align-items: center;
      z-index: 100;
      opacity: 0;
      pointer-events: none;
      transition: opacity 0.3s ease;
    }
   
    .playlist-container.active {
      opacity: 1;
      pointer-events: all;
    }
   
    .playlist-content {
      background: #fff;
     width: 80%;
      max-width: 500px;
      max-height: 80vh;
      padding: 20px;
      border-radius: 8px;
      overflow-y: auto;
      box-shadow: 0 5px 25px rgba(0,0,0,0.5);
    }
   
    .playlist-header {
      font-size: 24px;
      margin-bottom: 15px;
      color: #515044;
     border-bottom: 1px solid #ddd;
     padding-bottom: 10px;
      display: flex;
      justify-content: space-between;
      align-items: center;
    }
   
    .playlist-item {
      padding: 12px;
      border-bottom: 1px solid #eee;
     cursor: pointer;
      display: flex;
      justify-content: space-between;
      align-items: center;
    }
   
    .playlist-item:hover {
      background: #f0f0f0;
   }
   
    .playlist-item.active {
      background: #fef29c;
     font-weight: bold;
    }
   
    .playlist-info {
      flex: 1;
    }
   
    .song-name {
      font-size: 16px;
      margin-bottom: 5px;
      cursor: pointer;
      color: #000000;
     transition: all 0.2s ease;
    }
   
    .song-name:hover {
      text-decoration: underline;
      color: #878787;
   }
   
    .song-singer {
      font-size: 14px;
      color: #666;
   }
   
    .close-btn {
      position: absolute;
      top: 20px;
      right: 20px;
      background: transparent;
      border: none;
      color: white;
      font-size: 24px;
      cursor: pointer;
      transition: all 0.3s ease;
    }
   
    .close-btn:hover {
      transform: scale(1.2);
      color: #f1c40f;
   }
   
    .song-link-btn {
      background: #5c5c5c;
     color: white;
      border: none;
      border-radius: 4px;
      padding: 5px 10px;
      cursor: pointer;
      font-size: 12px;
      transition: all 0.3s ease;
    }
   
    .song-link-btn:hover {
      background: #000000;
   }
   
    /* 响应式设计 */
    @media (max-width: 600px) {
      .music-player-container {
        transform: translate(-50%, -50%) scale(0.8);
      }
     
      .playlist-content {
        width: 90%;
      }
    }
     /* 提示信息 */
    .click-outside-hint {
      position: absolute;
      bottom: 15px;
      left: 0;
      width: 100%;
      text-align: center;
      font-size: 12px;
      color: #999;
     font-style: italic;
    }
  </style>
</head>
<body>
  <!-- 移除了初始的 is-playing 类 -->
  <div class="music-player-container">
    <div class="music-player">
      <div class="player-content-container">
        <h1 class="song-title">歌曲标题</h1>
        <h2 class="artist-name">歌手</h2>
        <h3 class="album-title">专辑</h3>
       
        <div class="music-player-controls">
          <div class="control-back"></div>
          <div class="control-play"></div>
          <div class="control-forwards"></div>
        </div>
       
        <div class="player-controls">
          <div class="progress-container">
            <div class="progress-bar" style="width: 0%"></div>
          </div>
          <div class="time-display">
            <span class="current-time">0:00</span>
            <span class="total-time">0:00</span>
          </div>
         
          <div class="volume-container">
            <div class="volume-icon">🔊</div>
            <div class="volume-slider">
              <div class="volume-level" style="width: 80%"></div>
            </div>
          </div>
         
          <button class="playlist-btn">播放列表 (4)</button>
        </div>
      </div>
    </div>

    <div class="album">
      <div class="album-art"></div>
      <div class="vinyl"></div>
    </div>
  </div>
 
  <div class="playlist-container">
    <button class="close-btn">×</button>
    <div class="playlist-content">
      <div class="playlist-header">
        <span>播放列表</span>
        <span>当前歌曲: <span id="current-song-indicator">1</span></span>
      </div>
      <div class="playlist-items">
        <!-- 播放列表内容由JS生成 -->
      </div>
      <div class="click-outside-hint">点击播放列表外部区域关闭</div>
    </div>
  </div>

  <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
  <script>
   // 歌曲数据
    const songs = [
      {
        name: "归",
        singer: "龙井",
        album: "龙井摇滚1",
        path: "https://edzbecom.edzbe.com/Music/2014031305281167131.mp3",
        image: "https://www.edzbe.com/wp-content/uploads/2010/10/15102-150x150.jpg",
        url: "https://www.example.com/song1"
      },
      {
        name: "Tu Phir Se Aana",
        singer: "Raftaar x Salim Merchant x Karma",
        album: "龙井摇滚2",
        path: "https://mp3.vlcmusic.com/download.php?track_id=34213&format=320",
        image: "https://1.bp.blogspot.com/-kX21dGUuTdM/X85ij1SBeEI/AAAAAAAAKK4/feboCtDKkls19cZw3glZWRdJ6J8alCm-gCNcBGAsYHQ/s16000/Tu%2BAana%2BPhir%2BSe%2BRap%2BSong%2BLyrics%2BBy%2BRaftaar.jpg",
        url: "https://www.example.com/song2"
      },
      {
        name: "时间里的",
        singer: "马頔",
        album: "龙井摇滚3",
        path: "https://edzbecom.edzbe.com/Music/2015080304061065494.mp3",
        image: "https://www.edzbe.com/wp-content/uploads/2015/08/13116882321422539101.jpg",
        url: "https://www.example.com/song15"
      },
      {
        name: "Feeling You",
        singer: "Raftaar x Harjas",
        album: "龙井摇滚4",
        path: "https://mp3.filmisongs.com/go.php?id=Damn%20Song%20Raftaar%20Ft%20KrSNa.mp3",
        image: "https://a10.gaanacdn.com/gn_img/albums/YoEWlabzXB/oEWlj5gYKz/size_xxl_1586752323.webp",
        url: "https://www.example.com/song18"
      }
    ];
    </script>
  <script>
    (function($) {
      $(document).ready(function() {
        // 创建音频对象
        const audio = new Audio();
        let currentSongIndex = 0;
        let isPlaying = false;
       
        // 获取DOM元素
        const playerContainer = $('.music-player-container');
        const artistName = $('.artist-name');
        const albumTitle = $('.album-title');
        const songTitle = $('.song-title');
        const albumArt = $('.album-art');
        const vinyl = $('.vinyl');
        const backBtn = $('.control-back');
        const playBtn = $('.control-play');
        const forwardBtn = $('.control-forwards');
        const progressBar = $('.progress-bar');
        const progressContainer = $('.progress-container');
        const currentTimeEl = $('.current-time');
        const totalTimeEl = $('.total-time');
        const volumeSlider = $('.volume-level');
        const volumeContainer = $('.volume-slider');
        const playlistBtn = $('.playlist-btn');
        const playlistContainer = $('.playlist-container');
        const playlistItems = $('.playlist-items');
        const currentSongIndicator = $('#current-song-indicator');
       
        // 初始化播放器
        function initPlayer() {
          // 确保初始状态正确
          playerContainer.removeClass('is-playing');
          vinyl.css('animation-play-state', 'paused');
         
          // 加载第一首歌
          loadSong(currentSongIndex);
         
          // 初始化播放列表
          renderPlaylist();
         
          // 为歌曲标题添加点击事件
          songTitle.on('click', function() {
            const currentSong = songs[currentSongIndex];
            window.open(currentSong.url, '_blank');
          });
         
          // 添加点击外部关闭播放列表的功能
          addClickOutsideClose();
        }
       
        // 添加点击外部关闭播放列表的功能
        function addClickOutsideClose() {
          // 点击播放列表外部区域关闭
          playlistContainer.on('click', function(e) {
            // 如果点击的是背景(不是播放列表内容区域)
            if (e.target === this) {
              togglePlaylist();
            }
          });
         
          // 阻止播放列表内容区域的点击事件冒泡
          $('.playlist-content').on('click', function(e) {
            e.stopPropagation();
          });
        }
       
        // 加载歌曲
        function loadSong(index) {
          currentSongIndex = index;
          const song = songs[index];
         
          // 更新UI
          artistName.text(song.singer);
          albumTitle.text(song.album);
          songTitle.text(`"${song.name}"`);
          albumArt.css('background-image', `url(${song.image})`);
         
          // 更新唱片背景
          vinyl.css('background-image',
                    `url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/83141/vinyl.png'), url('${song.image}')`);
         
          // 设置音频源
          audio.src = song.path;
         
          // 重置进度条
          progressBar.css('width', '0%');
          currentTimeEl.text('0:00');
         
          // 更新当前歌曲指示器
          currentSongIndicator.text(index + 1);
         
          // 加载完成后更新总时长
          audio.addEventListener('loadedmetadata', function() {
            const totalMinutes = Math.floor(audio.duration / 60);
            const totalSeconds = Math.floor(audio.duration % 60);
            totalTimeEl.text(`${totalMinutes}:${totalSeconds < 10 ? '0' : ''}${totalSeconds}`);
          });
         
          // 更新播放列表高亮
          updatePlaylistHighlight();
         
          // 自动播放当前歌曲(如果正在播放)
          if (isPlaying) {
            audio.play();
          }
        }
       
        // 播放/暂停功能
        function togglePlayback() {
          if (isPlaying) {
            audio.pause();
            playerContainer.removeClass('is-playing');
            vinyl.css('animation-play-state', 'paused');
          } else {
            audio.play();
            playerContainer.addClass('is-playing');
            vinyl.css('animation-play-state', 'running');
          }
          isPlaying = !isPlaying;
        }
       
        // 上一首
        function prevSong() {
          currentSongIndex = (currentSongIndex - 1 + songs.length) % songs.length;
          loadSong(currentSongIndex);
          if (isPlaying) {
            audio.play();
          }
        }
       
        // 下一首
        function nextSong() {
          currentSongIndex = (currentSongIndex + 1) % songs.length;
          loadSong(currentSongIndex);
          if (isPlaying) {
            audio.play();
          }
        }
       
        // 更新进度条
        function updateProgress(e) {
          const { duration, currentTime } = e.target;
          const progressPercent = (currentTime / duration) * 100;
          progressBar.css('width', `${progressPercent}%`);
         
          // 更新当前时间
          const currentMinutes = Math.floor(currentTime / 60);
          const currentSeconds = Math.floor(currentTime % 60);
          currentTimeEl.text(`${currentMinutes}:${currentSeconds < 10 ? '0' : ''}${currentSeconds}`);
        }
       
        // 设置进度
        function setProgress(e) {
          const width = progressContainer.width();
          const clickX = e.offsetX;
          const duration = audio.duration;
         
          audio.currentTime = (clickX / width) * duration;
        }
       
        // 设置音量
        function setVolume(e) {
          const width = volumeContainer.width();
          const clickX = e.offsetX;
          const volume = clickX / width;
         
          audio.volume = volume;
          volumeSlider.css('width', `${volume * 100}%`);
        }
       
        // 渲染播放列表
        function renderPlaylist() {
          playlistItems.empty();
         
          songs.forEach((song, index) => {
            const playlistItem = $('<div>').addClass('playlist-item').data('index', index).html(`
              <div class="playlist-info">
                <div class="song-name" data-url="${song.url}">${song.name}</div>
                <div class="song-singer">${song.singer}</div>
              </div>
              <button class="song-link-btn" data-url="${song.url}">歌曲详情</button>
            `);
           
            // 绑定播放列表项的点击事件
            playlistItem.on('click', function() {
              const index = $(this).data('index');
              loadSong(index);
              if (!isPlaying) {
                togglePlayback();
              }
            });
           
            // 绑定歌曲名称的点击事件  这个我先隐藏了
    //        playlistItem.find('.song-name').on('click', function(e) {
    //          e.stopPropagation();
    //          window.open($(this).data('url'), '_blank');
    //        });
           
            // 绑定按钮的点击事件
            playlistItem.find('.song-link-btn').on('click', function(e) {
              e.stopPropagation();
              window.open($(this).data('url'), '_blank');
            });
           
            playlistItems.append(playlistItem);
          });
         
          // 更新播放列表高亮
          updatePlaylistHighlight();
        }
       
        // 更新播放列表高亮
        function updatePlaylistHighlight() {
          $('.playlist-item').removeClass('active');
          $('.playlist-item').eq(currentSongIndex).addClass('active');
        }
       
        // 显示/隐藏播放列表
        function togglePlaylist() {
          playlistContainer.toggleClass('active');
        }
       
        // 事件监听
        playBtn.on('click', togglePlayback);
        backBtn.on('click', prevSong);
        forwardBtn.on('click', nextSong);
        playlistBtn.on('click', togglePlaylist);
        $('.close-btn').on('click', togglePlaylist);
       
        // 进度条控制
        progressContainer.on('click', setProgress);
        volumeContainer.on('click', setVolume);
       
        // 音频事件
        audio.addEventListener('timeupdate', updateProgress);
        audio.addEventListener('ended', nextSong);
       
        // 初始化播放器
        initPlayer();
      });
    })(jQuery);
  </div></script>
</body>
</html>

手机端:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8"/>
  <title>耳朵电台手机端播放器</title>
  <link rel="stylesheet" href="./style.css"/>

</head>
<body>
<!-- partial:index.partial.html -->
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css" integrity="sha512-HK5fgLBL+xu6dm/Ii3z4xhlSUyZgTT9tuc/hSrtw6uzJOvgRr2a9jyxxT1ely+B+xFAmJKVSTbpM/CuL7qxO8w==" crossorigin="anonymous" />
<link rel="preconnect" href="https://fonts.gstatic.com"/>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet"/>

<div class="player">
  <!-- Dashboard -->
  <div class="dashboard">
    <!-- Header -->
    <header>
      <h4>Now playing:</h4>
      <h2>String 57th & 9th</h2>
    </header>

    <!-- CD -->
    <div class="cd">
      <div class="cd-thumb">
      </div>
    </div>

    <!-- Control -->
    <div class="control">
      <div class="btn btn-repeat">
        <i class="fas fa-redo"></i>
      </div>
      <div class="btn btn-prev">
        <i class="fas fa-step-backward"></i>
      </div>
      <div class="btn btn-toggle-play">
        <i class="fas fa-pause icon-pause"></i>
        <i class="fas fa-play icon-play"></i>
      </div>
      <div class="btn btn-next">
        <i class="fas fa-step-forward"></i>
      </div>
      <div class="btn btn-random">
        <i class="fas fa-random"></i>
      </div>
    </div>

    <input id="progress" class="progress" type="range" value="0" step="1" min="0" max="100"/>

    <audio id="audio" src=""></audio>
  </div>

  <!-- Playlist -->
  <div class="playlist">
  </div>
</div>

<!-- partial -->

<script>
const songs = [
  {
    name: "镜子中",
    singer: "扭曲的机器",
    path: "https://edzbecom.oss-cn-hangzhou.aliyuncs.com/Music/2014031305281167131.mp3",
    image: "https://www.edzbe.com/wp-content/uploads/2010/10/15102-150x150.jpg"
  },
  {
    name: "Tu Phir Se Aana",
    singer: "Raftaar x Salim Merchant x Karma",
    path: "https://mp3.vlcmusic.com/download.php?track_id=34213&format=320",
    image:
      "https://1.bp.blogspot.com/-kX21dGUuTdM/X85ij1SBeEI/AAAAAAAAKK4/feboCtDKkls19cZw3glZWRdJ6J8alCm-gCNcBGAsYHQ/s16000/Tu%2BAana%2BPhir%2BSe%2BRap%2BSong%2BLyrics%2BBy%2BRaftaar.jpg"
  },
  {
    name: "时间里的",
    singer: "马頔",
    path: "https://edzbecom.oss-cn-hangzhou.aliyuncs.com/Music/2015080304061065494.mp3",
    image: "https://www.edzbe.com/wp-content/uploads/2015/08/13116882321422539101.jpg"
  },
  {
    name: "Feeling You",
    singer: "Raftaar x Harjas",
    path: "https://mp3.filmisongs.com/go.php?id=Damn%20Song%20Raftaar%20Ft%20KrSNa.mp3",
    image:
      "https://a10.gaanacdn.com/gn_img/albums/YoEWlabzXB/oEWlj5gYKz/size_xxl_1586752323.webp"
  }
];

</script>

<!--音频数据一定要在APP.JS之前加载-->
<script src="./app.js"></script>
</body>
</html>

手机端 App.js 文件代码:

const $ = document.querySelector.bind(document);
const $$ = document.querySelectorAll.bind(document);

const PlAYER_STORAGE_KEY = "F8_PLAYER";

const player = $(".player");
const cd = $(".cd");
const heading = $("header h2");
const cdThumb = $(".cd-thumb");
const audio = $("#audio");
const playBtn = $(".btn-toggle-play");
const progress = $("#progress");
const prevBtn = $(".btn-prev");
const nextBtn = $(".btn-next");
const randomBtn = $(".btn-random");
const repeatBtn = $(".btn-repeat");
const playlist = $(".playlist");

const app = {
  currentIndex: 0,
  isPlaying: false,
  isRandom: false,
  isRepeat: false,
  config: {},
  // (1/2) 解注释以下代码行以使用localStorage
  // config: JSON.parse(localStorage.getItem(PlAYER_STORAGE_KEY)) || {},
  songs: [], // 从data.js文件中导入歌曲数据
  setConfig: function (key, value) {
    this.config[key] = value;
    // (2/2) 解注释以下代码行以使用localStorage
    // localStorage.setItem(PlAYER_STORAGE_KEY, JSON.stringify(this.config));
  },
  render: function () {
    const htmls = this.songs.map((song, index) => {
      return `
                        <div class="song ${
                          index === this.currentIndex ? "
active" : ""
                        }"
data-index="${index}">
                            <div class="thumb"
                                style="background-image: url('${song.image}')">
                            </div>
                            <div class="body">
                                <h3 class="title">${song.name}</h3>
                                <p class="author">${song.singer}</p>
                            </div>
                            <div class="option">
                                <i class="fas fa-ellipsis-h"></i>
                            </div>
                        </div>
                    `;
    });
    playlist.innerHTML = htmls.join("");
  },
  defineProperties: function () {
    Object.defineProperty(this, "currentSong", {
      get: function () {
        return this.songs[this.currentIndex];
      }
    });
  },
  handleEvents: function () {
    const _this = this;
    const cdWidth = cd.offsetWidth;

    // 处理CD旋转/停止
    const cdThumbAnimate = cdThumb.animate([{ transform: "rotate(360deg)" }], {
      duration: 10000, // 10秒
      iterations: Infinity
    });
    cdThumbAnimate.pause();

    // 处理CD放大/缩小
    document.onscroll = function () {
      const scrollTop = window.scrollY || document.documentElement.scrollTop;
      const newCdWidth = cdWidth - scrollTop;

      cd.style.width = newCdWidth > 0 ? newCdWidth + "px" : 0;
      cd.style.opacity = newCdWidth / cdWidth;
    };

    // 处理点击播放
    playBtn.onclick = function () {
      if (_this.isPlaying) {
        audio.pause();
      } else {
        audio.play();
      }
    };

    // 当歌曲播放时
    audio.onplay = function () {
      _this.isPlaying = true;
      player.classList.add("playing");
      cdThumbAnimate.play();
    };

    // 当歌曲暂停时
    audio.onpause = function () {
      _this.isPlaying = false;
      player.classList.remove("playing");
      cdThumbAnimate.pause();
    };

    // 当歌曲进度改变时
    audio.ontimeupdate = function () {
      if (audio.duration) {
        const progressPercent = Math.floor(
          (audio.currentTime / audio.duration) * 100
        );
        progress.value = progressPercent;
      }
    };

    // 处理歌曲拖动
    progress.onchange = function (e) {
      const seekTime = (audio.duration / 100) * e.target.value;
      audio.currentTime = seekTime;
    };

    // 下一首歌曲
    nextBtn.onclick = function () {
      if (_this.isRandom) {
        _this.playRandomSong();
      } else {
        _this.nextSong();
      }
      audio.play();
      _this.render();
      _this.scrollToActiveSong();
    };

    // 上一首歌曲
    prevBtn.onclick = function () {
      if (_this.isRandom) {
        _this.playRandomSong();
      } else {
        _this.prevSong();
      }
      audio.play();
      _this.render();
      _this.scrollToActiveSong();
    };

    // 处理随机播放开关
    randomBtn.onclick = function (e) {
      _this.isRandom = !_this.isRandom;
      _this.setConfig("isRandom", _this.isRandom);
      randomBtn.classList.toggle("active", _this.isRandom);
    };

    // 处理单曲循环
    repeatBtn.onclick = function (e) {
      _this.isRepeat = !_this.isRepeat;
      _this.setConfig("isRepeat", _this.isRepeat);
      repeatBtn.classList.toggle("active", _this.isRepeat);
    };

    // 处理音频播放结束后的下一首歌曲
    audio.onended = function () {
      if (_this.isRepeat) {
        audio.play();
      } else {
        nextBtn.click();
      }
    };

    // 监听播放列表点击事件
    playlist.onclick = function (e) {
      const songNode = e.target.closest(".song:not(.active)");

      if (songNode || e.target.closest(".option")) {
        // 处理点击歌曲
        if (songNode) {
          _this.currentIndex = Number(songNode.dataset.index);
          _this.loadCurrentSong();
          _this.render();
          audio.play();
        }

        // 处理点击歌曲选项
        if (e.target.closest(".option")) {
        }
      }
    };
  },
  scrollToActiveSong: function () {
    setTimeout(() => {
      $(".song.active").scrollIntoView({
        behavior: "smooth",
        block: "nearest"
      });
    }, 300);
  },
  loadCurrentSong: function () {
    heading.textContent = this.currentSong.name;
    cdThumb.style.backgroundImage = `url('${this.currentSong.image}')`;
    audio.src = this.currentSong.path;
  },
  loadConfig: function () {
    this.isRandom = this.config.isRandom;
    this.isRepeat = this.config.isRepeat;
  },
  nextSong: function () {
    this.currentIndex++;
    if (this.currentIndex >= this.songs.length) {
      this.currentIndex = 0;
    }
    this.loadCurrentSong();
  },
  prevSong: function () {
    this.currentIndex--;
    if (this.currentIndex < 0) {
      this.currentIndex = this.songs.length - 1;
    }
    this.loadCurrentSong();
  },
  playRandomSong: function () {
    let newIndex;
    do {
      newIndex = Math.floor(Math.random() * this.songs.length);
    } while (newIndex === this.currentIndex);

    this.currentIndex = newIndex;
    this.loadCurrentSong();
  },
  start: function () {
    // 从data.js加载歌曲数据
    this.songs = songs;

    // 将配置从config赋值给应用
    this.loadConfig();

    // 定义对象的属性
    this.defineProperties();

    // 监听/处理事件(DOM事件)
    this.handleEvents();

    // 运行应用时将第一首歌曲信息加载到UI
    this.loadCurrentSong();

    // 渲染播放列表
    this.render();

    // 显示重复和随机按钮的初始状态
    randomBtn.classList.toggle("active", this.isRandom);
    repeatBtn.classList.toggle("active", this.isRepeat);
  }
};

app.start();

手机端 style.css 样式代码:

:root {
  --primary-color: #ec1f55;
 --text-color: #333;
}

* {
  padding: 0;
  margin: 0;
  box-sizing: inherit;
}

body {
  background-color: #f5f5f5;
}

html {
  box-sizing: border-box;
  font-family: "Poppins", sans-serif;
}

.player {
  position: relative;
  max-width: 480px;
  margin: 0 auto;
}

.player .icon-pause {
  display: none;
}

.player.playing .icon-pause {
  display: inline-block;
}

.player.playing .icon-play {
  display: none;
}

.dashboard {
  padding: 16px 16px 14px;
  background-color: #fff;
 position: fixed;
  top: 0;
  width: 100%;
  max-width: 480px;
  border-bottom: 1px solid #ebebeb;
}

/* HEADER */
header {
  text-align: center;
  margin-bottom: 10px;
}

header h4 {
  color: var(--primary-color);
  font-size: 12px;
}

header h2 {
  color: var(--text-color);
  font-size: 20px;
}

/* CD */
.cd {
  display: flex;
  margin: auto;
  width: 200px;
}

.cd-thumb {
  width: 100%;
  padding-top: 100%;
  border-radius: 50%;
  background-color: #333;
 background-size: cover;
  margin: auto;
}

/* CONTROL */
.control {
  display: flex;
  align-items: center;
  justify-content: space-around;
  padding: 18px 0 8px 0;
}

.control .btn {
  color: #666;
 padding: 18px;
  font-size: 18px;
}

.control .btn.active {
  color: var(--primary-color);
}

.control .btn-toggle-play {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  font-size: 24px;
  color: #fff;
 display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--primary-color);
}

.progress {
  width: 100%;
  -webkit-appearance: none;
  height: 6px;
  background: #d3d3d3;
 outline: none;
  opacity: 0.7;
  -webkit-transition: 0.2s;
  transition: opacity 0.2s;
}

.progress::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 12px;
  height: 6px;
  background-color: var(--primary-color);
  cursor: pointer;
}

/* PLAYLIST */
.playlist {
  margin-top: 408px;
  padding: 12px;
}

.song {
  display: flex;
  align-items: center;
  margin-bottom: 12px;
  background-color: #fff;
 padding: 8px 16px;
  border-radius: 5px;
  box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1);
}

.song.active {
  background-color: var(--primary-color);
}

.song:active {
  opacity: 0.8;
}

.song.active .option,
.song.active .author,
.song.active .title {
  color: #fff;
}

.song .thumb {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background-size: cover;
  margin: 0 8px;
}

.song .body {
  flex: 1;
  padding: 0 16px;
}

.song .title {
  font-size: 18px;
  color: var(--text-color);
}

.song .author {
  font-size: 12px;
  color: #999;
}

.song .option {
  padding: 16px 8px;
  color: #999;
 font-size: 18px;
}

啊啊啊啊啊啊啊,我又想到了,安卓版好久没维护更新了,啊啊啊啊啊啊啊啊啊,当时弄的安卓版还是独立的系统,需要我博客更新一篇音频,安卓后台在更新一遍,啊,双遍工作量,我不玩了,我不玩了。

哎呀,唉,我不玩了,我好饿,我叫了份霸王牛肉面,三点多送来了,凉了,我要去吃了。