newraina 9 years ago
parent
commit
32a5318b17

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+node_modules
+.idea

+ 2 - 0
.npmignore

@@ -0,0 +1,2 @@
+.travis.yml
+.idea

+ 4 - 0
.travis.yml

@@ -0,0 +1,4 @@
+language: node_js
+node_js:
+  - "4.1"
+  - "4.0"

+ 38 - 0
README.md

@@ -0,0 +1,38 @@
+# mePlayer
+一款简洁的HTML5音乐播放器。内置两套主题,可在运行时一键切换
+![](demo/toggleTheme.gif)
+
+## 主题预览
+### 默认主题
+- 有歌词时滚动显示歌词,无歌词时显示模拟频谱动画
+- 播放中鼠标悬停在界面上滑动滚轮可调节音量,音量大小用音量条表示
+![](demo/default-theme.gif)
+![](demo/default-theme-nolrc.gif)
+
+### 迷你主题
+- 去掉了大部分控件,仅保留音量调节和播放暂停按钮
+- 播放中鼠标悬停在界面上滑动滚轮可调节音量,音量大小用音量图标透明度表示
+![](demo/mini-theme.gif)
+
+## 使用方法
+- 引入`meplayer.min.css`、`meplayer.min.js`以及`fonts`文件夹
+- 初始化
+  ```javascript
+mePlayer({
+    theme: '可选,不指定时为默认主题,值为"mini"时为迷你版主题',
+    music : {
+        src   : '音乐文件地址',
+        title : '歌名',
+        author: '歌手名',
+        cover : '封面路径',
+        lrc   : '歌词字符串:[00:24.600]温柔的晚风\n[00:27.830]轻轻吹过 爱人的梦中\n ...'
+    },
+    target: '放置播放器的DOM容器,如: .music'
+});
+  ```
+- 运行中可使用`meplayer.play()`和`meplayer.pause`手动播放暂停
+- `meplayer.toggleTheme()`可一键切换主题
+
+## 致谢
+- 制作过程中参考了[APlayer](https://github.com/DIYgod/APlayer)的部分代码
+- UI设计参考了[bottom-music-player](http://www.materialup.com/posts/a-or-b-bottom-music-player-dashboard)

BIN
demo/default-theme-nolrc.gif


BIN
demo/default-theme.gif


+ 14 - 0
demo/index.html

@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>mePlayer</title>
+    <link rel="stylesheet" href="../dist/meplayer.css">
+    <link rel="stylesheet" href="main.css">
+</head>
+<body>
+<div class="music"></div>
+<script src="../dist/meplayer.min.js"></script>
+<script src="main.js"></script>
+</body>
+</html>

+ 18 - 0
demo/main.css

@@ -0,0 +1,18 @@
+html {
+    width: 100%;
+    height: 100%;
+    margin: 0;
+    padding: 0;
+}
+
+body {
+    margin: 0;
+    padding: 0;
+
+    background: #E6EAF1;
+}
+
+.music {
+    width: 400px;
+    margin: 120px auto 0;
+}

+ 10 - 0
demo/main.js

@@ -0,0 +1,10 @@
+mePlayer({
+    music : {
+        src   : 'http://my-typecho-blog.b0.upaiyun.com/usr/uploads/2016/02/3528841697.mp3',
+        title : '晚风',
+        author: '好妹妹乐队',
+        cover : 'http://my-typecho-blog.b0.upaiyun.com/usr/uploads/2016/02/462344463.jpg',
+        lrc   : '[00:24.600]温柔的晚风\n[00:27.830]轻轻吹过 爱人的梦中\n[00:36.690]温柔的晚风\n[00:39.129]轻轻吹过 故乡的天空\n[00:47.690]温柔的晚风\n[00:50.749]轻轻吹过 城市的灯火\n[00:59.119]今夜的晚风\n[01:02.439]你去哪里 请告诉我\n[01:08.249]\n[01:10.879]温柔的晚风\n[01:14.590]轻轻吹过 爱人的梦中\n[01:22.179]温柔的晚风\n[01:25.549]轻轻吹过 故乡的天空\n[01:33.809]温柔的晚风\n[01:37.539]轻轻地吹过 城市的灯火\n[01:46.509]今夜的晚风\n[01:49.919]你要去哪里 请告诉我\n[01:56.419]\n[02:37.140]温柔的晚风\n[02:40.740]轻轻吹过 爱人的梦中\n[02:49.060]温柔的晚风\n[02:52.370]轻轻吹过 故乡的天空\n[03:00.680]温柔的晚风\n[03:03.860]轻轻吹过 城市的灯火\n[03:12.190]今夜的晚风\n[03:15.440]你要去哪里 请告诉我\n[03:21.370]\n[03:23.620]温柔的晚风\n[03:27.090]轻轻吹过 爱人的梦中\n[03:35.280]温柔的晚风\n[03:39.570]轻轻吹过 故乡的天空\n[03:47.620]温柔的晚风\n[03:50.880]轻轻地吹过 城市的灯火\n[03:59.180]今夜的晚风\n[04:02.680]你要去哪里 请告诉我\n[04:08.800]\n[04:33.830]温柔的晚风\n[04:37.350]请你带走 我昨天的梦\n[04:45.350]今夜的晚风\n[04:48.960]我要去哪里 请告诉我\n[04:59.690]\n'
+    },
+    target: '.music'
+});

BIN
demo/mini-theme.gif


BIN
demo/toggleTheme.gif


BIN
dist/fonts/fontello.eot


+ 16 - 0
dist/fonts/fontello.svg

@@ -0,0 +1,16 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata>Copyright (C) 2016 by original authors @ fontello.com</metadata>
+<defs>
+<font id="fontello" horiz-adv-x="1000" >
+<font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
+<missing-glyph horiz-adv-x="1000" />
+<glyph glyph-name="spin6" unicode="&#xe800;" d="m855 9c-189-190-520-172-705 13-190 190-200 494-28 695 11 13 21 26 35 34 36 23 85 18 117-13 30-31 35-76 16-112-5-9-9-15-16-22-140-151-145-379-8-516 153-153 407-121 542 34 106 122 142 297 77 451-83 198-305 291-510 222l0 1c236 82 492-24 588-252 71-167 37-355-72-493-11-15-23-29-36-42z" horiz-adv-x="1000" />
+<glyph glyph-name="play" unicode="&#xe801;" d="m772 333l-741-412q-13-7-22-2t-9 20v822q0 14 9 20t22-2l741-412q13-7 13-17t-13-17z" horiz-adv-x="785.7" />
+<glyph glyph-name="pause" unicode="&#xe802;" d="m857 743v-786q0-14-10-25t-26-11h-285q-15 0-25 11t-11 25v786q0 14 11 25t25 11h285q15 0 26-11t10-25z m-500 0v-786q0-14-10-25t-26-11h-285q-15 0-25 11t-11 25v786q0 14 11 25t25 11h285q15 0 26-11t10-25z" horiz-adv-x="857.1" />
+<glyph glyph-name="clock" unicode="&#xe803;" d="m0 350q0 95 37 182t100 149 150 100 182 37 182-37 149-100 100-149 37-182-37-182-100-150-149-100-182-37-182 37-150 100-100 150-37 182z m117 0q0-96 47-177t128-128 177-47q95 0 176 47t128 128 47 177q0 95-47 176t-128 128-176 47q-72 0-137-28t-112-75-75-112-28-136z m293 0v224q0 24 17 41t42 18 41-18 17-41v-200l142-141q17-17 17-42t-17-41-41-17q-25 0-42 17l-159 158q-1 2-4 5t-3 4q-1 2-2 4l-2 3t-1 4q-1 0-2 5-2 5-2 5-1 6-1 12z" horiz-adv-x="937.5" />
+<glyph glyph-name="volume" unicode="&#xe804;" d="m0 142l0 416 236 0 354 289 0-994-354 289-236 0z m652 35q73 74 73 176t-73 178l71 74q105-106 107-254 0-145-107-246z m118-119q123 119 123 295t-123 299l76 74q154-154 154-372t-154-372z" horiz-adv-x="1000" />
+</font>
+</defs>
+</svg>

BIN
dist/fonts/fontello.ttf


BIN
dist/fonts/fontello.woff


+ 757 - 0
dist/meplayer.css

@@ -0,0 +1,757 @@
+/*UI设计参考:http://www.materialup.com/posts/a-or-b-bottom-music-player-dashboard*/
+
+.meplayer-container {
+    font-family: Helvetica, Tahoma, Arial, STXihei, '华文细黑', 'Microsoft YaHei', '微软雅黑', SimSun, '宋体', Heiti, '黑体', sans-serif;
+    line-height: initial;
+
+    position: relative;
+
+    box-sizing: border-box;
+    width: 100%;
+    height: 90px;
+
+    background: #FFF;
+    box-shadow: 0 0 20px rgba(59, 59, 177, .18);
+}
+
+.meplayer-container .meplayer-info {
+    font-weight: 300;
+
+    position: relative;
+    left: 0;
+
+    opacity: 1;
+}
+
+.meplayer-container .meplayer-info-cover {
+    position: absolute;
+    top: 0;
+    left: 0;
+
+    overflow: hidden;
+
+    height: 90px;
+    padding-right: 20px;
+
+    -webkit-transition: all .6s cubic-bezier(0, .36, .51, 1.39);
+
+    transition: all .6s cubic-bezier(0, .36, .51, 1.39);
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-info-cover {
+    left: -90px;
+
+    opacity: 0;
+}
+
+.meplayer-container .meplayer-info-cover img {
+    width: 78px;
+    height: 78px;
+
+    border: 6px solid #FFF;
+    box-shadow: 0 0 20px rgba(59, 59, 177, .35);
+}
+
+.meplayer-container .meplayer-meta {
+    float: left;
+
+    margin-left: 110px;
+
+    -webkit-transition: all .6s cubic-bezier(0, .36, .51, 1.39);
+
+    transition: all .6s cubic-bezier(0, .36, .51, 1.39);
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-meta {
+    margin-left: 10px;
+
+    -webkit-transform: scale(.85, .85);
+
+            transform: scale(.85, .85);
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-meta .meplayer-meta-title {
+    margin-top: 4px;
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-meta .meplayer-meta-time-tick {
+    -webkit-transition: all .6s cubic-bezier(0, .36, .51, 1.39) .65s;
+    transition: all .6s cubic-bezier(0, .36, .51, 1.39) .65s;
+    -webkit-transform: translateY(0);
+            transform: translateY(0);
+
+    opacity: 1;
+}
+
+.meplayer-container .meplayer-meta .meplayer-meta-time-tick {
+    font-size: 13px;
+
+    margin-top: 30px;
+
+    -webkit-transform: translateY(10px);
+
+            transform: translateY(10px);
+    letter-spacing: 1px;
+
+    opacity: 0;
+    color: rgba(0, 0, 0, .6);
+}
+
+.meplayer-container .meplayer-meta-title {
+    font-size: 14px;
+
+    margin-top: 27px;
+    margin-bottom: 2px;
+
+    -webkit-transition: all .6s cubic-bezier(0, .36, .51, 1.39);
+
+    transition: all .6s cubic-bezier(0, .36, .51, 1.39);
+    letter-spacing: 1px;
+
+    color: #6A6B6F;
+}
+
+.meplayer-container .meplayer-meta-author {
+    font-size: 12px;
+
+    color: #CECED6;
+}
+
+.meplayer-container .meplayer-spectrum {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+
+    display: block;
+
+    width: 0;
+    height: 30px;
+    margin-top: -15px;
+    margin-left: -120px;
+
+    -webkit-transition: all .7s cubic-bezier(.17, .67, .45, 1.26) .1s;
+
+    transition: all .7s cubic-bezier(.17, .67, .45, 1.26) .1s;
+    -webkit-transform: translateX(110px);
+            transform: translateX(110px);
+
+    opacity: 0;
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-spectrum {
+    width: 220px;
+
+    -webkit-transform: translateX(0);
+
+            transform: translateX(0);
+
+    opacity: 1;
+}
+
+.meplayer-container.meplayer-haslrc .meplayer-spectrum {
+    display: none;
+}
+
+.meplayer-container .meplayer-lyric {
+    position: absolute;
+    z-index: -2;
+    top: 50%;
+    left: 50%;
+
+    overflow: hidden;
+
+    width: 220px;
+    height: 100%;
+    margin-top: -45px;
+    margin-left: -120px;
+
+    -webkit-transition: all 1s;
+
+    transition: all 1s;
+    -webkit-transform: translateY(15px);
+            transform: translateY(15px);
+
+    opacity: 0;
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-lyric {
+    z-index: 0;
+
+    -webkit-transform: translateY(0);
+
+            transform: translateY(0);
+
+    opacity: 1;
+}
+
+.meplayer-container .meplayer-lyric-area {
+    font-size: 12px;
+
+    margin-top: 35px;
+
+    -webkit-transition: -webkit-transform .7s;
+
+    transition: -webkit-transform .7s;
+
+    transition: transform .7s;
+
+    text-align: center;
+
+    opacity: 0;
+    color: rgba(0, 0, 0, .7);
+}
+
+.meplayer-container .meplayer-lyric-area p {
+    line-height: 0;
+
+    width: 100%;
+    margin: 0;
+    padding: 0;
+
+    -webkit-transition: all .6s;
+
+    transition: all .6s;
+
+    opacity: 0;
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-lyric-area p {
+    line-height: 20px;
+}
+
+.meplayer-container .meplayer-haslrc .meplayer-lyric-area {
+    display: block;
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-lyric-area {
+    opacity: 1;
+}
+
+.meplayer-container .meplayer-lyric-area .meplayer-lyric-current {
+    font-size: 1.1em;
+
+    opacity: 1;
+}
+
+.meplayer-container .meplayer-lyric-area .meplayer-lyric-pre,
+.meplayer-container .meplayer-lyric-area .meplayer-lyric-next {
+    opacity: .35;
+}
+
+.meplayer-container .meplayer-control {
+    position: relative;
+
+    float: right;
+
+    margin-right: 40px;
+}
+
+.meplayer-container .meplayer-volume-bg {
+    position: absolute;
+    z-index: -1;
+
+    width: 100%;
+    height: 100%;
+
+    -webkit-transition: all .8s;
+
+    transition: all .8s;
+
+    opacity: 0;
+    background: rgba(255, 255, 255, .8);
+}
+
+.meplayer-container.meplayer-adjusting-volume .meplayer-volume-bg {
+    z-index: 20;
+}
+
+.meplayer-container .meplayer-volume {
+    font-size: 50px;
+
+    width: 60px;
+    margin: 13px auto 0;
+
+    -webkit-transition: all .9s;
+
+    transition: all .9s;
+    text-align: center;
+
+    color: rgba(150, 150, 150, .75);
+}
+
+.meplayer-container.meplayer-adjusting-volume .meplayer-volume-bg {
+    opacity: 1;
+}
+
+.meplayer-container .meplayer-volume-progress {
+    height: 4px;
+    /*margin-top: -1px;*/
+
+    -webkit-transition: width .2s;
+
+    transition: width .2s;
+
+    border-radius: 1px;
+    background: rgba(150, 150, 150, .75);
+}
+
+.meplayer-container .meplayer-control-play {
+    position: absolute;
+    top: -25px;
+    right: 0;
+
+    width: 50px;
+    height: 50px;
+
+    cursor: pointer;
+    -webkit-transition: top .6s cubic-bezier(0, .74, .61, 1.35);
+    transition: top .6s cubic-bezier(0, .74, .61, 1.35);
+    text-align: center;
+
+    color: #D94240;
+    border-radius: 50%;
+    background: #FFF;
+    box-shadow: 0 0 10px rgba(59, 59, 177, .22);
+}
+
+.meplayer-container .meplayer-control-play:hover {
+    -webkit-animation: breath 2s infinite alternate;
+            animation: breath 2s infinite alternate;
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-control-play {
+    top: 20px;
+
+    -webkit-animation: breath 2s infinite alternate;
+
+            animation: breath 2s infinite alternate;
+}
+
+.meplayer-container .meplayer-control-play [class^='icon-'] {
+    line-height: 50px;
+
+    position: absolute;
+    left: 50%;
+
+    margin-left: -7px;
+
+    -webkit-transition: all .5s;
+
+    transition: all .5s;
+}
+
+.meplayer-container .meplayer-control-play .icon-play {
+    -webkit-transform: translateX(0);
+            transform: translateX(0);
+
+    opacity: 1;
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-control-play .icon-play {
+    -webkit-transform: translateX(8px);
+            transform: translateX(8px);
+
+    opacity: 0;
+}
+
+.meplayer-container .meplayer-control-play .icon-pause {
+    -webkit-transform: translateX(-8px);
+            transform: translateX(-8px);
+
+    opacity: 0;
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-control-play .icon-pause {
+    -webkit-transform: translateX(-1px);
+            transform: translateX(-1px);
+
+    opacity: 1;
+}
+
+.meplayer-container .meplayer-duration,
+.meplayer-container .meplayer-loadingsign {
+    font-size: 12px;
+
+    position: absolute;
+    right: 40px;
+    bottom: 24px;
+
+    -webkit-transition: all .6s cubic-bezier(0, .74, .61, 1.35);
+
+    transition: all .6s cubic-bezier(0, .74, .61, 1.35);
+    letter-spacing: 1px;
+
+    color: rgba(0, 0, 0, .6);
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-duration,
+.meplayer-container.meplayer-isplaying .meplayer-loadingsign {
+    z-index: -1;
+    bottom: 5px;
+
+    -webkit-transform: scale(.5, .5);
+
+            transform: scale(.5, .5);
+
+    opacity: 0;
+}
+
+.meplayer-container.meplayer-isloading .meplayer-duration {
+    opacity: 0;
+}
+
+.meplayer-container .meplayer-loadingsign {
+    opacity: 0;
+}
+
+.meplayer-container.meplayer-isloading .meplayer-loadingsign {
+    opacity: 1;
+}
+
+.meplayer-container .meplayer-duration i,
+.meplayer-container .meplayer-loadingsign i {
+    margin-right: 3px;
+
+    -webkit-transition: all .7s;
+
+    transition: all .7s;
+    -webkit-transform: scale(.9, .9);
+            transform: scale(.9, .9);
+
+    color: rgba(217, 66, 64, .5);
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-duration i {
+    -webkit-transform: rotateZ(360deg);
+            transform: rotateZ(360deg);
+}
+
+.meplayer-container .meplayer-timeline-bg {
+    position: absolute;
+    bottom: 0;
+
+    width: 100%;
+    height: 8px;
+}
+
+.meplayer-container .meplayer-timeline {
+    position: absolute;
+    bottom: 0;
+
+    overflow: hidden;
+
+    width: 100%;
+    height: 2px;
+
+    -webkit-transition: all .5s;
+
+    transition: all .5s;
+    -webkit-transform: translateY(2px);
+            transform: translateY(2px);
+
+    opacity: 0;
+    background: rgba(231, 231, 239, .8);
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-timeline {
+    cursor: pointer;
+    -webkit-transform: translateY(0);
+            transform: translateY(0);
+
+    opacity: 1;
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-timeline-bg:hover .meplayer-timeline {
+    height: 8px;
+}
+
+.meplayer-container .meplayer-timeline .meplayer-timeline-passed {
+    position: absolute;
+    bottom: 0;
+
+    width: 0;
+    height: 100%;
+
+    background: #D94240;
+}
+
+.meplayer-container.meplayer-changing-theme .meplayer-volume-bg {
+    display: none;
+}
+
+@-webkit-keyframes breath {
+    0% {
+        box-shadow: 0 0 35px rgba(59, 59, 177, .22);
+    }
+
+    100% {
+        box-shadow: 0 0 10px rgba(59, 59, 177, .33);
+    }
+}
+
+@keyframes breath {
+    0% {
+        box-shadow: 0 0 35px rgba(59, 59, 177, .22);
+    }
+
+    100% {
+        box-shadow: 0 0 10px rgba(59, 59, 177, .33);
+    }
+}
+
+.meplayer-container-mini {
+    position: relative;
+    width: 90px;
+    height: 90px;
+    background: #FFF;
+    border-radius: 50%;
+    box-shadow: 0 0 20px rgba(59, 59, 177, .18);
+}
+
+.meplayer-isplaying.meplayer-container-mini {
+    -webkit-animation: breath 2s infinite alternate;
+    animation: breath 2s infinite alternate;
+}
+
+.meplayer-container-mini .meplayer-info, .meplayer-container-mini .meplayer-spectrum,
+.meplayer-container-mini .meplayer-lyric, .meplayer-container-mini .meplayer-duration,
+.meplayer-container-mini .meplayer-loadingsign, .meplayer-container-mini .meplayer-timeline-bg {
+    display: none;
+}
+
+.meplayer-container-mini .meplayer-control-play {
+    width: 90px;
+    height: 90px;
+    position: absolute;
+    top: 50%;
+    font-size: 26px;
+    line-height: 90px;
+    left: 50%;
+    margin-top: -45px;
+    margin-left: -45px;
+    color: #D94240;
+}
+
+.meplayer-container-mini .meplayer-control-play [class^='icon-'] {
+    line-height: 90px;
+
+    position: absolute;
+    left: 50%;
+
+    margin-left: -11px;
+
+    -webkit-transition: all .5s;
+
+    transition: all .5s;
+    cursor: pointer;
+}
+
+.meplayer-container-mini .meplayer-control-play .icon-play {
+    -webkit-transform: translateX(0);
+    transform: translateX(0);
+    opacity: 1;
+}
+
+.meplayer-container-mini.meplayer-isplaying .meplayer-control-play .icon-play {
+    -webkit-transform: translateX(16px);
+    transform: translateX(16px);
+    opacity: 0;
+}
+
+.meplayer-container-mini .meplayer-control-play .icon-pause {
+    -webkit-transform: translateX(-16px);
+    transform: translateX(-16px);
+    opacity: 0;
+}
+
+.meplayer-container-mini.meplayer-isplaying .meplayer-control-play .icon-pause {
+    -webkit-transform: translateX(0);
+    transform: translateX(0);
+    opacity: 1;
+}
+
+.meplayer-container-mini .meplayer-volume-bg {
+    z-index: -1;
+    position: absolute;
+    width: 100%;
+    height: 100%;
+    background: rgba(255, 255, 255, 0.98);
+    line-height: 90px;
+    border-radius: 50%;
+    text-align: center;
+    color: rgba(0, 0, 0, 0.9);
+    font-size: 30px;
+    -webkit-transition: all 0.8s;
+    transition: all 0.8s;
+}
+
+.meplayer-container-mini.meplayer-adjusting-volume .meplayer-volume-bg {
+    opacity: 1;
+    z-index: 0;
+}
+
+.meplayer-container-mini.meplayer-adjusting-volume .meplayer-volume-bg i {
+    opacity: 1;
+    -webkit-transform: translateX(0px);
+            transform: translateX(0px);
+}
+
+.meplayer-container-mini .meplayer-volume-bg i {
+    -webkit-transition: all 0.7s;
+    transition: all 0.7s;
+    opacity: 0;
+    -webkit-transform: translateX(-20px);
+            transform: translateX(-20px);
+}
+
+.meplayer-container-mini.meplayer-changing-theme .meplayer-volume-bg {
+    display: none;
+}
+
+@-webkit-keyframes breath {
+    0% {
+        box-shadow: 0 0 35px rgba(59, 59, 177, .25);
+    }
+
+    100% {
+        box-shadow: 0 0 10px rgba(59, 59, 177, .33);
+    }
+}
+
+@keyframes breath {
+    0% {
+        box-shadow: 0 0 35px rgba(59, 59, 177, .25);
+    }
+
+    100% {
+        box-shadow: 0 0 10px rgba(59, 59, 177, .33);
+    }
+}
+
+/*
+   Animation example, for spinners
+*/
+.animate-spin {
+  -moz-animation: spin 2s infinite linear;
+  -o-animation: spin 2s infinite linear;
+  -webkit-animation: spin 2s infinite linear;
+  animation: spin 2s infinite linear;
+  display: inline-block;
+}
+@-moz-keyframes spin {
+  0% {
+    -moz-transform: rotate(0deg);
+    -o-transform: rotate(0deg);
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+
+  100% {
+    -moz-transform: rotate(359deg);
+    -o-transform: rotate(359deg);
+    -webkit-transform: rotate(359deg);
+    transform: rotate(359deg);
+  }
+}
+@-webkit-keyframes spin {
+  0% {
+    -moz-transform: rotate(0deg);
+    -o-transform: rotate(0deg);
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+
+  100% {
+    -moz-transform: rotate(359deg);
+    -o-transform: rotate(359deg);
+    -webkit-transform: rotate(359deg);
+    transform: rotate(359deg);
+  }
+}
+@-o-keyframes spin {
+  0% {
+    -moz-transform: rotate(0deg);
+    -o-transform: rotate(0deg);
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+
+  100% {
+    -moz-transform: rotate(359deg);
+    -o-transform: rotate(359deg);
+    -webkit-transform: rotate(359deg);
+    transform: rotate(359deg);
+  }
+}
+@-ms-keyframes spin {
+  0% {
+    -moz-transform: rotate(0deg);
+    -o-transform: rotate(0deg);
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+
+  100% {
+    -moz-transform: rotate(359deg);
+    -o-transform: rotate(359deg);
+    -webkit-transform: rotate(359deg);
+    transform: rotate(359deg);
+  }
+}
+@keyframes spin {
+  0% {
+    -moz-transform: rotate(0deg);
+    -o-transform: rotate(0deg);
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+
+  100% {
+    -moz-transform: rotate(359deg);
+    -o-transform: rotate(359deg);
+    -webkit-transform: rotate(359deg);
+    transform: rotate(359deg);
+  }
+}
+
+@font-face {
+  font-family: 'fontello';
+  src: url('fonts/fontello.eot?77128880');
+  src: url('fonts/fontello.eot?77128880#iefix') format('embedded-opentype'),
+       url('fonts/fontello.woff?77128880') format('woff'),
+       url('fonts/fontello.ttf?77128880') format('truetype'),
+       url('fonts/fontello.svg?77128880#fontello') format('svg');
+  font-weight: normal;
+  font-style: normal;
+}
+/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
+/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
+/*
+@media screen and (-webkit-min-device-pixel-ratio:0) {
+  @font-face {
+    font-family: 'fontello';
+    src: url('../font/fontello.svg?77128880#fontello') format('svg');
+  }
+}
+*/
+
+ [class^="icon-"]:before, [class*=" icon-"]:before {
+  font-family: "fontello";
+  font-style: normal;
+  font-weight: normal;
+  speak: none;
+
+  display: inline-block;
+  text-decoration: inherit;
+  text-align: center;
+  font-variant: normal;
+  text-transform: none;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-play:before { content: '\e801'; } /* '' */
+.icon-pause:before { content: '\e802'; } /* '' */
+.icon-clock:before { content: '\e803'; } /* '' */
+.icon-volume:before { content: '\e804'; } /* '' */
+.icon-spin:before { content: '\e800'; } /* '' */

+ 535 - 0
dist/meplayer.js

@@ -0,0 +1,535 @@
+/******/ (function(modules) { // webpackBootstrap
+/******/ 	// The module cache
+/******/ 	var installedModules = {};
+
+/******/ 	// The require function
+/******/ 	function __webpack_require__(moduleId) {
+
+/******/ 		// Check if module is in cache
+/******/ 		if(installedModules[moduleId])
+/******/ 			return installedModules[moduleId].exports;
+
+/******/ 		// Create a new module (and put it into the cache)
+/******/ 		var module = installedModules[moduleId] = {
+/******/ 			exports: {},
+/******/ 			id: moduleId,
+/******/ 			loaded: false
+/******/ 		};
+
+/******/ 		// Execute the module function
+/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+
+/******/ 		// Flag the module as loaded
+/******/ 		module.loaded = true;
+
+/******/ 		// Return the exports of the module
+/******/ 		return module.exports;
+/******/ 	}
+
+
+/******/ 	// expose the modules object (__webpack_modules__)
+/******/ 	__webpack_require__.m = modules;
+
+/******/ 	// expose the module cache
+/******/ 	__webpack_require__.c = installedModules;
+
+/******/ 	// __webpack_public_path__
+/******/ 	__webpack_require__.p = "";
+
+/******/ 	// Load entry module and return exports
+/******/ 	return __webpack_require__(0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ function(module, exports, __webpack_require__) {
+
+	'use strict';
+
+	var _constants = __webpack_require__(1);
+
+	var _lyric = __webpack_require__(2);
+
+	var lyric = _interopRequireWildcard(_lyric);
+
+	var _utils = __webpack_require__(3);
+
+	var utils = _interopRequireWildcard(_utils);
+
+	var _spectrum = __webpack_require__(4);
+
+	var spectrum = _interopRequireWildcard(_spectrum);
+
+	function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+	window.mePlayer = function (options) {
+	    // 检查必填选项
+	    if (!(options.music && options.music.src)) {
+	        console.error('必须指定音乐地址哦~');
+	        return;
+	    }
+
+	    var musicConf = options.music,
+	        target = getTarget(options.target),
+	        theme = options.theme ? options.theme : _constants.THEME_DEFAULT,
+	        hasLrc = musicConf.lrc ? true : false,
+	        coverSrc = musicConf.cover ? musicConf.cover : 'https://unsplash.it/78/?random',
+	        currentThemeClass = theme === _constants.THEME_DEFAULT ? 'meplayer-container' : 'meplayer-container-mini',
+	        containerClass = currentThemeClass + ' ' + (hasLrc ? 'meplayer-haslrc' : '') + ' meplayer-isloading',
+	        playerHTMLContent = '<div class="' + containerClass + '">\n                             <audio src=' + musicConf.src + '></audio>\n                             <div class="meplayer-info">\n                             <div class="meplayer-info-cover"><img src=' + coverSrc + ' alt="cd-cover"></div>\n                             <div class="meplayer-meta">\n                             <div class="meplayer-meta-title">' + musicConf.title + '</div>\n                             <div class="meplayer-meta-author">' + musicConf.author + '</div>\n                             <div class="meplayer-meta-time-tick"><span class="meplayer-meta-time-tick-text"></span></div>\n                             </div>\n                             </div>\n                             <canvas class="meplayer-spectrum"></canvas>\n                             <div class="meplayer-lyric"><div class="meplayer-lyric-area"></div></div>\n                             <div class="meplayer-control"><div class="meplayer-control-play"><i class="icon-play"></i><i class="icon-pause"></i></div></div>\n                             <div class="meplayer-volume-bg"><div class="meplayer-volume"><i class="icon-volume"></i><div class="meplayer-volume-progress"></div></div></div>\n                             <div class="meplayer-duration"><i class="icon-clock"></i><span class="meplayer-duration-text">loading</span></div>\n                             <div class="meplayer-loadingsign"><i class="icon-spin animate-spin"></i>loading</div>\n                             <div class="meplayer-timeline-bg"><div class="meplayer-timeline"><div class="meplayer-timeline-passed"></div></div></div>\n                             </div>';
+
+	    target.innerHTML = playerHTMLContent;
+
+	    var meplayerContainer = target.querySelector('.' + currentThemeClass),
+	        audio = target.querySelector('audio'),
+	        playBtn = target.querySelector('.meplayer-control-play'),
+	        timeTick = target.querySelector('.meplayer-meta-time-tick-text'),
+	        timeCount = target.querySelector('.meplayer-duration'),
+	        timeLine = target.querySelector('.meplayer-timeline'),
+	        timePassed = target.querySelector('.meplayer-timeline-passed'),
+	        volumeArea = target.querySelector('.meplayer-volume'),
+	        volumeProgress = target.querySelector('.meplayer-volume-progress'),
+	        lyricArea = target.querySelector('.meplayer-lyric-area'),
+	        canvas = target.querySelector('.meplayer-spectrum'),
+	        duration;
+
+	    // 设置在页面加载后立即加载音频
+	    audio.preload = 'auto';
+
+	    if (hasLrc) {
+	        lyric.parse(musicConf.lrc);
+	        lyric.render(lyricArea);
+	    } else {
+	        // 频谱动画初始化
+	        spectrum.init(canvas);
+	    }
+
+	    eventInit();
+
+	    // 重定义meplayer
+	    window.mePlayer = {
+	        play: play,
+	        pause: pause,
+	        toggleTheme: toggleTheme
+	    };
+
+	    /*
+	     * 工具函数
+	     * */
+
+	    // 给播放器绑定各种事件
+	    function eventInit() {
+	        audio.addEventListener('ended', function () {
+	            utils.removeClass(meplayerContainer, 'meplayer-isplaying');
+	        });
+
+	        audio.addEventListener('canplaythrough', function () {
+	            duration = this.duration;
+	            setTimeout(function () {
+	                utils.removeClass(meplayerContainer, 'meplayer-isloading');
+	                timeCount.querySelector('.meplayer-duration-text').innerText = utils.parseSec(duration.toFixed(0));
+	            }, 1000);
+	        });
+
+	        audio.addEventListener('durationchange', function () {
+	            duration = this.duration;
+	        });
+
+	        audio.addEventListener('timeupdate', function () {
+	            var curTime = audio.currentTime.toFixed(0);
+	            var curTimeForLrc = audio.currentTime.toFixed(3);
+	            var playPercent = 100 * (curTime / duration);
+
+	            timePassed.style.width = playPercent.toFixed(2) + '%';
+	            timeTick.innerText = utils.parseSec(curTime);
+
+	            if (hasLrc && theme === _constants.THEME_DEFAULT) {
+	                var tempLrcIndex = lyric.currentIndex(curTimeForLrc);
+	                var tempLrcLines = lyricArea.querySelectorAll('p');
+	                var tempLrcLinePre = tempLrcLines[tempLrcIndex - 1];
+	                var tempLrcLine = tempLrcLines[tempLrcIndex];
+	                var tempLrcLineNext = tempLrcLines[tempLrcIndex + 1];
+
+	                if (!tempLrcLine.className.includes('meplayer-lyric-current')) {
+	                    utils.removeClass(lyricArea.querySelector('.meplayer-lyric-current'), 'meplayer-lyric-current');
+	                    if (lyricArea.querySelector('.meplayer-lyric-pre')) {
+	                        utils.removeClass(lyricArea.querySelector('.meplayer-lyric-pre'), 'meplayer-lyric-pre');
+	                    }
+	                    if (lyricArea.querySelector('.meplayer-lyric-next')) {
+	                        utils.removeClass(lyricArea.querySelector('.meplayer-lyric-next'), 'meplayer-lyric-next');
+	                    }
+	                    utils.addClass(tempLrcLine, 'meplayer-lyric-current');
+	                    if (tempLrcLinePre) {
+	                        utils.addClass(tempLrcLinePre, 'meplayer-lyric-pre');
+	                    }
+	                    if (tempLrcLineNext) {
+	                        utils.addClass(tempLrcLineNext, 'meplayer-lyric-next');
+	                    }
+
+	                    lyricArea.style.webkitTransform = 'translateY(-' + 20 * tempLrcIndex + 'px)';
+	                    lyricArea.style.transform = 'translateY(-' + 20 * tempLrcIndex + 'px)';
+	                }
+	            }
+	        });
+
+	        var _handleMouseWheel;
+	        playBtn.addEventListener('click', function () {
+	            if (audio.paused) {
+	                audio.play();
+	                if (theme === _constants.THEME_DEFAULT && !hasLrc) {
+	                    spectrum.draw();
+	                }
+	                // 播放状态中可以用滑轮调节音量
+	                meplayerContainer.addEventListener('mousewheel', function handleMouseWheel() {
+	                    var timer = null;
+	                    var step = 0.05;
+	                    _handleMouseWheel = function _handleMouseWheel(event) {
+	                        if (timer) {
+	                            clearTimeout(timer);
+	                        }
+	                        if (!meplayerContainer.className.includes('meplayer-adjusting-volume')) {
+	                            utils.addClass(meplayerContainer, 'meplayer-adjusting-volume');
+	                        }
+	                        if (event.wheelDeltaY < 0 && audio.volume > step) {
+	                            audio.volume -= step;
+	                        }
+	                        if (event.wheelDeltaY > 0 && audio.volume < 1 - step) {
+	                            audio.volume += step;
+	                        }
+	                        if (theme === _constants.THEME_DEFAULT) {
+	                            volumeProgress.style.width = audio.volume * 100 + '%';
+	                        } else {
+	                            volumeArea.querySelector('i').style.opacity = audio.volume;
+	                        }
+	                        event.preventDefault();
+
+	                        timer = setTimeout(function () {
+	                            utils.removeClass(meplayerContainer, 'meplayer-adjusting-volume');
+	                        }, 1000);
+	                    };
+	                    return _handleMouseWheel;
+	                }());
+	            } else {
+	                audio.pause();
+	                spectrum.stop();
+	                meplayerContainer.removeEventListener('mousewheel', _handleMouseWheel);
+	            }
+	            utils.toggleClass(meplayerContainer, 'meplayer-isplaying');
+	        });
+
+	        timeLine.addEventListener('click', function (event) {
+	            var clickPercent = (event.pageX - utils.getAbsLeft(this)) / this.offsetWidth;
+	            timePassed.style.width = clickPercent * 100 + '%';
+	            audio.currentTime = (clickPercent * duration).toFixed(0);
+	        });
+	    }
+
+	    function play() {
+	        if (audio.paused) {
+	            audio.play();
+	        }
+	    }
+
+	    function pause() {
+	        if (!audio.paused) {
+	            audio.pause();
+	        }
+	    }
+
+	    function toggleTheme() {
+	        var step = 0.03;
+	        var count = 0;
+	        var maxCount = 200;
+
+	        utils.addClass(meplayerContainer, 'meplayer-changing-theme');
+
+	        theme = theme === _constants.THEME_DEFAULT ? _constants.THEME_MINI : _constants.THEME_DEFAULT;
+
+	        loop();
+
+	        function loop() {
+	            count++;
+	            meplayerContainer.style.opacity -= step;
+	            if (meplayerContainer.style.opacity <= 0) {
+	                step *= -1;
+	                meplayerContainer.style.opacity = 0;
+	                utils.toggleClass(meplayerContainer, 'meplayer-container-mini');
+	                utils.toggleClass(meplayerContainer, 'meplayer-container');
+	            }
+	            if (meplayerContainer.style.opacity < 1 && count < maxCount) {
+	                requestAnimationFrame(loop);
+	            } else {
+	                setTimeout(function () {
+	                    utils.removeClass(meplayerContainer, 'meplayer-changing-theme');
+	                }, 500);
+	            }
+	        }
+	    }
+	};
+
+	function getTarget(option) {
+	    if (typeof option === 'string') {
+	        return document.querySelector(option);
+	    } else if (option.toString().includes('HTMLDivElement')) {
+	        return option;
+	    } else {
+	        return document.querySelector('.meplayer');
+	    }
+	}
+
+/***/ },
+/* 1 */
+/***/ function(module, exports) {
+
+	'use strict';
+
+	Object.defineProperty(exports, "__esModule", {
+	  value: true
+	});
+	/*
+	 * 全局常量声明
+	 */
+
+	var THEME_DEFAULT = 'default';
+	var THEME_MINI = 'mini';
+	var LYRIC_CURRENT_CLASS = 'meplayer-lyric-current';
+	var LYRIC_NEXT_CLASS = 'meplayer-lyric-next';
+
+	exports.THEME_DEFAULT = THEME_DEFAULT;
+	exports.THEME_MINI = THEME_MINI;
+	exports.LYRIC_CURRENT_CLASS = LYRIC_CURRENT_CLASS;
+	exports.LYRIC_NEXT_CLASS = LYRIC_NEXT_CLASS;
+
+/***/ },
+/* 2 */
+/***/ function(module, exports, __webpack_require__) {
+
+	'use strict';
+
+	Object.defineProperty(exports, "__esModule", {
+	    value: true
+	});
+	exports.currentIndex = exports.render = exports.parse = undefined;
+
+	var _constants = __webpack_require__(1);
+
+	var lyrics;
+
+	// 歌词解析脚本
+	// 修改自:https://github.com/DIYgod/APlayer
+	function parse(text) {
+	    var lyric = text.split('\n');
+	    var lrc = [];
+	    var len = lyric.length;
+	    var reg1 = /\[(\d{2}):(\d{2})\.(\d{2,3})]/g;
+	    var reg2 = /\[(\d{2}):(\d{2})\.(\d{2,3})]/;
+	    for (var i = 0; i < len; i++) {
+	        var time = lyric[i].match(reg1);
+	        var lrcText = lyric[i].replace(reg1, '').replace(/^\s+|\s+$/g, '');
+	        // 排除空行
+	        if (!lrcText) {
+	            continue;
+	        }
+	        if (time != null) {
+	            var timeLen = time.length;
+	            for (var j = 0; j < timeLen; j++) {
+	                var oneTime = reg2.exec(time[j]);
+	                var lrcTime = oneTime[1] * 60 + parseInt(oneTime[2]) + parseInt(oneTime[3]) / ((oneTime[3] + '').length === 2 ? 100 : 1000);
+	                lrc.push({
+	                    time: lrcTime,
+	                    text: lrcText
+	                });
+	            }
+	        }
+	    }
+	    lrc.sort(function (a, b) {
+	        return a.time - b.time;
+	    });
+
+	    lyrics = lrc;
+	    return lrc;
+	}
+
+	// 歌词文本解析成DOM结构
+	function render(target) {
+	    if (!lyrics) {
+	        console.error('未指定歌词文本!');
+	        return;
+	    }
+	    var lyricHTML = '';
+	    for (var i = 0; i < lyrics.length; i++) {
+	        lyricHTML += '<p>' + lyrics[i].text + '</p>';
+	    }
+	    target.innerHTML = lyricHTML;
+	    target.querySelector('p').className = _constants.LYRIC_CURRENT_CLASS;
+	    target.querySelector('p + p').className = _constants.LYRIC_NEXT_CLASS;
+	}
+
+	function currentIndex(time) {
+	    if (time < lyrics[0].time) return 0;
+	    for (var i = 0, l = lyrics.length; i < l; i++) {
+	        if (time >= lyrics[i].time && (!lyrics[i + 1] || time <= lyrics[i + 1].time)) {
+	            break;
+	        }
+	    }
+	    return i;
+	}
+
+	exports.parse = parse;
+	exports.render = render;
+	exports.currentIndex = currentIndex;
+
+/***/ },
+/* 3 */
+/***/ function(module, exports) {
+
+	'use strict';
+
+	Object.defineProperty(exports, "__esModule", {
+	    value: true
+	});
+	function toggleClass(el, className) {
+	    if (el.classList) {
+	        el.classList.toggle(className);
+	    } else {
+	        var classes = el.className.split(' ');
+	        var existingIndex = classes.indexOf(className);
+
+	        if (existingIndex >= 0) classes.splice(existingIndex, 1);else classes.push(className);
+
+	        el.className = classes.join(' ');
+	    }
+	}
+
+	function addClass(el, className) {
+	    if (el.classList) el.classList.add(className);else el.className += ' ' + className;
+	}
+
+	function removeClass(el, className) {
+	    if (el.classList) el.classList.remove(className);else el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
+	}
+
+	function getAbsLeft(el) {
+	    var left = el.offsetLeft;
+	    while (el.offsetParent) {
+	        el = el.offsetParent;
+	        left += el.offsetLeft;
+	    }
+	    return left;
+	}
+
+	function parseSec(sec) {
+	    var tempMin = (sec / 60).toFixed(0);
+	    var tempSec = (sec % 60).toFixed(0);
+	    var curMin = tempMin < 10 ? '0' + tempMin : tempMin;
+	    var curSec = tempSec < 10 ? '0' + tempSec : tempSec;
+	    return curMin + ':' + curSec;
+	}
+
+	exports.toggleClass = toggleClass;
+	exports.addClass = addClass;
+	exports.removeClass = removeClass;
+	exports.getAbsLeft = getAbsLeft;
+	exports.parseSec = parseSec;
+
+/***/ },
+/* 4 */
+/***/ function(module, exports) {
+
+	'use strict';
+
+	Object.defineProperty(exports, "__esModule", {
+	    value: true
+	});
+	/*
+	 * 频谱动画模拟
+	 * */
+	var canvas,
+	    ctx,
+	    specItems = [],
+	    needStop = false,
+	    timer = null,
+	    random = Math.random;
+
+	function randHeight() {
+	    if (random() > 0.8) {
+	        return random() * 8 + 11;
+	    } else {
+	        return random() * 6 + 2;
+	    }
+	}
+
+	var randHeightGenerator = function randHeightGenerator(base) {
+	    var max = base * 1.5 > 28 ? 28 : base * 1.5,
+	        min = 1,
+	        direction = random() > 0.5 ? 1 : -1,
+	        tempHeight = base,
+	        curStep;
+	    return function () {
+	        curStep = direction;
+	        tempHeight += curStep;
+	        if (tempHeight >= max) {
+	            direction *= -1;
+	            tempHeight = max;
+	        } else if (tempHeight <= min) {
+	            direction *= -1;
+	            tempHeight = min;
+	        }
+	        if (random() > 0.9) {
+	            direction *= -1;
+	        }
+	        return tempHeight;
+	    };
+	};
+
+	function loop() {
+	    ctx.clearRect(0, -canvas.height / 2, canvas.width, canvas.height);
+	    for (var i = 0; i < specItems.length; i++) {
+	        var item = specItems[i];
+	        var height = item.getHeight();
+	        ctx.fillRect(i + specItems[i].xSpace, -height / 2, specItems[i].width, height);
+	    }
+
+	    if (!needStop) {
+	        timer = requestAnimationFrame(loop);
+	    }
+	}
+
+	function init(canvasElem) {
+	    var width = arguments.length <= 1 || arguments[1] === undefined ? 220 : arguments[1];
+	    var height = arguments.length <= 2 || arguments[2] === undefined ? 30 : arguments[2];
+	    var color = arguments.length <= 3 || arguments[3] === undefined ? '#D94240' : arguments[3];
+
+	    canvas = canvasElem;
+	    canvas.width = width;
+	    canvas.height = height;
+	    ctx = canvas.getContext('2d');
+	    ctx.fillStyle = color;
+	    ctx.translate(0, height / 2);
+
+	    for (var i = 0; i < 64; i++) {
+	        var xSpace = i == 0 ? 0 : 5 * i;
+	        var tempItem = {
+	            xSpace: xSpace,
+	            width: 1,
+	            getHeight: randHeightGenerator(randHeight())
+	        };
+	        specItems.push(tempItem);
+	    }
+	}
+
+	function draw() {
+	    needStop = false;
+	    loop();
+	}
+
+	function stop() {
+	    needStop = true;
+	}
+
+	exports.init = init;
+	exports.draw = draw;
+	exports.stop = stop;
+
+/***/ }
+/******/ ]);

File diff suppressed because it is too large
+ 0 - 0
dist/meplayer.min.css


File diff suppressed because it is too large
+ 0 - 0
dist/meplayer.min.js


+ 40 - 0
gulpfile.js

@@ -0,0 +1,40 @@
+var gulp          = require('gulp'),
+    minifycss     = require('gulp-minify-css'),
+    rename        = require('gulp-rename'),
+    concat        = require('gulp-concat'),
+    uglify        = require('gulp-uglify'),
+    webpack       = require('gulp-webpack'),
+    webpackConfig = require('./webpack.config');
+
+gulp.task('compileEs6', function () {
+    return gulp.src('./src/js/main.js')
+        .pipe(webpack(webpackConfig))
+        .pipe(rename('meplayer.js'))
+        .pipe(gulp.dest('./dist/'))
+        .pipe(uglify())
+        .pipe(rename({suffix: '.min'}))
+        .pipe(gulp.dest('./dist/'))
+});
+
+gulp.task('copyFont', function () {
+    return gulp.src('./src/fontello/fonts/*')
+        .pipe(gulp.dest('./dist/fonts'))
+});
+
+gulp.task('handleCss', function () {
+    return gulp.src(['src/css/*', 'src/fontello/*.css'])
+        .pipe(concat('meplayer.css'))
+        .pipe(gulp.dest('./dist/'))
+        .pipe(minifycss())
+        .pipe(rename({suffix: '.min'}))
+        .pipe(gulp.dest('./dist/'))
+});
+
+gulp.task('watch', function () {
+    gulp.watch('./src/js/*', ['compileEs6']);
+    gulp.watch('./src/css/*', ['handleCss']);
+});
+
+gulp.task('default', function () {
+    gulp.start('copyFont', 'handleCss', 'compileEs6', 'watch');
+});

+ 26 - 0
package.json

@@ -0,0 +1,26 @@
+{
+  "name": "meplayer",
+  "version": "0.1.0",
+  "description": "a simple and reliable HTML5 music player",
+  "main": "dist/meplayer.min.js",
+  "scripts": {
+    "test": "gulp"
+  },
+  "keywords": [
+    "music",
+    "player"
+  ],
+  "author": "newraina",
+  "license": "MIT",
+  "devDependencies": {
+    "babel-core": "^6.4.5",
+    "babel-loader": "^6.2.2",
+    "babel-preset-es2015": "^6.3.13",
+    "gulp": "^3.9.0",
+    "gulp-concat": "^2.6.0",
+    "gulp-minify-css": "^1.2.3",
+    "gulp-rename": "^1.2.2",
+    "gulp-uglify": "^1.5.1",
+    "gulp-webpack": "^1.5.0"
+  }
+}

+ 500 - 0
src/css/theme-default.css

@@ -0,0 +1,500 @@
+/*UI设计参考:http://www.materialup.com/posts/a-or-b-bottom-music-player-dashboard*/
+
+.meplayer-container {
+    font-family: Helvetica, Tahoma, Arial, STXihei, '华文细黑', 'Microsoft YaHei', '微软雅黑', SimSun, '宋体', Heiti, '黑体', sans-serif;
+    line-height: initial;
+
+    position: relative;
+
+    box-sizing: border-box;
+    width: 100%;
+    height: 90px;
+
+    background: #FFF;
+    box-shadow: 0 0 20px rgba(59, 59, 177, .18);
+}
+
+.meplayer-container .meplayer-info {
+    font-weight: 300;
+
+    position: relative;
+    left: 0;
+
+    opacity: 1;
+}
+
+.meplayer-container .meplayer-info-cover {
+    position: absolute;
+    top: 0;
+    left: 0;
+
+    overflow: hidden;
+
+    height: 90px;
+    padding-right: 20px;
+
+    -webkit-transition: all .6s cubic-bezier(0, .36, .51, 1.39);
+
+    transition: all .6s cubic-bezier(0, .36, .51, 1.39);
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-info-cover {
+    left: -90px;
+
+    opacity: 0;
+}
+
+.meplayer-container .meplayer-info-cover img {
+    width: 78px;
+    height: 78px;
+
+    border: 6px solid #FFF;
+    box-shadow: 0 0 20px rgba(59, 59, 177, .35);
+}
+
+.meplayer-container .meplayer-meta {
+    float: left;
+
+    margin-left: 110px;
+
+    -webkit-transition: all .6s cubic-bezier(0, .36, .51, 1.39);
+
+    transition: all .6s cubic-bezier(0, .36, .51, 1.39);
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-meta {
+    margin-left: 10px;
+
+    -webkit-transform: scale(.85, .85);
+
+            transform: scale(.85, .85);
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-meta .meplayer-meta-title {
+    margin-top: 4px;
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-meta .meplayer-meta-time-tick {
+    -webkit-transition: all .6s cubic-bezier(0, .36, .51, 1.39) .65s;
+    transition: all .6s cubic-bezier(0, .36, .51, 1.39) .65s;
+    -webkit-transform: translateY(0);
+            transform: translateY(0);
+
+    opacity: 1;
+}
+
+.meplayer-container .meplayer-meta .meplayer-meta-time-tick {
+    font-size: 13px;
+
+    margin-top: 30px;
+
+    -webkit-transform: translateY(10px);
+
+            transform: translateY(10px);
+    letter-spacing: 1px;
+
+    opacity: 0;
+    color: rgba(0, 0, 0, .6);
+}
+
+.meplayer-container .meplayer-meta-title {
+    font-size: 14px;
+
+    margin-top: 27px;
+    margin-bottom: 2px;
+
+    -webkit-transition: all .6s cubic-bezier(0, .36, .51, 1.39);
+
+    transition: all .6s cubic-bezier(0, .36, .51, 1.39);
+    letter-spacing: 1px;
+
+    color: #6A6B6F;
+}
+
+.meplayer-container .meplayer-meta-author {
+    font-size: 12px;
+
+    color: #CECED6;
+}
+
+.meplayer-container .meplayer-spectrum {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+
+    display: block;
+
+    width: 0;
+    height: 30px;
+    margin-top: -15px;
+    margin-left: -120px;
+
+    -webkit-transition: all .7s cubic-bezier(.17, .67, .45, 1.26) .1s;
+
+    transition: all .7s cubic-bezier(.17, .67, .45, 1.26) .1s;
+    -webkit-transform: translateX(110px);
+            transform: translateX(110px);
+
+    opacity: 0;
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-spectrum {
+    width: 220px;
+
+    -webkit-transform: translateX(0);
+
+            transform: translateX(0);
+
+    opacity: 1;
+}
+
+.meplayer-container.meplayer-haslrc .meplayer-spectrum {
+    display: none;
+}
+
+.meplayer-container .meplayer-lyric {
+    position: absolute;
+    z-index: -2;
+    top: 50%;
+    left: 50%;
+
+    overflow: hidden;
+
+    width: 220px;
+    height: 100%;
+    margin-top: -45px;
+    margin-left: -120px;
+
+    -webkit-transition: all 1s;
+
+    transition: all 1s;
+    -webkit-transform: translateY(15px);
+            transform: translateY(15px);
+
+    opacity: 0;
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-lyric {
+    z-index: 0;
+
+    -webkit-transform: translateY(0);
+
+            transform: translateY(0);
+
+    opacity: 1;
+}
+
+.meplayer-container .meplayer-lyric-area {
+    font-size: 12px;
+
+    margin-top: 35px;
+
+    -webkit-transition: -webkit-transform .7s;
+
+    transition: -webkit-transform .7s;
+
+    transition: transform .7s;
+
+    text-align: center;
+
+    opacity: 0;
+    color: rgba(0, 0, 0, .7);
+}
+
+.meplayer-container .meplayer-lyric-area p {
+    line-height: 0;
+
+    width: 100%;
+    margin: 0;
+    padding: 0;
+
+    -webkit-transition: all .6s;
+
+    transition: all .6s;
+
+    opacity: 0;
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-lyric-area p {
+    line-height: 20px;
+}
+
+.meplayer-container .meplayer-haslrc .meplayer-lyric-area {
+    display: block;
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-lyric-area {
+    opacity: 1;
+}
+
+.meplayer-container .meplayer-lyric-area .meplayer-lyric-current {
+    font-size: 1.1em;
+
+    opacity: 1;
+}
+
+.meplayer-container .meplayer-lyric-area .meplayer-lyric-pre,
+.meplayer-container .meplayer-lyric-area .meplayer-lyric-next {
+    opacity: .35;
+}
+
+.meplayer-container .meplayer-control {
+    position: relative;
+
+    float: right;
+
+    margin-right: 40px;
+}
+
+.meplayer-container .meplayer-volume-bg {
+    position: absolute;
+    z-index: -1;
+
+    width: 100%;
+    height: 100%;
+
+    -webkit-transition: all .8s;
+
+    transition: all .8s;
+
+    opacity: 0;
+    background: rgba(255, 255, 255, .8);
+}
+
+.meplayer-container.meplayer-adjusting-volume .meplayer-volume-bg {
+    z-index: 20;
+}
+
+.meplayer-container .meplayer-volume {
+    font-size: 50px;
+
+    width: 60px;
+    margin: 13px auto 0;
+
+    -webkit-transition: all .9s;
+
+    transition: all .9s;
+    text-align: center;
+
+    color: rgba(150, 150, 150, .75);
+}
+
+.meplayer-container.meplayer-adjusting-volume .meplayer-volume-bg {
+    opacity: 1;
+}
+
+.meplayer-container .meplayer-volume-progress {
+    height: 4px;
+    /*margin-top: -1px;*/
+
+    -webkit-transition: width .2s;
+
+    transition: width .2s;
+
+    border-radius: 1px;
+    background: rgba(150, 150, 150, .75);
+}
+
+.meplayer-container .meplayer-control-play {
+    position: absolute;
+    top: -25px;
+    right: 0;
+
+    width: 50px;
+    height: 50px;
+
+    cursor: pointer;
+    -webkit-transition: top .6s cubic-bezier(0, .74, .61, 1.35);
+    transition: top .6s cubic-bezier(0, .74, .61, 1.35);
+    text-align: center;
+
+    color: #D94240;
+    border-radius: 50%;
+    background: #FFF;
+    box-shadow: 0 0 10px rgba(59, 59, 177, .22);
+}
+
+.meplayer-container .meplayer-control-play:hover {
+    -webkit-animation: breath 2s infinite alternate;
+            animation: breath 2s infinite alternate;
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-control-play {
+    top: 20px;
+
+    -webkit-animation: breath 2s infinite alternate;
+
+            animation: breath 2s infinite alternate;
+}
+
+.meplayer-container .meplayer-control-play [class^='icon-'] {
+    line-height: 50px;
+
+    position: absolute;
+    left: 50%;
+
+    margin-left: -7px;
+
+    -webkit-transition: all .5s;
+
+    transition: all .5s;
+}
+
+.meplayer-container .meplayer-control-play .icon-play {
+    -webkit-transform: translateX(0);
+            transform: translateX(0);
+
+    opacity: 1;
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-control-play .icon-play {
+    -webkit-transform: translateX(8px);
+            transform: translateX(8px);
+
+    opacity: 0;
+}
+
+.meplayer-container .meplayer-control-play .icon-pause {
+    -webkit-transform: translateX(-8px);
+            transform: translateX(-8px);
+
+    opacity: 0;
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-control-play .icon-pause {
+    -webkit-transform: translateX(-1px);
+            transform: translateX(-1px);
+
+    opacity: 1;
+}
+
+.meplayer-container .meplayer-duration,
+.meplayer-container .meplayer-loadingsign {
+    font-size: 12px;
+
+    position: absolute;
+    right: 40px;
+    bottom: 24px;
+
+    -webkit-transition: all .6s cubic-bezier(0, .74, .61, 1.35);
+
+    transition: all .6s cubic-bezier(0, .74, .61, 1.35);
+    letter-spacing: 1px;
+
+    color: rgba(0, 0, 0, .6);
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-duration,
+.meplayer-container.meplayer-isplaying .meplayer-loadingsign {
+    z-index: -1;
+    bottom: 5px;
+
+    -webkit-transform: scale(.5, .5);
+
+            transform: scale(.5, .5);
+
+    opacity: 0;
+}
+
+.meplayer-container.meplayer-isloading .meplayer-duration {
+    opacity: 0;
+}
+
+.meplayer-container .meplayer-loadingsign {
+    opacity: 0;
+}
+
+.meplayer-container.meplayer-isloading .meplayer-loadingsign {
+    opacity: 1;
+}
+
+.meplayer-container .meplayer-duration i,
+.meplayer-container .meplayer-loadingsign i {
+    margin-right: 3px;
+
+    -webkit-transition: all .7s;
+
+    transition: all .7s;
+    -webkit-transform: scale(.9, .9);
+            transform: scale(.9, .9);
+
+    color: rgba(217, 66, 64, .5);
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-duration i {
+    -webkit-transform: rotateZ(360deg);
+            transform: rotateZ(360deg);
+}
+
+.meplayer-container .meplayer-timeline-bg {
+    position: absolute;
+    bottom: 0;
+
+    width: 100%;
+    height: 8px;
+}
+
+.meplayer-container .meplayer-timeline {
+    position: absolute;
+    bottom: 0;
+
+    overflow: hidden;
+
+    width: 100%;
+    height: 2px;
+
+    -webkit-transition: all .5s;
+
+    transition: all .5s;
+    -webkit-transform: translateY(2px);
+            transform: translateY(2px);
+
+    opacity: 0;
+    background: rgba(231, 231, 239, .8);
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-timeline {
+    cursor: pointer;
+    -webkit-transform: translateY(0);
+            transform: translateY(0);
+
+    opacity: 1;
+}
+
+.meplayer-container.meplayer-isplaying .meplayer-timeline-bg:hover .meplayer-timeline {
+    height: 8px;
+}
+
+.meplayer-container .meplayer-timeline .meplayer-timeline-passed {
+    position: absolute;
+    bottom: 0;
+
+    width: 0;
+    height: 100%;
+
+    background: #D94240;
+}
+
+.meplayer-container.meplayer-changing-theme .meplayer-volume-bg {
+    display: none;
+}
+
+@-webkit-keyframes breath {
+    0% {
+        box-shadow: 0 0 35px rgba(59, 59, 177, .22);
+    }
+
+    100% {
+        box-shadow: 0 0 10px rgba(59, 59, 177, .33);
+    }
+}
+
+@keyframes breath {
+    0% {
+        box-shadow: 0 0 35px rgba(59, 59, 177, .22);
+    }
+
+    100% {
+        box-shadow: 0 0 10px rgba(59, 59, 177, .33);
+    }
+}

+ 128 - 0
src/css/theme-mini.css

@@ -0,0 +1,128 @@
+.meplayer-container-mini {
+    position: relative;
+    width: 90px;
+    height: 90px;
+    background: #FFF;
+    border-radius: 50%;
+    box-shadow: 0 0 20px rgba(59, 59, 177, .18);
+}
+
+.meplayer-isplaying.meplayer-container-mini {
+    -webkit-animation: breath 2s infinite alternate;
+    animation: breath 2s infinite alternate;
+}
+
+.meplayer-container-mini .meplayer-info, .meplayer-container-mini .meplayer-spectrum,
+.meplayer-container-mini .meplayer-lyric, .meplayer-container-mini .meplayer-duration,
+.meplayer-container-mini .meplayer-loadingsign, .meplayer-container-mini .meplayer-timeline-bg {
+    display: none;
+}
+
+.meplayer-container-mini .meplayer-control-play {
+    width: 90px;
+    height: 90px;
+    position: absolute;
+    top: 50%;
+    font-size: 26px;
+    line-height: 90px;
+    left: 50%;
+    margin-top: -45px;
+    margin-left: -45px;
+    color: #D94240;
+}
+
+.meplayer-container-mini .meplayer-control-play [class^='icon-'] {
+    line-height: 90px;
+
+    position: absolute;
+    left: 50%;
+
+    margin-left: -11px;
+
+    -webkit-transition: all .5s;
+
+    transition: all .5s;
+    cursor: pointer;
+}
+
+.meplayer-container-mini .meplayer-control-play .icon-play {
+    -webkit-transform: translateX(0);
+    transform: translateX(0);
+    opacity: 1;
+}
+
+.meplayer-container-mini.meplayer-isplaying .meplayer-control-play .icon-play {
+    -webkit-transform: translateX(16px);
+    transform: translateX(16px);
+    opacity: 0;
+}
+
+.meplayer-container-mini .meplayer-control-play .icon-pause {
+    -webkit-transform: translateX(-16px);
+    transform: translateX(-16px);
+    opacity: 0;
+}
+
+.meplayer-container-mini.meplayer-isplaying .meplayer-control-play .icon-pause {
+    -webkit-transform: translateX(0);
+    transform: translateX(0);
+    opacity: 1;
+}
+
+.meplayer-container-mini .meplayer-volume-bg {
+    z-index: -1;
+    position: absolute;
+    width: 100%;
+    height: 100%;
+    background: rgba(255, 255, 255, 0.98);
+    line-height: 90px;
+    border-radius: 50%;
+    text-align: center;
+    color: rgba(0, 0, 0, 0.9);
+    font-size: 30px;
+    -webkit-transition: all 0.8s;
+    transition: all 0.8s;
+}
+
+.meplayer-container-mini.meplayer-adjusting-volume .meplayer-volume-bg {
+    opacity: 1;
+    z-index: 0;
+}
+
+.meplayer-container-mini.meplayer-adjusting-volume .meplayer-volume-bg i {
+    opacity: 1;
+    -webkit-transform: translateX(0px);
+            transform: translateX(0px);
+}
+
+.meplayer-container-mini .meplayer-volume-bg i {
+    -webkit-transition: all 0.7s;
+    transition: all 0.7s;
+    opacity: 0;
+    -webkit-transform: translateX(-20px);
+            transform: translateX(-20px);
+}
+
+.meplayer-container-mini.meplayer-changing-theme .meplayer-volume-bg {
+    display: none;
+}
+
+@-webkit-keyframes breath {
+    0% {
+        box-shadow: 0 0 35px rgba(59, 59, 177, .25);
+    }
+
+    100% {
+        box-shadow: 0 0 10px rgba(59, 59, 177, .33);
+    }
+}
+
+@keyframes breath {
+    0% {
+        box-shadow: 0 0 35px rgba(59, 59, 177, .25);
+    }
+
+    100% {
+        box-shadow: 0 0 10px rgba(59, 59, 177, .33);
+    }
+}

+ 85 - 0
src/fontello/animation.css

@@ -0,0 +1,85 @@
+/*
+   Animation example, for spinners
+*/
+.animate-spin {
+  -moz-animation: spin 2s infinite linear;
+  -o-animation: spin 2s infinite linear;
+  -webkit-animation: spin 2s infinite linear;
+  animation: spin 2s infinite linear;
+  display: inline-block;
+}
+@-moz-keyframes spin {
+  0% {
+    -moz-transform: rotate(0deg);
+    -o-transform: rotate(0deg);
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+
+  100% {
+    -moz-transform: rotate(359deg);
+    -o-transform: rotate(359deg);
+    -webkit-transform: rotate(359deg);
+    transform: rotate(359deg);
+  }
+}
+@-webkit-keyframes spin {
+  0% {
+    -moz-transform: rotate(0deg);
+    -o-transform: rotate(0deg);
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+
+  100% {
+    -moz-transform: rotate(359deg);
+    -o-transform: rotate(359deg);
+    -webkit-transform: rotate(359deg);
+    transform: rotate(359deg);
+  }
+}
+@-o-keyframes spin {
+  0% {
+    -moz-transform: rotate(0deg);
+    -o-transform: rotate(0deg);
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+
+  100% {
+    -moz-transform: rotate(359deg);
+    -o-transform: rotate(359deg);
+    -webkit-transform: rotate(359deg);
+    transform: rotate(359deg);
+  }
+}
+@-ms-keyframes spin {
+  0% {
+    -moz-transform: rotate(0deg);
+    -o-transform: rotate(0deg);
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+
+  100% {
+    -moz-transform: rotate(359deg);
+    -o-transform: rotate(359deg);
+    -webkit-transform: rotate(359deg);
+    transform: rotate(359deg);
+  }
+}
+@keyframes spin {
+  0% {
+    -moz-transform: rotate(0deg);
+    -o-transform: rotate(0deg);
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+
+  100% {
+    -moz-transform: rotate(359deg);
+    -o-transform: rotate(359deg);
+    -webkit-transform: rotate(359deg);
+    transform: rotate(359deg);
+  }
+}

+ 41 - 0
src/fontello/fontello.css

@@ -0,0 +1,41 @@
+@font-face {
+  font-family: 'fontello';
+  src: url('fonts/fontello.eot?77128880');
+  src: url('fonts/fontello.eot?77128880#iefix') format('embedded-opentype'),
+       url('fonts/fontello.woff?77128880') format('woff'),
+       url('fonts/fontello.ttf?77128880') format('truetype'),
+       url('fonts/fontello.svg?77128880#fontello') format('svg');
+  font-weight: normal;
+  font-style: normal;
+}
+/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
+/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
+/*
+@media screen and (-webkit-min-device-pixel-ratio:0) {
+  @font-face {
+    font-family: 'fontello';
+    src: url('../font/fontello.svg?77128880#fontello') format('svg');
+  }
+}
+*/
+
+ [class^="icon-"]:before, [class*=" icon-"]:before {
+  font-family: "fontello";
+  font-style: normal;
+  font-weight: normal;
+  speak: none;
+
+  display: inline-block;
+  text-decoration: inherit;
+  text-align: center;
+  font-variant: normal;
+  text-transform: none;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-play:before { content: '\e801'; } /* '' */
+.icon-pause:before { content: '\e802'; } /* '' */
+.icon-clock:before { content: '\e803'; } /* '' */
+.icon-volume:before { content: '\e804'; } /* '' */
+.icon-spin:before { content: '\e800'; } /* '' */

BIN
src/fontello/fonts/fontello.eot


+ 16 - 0
src/fontello/fonts/fontello.svg

@@ -0,0 +1,16 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata>Copyright (C) 2016 by original authors @ fontello.com</metadata>
+<defs>
+<font id="fontello" horiz-adv-x="1000" >
+<font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
+<missing-glyph horiz-adv-x="1000" />
+<glyph glyph-name="spin6" unicode="&#xe800;" d="m855 9c-189-190-520-172-705 13-190 190-200 494-28 695 11 13 21 26 35 34 36 23 85 18 117-13 30-31 35-76 16-112-5-9-9-15-16-22-140-151-145-379-8-516 153-153 407-121 542 34 106 122 142 297 77 451-83 198-305 291-510 222l0 1c236 82 492-24 588-252 71-167 37-355-72-493-11-15-23-29-36-42z" horiz-adv-x="1000" />
+<glyph glyph-name="play" unicode="&#xe801;" d="m772 333l-741-412q-13-7-22-2t-9 20v822q0 14 9 20t22-2l741-412q13-7 13-17t-13-17z" horiz-adv-x="785.7" />
+<glyph glyph-name="pause" unicode="&#xe802;" d="m857 743v-786q0-14-10-25t-26-11h-285q-15 0-25 11t-11 25v786q0 14 11 25t25 11h285q15 0 26-11t10-25z m-500 0v-786q0-14-10-25t-26-11h-285q-15 0-25 11t-11 25v786q0 14 11 25t25 11h285q15 0 26-11t10-25z" horiz-adv-x="857.1" />
+<glyph glyph-name="clock" unicode="&#xe803;" d="m0 350q0 95 37 182t100 149 150 100 182 37 182-37 149-100 100-149 37-182-37-182-100-150-149-100-182-37-182 37-150 100-100 150-37 182z m117 0q0-96 47-177t128-128 177-47q95 0 176 47t128 128 47 177q0 95-47 176t-128 128-176 47q-72 0-137-28t-112-75-75-112-28-136z m293 0v224q0 24 17 41t42 18 41-18 17-41v-200l142-141q17-17 17-42t-17-41-41-17q-25 0-42 17l-159 158q-1 2-4 5t-3 4q-1 2-2 4l-2 3t-1 4q-1 0-2 5-2 5-2 5-1 6-1 12z" horiz-adv-x="937.5" />
+<glyph glyph-name="volume" unicode="&#xe804;" d="m0 142l0 416 236 0 354 289 0-994-354 289-236 0z m652 35q73 74 73 176t-73 178l71 74q105-106 107-254 0-145-107-246z m118-119q123 119 123 295t-123 299l76 74q154-154 154-372t-154-372z" horiz-adv-x="1000" />
+</font>
+</defs>
+</svg>

BIN
src/fontello/fonts/fontello.ttf


BIN
src/fontello/fonts/fontello.woff


+ 10 - 0
src/js/constants.js

@@ -0,0 +1,10 @@
+/*
+ * 全局常量声明
+ */
+
+const THEME_DEFAULT = 'default';
+const THEME_MINI    = 'mini';
+const LYRIC_CURRENT_CLASS = 'meplayer-lyric-current';
+const LYRIC_NEXT_CLASS = 'meplayer-lyric-next';
+
+export {THEME_DEFAULT, THEME_MINI, LYRIC_CURRENT_CLASS, LYRIC_NEXT_CLASS};

+ 65 - 0
src/js/lyric.js

@@ -0,0 +1,65 @@
+import {LYRIC_CURRENT_CLASS, LYRIC_NEXT_CLASS} from './constants';
+
+var lyrics;
+
+// 歌词解析脚本
+// 修改自:https://github.com/DIYgod/APlayer
+function parse(text) {
+    var lyric = text.split('\n');
+    var lrc   = [];
+    var len   = lyric.length;
+    var reg1  = /\[(\d{2}):(\d{2})\.(\d{2,3})]/g;
+    var reg2  = /\[(\d{2}):(\d{2})\.(\d{2,3})]/;
+    for (var i = 0; i < len; i++) {
+        var time    = lyric[i].match(reg1);
+        var lrcText = lyric[i].replace(reg1, '').replace(/^\s+|\s+$/g, '');
+        // 排除空行
+        if (!lrcText) {
+            continue;
+        }
+        if (time != null) {
+            var timeLen = time.length;
+            for (var j = 0; j < timeLen; j++) {
+                var oneTime = reg2.exec(time[j]);
+                var lrcTime = (oneTime[1]) * 60 + parseInt(oneTime[2]) + parseInt(oneTime[3]) / ((oneTime[3] + '').length === 2 ? 100 : 1000);
+                lrc.push({
+                    time: lrcTime,
+                    text: lrcText
+                });
+            }
+        }
+    }
+    lrc.sort(function (a, b) {
+        return a.time - b.time;
+    });
+
+    lyrics = lrc;
+    return lrc;
+}
+
+// 歌词文本解析成DOM结构
+function render(target) {
+    if (!lyrics) {
+        console.error('未指定歌词文本!');
+        return;
+    }
+    var lyricHTML = '';
+    for (let i = 0; i < lyrics.length; i++) {
+        lyricHTML += `<p>${lyrics[i].text}</p>`;
+    }
+    target.innerHTML                        = lyricHTML;
+    target.querySelector('p').className     = LYRIC_CURRENT_CLASS;
+    target.querySelector('p + p').className = LYRIC_NEXT_CLASS;
+}
+
+function currentIndex(time) {
+    if (time < lyrics[0].time) return 0;
+    for (var i = 0, l = lyrics.length; i < l; i++) {
+        if (time >= lyrics[i].time && (!(lyrics[i + 1]) || time <= lyrics[i + 1].time)) {
+            break;
+        }
+    }
+    return i;
+}
+
+export {parse, render, currentIndex};

+ 239 - 0
src/js/main.js

@@ -0,0 +1,239 @@
+import {THEME_DEFAULT, THEME_MINI} from './constants';
+import * as lyric from './lyric';
+import * as utils from './utils';
+import * as spectrum from './spectrum';
+
+window.mePlayer = function (options) {
+    // 检查必填选项
+    if (!(options.music && options.music.src)) {
+        console.error('必须指定音乐地址哦~');
+        return;
+    }
+
+    var musicConf         = options.music,
+        target            = getTarget(options.target),
+        theme             = options.theme ? options.theme : THEME_DEFAULT,
+        hasLrc            = musicConf.lrc ? true : false,
+        coverSrc          = musicConf.cover ? musicConf.cover : 'https://unsplash.it/78/?random',
+
+        currentThemeClass = theme === THEME_DEFAULT ? 'meplayer-container' : 'meplayer-container-mini',
+        containerClass    = `${currentThemeClass} ${hasLrc ? 'meplayer-haslrc' : ''} meplayer-isloading`,
+
+        playerHTMLContent = `<div class="${containerClass}">
+                             <audio src=${musicConf.src}></audio>
+                             <div class="meplayer-info">
+                             <div class="meplayer-info-cover"><img src=${coverSrc} alt="cd-cover"></div>
+                             <div class="meplayer-meta">
+                             <div class="meplayer-meta-title">${musicConf.title}</div>
+                             <div class="meplayer-meta-author">${musicConf.author}</div>
+                             <div class="meplayer-meta-time-tick"><span class="meplayer-meta-time-tick-text"></span></div>
+                             </div>
+                             </div>
+                             <canvas class="meplayer-spectrum"></canvas>
+                             <div class="meplayer-lyric"><div class="meplayer-lyric-area"></div></div>
+                             <div class="meplayer-control"><div class="meplayer-control-play"><i class="icon-play"></i><i class="icon-pause"></i></div></div>
+                             <div class="meplayer-volume-bg"><div class="meplayer-volume"><i class="icon-volume"></i><div class="meplayer-volume-progress"></div></div></div>
+                             <div class="meplayer-duration"><i class="icon-clock"></i><span class="meplayer-duration-text">loading</span></div>
+                             <div class="meplayer-loadingsign"><i class="icon-spin animate-spin"></i>loading</div>
+                             <div class="meplayer-timeline-bg"><div class="meplayer-timeline"><div class="meplayer-timeline-passed"></div></div></div>
+                             </div>`;
+
+    target.innerHTML = playerHTMLContent;
+
+    var meplayerContainer = target.querySelector(`.${currentThemeClass}`),
+        audio             = target.querySelector('audio'),
+        playBtn           = target.querySelector('.meplayer-control-play'),
+        timeTick          = target.querySelector('.meplayer-meta-time-tick-text'),
+        timeCount         = target.querySelector('.meplayer-duration'),
+        timeLine          = target.querySelector('.meplayer-timeline'),
+        timePassed        = target.querySelector('.meplayer-timeline-passed'),
+        volumeArea        = target.querySelector('.meplayer-volume'),
+        volumeProgress    = target.querySelector('.meplayer-volume-progress'),
+        lyricArea         = target.querySelector('.meplayer-lyric-area'),
+        canvas            = target.querySelector('.meplayer-spectrum'),
+        duration;
+
+    // 设置在页面加载后立即加载音频
+    audio.preload = 'auto';
+
+    if (hasLrc) {
+        lyric.parse(musicConf.lrc);
+        lyric.render(lyricArea);
+    } else {
+        // 频谱动画初始化
+        spectrum.init(canvas);
+    }
+
+    eventInit();
+
+    // 重定义meplayer
+    window.mePlayer = {
+        play       : play,
+        pause      : pause,
+        toggleTheme: toggleTheme
+    };
+
+
+    /*
+     * 工具函数
+     * */
+
+    // 给播放器绑定各种事件
+    function eventInit() {
+        audio.addEventListener('ended', function () {
+            utils.removeClass(meplayerContainer, 'meplayer-isplaying');
+        });
+
+        audio.addEventListener('canplaythrough', function () {
+            duration = this.duration;
+            setTimeout(function () {
+                utils.removeClass(meplayerContainer, 'meplayer-isloading');
+                timeCount.querySelector('.meplayer-duration-text').innerText = utils.parseSec(duration.toFixed(0));
+            }, 1000);
+        });
+
+        audio.addEventListener('durationchange', function () {
+            duration = this.duration;
+        });
+
+        audio.addEventListener('timeupdate', function () {
+            var curTime       = (audio.currentTime).toFixed(0);
+            var curTimeForLrc = (audio.currentTime).toFixed(3);
+            var playPercent   = 100 * (curTime / duration);
+
+            timePassed.style.width = playPercent.toFixed(2) + '%';
+            timeTick.innerText     = utils.parseSec(curTime);
+
+            if (hasLrc && theme === THEME_DEFAULT) {
+                var tempLrcIndex    = lyric.currentIndex(curTimeForLrc);
+                var tempLrcLines    = lyricArea.querySelectorAll('p');
+                var tempLrcLinePre  = tempLrcLines[tempLrcIndex - 1];
+                var tempLrcLine     = tempLrcLines[tempLrcIndex];
+                var tempLrcLineNext = tempLrcLines[tempLrcIndex + 1];
+
+                if (!tempLrcLine.className.includes('meplayer-lyric-current')) {
+                    utils.removeClass(lyricArea.querySelector('.meplayer-lyric-current'), 'meplayer-lyric-current');
+                    if (lyricArea.querySelector('.meplayer-lyric-pre')) {
+                        utils.removeClass(lyricArea.querySelector('.meplayer-lyric-pre'), 'meplayer-lyric-pre');
+                    }
+                    if (lyricArea.querySelector('.meplayer-lyric-next')) {
+                        utils.removeClass(lyricArea.querySelector('.meplayer-lyric-next'), 'meplayer-lyric-next');
+                    }
+                    utils.addClass(tempLrcLine, 'meplayer-lyric-current');
+                    if (tempLrcLinePre) {
+                        utils.addClass(tempLrcLinePre, 'meplayer-lyric-pre');
+                    }
+                    if (tempLrcLineNext) {
+                        utils.addClass(tempLrcLineNext, 'meplayer-lyric-next');
+                    }
+
+                    lyricArea.style.webkitTransform = 'translateY(-' + 20 * tempLrcIndex + 'px)';
+                    lyricArea.style.transform       = 'translateY(-' + 20 * tempLrcIndex + 'px)';
+                }
+            }
+        });
+
+        var _handleMouseWheel;
+        playBtn.addEventListener('click', function () {
+            if (audio.paused) {
+                audio.play();
+                if (theme === THEME_DEFAULT && !hasLrc) {
+                    spectrum.draw();
+                }
+                // 播放状态中可以用滑轮调节音量
+                meplayerContainer.addEventListener('mousewheel', function handleMouseWheel() {
+                    var timer         = null;
+                    var step          = 0.05;
+                    _handleMouseWheel = function (event) {
+                        if (timer) {
+                            clearTimeout(timer);
+                        }
+                        if (!meplayerContainer.className.includes('meplayer-adjusting-volume')) {
+                            utils.addClass(meplayerContainer, 'meplayer-adjusting-volume');
+                        }
+                        if (event.wheelDeltaY < 0 && audio.volume > step) {
+                            audio.volume -= step;
+                        }
+                        if (event.wheelDeltaY > 0 && audio.volume < 1 - step) {
+                            audio.volume += step;
+                        }
+                        if (theme === THEME_DEFAULT) {
+                            volumeProgress.style.width = audio.volume * 100 + '%';
+                        } else {
+                            volumeArea.querySelector('i').style.opacity = audio.volume;
+                        }
+                        event.preventDefault();
+
+                        timer = setTimeout(function () {
+                            utils.removeClass(meplayerContainer, 'meplayer-adjusting-volume');
+                        }, 1000);
+                    };
+                    return _handleMouseWheel;
+                }());
+            } else {
+                audio.pause();
+                spectrum.stop();
+                meplayerContainer.removeEventListener('mousewheel', _handleMouseWheel);
+            }
+            utils.toggleClass(meplayerContainer, 'meplayer-isplaying');
+        });
+
+        timeLine.addEventListener('click', function (event) {
+            var clickPercent       = (event.pageX - utils.getAbsLeft(this)) / this.offsetWidth;
+            timePassed.style.width = clickPercent * 100 + '%';
+            audio.currentTime      = (clickPercent * duration).toFixed(0);
+        });
+    }
+
+    function play() {
+        if (audio.paused) {
+            audio.play();
+        }
+    }
+
+    function pause() {
+        if (!audio.paused) {
+            audio.pause();
+        }
+    }
+
+    function toggleTheme() {
+        var step     = 0.03;
+        var count    = 0;
+        var maxCount = 200;
+
+        utils.addClass(meplayerContainer, 'meplayer-changing-theme');
+
+        theme = theme === THEME_DEFAULT ? THEME_MINI : THEME_DEFAULT;
+
+        loop();
+
+        function loop() {
+            count++;
+            meplayerContainer.style.opacity -= step;
+            if (meplayerContainer.style.opacity <= 0) {
+                step *= -1;
+                meplayerContainer.style.opacity = 0;
+                utils.toggleClass(meplayerContainer, 'meplayer-container-mini');
+                utils.toggleClass(meplayerContainer, 'meplayer-container');
+            }
+            if (meplayerContainer.style.opacity < 1 && count < maxCount) {
+                requestAnimationFrame(loop);
+            } else {
+                setTimeout(function () {
+                    utils.removeClass(meplayerContainer, 'meplayer-changing-theme');
+                }, 500);
+            }
+        }
+    }
+};
+
+function getTarget(option) {
+    if (typeof option === 'string') {
+        return document.querySelector(option);
+    } else if (option.toString().includes('HTMLDivElement')) {
+        return option;
+    } else {
+        return document.querySelector('.meplayer');
+    }
+}

+ 0 - 0
src/js/search.js


+ 83 - 0
src/js/spectrum.js

@@ -0,0 +1,83 @@
+/*
+ * 频谱动画模拟
+ * */
+var canvas, ctx,
+    specItems = [],
+    needStop  = false,
+    timer     = null,
+
+    random    = Math.random;
+
+function randHeight() {
+    if (random() > 0.8) {
+        return random() * 8 + 11;
+    } else {
+        return random() * 6 + 2;
+    }
+}
+
+var randHeightGenerator = function (base) {
+    var max        = base * 1.5 > 28 ? 28 : base * 1.5,
+        min        = 1,
+        direction  = random() > 0.5 ? 1 : -1,
+        tempHeight = base,
+        curStep;
+    return function () {
+        curStep = direction;
+        tempHeight += curStep;
+        if (tempHeight >= max) {
+            direction *= -1;
+            tempHeight = max;
+        } else if (tempHeight <= min) {
+            direction *= -1;
+            tempHeight = min;
+        }
+        if (random() > 0.9) {
+            direction *= -1;
+        }
+        return tempHeight;
+    }
+};
+
+function loop() {
+    ctx.clearRect(0, -canvas.height / 2, canvas.width, canvas.height);
+    for (var i = 0; i < specItems.length; i++) {
+        var item   = specItems[i];
+        var height = item.getHeight();
+        ctx.fillRect(i + specItems[i].xSpace, -height / 2, specItems[i].width, height);
+    }
+
+    if (!needStop) {
+        timer = requestAnimationFrame(loop);
+    }
+}
+
+function init(canvasElem, width = 220, height = 30, color = '#D94240') {
+    canvas        = canvasElem;
+    canvas.width  = width;
+    canvas.height = height;
+    ctx           = canvas.getContext('2d');
+    ctx.fillStyle = color;
+    ctx.translate(0, height / 2);
+
+    for (let i = 0; i < 64; i++) {
+        var xSpace   = i == 0 ? 0 : 5 * i;
+        var tempItem = {
+            xSpace   : xSpace,
+            width    : 1,
+            getHeight: randHeightGenerator(randHeight())
+        };
+        specItems.push(tempItem);
+    }
+}
+
+function draw() {
+    needStop = false;
+    loop();
+}
+
+function stop() {
+    needStop = true;
+}
+
+export {init, draw, stop};

+ 48 - 0
src/js/utils.js

@@ -0,0 +1,48 @@
+function toggleClass(el, className) {
+    if (el.classList) {
+        el.classList.toggle(className);
+    } else {
+        var classes       = el.className.split(' ');
+        var existingIndex = classes.indexOf(className);
+
+        if (existingIndex >= 0)
+            classes.splice(existingIndex, 1);
+        else
+            classes.push(className);
+
+        el.className = classes.join(' ');
+    }
+}
+
+function addClass(el, className) {
+    if (el.classList)
+        el.classList.add(className);
+    else
+        el.className += ' ' + className;
+}
+
+function removeClass(el, className) {
+    if (el.classList)
+        el.classList.remove(className);
+    else
+        el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
+}
+
+function getAbsLeft(el) {
+    var left = el.offsetLeft;
+    while (el.offsetParent) {
+        el = el.offsetParent;
+        left += el.offsetLeft;
+    }
+    return left;
+}
+
+function parseSec(sec) {
+    var tempMin = (sec / 60).toFixed(0);
+    var tempSec = (sec % 60).toFixed(0);
+    var curMin  = tempMin < 10 ? ('0' + tempMin) : tempMin;
+    var curSec  = tempSec < 10 ? ('0' + tempSec) : tempSec;
+    return curMin + ':' + curSec;
+}
+
+export {toggleClass, addClass, removeClass, getAbsLeft, parseSec};

+ 24 - 0
webpack.config.js

@@ -0,0 +1,24 @@
+module.exports = {
+    entry: './src/js/main.js',
+
+    output: {
+        filename: 'main.js'
+    },
+
+    module: {
+        loaders: [
+            { test: /\.js$/,
+                loader: 'babel-loader',
+                query: {
+                    presets: ['es2015']
+                }
+            }
+        ]
+    },
+    resolve: {
+        extensions: ['', '.js', '.json']
+    },
+    externals: {
+        'mePlayer': 'mePlayer'
+    }
+};

Some files were not shown because too many files changed in this diff