diff --git a/config.yaml b/config.yaml index fb97bfd..160390c 100644 --- a/config.yaml +++ b/config.yaml @@ -101,6 +101,16 @@ site: avatar: description: + # my music + music: + title: Music + list: + - name: + singer: + cover: + music_url: + lyric_url: + statistics: enable: false type: baidu diff --git a/config/mMusic.go b/config/mMusic.go new file mode 100644 index 0000000..24c1461 --- /dev/null +++ b/config/mMusic.go @@ -0,0 +1,14 @@ +package config + +type mMusic struct { + Title string `yaml:"title"` + List []mMusicItem `yaml:"list"` +} + +type mMusicItem struct { + Name string `yaml:"name"` + Singer string `yaml:"singer"` + Cover string `yaml:"cover"` + MusicUrl string `yaml:"music_url"` + LyricUrl string `yaml:"lyric_url"` +} diff --git a/config/mSite.go b/config/mSite.go index 127642b..8f162cf 100644 --- a/config/mSite.go +++ b/config/mSite.go @@ -5,6 +5,7 @@ type mSite struct { Menu mMenu `yaml:"menu"` Post mPost `yaml:"post"` About mAbout `yaml:"about"` + Music mMusic `yaml:"music"` Friend mFriend `yaml:"friend"` Statistics mStatistics `yaml:"statistics"` } diff --git a/internal/mApp/mHandler.go b/internal/mApp/mHandler.go index 87c1f20..17e5b48 100644 --- a/internal/mApp/mHandler.go +++ b/internal/mApp/mHandler.go @@ -627,3 +627,36 @@ func (ma *MApp) FriendHandler(ctx *gin.Context) { ctx.HTML(http.StatusOK, "friend.html", resData) } + +func (ma *MApp) MusicHandler(ctx *gin.Context) { + resData := gin.H{ + "site_info": gin.H{ + "title": ma.Config.MSite.Info.Title, + "author": ma.Config.MSite.Info.Author, + "language": ma.Config.MSite.Info.Language, + "copyright": template.HTML(ma.Config.MSite.Info.Copyright), + }, + "menu": ma.Config.MSite.Menu, + "music": gin.H{ + "title": ma.Config.MSite.Music.Title, + "list": ma.Config.MSite.Music.List, + }, + } + + // statistics + var statistics = gin.H{} + if ma.Config.MSite.Statistics.Enable { + switch ma.Config.MSite.Statistics.Type { + case "baidu": + statistics["enable"] = true + statistics["script"] = template.HTML(ma.Config.MSite.Statistics.Baidu) + break + default: + statistics["enable"] = false + } + } + + resData["statistics"] = statistics + + ctx.HTML(http.StatusOK, "music.html", resData) +} diff --git a/internal/mApp/mRouter.go b/internal/mApp/mRouter.go index 518a7ef..bff263e 100644 --- a/internal/mApp/mRouter.go +++ b/internal/mApp/mRouter.go @@ -6,6 +6,7 @@ func (ma *MApp) loadRoutes() { ma.engine.GET("/", ma.IndexHandler) ma.engine.GET("/rss", ma.RSSHandler) ma.engine.GET("/about", ma.AboutHandler) + ma.engine.GET("/music", ma.MusicHandler) ma.engine.GET("/search", ma.SearchHandler) ma.engine.GET("/friend", ma.FriendHandler) ma.engine.GET("/archive", ma.ArchiveHandler) diff --git a/templates/default/assets/css/global.css b/templates/default/assets/css/global.css index df92154..0441f55 100644 --- a/templates/default/assets/css/global.css +++ b/templates/default/assets/css/global.css @@ -7,6 +7,7 @@ --dark-secondary-text-color: #a3a2ac; --dark-background-color: #131318; + --dark-panel-color: #1c1b1f; /* light mode */ --light-primary-color: #6d6faa; @@ -16,6 +17,7 @@ --light-secondary-text-color: #5f5e67; --light-background-color: #fbf8ff; + --light-panel-color: #e2e0f9; /* used color */ --primary-color: #0; @@ -25,6 +27,7 @@ --secondary-text-color: #0; --background-color: #0; + --panel-color: #0; } @font-face { diff --git a/templates/default/assets/css/lib/meplayer.css b/templates/default/assets/css/lib/meplayer.css new file mode 100644 index 0000000..8545cd7 --- /dev/null +++ b/templates/default/assets/css/lib/meplayer.css @@ -0,0 +1,755 @@ +@font-face { + font-weight: normal; + font-style: normal; + font-family: 'fontello'; + src: url('../../../assets/css/webfonts/fontello.eot?77128880'); + src: url('../../../assets/css/webfonts/fontello.eot?77128880#iefix') format('embedded-opentype'), + url('../../../assets/css/webfonts/fontello.woff?77128880') format('woff'), + url('../../../assets/css/webfonts/fontello.ttf?77128880') format('truetype'), + url('../../../assets/css/webfonts/fontello.svg?77128880#fontello') format('svg'); +} + +.meplayer-container { + position: relative; + + box-sizing: border-box; + width: 100%; + height: 90px; + + background: var(--panel-color); + box-shadow: 0 0 20px rgba(0, 0, 0, .18); + border-radius: 14px 14px 0 0; +} + +.meplayer-container .meplayer-info { + position: relative; + left: 0; + + opacity: 1; +} + +.meplayer-container .meplayer-info-cover { + overflow: hidden; + position: absolute; + top: 0; + left: 0; + + 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; + + box-shadow: 0 0 20px rgba(0, 0, 0, .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: 14px; + margin-top: 10px; + + -webkit-transform: translateY(10px); + transform: translateY(10px); + + letter-spacing: 1px; + + opacity: 0; + color: var(--primary-text-color); +} + +.meplayer-container .meplayer-meta-title { + font-size: 16px; + font-weight: bold; + + 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: var(--primary-text-color); +} + +.meplayer-container .meplayer-meta-author { + font-size: 14px; + color: var(--secondary-text-color); +} + +.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: var(--primary-text-color); +} + +.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.2em; + 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: var(--panel-color); +} + +.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: var(--secondary-color); +} + +.meplayer-container.meplayer-adjusting-volume .meplayer-volume-bg { + opacity: 1; +} + +.meplayer-container .meplayer-volume-progress { + height: 4px; + + -webkit-transition: width .2s; + transition: width .2s; + + border-radius: 1px; + background: var(--secondary-color); +} + +.meplayer-container .meplayer-control-play { + position: absolute; + top: -25px; + right: 0; + + width: 50px; + height: 50px; + + -webkit-transition: top .6s cubic-bezier(0, .74, .61, 1.35); + transition: top .6s cubic-bezier(0, .74, .61, 1.35); + + cursor: pointer; + text-align: center; + + color: var(--primary-color); + border-radius: 50%; + border: 1px var(--secondary-color) solid; + + background: var(--panel-color); + box-shadow: 0 0 15px rgba(0, 0, 0, .2); +} + +.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 i { + 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(2px); + transform: translateX(2px); + + 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: var(--primary-text-color); +} + +.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: var(--primary-color); +} + +.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: 3px; + + -webkit-transition: all .5s; + transition: all .5s; + -webkit-transform: translateY(2px); + + transform: translateY(2px); + + opacity: 0; + background: var(--panel-color); +} + +.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: var(--primary-color); +} + +.meplayer-container.meplayer-changing-theme .meplayer-volume-bg { + display: none; +} + +@-webkit-keyframes breath { + 0% { + box-shadow: 0 0 35px rgba(0, 0, 0, .22); + } + + 100% { + box-shadow: 0 0 10px rgba(0, 0, 0, .33); + } +} + +@keyframes breath { + 0% { + box-shadow: 0 0 35px rgba(0, 0, 0, .22); + } + + 100% { + box-shadow: 0 0 10px rgba(0, 0, 0, .33); + } +} + +.meplayer-container-mini { + position: relative; + width: 90px; + height: 90px; + border-radius: 50%; + background: var(--panel-color); + box-shadow: 0 0 20px rgba(0, 0, 0, .3); +} + +.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%; + left: 50%; + + font-size: 26px; + line-height: 90px; + margin-top: -45px; + margin-left: -45px; + color: var(--primary-color); +} + +.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(4px); + transform: translateX(4px); + + 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%; + + font-size: 30px; + text-align: center; + line-height: 90px; + border-radius: 50%; + + background: var(--panel-color); + color: var(--primary-text-color); + + -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(0, 0, 0, .25); + } + + 100% { + box-shadow: 0 0 10px rgba(0, 0, 0, .33); + } +} + +@keyframes breath { + 0% { + box-shadow: 0 0 35px rgba(0, 0, 0, .25); + } + + 100% { + box-shadow: 0 0 10px rgba(0, 0, 0, .33); + } +} + +.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); + } +} + + +[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'; +} + diff --git a/templates/default/assets/css/music.css b/templates/default/assets/css/music.css new file mode 100644 index 0000000..e533a5f --- /dev/null +++ b/templates/default/assets/css/music.css @@ -0,0 +1,58 @@ +.music-player-wrap { + padding: 0; + height: 90px; + position: fixed; + left: 50%; + bottom: 0; + transform: translateX(-50%); +} + +.music-player { + width: 100%; + height: 90px; +} + + +.music-title { + color: var(--primary-color); +} + +.music-item { + margin-top: 20px; + padding: 10px; + display: flex; + align-items: center; + color: var(--primary-text-color); + border: var(--secondary-text-color) 1px dashed; + border-radius: 4px; +} + +.music-item:hover { + cursor: pointer; + border: var(--primary-color) 1px solid; +} + +.music-cover { + width: 64px; + height: 64px; + object-fit: cover; + border-radius: 50%; +} + +.music-info-wrap { + padding-left: 10px; +} + +.music-name { + font-size: 18px; + font-weight: bolder; +} + +.music-singer { + width: 200px; + font-size: 14px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + color: var(--secondary-text-color); +} \ No newline at end of file diff --git a/templates/default/assets/css/webfonts/fontello.eot b/templates/default/assets/css/webfonts/fontello.eot new file mode 100644 index 0000000..2d1c6f0 Binary files /dev/null and b/templates/default/assets/css/webfonts/fontello.eot differ diff --git a/templates/default/assets/css/webfonts/fontello.svg b/templates/default/assets/css/webfonts/fontello.svg new file mode 100644 index 0000000..efdb968 --- /dev/null +++ b/templates/default/assets/css/webfonts/fontello.svg @@ -0,0 +1,16 @@ + + + +Copyright (C) 2016 by original authors @ fontello.com + + + + + + + + + + + + \ No newline at end of file diff --git a/templates/default/assets/css/webfonts/fontello.ttf b/templates/default/assets/css/webfonts/fontello.ttf new file mode 100644 index 0000000..b85b74e Binary files /dev/null and b/templates/default/assets/css/webfonts/fontello.ttf differ diff --git a/templates/default/assets/css/webfonts/fontello.woff b/templates/default/assets/css/webfonts/fontello.woff new file mode 100644 index 0000000..cd4bbbc Binary files /dev/null and b/templates/default/assets/css/webfonts/fontello.woff differ diff --git a/templates/default/assets/img/music.png b/templates/default/assets/img/music.png new file mode 100644 index 0000000..e9ff4a3 Binary files /dev/null and b/templates/default/assets/img/music.png differ diff --git a/templates/default/assets/js/global.js b/templates/default/assets/js/global.js index 9ed86c2..ba3d114 100644 --- a/templates/default/assets/js/global.js +++ b/templates/default/assets/js/global.js @@ -30,6 +30,7 @@ function setTheme() { root.style.setProperty("--secondary-text-color", `var(--${theme}-secondary-text-color)`); root.style.setProperty("--background-color", `var(--${theme}-background-color)`); + root.style.setProperty("--panel-color", `var(--${theme}-panel-color)`); const logo = document.querySelector(".main-logo-img") if (logo !== null) { diff --git a/templates/default/assets/js/lib/meplayer.js b/templates/default/assets/js/lib/meplayer.js new file mode 100644 index 0000000..e35ab0e --- /dev/null +++ b/templates/default/assets/js/lib/meplayer.js @@ -0,0 +1,660 @@ +// webpackBootstrap +(function (modules) { + // 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); + +}) + +([(function (module, exports, __webpack_require__) { + + (function (global) { + 'use strict'; + + var _slicedToArray = function () { + function sliceIterator(arr, i) { + var _arr = []; + var _n = true; + var _d = false; + var _e = undefined; + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"]) _i["return"](); + } finally { + if (_d) throw _e; + } + } + return _arr; + } + + return function (arr, i) { + if (Array.isArray(arr)) { + return arr; + } else if (Symbol.iterator in Object(arr)) { + return sliceIterator(arr, i); + } else { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } + }; + }(); + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { + return typeof obj; + } : function (obj) { + return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; + }; + + 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); + + var _selector = __webpack_require__(5); + + var selector = _interopRequireWildcard(_selector); + + 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; + } + } + + var root = (typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.window === window ? window : (typeof global === 'undefined' ? 'undefined' : _typeof(global)) === 'object' && global.global === global ? global : undefined; + + root.MollyPlayer = function (options) { + // 检查必填选项 + if (!(options.music && options.music.src)) { + console.error('未指定音乐地址'); + return; + } + + var musicConf = options.music, target = selector.$(options.target) || document.querySelector('.meplayer'), + theme = options.theme || _constants.THEME_DEFAULT, hasLrc = !!musicConf.lrc, + coverSrc = musicConf.cover || '../../../assets/img/music.png', loop = musicConf.loop || false, + autoplay = options.autoplay, + currentThemeClass = theme === _constants.THEME_DEFAULT ? 'meplayer-container' : 'meplayer-container-mini', + containerClass = currentThemeClass + ' ' + (hasLrc ? 'meplayer-haslrc' : '') + ' meplayer-isloading'; + + target.innerHTML = '
\n \n
\n
cd-cover
\n
\n
' + musicConf.title + '
\n
' + musicConf.author + '
\n
\n
\n
\n \n
\n
\n
\n
loading
\n
loading
\n
\n
'; + + var meplayerContainer = target.querySelector('.' + currentThemeClass), + _selector$init$select = selector.init(meplayerContainer).select(['audio', '.meplayer-control-play', '.meplayer-meta-time-tick-text', '.meplayer-duration', '.meplayer-timeline', '.meplayer-timeline-passed', '.meplayer-volume', '.meplayer-volume-progress', '.meplayer-lyric-area', '.meplayer-spectrum']), + _selector$init$select2 = _slicedToArray(_selector$init$select, 10), audio = _selector$init$select2[0], + playBtn = _selector$init$select2[1], timeTick = _selector$init$select2[2], + timeCount = _selector$init$select2[3], timeLine = _selector$init$select2[4], + timePassed = _selector$init$select2[5], volumeArea = _selector$init$select2[6], + volumeProgress = _selector$init$select2[7], lyricArea = _selector$init$select2[8], + canvas = _selector$init$select2[9], duration; + + + if (hasLrc) { + lyric.parse(musicConf.lrc).renderTo(lyricArea); + } else { + // 频谱动画初始化 + spectrum.init(canvas); + } + + eventInit(); + + if (autoplay) { + handlePlayClick(); + } + + // 重定义meplayer + root.mePlayer = { + play: play, pause: pause, toggleTheme: toggleTheme + + // 给播放器绑定各种事件 + }; + + function eventInit() { + audio.addEventListener('play', handleAudioStart); + audio.addEventListener('ended', handleAudioEnd); + audio.addEventListener('canplaythrough', handleCanPlayThrough); + audio.addEventListener('durationchange', handleDurationChange); + audio.addEventListener('timeupdate', handleTimeUpdate); + playBtn.addEventListener('click', handlePlayClick); + timeLine.addEventListener('click', handleTimeLineClick); + } + + function handleAudioStart() { + utils.addClass(meplayerContainer, 'meplayer-isplaying'); + } + + function handleAudioEnd() { + if (loop) { + audio.play(); + } else { + utils.removeClass(meplayerContainer, 'meplayer-isplaying'); + } + } + + function handleCanPlayThrough() { + duration = this.duration; + setTimeout(function () { + utils.removeClass(meplayerContainer, 'meplayer-isloading'); + timeCount.querySelector('.meplayer-duration-text').innerText = utils.parseSec(duration.toFixed(0)); + }, 1000); + } + + function handleDurationChange() { + duration = this.duration; + } + + function handleTimeUpdate() { + var curTime = audio.currentTime; + 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(-' + tempLrcLines[tempLrcIndex].offsetTop + 'px)'; + lyricArea.style.transform = 'translateY(-' + tempLrcLines[tempLrcIndex].offsetTop + 'px)'; + } + } + } + + function handlePlayClick() { + var _handleMouseWheel; + + 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'); + } + + function handleTimeLineClick(event) { + var rect = this.getBoundingClientRect(); + var clickPosition = event.clientX - rect.left; + var clickPercent = clickPosition / rect.width; + timePassed.style.width = clickPercent * 100 + '%'; + audio.currentTime = (clickPercent * duration).toFixed(0); + } + + function play() { + if (audio.paused) { + audio.play(); + } + } + + function pause() { + if (!audio.paused) { + utils.removeClass(meplayerContainer, 'meplayer-isplaying'); + 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); + } + } + } + }; + + if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { + module.exports = root.mePlayer; + } + + }.call(exports, (function () { + return this; + }()))) + +}), + + (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; + + + }), + + (function (module, exports, __webpack_require__) { + + 'use strict'; + + Object.defineProperty(exports, "__esModule", { + value: true + }); + exports.currentIndex = exports.renderTo = 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 this; + } + + // 歌词文本解析成DOM结构 + function renderTo(target) { + if (!lyrics) { + console.error('未指定歌词文本!'); + return; + } + var lyricHTML = ''; + for (var i = 0; i < lyrics.length; i++) { + lyricHTML += '

' + lyrics[i].text + '

'; + } + target.innerHTML = lyricHTML; + target.querySelector('p').className = _constants.LYRIC_CURRENT_CLASS; + target.querySelector('p + p').className = _constants.LYRIC_NEXT_CLASS; + return this; + } + + 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.renderTo = renderTo; + exports.currentIndex = currentIndex; + }), + + (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 | 0; + var tempSec = sec % 60 | 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; + + }), + + (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 ? arguments[1] : 220; + var height = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 30; + var color = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : '#D94240'; + + 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; + + }), + + (function (module, exports) { + + 'use strict'; + + Object.defineProperty(exports, "__esModule", { + value: true + }); + + var container; + + function init(element) { + container = $(element); + return this; + } + + function select(element) { + var result; + if (Array.isArray(element)) { + var tempResults = []; + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = element[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var value = _step.value; + + tempResults.push($(value, container)); + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + result = tempResults; + } else { + result = $(element, container); + } + return result; + } + + function $(element, context) { + var result; + context = context || document; + if (typeof element === 'string') { + result = context.querySelector(element); + } else if (element.toString().includes('HTMLDivElement')) { + result = element; + } + + return result; + } + + exports.init = init; + exports.select = select; + exports.$ = $; + + })]); \ No newline at end of file diff --git a/templates/default/assets/js/music.js b/templates/default/assets/js/music.js new file mode 100644 index 0000000..696dde1 --- /dev/null +++ b/templates/default/assets/js/music.js @@ -0,0 +1,33 @@ +const bodyWrap = document.getElementById('body-wrap'); +const playerWrap = document.getElementById('music-player-wrap'); + +syncWidth(); +window.addEventListener('resize', syncWidth); + +function syncWidth() { + playerWrap.style.width =window.getComputedStyle(bodyWrap).width; +} + +function play(name, singer, coverSrc, musicSrc, lyricSrc) { + fetch(lyricSrc) + .then((res) => { + return res.text(); + }) + .then((data) => { + const musicData = musicSrc; + const lyricData = data; + + MollyPlayer({ + music: { + src: musicData, + lrc: lyricData, + cover: coverSrc, + title: name, + author: singer, + loop: true, + }, + target: '#music-player', + autoplay: true, + }); + }); +} \ No newline at end of file diff --git a/templates/default/html/music.html b/templates/default/html/music.html new file mode 100644 index 0000000..60e912a --- /dev/null +++ b/templates/default/html/music.html @@ -0,0 +1,93 @@ +{{ define "music.html" }} + + + + + + {{ .site_info.title }} + + + + + + + + + + + + + {{ if .statistics.enable }} + {{ .statistics.script }} + {{ end }} + + + +
+
+ + +
+
+
+ {{ range $i, $v := .menu.Items }} + + + {{ $v.Name }} + + {{ end }} +
+
+
+ + + +
+
+
+

# {{ .music.title }}

+
+
+ {{ range $i, $v := .music.list }} +
+
+ +
+
+ {{ $v.Name }} +
+
+ {{ $v.Singer }} +
+
+
+
+ {{ end }} +
+
+
+
+
+ +
+ + +
+ + + +
+ + +
+
+
+ + + + + + +{{ end }} \ No newline at end of file