Widget:AudioPlayer2: Difference between revisions

From The Midnight Wiki
No edit summary
m (Text replacement - "f30b43" to "fd184e")
 
(91 intermediate revisions by the same user not shown)
Line 1: Line 1:
<noinclude>__NOTOC__
<noinclude>__NOTOC__
{{#widget:AudioPlayer2|mp3=/images/b/be/Lost_boy_v2_80_.mp3}}
{{#widget:AudioPlayer2|mp3=/images/5/5a/Gloria_rough_08.12.12_guide_.mp3}}


== Sample result ==
== Sample result ==
{{#widget:AudioPlayer2|mp3=https://themidnight.wiki/images/9/9e/Carl_Sagan_Show_Intro.mp3}}
 
</noinclude>
</noinclude>


<includeonly>
<includeonly>
<html>
<html>
<style>
.player {
  background: var(--tmw-after-gradient);
  width: 330px;
  height: 190px;
  position: relative;
  border-radius: 8px;
  box-shadow: -1px 4px 10px 5px hsl(216,100%,8%);
  z-index: 1;
}
.record {
  height: 175px;
  width: 175px;
  background-color: #181312;
  border-radius: 50%;
  position: absolute;
  top: 7px;
  left: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.record:before,
.record:after {
  position: absolute;
  content: "";
  border: 5px solid transparent;
  border-top-color: #2c2424;
  border-bottom-color: #2c2424;
  border-radius: 50%;
}
.record:before {
  height: 135px;
  width: 135px;
}
.record:after {
  height: 95px;
  width: 95px;
}
.player-label {
  background-color: #181312;
  height: 15px;
  width: 15px;
  border: 20px solid #fd184e;
  border-radius: 50%;
}


.tone-arm {
  height: 90px;
  width: 6px;
  background-color: #ffffff;
  position: absolute;
  top: 25px;
  right: 95px;
  transition: 1s;
  transform-origin: top;
}
.control {
  background-color: #181312;
  height: 17px;
  width: 17px;
  border: 10px solid #2c2c2c;
  border-radius: 50%;
  position: absolute;
  top: -16px;
  left: -16px;
}
.tone-arm:before {
  content: "";
  height: 40px;
  width: 6px;
  background-color: #ffffff;
  position: absolute;
  transform: rotate(30deg);
  bottom: -36px;
  right: 10px;
}
.tone-arm:after {
  content: "";
  position: absolute;
  height: 0;
  width: 10px;
  border-top: 18px solid #b2aea6;
  border-left: 2px solid transparent;
  border-right: 2px solid transparent;
  top: 108px;
  right: 12.5px;
  transform: rotate(30deg);
}
.btn {
  height: 28px;
  width: 28px;
  background-color: #d11b66;
  border-radius: 50%;
  position: absolute;
  bottom: 5px;
  left: 7px;
  border: 3.5px solid #95003d;
  outline: none;
  padding: 0 !important;
  cursor: pointer;
}
.slider {
  -webkit-appearance: none;
  appearance: none;
  transform: rotate(-90deg);
  width: 90px;
  height: 7px;
  position: absolute;
  left: 252px;
  top: 60px;
  background-color: #d11b66;
  outline: none;
  border-radius: 3px;
  border: 6px solid #95003d;
}
.slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 10px;
  height: 12px;
  background-color: #ffffff;
  cursor: pointer;
}
.play {
  transform: rotate(30deg);
  transform-origin: top;
  transition: 1s;
}
.on {
  animation: spin 3s 1s linear infinite;
}
@keyframes spin {
  100% {
    transform: rotate(360deg);
  }
}


        <style>
.player-wrapper .sign-logo {
            button {
    width: 120px;
                padding: 0;
    height: 50.14px;
                border: 0;
    right: 6px;
                background: transparent;
    top: 131px;
                cursor: pointer;
    filter: none;
                outline: none;
                width: 40px;
                height: 40px;
                float: left;
            }
            #audio-player-container {
                position: relative;
                margin: 100px 2.5% auto 2.5%;
                width: 95%;
                max-width: 500px;
                height: 132px;
                background: #fff;
                font-family: Arial, Helvetica, sans-serif;
                --seek-before-width: 0%;
                --volume-before-width: 100%;
                --buffered-width: 0%;
                letter-spacing: -0.5px;
            }
            #audio-player-container::before {
                position: absolute;
                content: '';
                width: calc(100% + 4px);
                height: calc(100% + 4px);
                left: -2px;
                top: -2px;
                background: linear-gradient(to left, #007db5, #ff8a00);
                z-index: -1;
            }
            p {
                position: absolute;
                top: -18px;
                right: 5%;
                padding: 0 5px;
                margin: 0;
                font-size: 28px;
                background: #fff;
            }
            #play-icon {
                margin: 20px 2.5% 10px 2.5%;
            }
            path {
                stroke: #007db5;
            }
            .time {
                display: inline-block;
                width: 37px;
                text-align: center;
                font-size: 20px;
                margin: 28.5px 0 18.5px 0;
                float: left;
            }
            output {
                display: inline-block;
                width: 32px;
                text-align: center;
                font-size: 20px;
                margin: 10px 2.5% 0 5%;
                float: left;
                clear: left;
            }
            #volume-slider {
                margin: 10px 2.5%;
                width: 58%;
            }
            #volume-slider::-webkit-slider-runnable-track {
                background: rgba(0, 125, 181, 0.6);
            }
            #volume-slider::-moz-range-track {
                background: rgba(0, 125, 181, 0.6);
            }
            #volume-slider::-ms-fill-upper {
                background: rgba(0, 125, 181, 0.6);
            }
            #volume-slider::before {
                width: var(--volume-before-width);
            }
            #mute-icon {
                margin: 0 2.5%;
            }
            input[type="range"] {
                position: relative;
                -webkit-appearance: none;
                width: 48%;
                margin: 0;
                padding: 0;
                height: 19px;
                margin: 30px 2.5% 20px 2.5%;
                float: left;
                outline: none;
            }
            input[type="range"]::-webkit-slider-runnable-track {
                width: 100%;
                height: 3px;
                cursor: pointer;
                background: linear-gradient(to right, rgba(0, 125, 181, 0.6) var(--buffered-width), rgba(0, 125, 181, 0.2) var(--buffered-width));
            }
            input[type="range"]::before {
                position: absolute;
                content: "";
                top: 8px;
                left: 0;
                width: var(--seek-before-width);
                height: 3px;
                background-color: #007db5;
                cursor: pointer;
            }
            input[type="range"]::-webkit-slider-thumb {
                position: relative;
                -webkit-appearance: none;
                box-sizing: content-box;
                border: 1px solid #007db5;
                height: 15px;
                width: 15px;
                border-radius: 50%;
                background-color: #fff;
                cursor: pointer;
                margin: -7px 0 0 0;
            }
            input[type="range"]:active::-webkit-slider-thumb {
                transform: scale(1.2);
                background: #007db5;
            }
            input[type="range"]::-moz-range-track {
                width: 100%;
                height: 3px;
                cursor: pointer;
                background: linear-gradient(to right, rgba(0, 125, 181, 0.6) var(--buffered-width), rgba(0, 125, 181, 0.2) var(--buffered-width));
            }
            input[type="range"]::-moz-range-progress {
                background-color: #007db5;
            }
            input[type="range"]::-moz-focus-outer {
                border: 0;
            }
            input[type="range"]::-moz-range-thumb {
                box-sizing: content-box;
                border: 1px solid #007db5;
                height: 15px;
                width: 15px;
                border-radius: 50%;
                background-color: #fff;
                cursor: pointer;
            }
            input[type="range"]:active::-moz-range-thumb {
                transform: scale(1.2);
                background: #007db5;
            }
            input[type="range"]::-ms-track {
                width: 100%;
                height: 3px;
                cursor: pointer;
                background: transparent;
                border: solid transparent;
                color: transparent;
            }
            input[type="range"]::-ms-fill-lower {
                background-color: #007db5;
            }
            input[type="range"]::-ms-fill-upper {
                background: linear-gradient(to right, rgba(0, 125, 181, 0.6) var(--buffered-width), rgba(0, 125, 181, 0.2) var(--buffered-width));
            }
            input[type="range"]::-ms-thumb {
                box-sizing: content-box;
                border: 1px solid #007db5;
                height: 15px;
                width: 15px;
                border-radius: 50%;
                background-color: #fff;
                cursor: pointer;
            }
            input[type="range"]:active::-ms-thumb {
                transform: scale(1.2);
                background: #007db5;
            }
        </style>
<script>
import lottieWeb from 'https://cdn.skypack.dev/lottie-web';
 
class AudioPlayer extends HTMLElement {
    constructor() {
        super();
        const template = document.querySelector('template');
        const templateContent = template.content;
        const shadow = this.attachShadow({mode: 'open'});
        shadow.appendChild(templateContent.cloneNode(true));
    }
 
    connectedCallback() {
        everything(this);
    }
}
}


const everything = function(element) { 
.player-wrapper {
  const shadow = element.shadowRoot;
     display: flex;
 
     flex-direction: column;
    const audioPlayerContainer = shadow.getElementById('audio-player-container');
     align-items: center;
    const playIconContainer = shadow.getElementById('play-icon');
    const seekSlider = shadow.getElementById('seek-slider');
    const volumeSlider = shadow.getElementById('volume-slider');
    const muteIconContainer = shadow.getElementById('mute-icon');
    const audio = shadow.querySelector('audio');
    const durationContainer = shadow.getElementById('duration');
    const currentTimeContainer = shadow.getElementById('current-time');
    const outputContainer = shadow.getElementById('volume-output');
    let playState = 'play';
    let muteState = 'unmute';
    let raf = null;
 
    audio.src = element.getAttribute('data-src');
 
    const playAnimation = lottieWeb.loadAnimation({
        container: playIconContainer,
        path: 'https://maxst.icons8.com/vue-static/landings/animated-icons/icons/pause/pause.json',
        renderer: 'svg',
        loop: false,
        autoplay: false,
        name: "Play Animation",
     });
         
    const muteAnimation = lottieWeb.loadAnimation({
        container: muteIconContainer,
        path: 'https://maxst.icons8.com/vue-static/landings/animated-icons/icons/mute/mute.json',
        renderer: 'svg',
        loop: false,
        autoplay: false,
        name: "Mute Animation",
    });
         
     playAnimation.goToAndStop(14, true);
 
    const whilePlaying = () => {
        seekSlider.value = Math.floor(audio.currentTime);
        currentTimeContainer.textContent = calculateTime(seekSlider.value);
        audioPlayerContainer.style.setProperty('--seek-before-width', `${seekSlider.value / seekSlider.max * 100}%`);
        raf = requestAnimationFrame(whilePlaying);
    }
 
    const showRangeProgress = (rangeInput) => {
        if(rangeInput === seekSlider) audioPlayerContainer.style.setProperty('--seek-before-width', rangeInput.value / rangeInput.max * 100 + '%');
        else audioPlayerContainer.style.setProperty('--volume-before-width', rangeInput.value / rangeInput.max * 100 + '%');
    }
 
    const calculateTime = (secs) => {
        const minutes = Math.floor(secs / 60);
        const seconds = Math.floor(secs % 60);
        const returnedSeconds = seconds < 10 ? `0${seconds}` : `${seconds}`;
        return `${minutes}:${returnedSeconds}`;
     }
       
    const displayDuration = () => {
        durationContainer.textContent = calculateTime(audio.duration);
    }
       
    const setSliderMax = () => {
        seekSlider.max = Math.floor(audio.duration);
    }
       
    const displayBufferedAmount = () => {
        const bufferedAmount = Math.floor(audio.buffered.end(audio.buffered.length - 1));
        audioPlayerContainer.style.setProperty('--buffered-width', `${(bufferedAmount / seekSlider.max) * 100}%`);
    }
 
    if (audio.readyState > 0) {
        displayDuration();
        setSliderMax();
        displayBufferedAmount();
    } else {
        audio.addEventListener('loadedmetadata', () => {
            displayDuration();
            setSliderMax();
            displayBufferedAmount();
        });
    }
 
    playIconContainer.addEventListener('click', () => {
        if(playState === 'play') {
            audio.play();
            playAnimation.playSegments([14, 27], true);
            requestAnimationFrame(whilePlaying);
            playState = 'pause';
        } else {
            audio.pause();
            playAnimation.playSegments([0, 14], true);
            cancelAnimationFrame(raf);
            playState = 'play';
        }
    });
       
    muteIconContainer.addEventListener('click', () => {
        if(muteState === 'unmute') {
            muteAnimation.playSegments([0, 15], true);
            audio.muted = true;
            muteState = 'mute';
        } else {
            muteAnimation.playSegments([15, 25], true);
            audio.muted = false;
            muteState = 'unmute';
        }
    });
 
    audio.addEventListener('progress', displayBufferedAmount);
 
    seekSlider.addEventListener('input', (e) => {
        showRangeProgress(e.target);
        currentTimeContainer.textContent = calculateTime(seekSlider.value);
        if(!audio.paused) {
            cancelAnimationFrame(raf);
        }
    });
 
    seekSlider.addEventListener('change', () => {
        audio.currentTime = seekSlider.value;
        if(!audio.paused) {
            requestAnimationFrame(whilePlaying);
        }
    });
 
    volumeSlider.addEventListener('input', (e) => {
        const value = e.target.value;
        showRangeProgress(e.target);
        outputContainer.textContent = value;
        audio.volume = value / 100;
    });
 
    if('mediaSession' in navigator) {
        navigator.mediaSession.metadata = new MediaMetadata({
            title: 'Komorebi',
            artist: 'Anitek',
            album: 'MainStay',
            artwork: [
                { src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '96x96', type: 'image/png' },
                { src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '128x128', type: 'image/png' },
                { src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '192x192', type: 'image/png' },
                { src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '256x256', type: 'image/png' },
                { src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '384x384', type: 'image/png' },
                { src: 'https://assets.codepen.io/4358584/1.300.jpg', sizes: '512x512', type: 'image/png' }
            ]
        });
        navigator.mediaSession.setActionHandler('play', () => {
            if(playState === 'play') {
                audio.play();
                playAnimation.playSegments([14, 27], true);
                requestAnimationFrame(whilePlaying);
                playState = 'pause';
            } else {
                audio.pause();
                playAnimation.playSegments([0, 14], true);
                cancelAnimationFrame(raf);
                playState = 'play';
            }
        });
        navigator.mediaSession.setActionHandler('pause', () => {
            if(playState === 'play') {
                audio.play();
                playAnimation.playSegments([14, 27], true);
                requestAnimationFrame(whilePlaying);
                playState = 'pause';
            } else {
                audio.pause();
                playAnimation.playSegments([0, 14], true);
                cancelAnimationFrame(raf);
                playState = 'play';
            }
        });
        navigator.mediaSession.setActionHandler('seekbackward', (details) => {
            audio.currentTime = audio.currentTime - (details.seekOffset || 10);
        });
        navigator.mediaSession.setActionHandler('seekforward', (details) => {
            audio.currentTime = audio.currentTime + (details.seekOffset || 10);
        });
        navigator.mediaSession.setActionHandler('seekto', (details) => {
            if (details.fastSeek && 'fastSeek' in audio) {
              audio.fastSeek(details.seekTime);
              return;
            }
            audio.currentTime = details.seekTime;
        });
        navigator.mediaSession.setActionHandler('stop', () => {
            audio.currentTime = 0;
            seekSlider.value = 0;
            audioPlayerContainer.style.setProperty('--seek-before-width', '0%');
            currentTimeContainer.textContent = '0:00';
            if(playState === 'pause') {
                playAnimation.playSegments([0, 14], true);
                cancelAnimationFrame(raf);
                playState = 'play';
            }
        });
    }
}
}
 
</style>
customElements.define('audio-player', AudioPlayer);
  <div class="player-wrapper">
</script>
    <div class="player">
         <div id="audio-player-container">
      <div class="record">
            <audio src="" preload="metadata" loop></audio>
         <div class="player-label"></div>
            <p>audio player ish</p>
      </div>
            <button id="play-icon"></button>
      <div class="tone-arm">
            <span id="current-time" class="time">0:00</span>
        <div class="control"></div>
            <input type="range" id="seek-slider" max="100" value="0">
      </div>
            <span id="duration" class="time">0:00</span>
      <button class="btn"></button>
            <output id="volume-output">100</output>
      <div class="slider-container">
            <input type="range" id="volume-slider" max="100" value="100">
        <input
            <button id="mute-icon"></button>
          type="range"
        </div>
          class="slider"
<audio-player data-src="<!--{$mp3|escape:'urlpathinfo'}-->"></audio-player>
          min="0"
          max="1"
          step="0.1"
          value="0.7"
        />
      </div>
    <img alt="logo" width="347" height="145" class="sign-logo" src="https://themidnight.wiki/images/2/24/The_Midnight_Wiki_Logo_2023.png" />
    </div>
    <audio loop class="my-song" src="<!--{$mp3|escape:'urlpathinfo'}-->" preload="auto"></audio>
  <p style="margin-bottom: 0;"><em>Press the button to play/pause</em></p>
  <p style="margin: 0;"><em>Adjust volume with slider</em></p>
  </div>
</html>
</html>
</includeonly>
</includeonly>

Latest revision as of 22:14, 1 April 2024

Press the button to play/pause

Adjust volume with slider

Press the button to play/pause

Adjust volume with slider

Sample result