- // ==UserScript==
- // @name audio player
- // @namespace http://tampermonkey.net/
- // @version 0.41
- // @description Add a audio player to listen audio without leaving current page.
- // @author oshibuki
- // @match https://t-nagano.com/projects/JapaneseGenki3rdEdAudio/
- // @icon https://www.google.com/s2/favicons?sz=64&domain=t-nagano.com
- // @grant none
- // @license MIT
- // ==/UserScript==
-
- (function() {
- 'use strict';
- // Your CSS code here
- var style = document.createElement('style');
- style.type = "text/css";
- var content = `
- *,
- *::before,
- *::after {
- box-sizing: border-box;
- }
-
- body {
- margin: 0;
- padding: 0;
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
- font-size: 14px;
- }
-
- pre, code {
- font-family: Consolas, Courier, monospace;
- font-size: inherit;
- color: #333;
- background: #fafafa;
- }
-
- pre {
- padding: 1rem;
- border: 1px solid #eee;
- overflow: auto;
- }
-
- .container-fluid {
- padding-bottom:50px;
- }
-
- /*-----------------------
- Audio Player - AP
- ------------------------*/
- .ap {
- position: fixed;
- left: 0;
- right: 0;
- bottom: 0;
- width: 100%;
- height: 50px;
- font-family: inherit;
- font-size: 14px;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- border-top: 1px solid #ccc;
- background: #f2f2f2;
- box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1);
- z-index: 99999;
- }
-
- .ap__inner {
- display: flex;
- max-width: 1440px;
- margin: auto;
- }
-
- .ap__item {
- display: flex;
- flex: 1;
- justify-content: center;
- align-items: center;
- }
-
- .ap__item--playback > .ap__controls,
- .ap__item--settings > .ap__controls {
- flex: 0 25%;
- }
-
- @-webkit-keyframes fs {
- 0% {
- opacity: 0;
- transform: scale(0.5);
- }
- 100% {
- opacity: 1;
- transform: scale(1);
- }
- }
-
- @keyframes fs {
- 0% {
- opacity: 0;
- transform: scale(0.5);
- }
- 100% {
- opacity: 1;
- transform: scale(1);
- }
- }
- .ap__item--track {
- flex: 1 40%;
- padding: 0 20px;
- }
-
- .track {
- position: relative;
- width: 100%;
- align-self: flex-start;
- padding: 5px 0 0;
- }
-
- .track__title {
- position: absolute;
- width: 100%;
- overflow: hidden;
- padding-right: 80px;
- text-align: left;
- white-space: nowrap;
- text-overflow: ellipsis;
- }
-
- .track__time {
- position: absolute;
- top: 5px;
- right: 0;
- }
-
- .progress-container {
- position: relative;
- padding: 7px 0;
- margin-top: 15px;
- overflow: hidden;
- cursor: pointer;
- }
- .progress-container:hover .progress__bar:after {
- opacity: 1;
- }
-
- .progress {
- height: 3px;
- border-radius: 3px;
- background: #ddd;
- }
-
- .progress__bar,
- .progress__preload {
- position: absolute;
- width: 0;
- height: 3px;
- border-radius: 3px 0 0 3px;
- }
-
- .progress__bar {
- background: steelblue;
- z-index: 1;
- }
- .progress__bar:after {
- position: absolute;
- top: 0;
- right: -10px;
- width: 10px;
- height: 10px;
- margin-top: -3px;
- content: "";
- border-radius: 6px;
- background: steelblue;
- opacity: 0;
- transition: opacity 0.3s ease;
- }
-
- .progress__bar--active:after {
- transform: scale(1.4);
- }
-
- .progress__preload {
- background: #c4c4c4;
- z-index: 0;
- }
-
- .ap__controls,
- .ap button {
- margin: 0;
- padding: 0;
- border: 0;
- outline: 0;
- background: transparent;
- position: relative;
- display: block;
- height: 50px;
- text-align: center;
- cursor: pointer;
- transition: background 0.3s ease;
- }
- .ap__controls:active,
- .ap button:active {
- background: rgba(0, 0, 0, 0.1);
- }
- .ap__controls:hover,
- .ap button:hover {
- opacity: 1;
- }
- .ap__controls--playlist {
- display: none;
- }
- .icon-play > path {
- transition: all 0.3s ease;
- }
-
- .is-playing .icon-play {
- fill: steelblue;
- }
-
- .volume-btn {
- display: block;
- text-align: center;
- width: 100%;
- }
-
- .volume {
- position: absolute;
- left: 50%;
- bottom: 45px;
- width: 40px;
- margin-left: -20px;
- height: 120px;
- opacity: 0;
- visibility: hidden;
- transform: translateY(10px);
- transition: all 0.3s cubic-bezier(0.17, 0.72, 0.26, 1.23);
- background: #f2f2f2;
- border: 1px solid #ccc;
- border-radius: 1px;
- z-index: 88888;
- }
- .volume::before, .volume::after {
- content: "";
- position: absolute;
- bottom: -12px;
- border: 7px solid transparent;
- border-top: 7px solid #f2f2f2;
- left: 50%;
- margin-left: -7px;
- }
- .volume::after {
- bottom: -14px;
- z-index: -1;
- border-top: 7px solid #ccc;
- }
-
- .volume-container:hover .volume {
- opacity: 1;
- transform: translateY(0);
- visibility: visible;
- }
-
- .volume__track {
- position: relative;
- display: block;
- width: 3px;
- height: 100px;
- margin: 10px auto;
- background: #ddd;
- border-radius: 3px;
- overflow: hidden;
- }
-
- .volume__bar {
- position: absolute;
- left: 0;
- right: 0;
- bottom: 0;
- background: steelblue;
- height: 50%;
- }
-
- .icon-volume-off {
- display: none;
- }
-
- .has-muted .icon-volume-on {
- display: none;
- }
- .has-muted .icon-volume-off {
- display: inline;
- opacity: 0.7;
- }
-
- .ap__controls.is-active > svg {
- fill: steelblue;
- filter: drop-shadow(0 0 3px rgba(70, 130, 180, 0.4));
- }
-
- @media (max-width: 1024px) {
- .ap__item > .ap__controls {
- flex: 1;
- }
- }
- @media (max-width: 580px) {
- .ap {
- min-width: 250px;
- }
-
- .ap, .ap__inner {
- height: auto;
- }
-
- .ap__inner {
- flex-wrap: wrap;
- }
-
- .ap__item--track {
- margin-bottom: 10px;
- padding: 0 20px;
- order: 1;
- flex: 1 1 100%;
- }
-
- .ap__item--playback,
- .ap__item--settings {
- flex: 1 1 50%;
- order: 2;
- }
- }
- /*-----------------------
- Playlist Player - PL
- ------------------------*/
- .pl-container {
- display: none;
- position: fixed;
- top: 0;
- right: 0;
- bottom: 50px;
- left: 0;
- overflow: auto;
- font-family: inherit;
- font-size: 14px;
- background: #fff;
- z-index: 77777;
- }
-
- .pl-ul {
- width: 100%;
- max-width: 550px;
- margin: 0 auto;
- padding: 30px 10px 100px 10px;
- }
-
- .pl-list {
- display: flex;
- align-items: center;
- height: 40px;
- line-height: 40px;
- }
- .pl-list svg {
- fill: steelblue;
- }
-
- .pl-list + .pl-list {
- border-top: 1px solid #eee;
- }
-
- .pl-list:not(.pl-list--current):hover {
- background: #f6f6f6;
- }
-
- .pl-list__track,
- .pl-list__remove {
- flex: 0 50px;
- text-align: center;
- }
-
- .pl-list__icon {
- display: inline-block;
- width: 0;
- height: 0;
- border-top: 5px solid transparent;
- border-bottom: 5px solid transparent;
- border-left: 8px solid #555;
- }
-
- .pl-list__title {
- overflow: hidden;
- padding-right: 10px;
- cursor: pointer;
- text-align: left;
- white-space: nowrap;
- text-overflow: ellipsis;
- flex: 1;
- }
-
- .pl-list__remove {
- height: 100%;
- background: transparent;
- border: 0;
- outline: 0;
- cursor: pointer;
- opacity: 0;
- transition: opacity 0.2s ease;
- }
-
- .pl-list__remove > svg {
- width: 16px;
- height: 16px;
- }
-
- .pl-list__eq {
- display: none;
- }
-
- .pl-list--current {
- background: steelblue;
- color: #fff;
- }
-
- .pl-list--current svg {
- fill: #fff;
- }
- .pl-list--current .pl-list__eq {
- display: block;
- }
- .pl-list--current .pl-list__icon {
- display: none;
- }
-
- .pl-list:hover .pl-list__remove,
- .pl-list--current .pl-list__remove {
- opacity: 1;
- }
-
- .pl-list--current .pl-list__remove:hover {
- background: #3f75a2;
- }
-
- .pl-list--empty {
- position: absolute;
- top: 50%;
- left: 50%;
- font-size: 2rem;
- transform: translate(-50%, -50%);
- letter-spacing: 2px;
- color: #ccc;
- }
-
- @-webkit-keyframes eq {
- 0% {
- height: 3px;
- }
- 50% {
- height: 20px;
- }
- 100% {
- height: 3px;
- }
- }
-
- @keyframes eq {
- 0% {
- height: 3px;
- }
- 50% {
- height: 20px;
- }
- 100% {
- height: 3px;
- }
- }
- .eq {
- display: flex;
- width: 20px;
- height: 20px;
- margin: 0 auto;
- justify-content: space-between;
- align-items: flex-end;
- }
-
- .eq__bar {
- width: 4px;
- background: #fff;
- filter: drop-shadow(0 0 5px #fff);
- }
-
- .eq__bar:nth-child(1) {
- -webkit-animation: eq 0.8s ease-in-out infinite 0s;
- animation: eq 0.8s ease-in-out infinite 0s;
- }
-
- .eq__bar:nth-child(2) {
- -webkit-animation: eq 0.8s ease-in-out infinite 0.2s;
- animation: eq 0.8s ease-in-out infinite 0.2s;
- }
-
- .eq__bar:nth-child(3) {
- -webkit-animation: eq 0.8s ease-in-out infinite 0.4s;
- animation: eq 0.8s ease-in-out infinite 0.4s;
- }
-
- .h-hide {
- display: none;
- }
-
- .h-show {
- display: block;
- }
- `;
- if (style.styleSheet) {
- style.styleSheet.cssText = content;
- } else {
- style.appendChild(document.createTextNode(content));
- }
- document.head.append(style);
-
- var myDiv = document.createElement('div');
- myDiv.innerHTML = `
- <!-- Audio player -->
- <div class="ap" id="ap">
- <div class="ap__inner">
- <div class="ap__item ap__item--playback">
- <button class="ap__controls ap__controls--prev">
- <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#333" width="24" height="24" viewBox="0 0 24 24">
- <path d="M9.516 12l8.484-6v12zM6 6h2.016v12h-2.016v-12z"></path>
- </svg>
- </button>
- <button class="ap__controls ap__controls--toggle">
- <svg class="icon-play" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#333" width="36" height="36" viewBox="0 0 36 36" data-play="M 12,26 18.5,22 18.5,14 12,10 z M 18.5,22 25,18 25,18 18.5,14 z" data-pause="M 12,26 16.33,26 16.33,10 12,10 z M 20.66,26 25,26 25,10 20.66,10 z">
- <path d="M 12,26 18.5,22 18.5,14 12,10 z M 18.5,22 25,18 25,18 18.5,14 z"></path>
- </svg>
- </button>
- <button class="ap__controls ap__controls--next">
- <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#333" width="24" height="24" viewBox="0 0 24 24">
- <path d="M15.984 6h2.016v12h-2.016v-12zM6 18v-12l8.484 6z"></path>
- </svg>
- </button>
- </div>
- <div class="ap__item ap__item--track">
- <div class="track">
- <div class="track__title">Queue is empty</div>
- <div class="track__time">
- <span class="track__time--current">--</span>
- <span> / </span>
- <span class="track__time--duration">--</span>
- </div>
-
- <div class="progress-container">
- <div class="progress">
- <div class="progress__bar"></div>
- <div class="progress__preload"></div>
- </div>
- </div>
-
- </div>
- </div>
- <div class="ap__item ap__item--settings">
- <div class="ap__controls volume-container">
- <button class="volume-btn">
- <svg class="icon-volume-on" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#333" width="24" height="24" viewBox="0 0 24 24">
- <path d="M14.016 3.234q3.047 0.656 5.016 3.117t1.969 5.648-1.969 5.648-5.016 3.117v-2.063q2.203-0.656 3.586-2.484t1.383-4.219-1.383-4.219-3.586-2.484v-2.063zM16.5 12q0 2.813-2.484 4.031v-8.063q2.484 1.219 2.484 4.031zM3 9h3.984l5.016-5.016v16.031l-5.016-5.016h-3.984v-6z"></path>
- </svg>
- <svg class="icon-volume-off" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#333" width="24" height="24" viewBox="0 0 24 24">
- <path d="M12 3.984v4.219l-2.109-2.109zM4.266 3l16.734 16.734-1.266 1.266-2.063-2.063q-1.734 1.359-3.656 1.828v-2.063q1.172-0.328 2.25-1.172l-4.266-4.266v6.75l-5.016-5.016h-3.984v-6h4.734l-4.734-4.734zM18.984 12q0-2.391-1.383-4.219t-3.586-2.484v-2.063q3.047 0.656 5.016 3.117t1.969 5.648q0 2.25-1.031 4.172l-1.5-1.547q0.516-1.266 0.516-2.625zM16.5 12q0 0.422-0.047 0.609l-2.438-2.438v-2.203q2.484 1.219 2.484 4.031z"></path>
- </svg>
- </button>
- <div class="volume">
- <div class="volume__track">
- <div class="volume__bar"></div>
- </div>
- </div>
- </div>
- <button class="ap__controls ap__controls--repeat">
- <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#333" width="24" height="24" viewBox="0 0 24 24">
- <path d="M17.016 17.016v-4.031h1.969v6h-12v3l-3.984-3.984 3.984-3.984v3h10.031zM6.984 6.984v4.031h-1.969v-6h12v-3l3.984 3.984-3.984 3.984v-3h-10.031z"></path>
- </svg>
- </button>
- <button class="ap__controls ap__controls--playlist" style="display:none;">
- <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="#333" width="24" height="24" viewBox="0 0 24 24">
- <path d="M17.016 12.984l4.969 3-4.969 3v-6zM2.016 15v-2.016h12.984v2.016h-12.984zM18.984 5.016v1.969h-16.969v-1.969h16.969zM18.984 9v2.016h-16.969v-2.016h16.969z"></path>
- </svg>
- </button>
- </div>
- </div>
- </div>
- `;
- var mainContent = document.getElementById('page-content-wrapper')
- mainContent.appendChild(myDiv);
-
- (function(window, undefined) {
-
- 'use strict';
-
- var AudioPlayer = (function() {
-
- // Player vars!
- var
- docTitle = document.title,
- player = document.getElementById('ap'),
- playBtn,
- playSvg,
- playSvgPath,
- prevBtn,
- nextBtn,
- plBtn,
- repeatBtn,
- volumeBtn,
- progressBar,
- preloadBar,
- curTime,
- durTime,
- trackTitle,
- audio,
- index = 0,
- playList,
- volumeBar,
- wheelVolumeValue = 0,
- volumeLength,
- repeating = false,
- seeking = false,
- seekingVol = false,
- rightClick = false,
- apActive = false,
- // playlist vars
- pl,
- plUl,
- plLi,
- tplList =
- '<li class="pl-list" data-track="{count}">'+
- '<div class="pl-list__track">'+
- '<div class="pl-list__icon"></div>'+
- '<div class="pl-list__eq">'+
- '<div class="eq">'+
- '<div class="eq__bar"></div>'+
- '<div class="eq__bar"></div>'+
- '<div class="eq__bar"></div>'+
- '</div>'+
- '</div>'+
- '</div>'+
- '<div class="pl-list__title">{title}</div>'+
- '<button class="pl-list__remove">'+
- '<svg fill="#000000" height="20" viewBox="0 0 24 24" width="20" xmlns="http://www.w3.org/2000/svg">'+
- '<path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/>'+
- '<path d="M0 0h24v24H0z" fill="none"/>'+
- '</svg>'+
- '</button>'+
- '</li>',
- // settings
- settings = {
- volume : 0.1,
- changeDocTitle: true,
- confirmClose : true,
- autoPlay : false,
- buffered : true,
- notification : true,
- playList : []
- };
-
- function init(options) {
-
- if(!('classList' in document.documentElement)) {
- return false;
- }
-
- if(apActive || player === null) {
- return 'Player already init';
- }
-
- settings = extend(settings, options);
-
- // get player elements
- playBtn = player.querySelector('.ap__controls--toggle');
- playSvg = playBtn.querySelector('.icon-play');
- playSvgPath = playSvg.querySelector('path');
- prevBtn = player.querySelector('.ap__controls--prev');
- nextBtn = player.querySelector('.ap__controls--next');
- repeatBtn = player.querySelector('.ap__controls--repeat');
- volumeBtn = player.querySelector('.volume-btn');
- plBtn = player.querySelector('.ap__controls--playlist');
- curTime = player.querySelector('.track__time--current');
- durTime = player.querySelector('.track__time--duration');
- trackTitle = player.querySelector('.track__title');
- progressBar = player.querySelector('.progress__bar');
- preloadBar = player.querySelector('.progress__preload');
- volumeBar = player.querySelector('.volume__bar');
-
- playList = settings.playList;
-
- playBtn.addEventListener('click', playToggle, false);
- volumeBtn.addEventListener('click', volumeToggle, false);
- repeatBtn.addEventListener('click', repeatToggle, false);
-
- progressBar.closest('.progress-container').addEventListener('mousedown', handlerBar, false);
- progressBar.closest('.progress-container').addEventListener('mousemove', seek, false);
-
- document.documentElement.addEventListener('mouseup', seekingFalse, false);
-
- volumeBar.closest('.volume').addEventListener('mousedown', handlerVol, false);
- volumeBar.closest('.volume').addEventListener('mousemove', setVolume);
- volumeBar.closest('.volume').addEventListener(wheel(), setVolume, false);
-
- prevBtn.addEventListener('click', prev, false);
- nextBtn.addEventListener('click', next, false);
-
- apActive = true;
-
- // Create playlist
- renderPL();
- plBtn.addEventListener('click', plToggle, false);
-
- // Create audio object
- audio = new Audio();
- audio.volume = settings.volume;
- audio.preload = 'auto';
- audio.id='audio'
-
- audio.addEventListener('error', errorHandler, false);
- audio.addEventListener('timeupdate', timeUpdate, false);
- audio.addEventListener('ended', doEnd, false);
-
- volumeBar.style.height = audio.volume * 100 + '%';
- volumeLength = volumeBar.css('height');
-
- if(settings.confirmClose) {
- window.addEventListener("beforeunload", beforeUnload, false);
- }
-
- if(isEmptyList()) {
- return false;
- }
- audio.src = playList[index].file;
- trackTitle.innerHTML = playList[index].title;
- document.body.append(audio)
-
- if(settings.autoPlay) {
- audio.play();
- playBtn.classList.add('is-playing');
- playSvgPath.setAttribute('d', playSvg.getAttribute('data-pause'));
- plLi[index].classList.add('pl-list--current');
- notify(playList[index].title, {
- icon: playList[index].icon,
- body: 'Now playing'
- });
- }
- }
-
- function changeDocumentTitle(title) {
- if(settings.changeDocTitle) {
- if(title) {
- document.title = title;
- }
- else {
- document.title = docTitle;
- }
- }
- }
-
- function beforeUnload(evt) {
- if(!audio.paused) {
- var message = 'Music still playing';
- evt.returnValue = message;
- return message;
- }
- }
-
- function errorHandler(evt) {
- if(isEmptyList()) {
- return;
- }
- var mediaError = {
- '1': 'MEDIA_ERR_ABORTED',
- '2': 'MEDIA_ERR_NETWORK',
- '3': 'MEDIA_ERR_DECODE',
- '4': 'MEDIA_ERR_SRC_NOT_SUPPORTED'
- };
- audio.pause();
- curTime.innerHTML = '--';
- durTime.innerHTML = '--';
- progressBar.style.width = 0;
- preloadBar.style.width = 0;
- playBtn.classList.remove('is-playing');
- playSvgPath.setAttribute('d', playSvg.getAttribute('data-play'));
- plLi[index] && plLi[index].classList.remove('pl-list--current');
- changeDocumentTitle();
- throw new Error('Houston we have a problem: ' + mediaError[evt.target.error.code]);
- }
-
- /**
- * UPDATE PL
- */
- function updatePL(addList) {
- if(!apActive) {
- return 'Player is not yet initialized';
- }
- if(!Array.isArray(addList)) {
- return;
- }
- if(addList.length === 0) {
- return;
- }
-
- var count = playList.length;
- var html = [];
- playList = addList
- audio.src = playList[index].file;
- trackTitle.innerHTML = playList[index].title;
- audio.currentTime = 0
- audio.pause()
- playToggle()
- }
-
- /**
- * PlayList methods
- */
- function renderPL() {
- var html = [];
-
- playList.forEach(function(item, i) {
- html.push(
- tplList.replace('{count}', i).replace('{title}', item.title)
- );
- });
-
- pl = create('div', {
- 'className': 'pl-container',
- 'id': 'pl',
- 'innerHTML': '<ul class="pl-ul">' + (!isEmptyList() ? html.join('') : '<li class="pl-list--empty">PlayList is empty</li>') + '</ul>'
- });
-
- player.parentNode.insertBefore(pl, player.nextSibling);
-
- plUl = pl.querySelector('.pl-ul');
- plLi = plUl.querySelectorAll('li');
-
- pl.addEventListener('click', listHandler, false);
- }
-
- function listHandler(evt) {
- evt.preventDefault();
-
- if(evt.target.matches('.pl-list__title') || evt.target.matches('.pl-list__track')) {
- var current = parseInt(evt.target.closest('.pl-list').getAttribute('data-track'), 10);
- if(index !== current) {
- index = current;
- play(current);
- }
- else {
- playToggle();
- }
- }
- else {
- if(!!evt.target.closest('.pl-list__remove')) {
- var parentEl = evt.target.closest('.pl-list');
- var isDel = parseInt(parentEl.getAttribute('data-track'), 10);
-
- playList.splice(isDel, 1);
- parentEl.closest('.pl-ul').removeChild(parentEl);
-
- plLi = pl.querySelectorAll('li');
-
- [].forEach.call(plLi, function(el, i) {
- el.setAttribute('data-track', i);
- });
-
- if(!audio.paused) {
-
- if(isDel === index) {
- play(index);
- }
-
- }
- else {
- if(isEmptyList()) {
- clearAll();
- }
- else {
- if(isDel === index) {
- if(isDel > playList.length - 1) {
- index -= 1;
- }
- audio.src = playList[index].file;
- trackTitle.innerHTML = playList[index].title;
- progressBar.style.width = 0;
- }
- }
- }
- if(isDel < index) {
- index--;
- }
- }
-
- }
- }
-
- function plActive() {
- if(audio.paused) {
- plLi[index].classList.remove('pl-list--current');
- return;
- }
- var current = index;
- for(var i = 0, len = plLi.length; len > i; i++) {
- plLi[i].classList.remove('pl-list--current');
- }
- plLi[current].classList.add('pl-list--current');
- }
-
-
- /**
- * Player methods
- */
- function play(currentIndex) {
-
- if(isEmptyList()) {
- return clearAll();
- }
-
- index = 0;
-
- audio.src = playList[index].file;
- trackTitle.innerHTML = playList[index].title;
-
- // Change document title
- changeDocumentTitle(playList[index].title);
-
- // Audio play
- audio.play();
-
- // Show notification
- notify(playList[index].title, {
- icon: playList[index].icon,
- body: 'Now playing',
- tag: 'music-player'
- });
-
- // Toggle play button
- playBtn.classList.add('is-playing');
- playSvgPath.setAttribute('d', playSvg.getAttribute('data-pause'));
-
- // Set active song playlist
- plActive();
- }
-
- function prev() {
- play(index - 1);
- }
-
- function next() {
- play(index + 1);
- }
-
- function isEmptyList() {
- return playList.length === 0;
- }
-
- function clearAll() {
- audio.pause();
- audio.src = '';
- trackTitle.innerHTML = 'queue is empty';
- curTime.innerHTML = '--';
- durTime.innerHTML = '--';
- progressBar.style.width = 0;
- preloadBar.style.width = 0;
- playBtn.classList.remove('is-playing');
- playSvgPath.setAttribute('d', playSvg.getAttribute('data-play'));
- if(!plUl.querySelector('.pl-list--empty')) {
- plUl.innerHTML = '<li class="pl-list--empty">PlayList is empty</li>';
- }
- changeDocumentTitle();
- }
-
- function playToggle() {
- if(isEmptyList()) {
- return;
- }
- if(audio.paused) {
-
- if(audio.currentTime === 0) {
- notify(playList[index].title, {
- icon: playList[index].icon,
- body: 'Now playing'
- });
- }
- changeDocumentTitle(playList[index].title);
-
- audio.play();
-
- playBtn.classList.add('is-playing');
- playSvgPath.setAttribute('d', playSvg.getAttribute('data-pause'));
- }
- else {
- changeDocumentTitle();
- audio.pause();
- playBtn.classList.remove('is-playing');
- playSvgPath.setAttribute('d', playSvg.getAttribute('data-play'));
- }
- plActive();
- }
-
- function volumeToggle() {
- if(audio.muted) {
- if(parseInt(volumeLength, 10) === 0) {
- volumeBar.style.height = settings.volume * 100 + '%';
- audio.volume = settings.volume;
- }
- else {
- volumeBar.style.height = volumeLength;
- }
- audio.muted = false;
- volumeBtn.classList.remove('has-muted');
- }
- else {
- audio.muted = true;
- volumeBar.style.height = 0;
- volumeBtn.classList.add('has-muted');
- }
- }
-
- function repeatToggle() {
- if(repeatBtn.classList.contains('is-active')) {
- repeating = false;
- repeatBtn.classList.remove('is-active');
- }
- else {
- repeating = true;
- repeatBtn.classList.add('is-active');
- }
- }
-
- function plToggle() {
- plBtn.classList.toggle('is-active');
- pl.classList.toggle('h-show');
- }
-
- function timeUpdate() {
- if(audio.readyState === 0 || seeking) return;
-
- var barlength = Math.round(audio.currentTime * (100 / audio.duration));
- progressBar.style.width = barlength + '%';
-
- var
- curMins = Math.floor(audio.currentTime / 60),
- curSecs = Math.floor(audio.currentTime - curMins * 60),
- mins = Math.floor(audio.duration / 60),
- secs = Math.floor(audio.duration - mins * 60);
- (curSecs < 10) && (curSecs = '0' + curSecs);
- (secs < 10) && (secs = '0' + secs);
-
- curTime.innerHTML = curMins + ':' + curSecs;
- durTime.innerHTML = mins + ':' + secs;
-
- if(settings.buffered) {
- var buffered = audio.buffered;
- if(buffered.length) {
- var loaded = Math.round(100 * buffered.end(0) / audio.duration);
- preloadBar.style.width = loaded + '%';
- }
- }
- }
-
- /**
- * TODO shuffle
- */
- function shuffle() {
- if(shuffle) {
- index = Math.round(Math.random() * playList.length);
- }
- }
-
- function doEnd() {
- if(index === playList.length - 1) {
- if(!repeating) {
- audio.pause();
- plActive();
- playBtn.classList.remove('is-playing');
- playSvgPath.setAttribute('d', playSvg.getAttribute('data-play'));
- return;
- }
- else {
- play(0);
- }
- }
- else {
- play(index + 1);
- }
- }
-
- function moveBar(evt, el, dir) {
- var value;
- if(dir === 'horizontal') {
- value = Math.round( ((evt.clientX - el.offset().left) + window.pageXOffset) * 100 / el.parentNode.offsetWidth);
- el.style.width = value + '%';
- return value;
- }
- else {
- if(evt.type === wheel()) {
- value = parseInt(volumeLength, 10);
- var delta = evt.deltaY || evt.detail || -evt.wheelDelta;
- value = (delta > 0) ? value - 10 : value + 10;
- }
- else {
- var offset = (el.offset().top + el.offsetHeight) - window.pageYOffset;
- value = Math.round((offset - evt.clientY));
- }
- if(value > 100) value = wheelVolumeValue = 100;
- if(value < 0) value = wheelVolumeValue = 0;
- volumeBar.style.height = value + '%';
- return value;
- }
- }
-
- function handlerBar(evt) {
- rightClick = (evt.which === 3) ? true : false;
- seeking = true;
- !rightClick && progressBar.classList.add('progress__bar--active');
- seek(evt);
- }
-
- function handlerVol(evt) {
- rightClick = (evt.which === 3) ? true : false;
- seekingVol = true;
- setVolume(evt);
- }
-
- function seek(evt) {
- evt.preventDefault();
- if(seeking && rightClick === false && audio.readyState !== 0) {
- window.value = moveBar(evt, progressBar, 'horizontal');
- }
- }
-
- function seekingFalse() {
- if(seeking && rightClick === false && audio.readyState !== 0) {
- audio.currentTime = audio.duration * (window.value / 100);
- progressBar.classList.remove('progress__bar--active');
- }
- seeking = false;
- seekingVol = false;
- }
-
- function setVolume(evt) {
- evt.preventDefault();
- volumeLength = volumeBar.css('height');
- if(seekingVol && rightClick === false || evt.type === wheel()) {
- var value = moveBar(evt, volumeBar.parentNode, 'vertical') / 100;
- if(value <= 0) {
- audio.volume = 0;
- audio.muted = true;
- volumeBtn.classList.add('has-muted');
- }
- else {
- if(audio.muted) audio.muted = false;
- audio.volume = value;
- volumeBtn.classList.remove('has-muted');
- }
- }
- }
-
- function notify(title, attr) {
- if(!settings.notification) {
- return;
- }
- if(window.Notification === undefined) {
- return;
- }
- attr.tag = 'AP music player';
- }
-
- /* Destroy method. Clear All */
- function destroy() {
- if(!apActive) return;
-
- if(settings.confirmClose) {
- window.removeEventListener('beforeunload', beforeUnload, false);
- }
-
- playBtn.removeEventListener('click', playToggle, false);
- volumeBtn.removeEventListener('click', volumeToggle, false);
- repeatBtn.removeEventListener('click', repeatToggle, false);
- plBtn.removeEventListener('click', plToggle, false);
-
- progressBar.closest('.progress-container').removeEventListener('mousedown', handlerBar, false);
- progressBar.closest('.progress-container').removeEventListener('mousemove', seek, false);
- document.documentElement.removeEventListener('mouseup', seekingFalse, false);
-
- volumeBar.closest('.volume').removeEventListener('mousedown', handlerVol, false);
- volumeBar.closest('.volume').removeEventListener('mousemove', setVolume);
- volumeBar.closest('.volume').removeEventListener(wheel(), setVolume);
- document.documentElement.removeEventListener('mouseup', seekingFalse, false);
-
- prevBtn.removeEventListener('click', prev, false);
- nextBtn.removeEventListener('click', next, false);
-
- audio.removeEventListener('error', errorHandler, false);
- audio.removeEventListener('timeupdate', timeUpdate, false);
- audio.removeEventListener('ended', doEnd, false);
-
- // Playlist
- pl.removeEventListener('click', listHandler, false);
- pl.parentNode.removeChild(pl);
-
- audio.pause();
- apActive = false;
- index = 0;
-
- playBtn.classList.remove('is-playing');
- playSvgPath.setAttribute('d', playSvg.getAttribute('data-play'));
- volumeBtn.classList.remove('has-muted');
- plBtn.classList.remove('is-active');
- repeatBtn.classList.remove('is-active');
-
- // Remove player from the DOM if necessary
- // player.parentNode.removeChild(player);
- }
-
-
- /**
- * Helpers
- */
- function wheel() {
- var wheel;
- if ('onwheel' in document) {
- wheel = 'wheel';
- } else if ('onmousewheel' in document) {
- wheel = 'mousewheel';
- } else {
- wheel = 'MozMousePixelScroll';
- }
- return wheel;
- }
-
- function extend(defaults, options) {
- for(var name in options) {
- if(defaults.hasOwnProperty(name)) {
- defaults[name] = options[name];
- }
- }
- return defaults;
- }
- function create(el, attr) {
- var element = document.createElement(el);
- if(attr) {
- for(var name in attr) {
- if(element[name] !== undefined) {
- element[name] = attr[name];
- }
- }
- }
- return element;
- }
-
- Element.prototype.offset = function() {
- var el = this.getBoundingClientRect(),
- scrollLeft = window.pageXOffset || document.documentElement.scrollLeft,
- scrollTop = window.pageYOffset || document.documentElement.scrollTop;
-
- return {
- top: el.top + scrollTop,
- left: el.left + scrollLeft
- };
- };
-
- Element.prototype.css = function(attr) {
- if(typeof attr === 'string') {
- return getComputedStyle(this, '')[attr];
- }
- else if(typeof attr === 'object') {
- for(var name in attr) {
- if(this.style[name] !== undefined) {
- this.style[name] = attr[name];
- }
- }
- }
- };
-
- // matches polyfill
- window.Element && function(ElementPrototype) {
- ElementPrototype.matches = ElementPrototype.matches ||
- ElementPrototype.matchesSelector ||
- ElementPrototype.webkitMatchesSelector ||
- ElementPrototype.msMatchesSelector ||
- function(selector) {
- var node = this, nodes = (node.parentNode || node.document).querySelectorAll(selector), i = -1;
- while (nodes[++i] && nodes[i] != node);
- return !!nodes[i];
- };
- }(Element.prototype);
-
- // closest polyfill
- window.Element && function(ElementPrototype) {
- ElementPrototype.closest = ElementPrototype.closest ||
- function(selector) {
- var el = this;
- while (el.matches && !el.matches(selector)) el = el.parentNode;
- return el.matches ? el : null;
- };
- }(Element.prototype);
-
- /**
- * Public methods
- */
- return {
- init: init,
- update: updatePL,
- destroy: destroy,
- playToggle:playToggle
- };
-
- })();
-
- window.AP = AudioPlayer;
-
- })(window);
-
- // TEST: image for web notifications
- var iconImage = 'http://funkyimg.com/i/21pX5.png';
-
- AP.init({
- playList: [
- {'icon': iconImage, 'title': 'JWS-01', 'file': 'https://tnagano-web.s3.amazonaws.com/2021/JapaneseGenki3rdEdExerciseFiles_audios/Genki3rdEdAudio_JWS-01.mp3'}
- ]
- });
-
- $(".container-fluid").click(function(event) {
- var target = $(event.target);
- if (target.is("a")) {
- event.preventDefault();
- let newAudio = [
- {'icon': iconImage, 'title': target.text(), 'file':target.attr('href')}
- ]
- AP.update(newAudio)
- }
- });
- $(document).on('keyup', function(e) {
- e.preventDefault();
- if (e.keyCode === 32) {
- AP.playToggle()
- }
- });
-
- })();