diff --git a/docs/architecture.md b/docs/architecture.md index 5ddc6ec8a..79532803d 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -107,4 +107,12 @@ However I think this is still feasible, considering I am providing user statisti --- +## Soundcloud music player + +I embedded [Soundcloud Widget API](https://developers.soundcloud.com/docs/api/html5-widget) on the header with some modifications. +I wrote some simple Javascript code to implement random music player. +For music sources, please [refer here](https://soundcloud.com/minsung-kim-mcdic/sets/blog-background-musics). + +--- + If there is anything you wonder, please ask in comments. diff --git a/docs/javascripts/musicplayer.js b/docs/javascripts/musicplayer.js new file mode 100644 index 000000000..f045f40c1 --- /dev/null +++ b/docs/javascripts/musicplayer.js @@ -0,0 +1,80 @@ +function getSC() { + var musicplayerElement = document.querySelector("iframe.soundcloud"); + if (musicplayerElement == null) { + return null; + } + return SC.Widget(musicplayerElement); +} + +async function musicplayerOnLoad() { + + // Private class for storing nonlocal static variables of music player + class MusicPlayerStaticVariables { + constructor(sc_widget) { + this.sc = sc_widget; + this.playlistLength = 1; + this.isPlaying = false; + this.ok_move = false; + } + + updateByGetters() { + this.ok_move = false; + this.sc.getSounds((sounds) => { + this.playlistLength = sounds.length; + this.sc.isPaused((paused) => { + this.isPlaying = !paused; + this.ok_move = true; + }) + }); + } + }; + + // Private function returning random integer in range [a, b) + function randomInt(a, b) { + return Math.floor(Math.random() * (b - a)) + a; + } + + // Private function waiting for condition to be true + async function whileWaiting(condition_callback, action_callback, timeout=200) { + while (!condition_callback()) { + await new Promise(resolve => setTimeout(resolve, timeout)); + if (action_callback != null) action_callback(); + } + } + + var widget = getSC(); + await whileWaiting(() => (widget != null), () => { widget = getSC(); }); + var controller_button = document.querySelector("header.md-header .music-player.mcdic"); + var musicState = new MusicPlayerStaticVariables(widget); + playButtonMode(); + + function playButtonMode() { + controller_button.classList.remove("pause-button"); + controller_button.classList.add("play-button"); + controller_button.title = "Play random music"; + } + + function stopButtonMode() { + controller_button.classList.remove("play-button"); + controller_button.classList.add("pause-button"); + controller_button.title = "Stop this music"; + } + + async function togglePlay() { + musicState.updateByGetters(); + await whileWaiting(() => musicState.ok_move, null); + if (musicState.isPlaying) { + widget.pause(); + playButtonMode(); + } else { + widget.skip(randomInt(0, musicState.playlistLength)); + widget.seekTo(0); + widget.setVolume(25); + widget.play(); + stopButtonMode(); + } + } + controller_button.addEventListener("click", () => togglePlay().then(null)); +} + +musicplayerOnLoad().then(null); diff --git a/docs/stylesheets/header.css b/docs/stylesheets/header.css index b0a89be2c..89089651c 100644 --- a/docs/stylesheets/header.css +++ b/docs/stylesheets/header.css @@ -16,3 +16,37 @@ header.md-header .auto-scroller:hover { cursor: pointer; opacity: 75%; } + +header.md-header .music-player { + display: flex; + width: 2.2rem; + height: 2.2rem; + float: inline-start; + fill: currentColor; + + svg { + width: 1.1rem; + height: 1.1rem; + margin: 0.55rem; + fill: currentColor; + } +} + +header.md-header .music-player.play-button { + background: url("/assets/icons/svgrepo/music_play.svg") no-repeat center/60%; +} + +header.md-header .music-player.pause-button { + background: url("/assets/icons/svgrepo/music_pause.svg") no-repeat center/60%; +} + +header.md-header .music-player:hover { + cursor: pointer; + opacity: 75%; +} + +header.md-header iframe.soundcloud { + visibility: hidden; + animation-duration: 0ms; + -webkit-animation-duration: 0ms; +} diff --git a/mkdocs.yml b/mkdocs.yml index a5039ac09..41e4ae732 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -118,6 +118,8 @@ extra_javascript: - https://polyfill.io/v3/polyfill.min.js?features=es6 - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js - javascripts/autoscroll.js + - https://w.soundcloud.com/player/api.js + - javascripts/musicplayer.js extra_css: - stylesheets/admonitions.css diff --git a/overrides/.icons/svgrepo/music_pause.svg b/overrides/.icons/svgrepo/music_pause.svg new file mode 100644 index 000000000..e7a4fbea9 --- /dev/null +++ b/overrides/.icons/svgrepo/music_pause.svg @@ -0,0 +1,2 @@ + + diff --git a/overrides/.icons/svgrepo/music_play.svg b/overrides/.icons/svgrepo/music_play.svg new file mode 100644 index 000000000..6b361b3c9 --- /dev/null +++ b/overrides/.icons/svgrepo/music_play.svg @@ -0,0 +1,2 @@ + + diff --git a/overrides/.icons/svgrepo/scroll.svg b/overrides/.icons/svgrepo/scroll.svg index 063829d0b..b3efa10fd 100644 --- a/overrides/.icons/svgrepo/scroll.svg +++ b/overrides/.icons/svgrepo/scroll.svg @@ -1,2 +1,2 @@ - + diff --git a/overrides/partials/header.html b/overrides/partials/header.html index c151803da..1bb0fc06f 100644 --- a/overrides/partials/header.html +++ b/overrides/partials/header.html @@ -52,6 +52,9 @@ + + {% include "partials/headers/musicplayer.html" %} + {% include "partials/headers/autoscroller.html" %} diff --git a/overrides/partials/headers/musicplayer.html b/overrides/partials/headers/musicplayer.html new file mode 100644 index 000000000..c2566ea80 --- /dev/null +++ b/overrides/partials/headers/musicplayer.html @@ -0,0 +1,7 @@ +
+