JWen's Blog

Personal website of JWen 丁文亮的个人网站

Add an Audio to Hugo with MetingJS

2024-08-21


Table of Contents

This post is a collection of notes made in the past few days, finding the way to add music to Hugo. These notes cover a wide range of topics, listed in the Table of Contents and ordered in an easily-understood manner. Failures (or Mistakes) are also included, because (from Yihui’s Blog)

“Everyone makes mistakes. The main difference is that successful people learn from them and unsuccessful people don’t.”

Make code block collapsible in Hugo

Mainly based on hugo-collapsible-code by Jiri De Jagere

  1. Store this script in layouts/shortcodes/code.html

    <div class="highlight-wrapper">
      <!-- <div class="highlight-before">{{ .Get 0 }}</div> -->
      {{ if len .Params | eq 2 }}
      {{ highlight (trim .Inner "\n\r") (.Get 0) (.Get 1) }}
      {{ else }}
      {{ highlight (trim .Inner "\n\r") (.Get 0) "" }}
      {{ end }}
    </div>
    
  2. Store this script in static/css/code-styles.css

    .highlight-wrapper {
        position: relative;
        /* border: 1px solid #ddd; */
        padding: 0;
    }
    
    .highlight-wrapper .highlight pre {
        /* margin-top: -2px; */
        /* margin-bottom: -2px; */
        margin-top: 0;
        margin-bottom: 0;
    }
    
    .highlight-link {
        position: absolute;
        bottom: 5px;
        right: 5px;
        font-size: 120%;
        font-style: italic;
        /* border: 1px solid #ddd; */
    }
    
  3. Store this script in static/js/code-scripts.js

var height = "300px";

if (
    document.readyState `=` "complete" ||
        (document.readyState !== "loading" &amp;&amp; !document.documentElement.doScroll)
) {
    makeCollapsible();
} else {
    document.addEventListener("DOMContentLoaded", makeCollapsible);
}

function toggle(e) {
    e.preventDefault();
    var link = e.target;
    var div = link.parentElement.parentElement;
    if (link.innerHTML == "more&amp;nbsp;") {
        link.innerHTML = "less&amp;nbsp;";
        div.style.maxHeight = "";
        div.style.overflow = "none";
    } else {
        link.innerHTML = "more&amp;nbsp;";
        div.style.maxHeight = height;
        div.style.overflow = "hidden";
        div.scrollIntoView({ behavior: 'smooth' });
    }
}

function makeCollapsible() {
    var divs = document.querySelectorAll('.highlight-wrapper');
    for (i=0; i &lt; divs.length; i++) {
        var div = divs[i];
        if (div.offsetHeight &gt; parseInt(height, 10)) {
            div.style.maxHeight = height;
            div.style.overflow = "hidden";
            var e = document.createElement('div');
            e.className = "highlight-link";
            var html = '&lt;a href=""&gt;more&amp;nbsp;&lt;/a&gt;';
            e.innerHTML = html;
            div.appendChild(e);
        }
    }
    var links = document.querySelectorAll('.highlight-link');
    for (i=0; i&lt;links.length; i++) {
        var link = links[i];
        link.addEventListener('click', toggle);
    }
}
  1. Add this script to themes/hugo-ivy/layouts/partials/head_highlightjs.html (See the usage tips)

    <script src="/js/code-scripts.js"></script>
    <link rel="stylesheet" href="/css/code-styles.css" />
    
  2. The above Step 3 is documented in .org file as follows:

    #+attr_shortcode: js
    #+begin_code
    var height = "300px";
    ...
    #+end_code
    

    and documented in .md file as follows (Ref: show raw shortcode):

    {{< code js >}}
    var height = "300px";
    ...
    {{< /code >}}
    
  3. Problems in ox-hugo:

    • (Unsolved!) In org, need to force ordered list numbering after using
      #+attr_shortcode: js
      #+begin_code
      ...
      #+end_code
      
    • (Solved!) In org, failed comment and indentation for hugo-collapsible-code. E.g. the following in .org file
      #+attr_shortcode: js
      #+begin_code
      // Collapsible Hugo code blocks
      // by Jiri De Jagere, @JiriDJ
      
      function makeCollapsible() {
          var divs = document.querySelectorAll('.highlight-wrapper');
      
          for (i=0; i < divs.length; i++) {
              ...
          }
      
          var links = document.querySelectorAll('.highlight-link');
          ...
      }
      #+end_code
      
      ends with the following in html file
_/ Collapsible Hugo code blocks
/_ by Jiri De Jagere, @JiriDJ

function makeCollapsible() {
    var divs = document.querySelectorAll('.highlight-wrapper');

for (i=0; i &lt; divs.length; i++) {
    ...
}

    var links = document.querySelectorAll('.highlight-link');
    ...
}

These two problems can be solved simultaneously by the discouraged method in ox-hugo: E.g. the following in .org file

#+begin_export hugo
{{< code js >}}
// Collapsible Hugo code blocks
// by Jiri De Jagere, @JiriDJ

function makeCollapsible() {
    var divs = document.querySelectorAll('.highlight-wrapper');

    for (i=0; i < divs.length; i++) {
        ...
    }

    var links = document.querySelectorAll('.highlight-link');
    ...
}
{{< /code >}}
#+end_export

ends with the following in html file

// Collapsible Hugo code blocks
// by Jiri De Jagere, @JiriDJ

function makeCollapsible() {
    var divs = document.querySelectorAll('.highlight-wrapper');

    for (i=0; i < divs.length; i++) {
        ...
    }

    var links = document.querySelectorAll('.highlight-link');
    ...
}

Add an audio to Hugo with MetingJS

Failures: APlayer => aplayer-hugo-module

  1. Store this script in layouts/shortcodes/music.html (read quickly: Ref1, Ref2; read carefully: Ref3)
{{- $scratch := .Page.Scratch.Get "scratch" -}}
<!-- require APlayer -->
<!-- <link rel="stylesheet" href="https://fastly.jsdelivr.net/npm/aplayer/dist/APlayer.min.css"> -->
<link rel="stylesheet" href="/css/Aplayer.min.css">
<script src="https://fastly.jsdelivr.net/npm/aplayer/dist/APlayer.min.js"></script>
<!-- require MetingJS -->
<script>
  var meting_api='https://api.injahow.cn/meting/?server=:server&type=:type&id=:id&auth=:auth&r=:r';
  // var meting_api='https://v.iarc.top/?server=:server&type=:type&id=:id&auth=:auth&r=:r';
</script>
<script src="https://fastly.jsdelivr.net/npm/meting@2.0.1/dist/Meting.min.js"></script>

{{- if .IsNamedParams -}}
    {{- if .Get "url" -}}
        <meting-js url="{{ .Get `url` }}" name="{{ .Get `name` }}" artist="{{ .Get `artist` }}" cover="{{ .Get `cover` }}" theme="{{ .Get `theme` | default `#2980b9` }}"
        {{- with .Get "fixed" }} fixed="{{ . }}"{{ end -}}
        {{- with .Get "mini" }} mini="{{ . }}"{{ end -}}
        {{- with .Get "autoplay" }} autoplay="{{ . }}"{{ end -}}
        {{- with .Get "volume" }} volume="{{ . }}"{{ end -}}
        {{- with .Get "mutex" }} mutex="{{ . }}"{{ end -}}
        ></meting-js>
    {{- else if .Get "auto" -}}
        <meting-js auto="{{ .Get `auto` }}" theme="{{ .Get `theme` | default `#2980b9` }}"
        {{- with .Get "fixed" }} fixed="{{ . }}"{{ end -}}
        {{- with .Get "mini" }} mini="{{ . }}"{{ end -}}
        {{- with .Get "autoplay" }} autoplay="{{ . }}"{{ end -}}
        {{- with .Get "loop" }} loop="{{ . }}"{{ end -}}
        {{- with .Get "order" }} order="{{ . }}"{{ end -}}
        {{- with .Get "volume" }} volume="{{ . }}"{{ end -}}
        {{- with .Get "mutex" }} mutex="{{ . }}"{{ end -}}
        {{- with .Get "list-folded" }} list-folded="{{ . }}"{{ end -}}
        {{- with .Get "list-max-height" }} list-max-height="{{ . }}"{{ end -}}
        ></meting-js>
    {{- else -}}
        <meting-js server="{{ .Get `server` }}" type="{{ .Get `type` }}" id="{{ .Get `id` }}" theme="{{ .Get `theme` | default `#2980b9` }}"
        {{- with .Get "fixed" }} fixed="{{ . }}"{{ end -}}
        {{- with .Get "mini" }} mini="{{ . }}"{{ end -}}
        {{- with .Get "autoplay" }} autoplay="{{ . }}"{{ end -}}
        {{- with .Get "loop" }} loop="{{ . }}"{{ end -}}
        {{- with .Get "order" }} order="{{ . }}"{{ end -}}
        {{- with .Get "volume" }} volume="{{ . }}"{{ end -}}
        {{- with .Get "mutex" }} mutex="{{ . }}"{{ end -}}
        {{- with .Get "list-folded" }} list-folded="{{ . }}"{{ end -}}
        {{- with .Get "list-max-height" }} list-max-height="{{ . }}"{{ end -}}
        ></meting-js>
    {{- end -}}
{{- else if strings.HasSuffix (.Get 0) "http" -}}
    <meting-js auto="{{ .Get 0 }}" theme="#2980b9"></meting-js>
{{- else -}}
    <meting-js server="{{ .Get 0 }}" type="{{ .Get 1 }}" id="{{ .Get 2 }}" theme="#2980b9"></meting-js>
{{- end -}}
{{- $scratch.Set "music" true -}}
  1. To change the appearance of audio player, store this script in static/css/Aplayer.min.css (Ref1)
.aplayer {
	background: #181B20;
	font-family: Arial,Helvetica,sans-serif;
	margin: 25px;
	/* box-shadow: 0 2px 2px 0 #ffffff,0 1px 5px 0 #ffffff; */
	box-shadow: 0 0px 2px 0 #ffffff,0 1px 10px 0 #ffffff;
	border-radius: 2px;
	overflow: hidden;
	-webkit-user-select: none;
	-moz-user-select: none;
	-ms-user-select: none;
	user-select: none;
	line-height: normal;
	position: relative
}

.aplayer * {
	box-sizing: content-box
}

.aplayer svg {
	width: 100%;
	height: 100%
}

.aplayer svg circle,.aplayer svg path {
	/* fill: rgba(0,0,0,.8) */
	fill: #ffffff
}

.aplayer.aplayer-withlist .aplayer-info {
	/* border-bottom: 1px solid #363636 */
	border-bottom: 1px solid #ffffff
}

.aplayer.aplayer-withlist .aplayer-list {
	display: block
}

.aplayer.aplayer-withlist .aplayer-icon-order,.aplayer.aplayer-withlist .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon.aplayer-icon-menu {
	display: inline
}

.aplayer.aplayer-withlrc .aplayer-pic {
	height: 90px;
	width: 90px
}

.aplayer.aplayer-withlrc .aplayer-info {
	margin-left: 90px;
	height: 90px;
	padding: 10px 7px 0
}

.aplayer.aplayer-withlrc .aplayer-lrc {
	display: block
}

.aplayer.aplayer-narrow {
	width: 66px
}

.aplayer.aplayer-narrow .aplayer-info,.aplayer.aplayer-narrow .aplayer-list {
	display: none
}

.aplayer.aplayer-narrow .aplayer-body,.aplayer.aplayer-narrow .aplayer-pic {
	height: 66px;
	width: 66px
}

.aplayer.aplayer-fixed {
	position: fixed;
	bottom: 0;
	left: 0;
	right: 0;
	margin: 0;
	z-index: 99;
	overflow: visible;
	max-width: 400px;
	box-shadow: none
}

.aplayer.aplayer-fixed .aplayer-list {
	margin-bottom: 65px;
	/* border: 1px solid #000000; */
	border: 1px solid #ffffff;
	border-bottom: none
}

.aplayer.aplayer-fixed .aplayer-body {
	position: fixed;
	bottom: 0;
	left: 0;
	right: 0;
	margin: 0;
	z-index: 99;
	/* background: rgba(0,0,0,.8); */
	background: #ffffff;
	padding-right: 18px;
	transition: all .3s ease;
	max-width: 400px
}

.aplayer.aplayer-fixed .aplayer-lrc {
	display: block;
	position: fixed;
	bottom: 10px;
	left: 0;
	right: 0;
	margin: 0;
	z-index: 98;
	pointer-events: none;
	/* text-shadow: -1px -1px 0 rgba(0,0,0,.8) */
	text-shadow: -1px -1px 0 #ffffff
}

.aplayer.aplayer-fixed .aplayer-lrc:after,.aplayer.aplayer-fixed .aplayer-lrc:before {
	display: none
}

.aplayer.aplayer-fixed .aplayer-info {
	-webkit-transform: scaleX(1);
	transform: scaleX(1);
	-webkit-transform-origin: 0 0;
	transform-origin: 0 0;
	transition: all .3s ease;
	border-bottom: none;
	border-top: 1px solid #626262
}

.aplayer.aplayer-fixed .aplayer-info .aplayer-music {
	width: calc(100% - 105px)
}

.aplayer.aplayer-fixed .aplayer-miniswitcher {
	display: block
}

.aplayer.aplayer-fixed.aplayer-narrow .aplayer-info {
	display: block;
	-webkit-transform: scaleX(0);
	transform: scaleX(0)
}

.aplayer.aplayer-fixed.aplayer-narrow .aplayer-body {
	width: 66px![]mportant
}

.aplayer.aplayer-fixed.aplayer-narrow .aplayer-miniswitcher .aplayer-icon {
	-webkit-transform: rotateY(0);
	transform: rotateY(0)
}

.aplayer.aplayer-fixed .aplayer-icon-back,.aplayer.aplayer-fixed .aplayer-icon-forward,.aplayer.aplayer-fixed .aplayer-icon-lrc,.aplayer.aplayer-fixed .aplayer-icon-play {
	display: inline-block
}

.aplayer.aplayer-fixed .aplayer-icon-back,.aplayer.aplayer-fixed .aplayer-icon-forward,.aplayer.aplayer-fixed .aplayer-icon-menu,.aplayer.aplayer-fixed .aplayer-icon-play {
	position: absolute;
	bottom: 27px;
	width: 20px;
	height: 20px
}

.aplayer.aplayer-fixed .aplayer-icon-back {
	right: 75px
}

.aplayer.aplayer-fixed .aplayer-icon-play {
	right: 50px
}

.aplayer.aplayer-fixed .aplayer-icon-forward {
	right: 25px
}

.aplayer.aplayer-fixed .aplayer-icon-menu {
	right: 0
}

.aplayer.aplayer-arrow .aplayer-icon-loop,.aplayer.aplayer-arrow .aplayer-icon-order,.aplayer.aplayer-mobile .aplayer-icon-volume-down {
	display: none
}

.aplayer.aplayer-loading .aplayer-info .aplayer-controller .aplayer-loading-icon {
	display: block
}

.aplayer.aplayer-loading .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-played .aplayer-thumb {
	-webkit-transform: scale(1);
	transform: scale(1)
}

.aplayer .aplayer-body {
	position: relative
}

.aplayer .aplayer-icon {
	width: 15px;
	height: 15px;
	border: none;
	background-color: transparent;
	outline: none;
	cursor: pointer;
	opacity: .8;
	vertical-align: middle;
	padding: 0;
	font-size: 12px;
	margin: 0;
	display: inline-block
}

.aplayer .aplayer-icon path {
	transition: all .2s ease-in-out
}

.aplayer .aplayer-icon-back,.aplayer .aplayer-icon-forward,.aplayer .aplayer-icon-lrc,.aplayer .aplayer-icon-order,.aplayer .aplayer-icon-play {
	display: none
}

.aplayer .aplayer-icon-lrc-inactivity svg {
	opacity: .4
}

.aplayer .aplayer-icon-forward {
	-webkit-transform: rotate(180deg);
	transform: rotate(180deg)
}

.aplayer .aplayer-lrc-content {
	display: none
}

.aplayer .aplayer-pic {
	position: relative;
	float: left;
	height: 66px;
	width: 66px;
	background-size: cover;
	background-position: 50%;
	transition: all .3s ease;
	cursor: pointer
}

.aplayer .aplayer-pic:hover .aplayer-button {
	opacity: 1
}

.aplayer .aplayer-pic .aplayer-button {
	position: absolute;
	border-radius: 50%;
	opacity: .8;
	text-shadow: 0 1px 1px rgba(255,255,255,.4);
	box-shadow: 0 1px 1px rgba(255,255,255,.4);
	background: rgba(255,255,255,.4);
	transition: all .1s ease
}

.aplayer .aplayer-pic .aplayer-button path {
	fill: rgba(255,255,255,.9);
}

.aplayer .aplayer-pic .aplayer-hide {
	display: none
}

.aplayer .aplayer-pic .aplayer-play {
	width: 26px;
	height: 26px;
	border: 2px solid rgba(255,255,255,.6);
	bottom: 50%;
	right: 50%;
	margin: 0 -15px -15px 0
}

.aplayer .aplayer-pic .aplayer-play svg {
	position: absolute;
	top: 3px;
	left: 4px;
	height: 20px;
	width: 20px
}

.aplayer .aplayer-pic .aplayer-pause {
	width: 16px;
	height: 16px;
	border: 2px solid rgba(255,255,255,.6);;
	bottom: 4px;
	right: 4px
}

.aplayer .aplayer-pic .aplayer-pause svg {
	position: absolute;
	top: 2px;
	left: 2px;
	height: 12px;
	width: 12px
}

.aplayer .aplayer-info {
	margin-left: 66px;
	padding: 14px 7px 0 10px;
	height: 66px;
	box-sizing: border-box
}

.aplayer .aplayer-info .aplayer-music {
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
	margin: 0 0 13px 5px;
	-webkit-user-select: text;
	-moz-user-select: text;
	-ms-user-select: text;
	user-select: text;
	cursor: default;
	padding-bottom: 2px;
	height: 20px
}

.aplayer .aplayer-info .aplayer-music .aplayer-title {
	font-size: 14px
}

.aplayer .aplayer-info .aplayer-music .aplayer-author {
	font-size: 12px;
	color: #aeaeae
}

.aplayer .aplayer-info .aplayer-controller {
	position: relative;
	display: flex
}

.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap {
	margin: 0 0 0 5px;
	padding: 4px 0;
	cursor: pointer![]mportant;
	flex: 1
}

.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap:hover .aplayer-bar .aplayer-played .aplayer-thumb {
	-webkit-transform: scale(1);
	transform: scale(1)
}

.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar {
	position: relative;
	height: 2px;
	width: 100%;
	/* background: #626262 */
	background: #ffffff
}

.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-loaded {
	position: absolute;
	left: 0;
	top: 0;
	bottom: 0;
	/* background: #626262; */
	background: #ffffff;
	height: 2px;
	transition: all .5s ease
}

.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-played {
	position: absolute;
	left: 0;
	top: 0;
	bottom: 0;
	height: 2px
}

.aplayer .aplayer-info .aplayer-controller .aplayer-bar-wrap .aplayer-bar .aplayer-played .aplayer-thumb {
	position: absolute;
	top: 0;
	right: 5px;
	margin-top: -4px;
	margin-right: -10px;
	height: 10px;
	width: 10px;
	border-radius: 50%;
	cursor: pointer;
	transition: all .3s ease-in-out;
	-webkit-transform: scale(0);
	transform: scale(0)
}

.aplayer .aplayer-info .aplayer-controller .aplayer-time {
	position: relative;
	right: 0;
	bottom: 4px;
	height: 17px;
	color: #aeaeae;
	font-size: 11px;
	padding-left: 7px
}

.aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-time-inner {
	vertical-align: middle
}

.aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon {
	cursor: pointer;
	transition: all .2s ease
}

.aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon path {
	fill: #AEAEAE
}

.aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon.aplayer-icon-loop {
	margin-right: 2px
}

.aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon:hover path {
	fill: #fff
}

.aplayer .aplayer-info .aplayer-controller .aplayer-time .aplayer-icon.aplayer-icon-menu,.aplayer .aplayer-info .aplayer-controller .aplayer-time.aplayer-time-narrow .aplayer-icon-menu,.aplayer .aplayer-info .aplayer-controller .aplayer-time.aplayer-time-narrow .aplayer-icon-mode {
	display: none
}

.aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap {
	position: relative;
	display: inline-block;
	margin-left: 3px;
	cursor: pointer![]mportant
}

.aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap:hover .aplayer-volume-bar-wrap {
	height: 40px
}

.aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap .aplayer-volume-bar-wrap {
	position: absolute;
	bottom: 15px;
	right: -3px;
	width: 25px;
	height: 0;
	z-index: 99;
	overflow: hidden;
	transition: all .2s ease-in-out
}

.aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap .aplayer-volume-bar-wrap.aplayer-volume-bar-wrap-active {
	height: 40px
}

.aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap .aplayer-volume-bar-wrap .aplayer-volume-bar {
	position: absolute;
	bottom: 0;
	right: 10px;
	width: 5px;
	height: 35px;
	background: #363636;
	border-radius: 2.5px;
	overflow: hidden
}

.aplayer .aplayer-info .aplayer-controller .aplayer-volume-wrap .aplayer-volume-bar-wrap .aplayer-volume-bar .aplayer-volume {
	position: absolute;
	bottom: 0;
	right: 0;
	width: 5px;
	transition: all .1s ease
}

.aplayer .aplayer-info .aplayer-controller .aplayer-loading-icon {
	display: none
}

.aplayer .aplayer-info .aplayer-controller .aplayer-loading-icon svg {
	position: absolute;
	-webkit-animation: rotate 1s linear infinite;
	animation: rotate 1s linear infinite
}

.aplayer .aplayer-lrc {
	display: none;
	position: relative;
	height: 30px;
	text-align: center;
	overflow: hidden;
	margin: -10px 0 7px
}

.aplayer .aplayer-lrc:before {
	top: 0;
	height: 10%;
	/* background: linear-gradient(180deg,rgba(0,0,0,.8) 0,hsla(0,0%,100%,0)); */
        /* line color under title */
	background: #181B20;
	filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="rgba(0,0,0,.8)fff",endColorstr="#00ffffff",GradientType=0)
}

.aplayer .aplayer-lrc:after,.aplayer .aplayer-lrc:before {
	position: absolute;
	z-index: 1;
	display: block;
	overflow: hidden;
	width: 100%;
	content: " "
}

.aplayer .aplayer-lrc:after {
	bottom: 0;
	height: 33%;
	/* background: linear-gradient(180deg,hsla(0,0%,100%,0) 0,hsla(0,0%,100%,.8)); */
        /* line color under lyric */
	background: linear-gradient(180deg,hsla(0,0%,100%,0) 0,hsla(0,0%,100%,0));
	filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#00ffffff",endColorstr="#ccffffff",GradientType=0)
}

.aplayer .aplayer-lrc p {
	font-size: 12px;
	color: #AEAEAE;
	line-height: 16px![]mportant;
	height: 16px![]mportant;
	padding: 0![]mportant;
	margin: 0![]mportant;
	transition: all .5s ease-out;
	opacity: .4;
	overflow: hidden
}

.aplayer .aplayer-lrc p.aplayer-lrc-current {
	opacity: 1;
	overflow: visible;
	height: auto![]mportant;
	min-height: 16px
}

.aplayer .aplayer-lrc.aplayer-lrc-hide {
	display: none
}

.aplayer .aplayer-lrc .aplayer-lrc-contents {
	width: 100%;
	transition: all .5s ease-out;
	-webkit-user-select: text;
	-moz-user-select: text;
	-ms-user-select: text;
	user-select: text;
	cursor: default
}

.aplayer .aplayer-list {
	overflow: auto;
	transition: all .5s ease;
	will-change: height;
	display: none;
	overflow: hidden
}

.aplayer .aplayer-list.aplayer-list-hide {
	max-height: 0![]mportant
}

.aplayer .aplayer-list ol {
	list-style-type: none;
	margin: 0;
	padding: 0;
	overflow-y: auto
}

.aplayer .aplayer-list ol::-webkit-scrollbar {
	width: 5px
}

.aplayer .aplayer-list ol::-webkit-scrollbar-thumb {
	border-radius: 3px;
	background-color: #363636
}

.aplayer .aplayer-list ol::-webkit-scrollbar-thumb:hover {
	background-color: #363636
}

.aplayer .aplayer-list ol li {
	position: relative;
	height: 32px;
	line-height: 32px;
	padding: 0 15px;
	font-size: 12px;
	border-top: 1px solid #363636;
	cursor: pointer;
	transition: all .2s ease;
	overflow: hidden;
	margin: 0
}

.aplayer .aplayer-list ol li:first-child {
	border-top: none
}

.aplayer .aplayer-list ol li:hover {
	background: #363636
}

.aplayer .aplayer-list ol li.aplayer-list-light {
	background: #363636
}

.aplayer .aplayer-list ol li.aplayer-list-light .aplayer-list-cur {
	display: inline-block
}

.aplayer .aplayer-list ol li .aplayer-list-cur {
	display: none;
	width: 3px;
	height: 22px;
	position: absolute;
	left: 0;
	top: 5px;
	cursor: pointer
}

.aplayer .aplayer-list ol li .aplayer-list-index {
	color: #AEAEAE;
	margin-right: 12px;
	cursor: pointer
}

.aplayer .aplayer-list ol li .aplayer-list-author {
	color: #AEAEAE;
	float: right;
	cursor: pointer
}

.aplayer .aplayer-notice {
	opacity: 0;
	position: absolute;
	top: 50%;
	left: 50%;
	-webkit-transform: translate(-50%,-50%);
	transform: translate(-50%,-50%);
	font-size: 12px;
	border-radius: 4px;
	padding: 5px 10px;
	transition: all .3s ease-in-out;
	overflow: hidden;
	color: rgba(0,0,0,.8);
	pointer-events: none;
	background-color: #363636;
	color: #626262
}

.aplayer .aplayer-miniswitcher {
	display: none;
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	height: 100%;
	background: #1B1C1D;
	width: 18px;
	border-radius: 0 2px 2px 0
}

.aplayer .aplayer-miniswitcher .aplayer-icon {
	height: 100%;
	width: 100%;
	-webkit-transform: rotateY(180deg);
	transform: rotateY(180deg);
	transition: all .3s ease
}

.aplayer .aplayer-miniswitcher .aplayer-icon path {
	fill: #626262
}

.aplayer .aplayer-miniswitcher .aplayer-icon:hover path {
	fill: #fff
}

@-webkit-keyframes aplayer-roll {
	0% {
		left: 0
	}

	to {
		left: -100%
	}
}

@keyframes aplayer-roll {
	0% {
		left: 0
	}

	to {
		left: -100%
	}
}

@-webkit-keyframes rotate {
	0% {
		-webkit-transform: rotate(0);
		transform: rotate(0)
	}

	to {
		-webkit-transform: rotate(1turn);
		transform: rotate(1turn)
	}
}

@keyframes rotate {
	0% {
		-webkit-transform: rotate(0);
		transform: rotate(0)
	}

	to {
		-webkit-transform: rotate(1turn);
		transform: rotate(1turn)
	}
}

/*# sourceMappingURL=APlayer.min.css.map*/
  1. From the homepage of the meting_api we used in Step 1, i.e. https://api.injahow.cn/meting/, we can

    • add non-VIP netease music. E.g. we want to add 谢天笑-命运还是巧合 to Hugo site, for .md file, we use

      {{< music id="25731674" type="song" server="netease" autoplay=false >}}
      

      while for .org file, we use

      #+begin_export hugo
      {{< music id="25731674" type="song" server="netease" autoplay=false >}}
      #+end_export
      
    • add self-hosted media (Ref). E.g. for .md file, we use

      <meting-js name="蒙古姑娘(live)" artist="刘欢" url="https://github.com/dwla/BM/blob/master/刘欢-蒙古姑娘(live).mp3?raw=true" cover="https://github.com/dwla/BM/blob/master/刘欢-蒙古姑娘(live).jpg?raw=true">
        <pre hidden>
          [00:00.00] 作词 : 刘欢[00:01.00] 作曲 : 刘欢[00:40.39]在一个静静的晚上[00:48.67]有一个蒙古姑娘[00:56.18]脸上的泪珠[01:04.02]好象天上的星光[01:11.62]为了那刚失去的[01:19.39]一只美丽羔羊[01:27.05]独自的悲伤[01:34.79]那样的悲伤[01:42.35]哦!美丽的姑娘[01:49.82]你不要再悲伤[01:57.50]你不见天上的白云[02:04.82]不就是你的羔羊[02:13.42]姑娘轻轻睡去[02:20.73]泪珠还在脸上[02:28.39]不觉是什么时候[02:35.45]东方已升起朝阳[03:13.80]哦!美丽的姑娘[03:21.41]你不要再悲伤[03:28.88]你不见天上的白云[03:36.55]不就是你的羔羊[03:44.99]姑娘轻轻睡去[03:52.27]泪珠还在脸上[03:59.85]不觉是什么时候[04:07.16]东方已升起朝阳
        </pre>
      </meting-js>
      

      while for .org file, we use

      #+begin_export hugo
      <meting-js name="蒙古姑娘(live)" artist="刘欢" url="https://github.com/dwla/BM/blob/master/刘欢-蒙古姑娘(live).mp3?raw=true" cover="https://github.com/dwla/BM/blob/master/刘欢-蒙古姑娘(live).jpg?raw=true">
      <pre hidden>
      [00:00.00] 作词 : 刘欢[00:01.00] 作曲 : 刘欢[00:40.39]在一个静静的晚上[00:48.67]有一个蒙古姑娘[00:56.18]脸上的泪珠[01:04.02]好象天上的星光[01:11.62]为了那刚失去的[01:19.39]一只美丽羔羊[01:27.05]独自的悲伤[01:34.79]那样的悲伤[01:42.35]哦!美丽的姑娘[01:49.82]你不要再悲伤[01:57.50]你不见天上的白云[02:04.82]不就是你的羔羊[02:13.42]姑娘轻轻睡去[02:20.73]泪珠还在脸上[02:28.39]不觉是什么时候[02:35.45]东方已升起朝阳[03:13.80]哦!美丽的姑娘[03:21.41]你不要再悲伤[03:28.88]你不见天上的白云[03:36.55]不就是你的羔羊[03:44.99]姑娘轻轻睡去[03:52.27]泪珠还在脸上[03:59.85]不觉是什么时候[04:07.16]东方已升起朝阳
      </pre>
      </meting-js>
      #+end_export
      
  2. We can use other API by change meting_api in layouts/shortcodes/music.html (MetingApi 接口):

    <script>
      // var meting_api='https://api.injahow.cn/meting/?server=:server&type=:type&id=:id&auth=:auth&r=:r';
      var meting_api='https://v.iarc.top/?server=:server&type=:type&id=:id&auth=:auth&r=:r';
    </script>
    

    Then, for those VIP songs in netease, e.g. 谢天笑-再次来临, we have

    See https://v.iarc.top/ and https://v.iarc.top/?server=netease&type=song&id=167597 for further details:

  3. Useful links

Debug [2024-08-30 Fri]: about “add self-hosted media”

In this post, we demonstrated that using meting-js directly can put a self-hosted media in a post. It works well in this post, however, doesn’t work in those post using meting-js only! (E.g. 老鸭 | 一时不足一刻) The reason is that, a shortcode of “music.html” is used in this post, and the required CSS and JS files are already included in the shortcode. If we use meting-js only in a post, then the shortcode “music.html” isn’t run, therefore the required CSS and JS are not included in such post. To make sure these files are included in those posts (had meting-js only, without shortcode “music”), we put the following script in themes/hugo-ivy/layouts/partials/head_custom.html

{{ if (findRE "<meting-js" .Content 1) }}
    <link rel="stylesheet" href="/css/Aplayer.min.css">
    <script src="https://fastly.jsdelivr.net/npm/aplayer/dist/APlayer.min.js"></script>
    <script>
      // var meting_api='https://api.injahow.cn/meting/?server=:server&type=:type&id=:id&auth=:auth&r=:r';
      var meting_api='https://v.iarc.top/?server=:server&type=:type&id=:id&auth=:auth&r=:r';
    </script>
    <script src="https://fastly.jsdelivr.net/npm/meting@2.0.1/dist/Meting.min.js"></script>
{{ end }}

Byproducts of web searching