JAVASCRIPT 27
Musicplayer.js Guest on 1st May 2021 04:06:21 PM
  1. /*
  2.  *  Author Sam Johnson
  3.  *  Under MIT License
  4.  */
  5. (function($, window, document, undefined) {
  6.   "use strict";
  7.   // Create the defaults once
  8.   var pluginName = "musicPlayer",
  9.     defaults = {
  10.       playlistItemSelector: "li",
  11.       autoPlay: false,
  12.       volume: 80,
  13.       loop: false,
  14.       timeSeparator: " / ",
  15.       playerAbovePlaylist: true,
  16.       infoElements: ["title", "artist"],
  17.       elements: [
  18.         "artwork",
  19.         "information",
  20.         "controls",
  21.         "progress",
  22.         "time",
  23.         "volume"
  24.       ],
  25.       timeElements: ["current", "duration"],
  26.       controlElements: ["backward", "play", "forward", "stop"],
  27.       onLoad: function() {},
  28.       onPlay: function() {},
  29.       onPause: function() {},
  30.       onStop: function() {},
  31.       onFwd: function() {},
  32.       onRew: function() {},
  33.       volumeChanged: function() {},
  34.       seeked: function() {},
  35.       trackClicked: function() {},
  36.       onMute: function() {}
  37.     };
  38.  
  39.   //Setup Touch Events
  40.   var isTouch = "ontouchstart" in window,
  41.     eStart = isTouch ? "touchstart" : "mousedown",
  42.     eMove = isTouch ? "touchmove" : "mousemove",
  43.     eEnd = isTouch ? "touchend" : "mouseup",
  44.     eCancel = isTouch ? "touchcancel" : "mouseup";
  45.  
  46.   function Plugin(element, options) {
  47.     this.element = element;
  48.     this.settings = $.extend({}, defaults, options);
  49.     this._defaults = defaults;
  50.     this._name = pluginName;
  51.     this.init();
  52.   }
  53.  
  54.   $.extend(Plugin.prototype, {
  55.     init: function() {
  56.       var controlInnerElem = "",
  57.         timeInnerElem = "",
  58.         infoElem = "",
  59.         infoInnerElem = "",
  60.         fullPlayerElem = "",
  61.         volumeElem = "",
  62.         progressElem = "",
  63.         artworkElem = "",
  64.         timeElem = "",
  65.         controlElem = "",
  66.         titleElem = "",
  67.         artistElem = "",
  68.         backwardElem = "",
  69.         forwardElem = "",
  70.         stopElem = "",
  71.         playElem = "",
  72.         curTimeElem = "",
  73.         durTimeElem = "",
  74.         timeSeparator = "",
  75.         playerElem = "",
  76.         playerThis = this;
  77.  
  78.       for (var elemItem in this.settings.elements) {
  79.         //PREPARE VOLUME
  80.         if (this.settings.elements[elemItem] == "volume") {
  81.           volumeElem =
  82.             "<div class='volume'><div class='volume-btn' title='Volume'></div><div class=' volume-adjust'><div><div></div></div></div></div>";
  83.           fullPlayerElem += volumeElem;
  84.         }
  85.         //PREPARE PROGRESS
  86.         else if (this.settings.elements[elemItem] == "progress") {
  87.           progressElem =
  88.             "<div class='progressbar'><div class='bar-loaded' ></div><div class='bar-played'></div></div>";
  89.           fullPlayerElem += progressElem;
  90.         }
  91.         //PREPARE ARTWORK
  92.         else if (this.settings.elements[elemItem] == "artwork") {
  93.           artworkElem = "<div class='cover'></div>";
  94.           fullPlayerElem += artworkElem;
  95.         }
  96.         //PREPARE INFORMATION displayed by the player in  the given order
  97.         else if (this.settings.elements[elemItem] == "information") {
  98.           $.inArray("title", this.settings.infoElements) != "-1"
  99.             ? (titleElem = "<div class='title'></div>")
  100.             : (titleElem = " ");
  101.           $.inArray("artist", this.settings.infoElements) != "-1"
  102.             ? (artistElem = "<div class='artist'></div>")
  103.             : (artistElem = " ");
  104.  
  105.           for (var item in this.settings.infoElements) {
  106.             if (this.settings.infoElements[item] == "title") {
  107.               infoInnerElem += titleElem;
  108.             } else if (this.settings.infoElements[item] == "artist") {
  109.               infoInnerElem += artistElem;
  110.             }
  111.           }
  112.           infoElem = "<div class='info' >" + infoInnerElem + "</div>";
  113.           fullPlayerElem += infoElem;
  114.         }
  115.         //PREPARE TIME (current & Duration) in the given order
  116.         else if (this.settings.elements[elemItem] == "time") {
  117.           $.inArray("current", this.settings.timeElements) != "-1"
  118.             ? (curTimeElem = "<div class='time-current'></div>")
  119.             : (curTimeElem = " ");
  120.           $.inArray("duration", this.settings.timeElements) != "-1"
  121.             ? (durTimeElem = "<div class='time-duration'></div>")
  122.             : (durTimeElem = " ");
  123.           timeSeparator =
  124.             "<div class='time-separator'>" +
  125.             this.settings.timeSeparator.replace(/\s/g, "&nbsp;") +
  126.             "</div>";
  127.  
  128.           for (var item in this.settings.timeElements) {
  129.             if (item == 1) {
  130.               timeInnerElem += timeSeparator;
  131.             }
  132.             if (this.settings.timeElements[item] == "current") {
  133.               timeInnerElem += curTimeElem;
  134.             } else if (this.settings.timeElements[item] == "duration") {
  135.               timeInnerElem += durTimeElem;
  136.             }
  137.           }
  138.           timeElem = "<div class='timeHolder'>" + timeInnerElem + "</div>";
  139.           fullPlayerElem += timeElem;
  140.         }
  141.         //PREPARE CONTROLS inner elements to display [play, stop, forward or backward] in the given order
  142.         else if (this.settings.elements[elemItem] == "controls") {
  143.           $.inArray("backward", this.settings.controlElements) != "-1"
  144.             ? (backwardElem = "<div class='rew'></div>")
  145.             : (backwardElem = " ");
  146.           $.inArray("forward", this.settings.controlElements) != "-1"
  147.             ? (forwardElem = "<div class='fwd'></div>")
  148.             : (forwardElem = " ");
  149.           $.inArray("stop", this.settings.controlElements) != "-1"
  150.             ? (stopElem = "<div class='stop'></div>")
  151.             : (stopElem = " ");
  152.           $.inArray("play", this.settings.controlElements) != "-1"
  153.             ? (playElem = "<div class='play'></div><div class='pause'></div>")
  154.             : (playElem = " ");
  155.  
  156.           for (var item in this.settings.controlElements) {
  157.             if (this.settings.controlElements[item] == "backward") {
  158.               controlInnerElem += backwardElem;
  159.             } else if (this.settings.controlElements[item] == "play") {
  160.               controlInnerElem += playElem;
  161.             } else if (this.settings.controlElements[item] == "forward") {
  162.               controlInnerElem += forwardElem;
  163.             } else if (this.settings.controlElements[item] == "stop") {
  164.               controlInnerElem += stopElem;
  165.             }
  166.           }
  167.           controlElem = "<div class='controls'>" + controlInnerElem + "</div>";
  168.           fullPlayerElem += controlElem;
  169.         }
  170.       }
  171.  
  172.       //ADD THE PREPARED ELEMENT SORTED IN THEIR RIGHT ORDER TO THE PLAYER ELEMENT
  173.       playerElem = $("<div class='player' >" + fullPlayerElem + "</div>");
  174.       //console.log(this.element);
  175.       if (this.settings.playerAbovePlaylist) {
  176.         $(playerElem).insertBefore($(this.element).find(".playlist"));
  177.       } else {
  178.         $(playerElem).insertAfter($(this.element).find(".playlist"));
  179.       }
  180.  
  181.       this.playlistItemSelector = this.settings.playlistItemSelector;
  182.       (this.playlistHolder = $(this.element).children(".playlist")),
  183.         (this.playerHolder = $(this.element).children(".player"));
  184.       this.song = "";
  185.       this.theBar = this.playerHolder.find(".progressbar");
  186.       this.barPlayed = this.playerHolder.find(".bar-played");
  187.       this.barLoaded = this.playerHolder.find(".bar-loaded");
  188.       this.timeCurrent = this.playerHolder.find(".time-current");
  189.       this.timeDuration = this.playerHolder.find(".time-duration");
  190.       this.timeSeparator = this.settings.timeSeparator;
  191.       this.volumeInfo = this.playerHolder.find(".volume");
  192.       this.volumeButton = this.playerHolder.find(".volume-btn");
  193.       this.volumeAdjuster = this.playerHolder.find(".volume-adjust" + " > div");
  194.       this.volumeValue = this.settings.volume / 100;
  195.       this.volumeDefault = 0;
  196.       this.trackInfo = this.playerHolder.find(".info");
  197.       //tracker           = playerHolder.find('.progressbar'),
  198.       //volume            = playerHolder.find('.volume'),
  199.       this.coverInfo = this.playerHolder.find(".cover");
  200.       this.controlsInfo = this.playerHolder.find(".controls");
  201.       this.controlPlay = $(this.controlsInfo).find(".play");
  202.       this.controlPause = $(this.controlsInfo).find(".pause");
  203.       this.controlStop = $(this.controlsInfo).find(".stop");
  204.       this.controlFwd = $(this.controlsInfo).find(".fwd");
  205.       this.controlRew = $(this.controlsInfo).find(".rew");
  206.       this.cssClass = {
  207.         playing: "playing",
  208.         mute: "mute"
  209.       };
  210.  
  211.       //Volume cannot be set using JavaScript, so the volumechange event will never be fired.
  212.       //Even if the user changes the volume on their device while mobile Safari is open, this event will not fire
  213.       //source: https://www.ibm.com/developerworks/library/wa-ioshtml5/
  214.       //Hide Volume control on IOS devices.
  215.       if (/iPad|iPhone|iPod/.test(navigator.userAgent))
  216.         $(this.volumeInfo).hide();
  217.  
  218.       // initialization - first element in playlist
  219.       this.initAudio(
  220.         $(this.playlistHolder.find(this.playlistItemSelector + ":first"))
  221.       );
  222.  
  223.       // set volume
  224.       this.song.volume = this.volumeValue;
  225.  
  226.       //set default time Current and duration time
  227.       this.timeDuration.html("&hellip;");
  228.       this.timeCurrent.text(this.secondsToTime(0));
  229.  
  230.       // play click
  231.       $(this.controlPlay).click(function(e) {
  232.         e.preventDefault();
  233.  
  234.         playerThis.playAudio();
  235.       });
  236.  
  237.       // pause click
  238.       $(this.controlPause).click(function(e) {
  239.         e.preventDefault();
  240.  
  241.         playerThis.stopAudio();
  242.  
  243.         //issue pause callback
  244.         playerThis.settings.onPause();
  245.       });
  246.  
  247.       // forward click
  248.       $(this.controlFwd).click(function(e) {
  249.         e.preventDefault();
  250.  
  251.         playerThis.stopAudio();
  252.  
  253.         var next = playerThis.getSong(true);
  254.  
  255.         //Looping Activated : play the first item on the playlist if there is no next item with(looping)
  256.         if (next.length == 0) {
  257.           next = $(playerThis.playlistHolder).find(
  258.             playerThis.playlistItemSelector + ":first"
  259.           );
  260.         }
  261.  
  262.         playerThis.loadNewSong(next);
  263.         playerThis.playAudio();
  264.  
  265.         //issue forward callback
  266.         playerThis.settings.onFwd();
  267.       });
  268.  
  269.       // rewind click
  270.       $(this.controlRew).click(function(e) {
  271.         e.preventDefault();
  272.  
  273.         playerThis.stopAudio();
  274.  
  275.         var prev = playerThis.getSong(false);
  276.  
  277.         //play the last item on the playlist if there is no previous item (looping)
  278.         if (prev.length == 0) {
  279.           prev = $(playerThis.playlistHolder).find(
  280.             playerThis.playlistItemSelector + ":last"
  281.           );
  282.         }
  283.  
  284.         playerThis.loadNewSong(prev);
  285.         playerThis.playAudio();
  286.  
  287.         //issue backward callback
  288.         playerThis.settings.onRew();
  289.       });
  290.  
  291.       //stop click
  292.       $(this.controlStop).click(function(e) {
  293.         e.preventDefault();
  294.  
  295.         playerThis.stopAudio();
  296.         playerThis.song.currentTime = 0;
  297.  
  298.         //issue stop callback
  299.         playerThis.settings.onStop();
  300.       });
  301.  
  302.       // Play clicked Playlist song.
  303.       $(this.playlistHolder)
  304.         .find(this.playlistItemSelector)
  305.         .click(function(e) {
  306.           e.preventDefault();
  307.  
  308.           playerThis.stopAudio();
  309.           playerThis.loadNewSong($(this));
  310.           playerThis.playAudio();
  311.  
  312.           //issue track clicked callback
  313.           playerThis.settings.trackClicked();
  314.         });
  315.     },
  316.  
  317.     secondsToTime: function(secs) {
  318.       var hours = Math.floor(secs / 3600),
  319.         minutes = Math.floor((secs % 3600) / 60),
  320.         seconds = Math.ceil((secs % 3600) % 60);
  321.  
  322.       return (
  323.         (hours == 0
  324.           ? ""
  325.           : hours > 0 && hours.toString().length < 2
  326.             ? "0" + hours + ":"
  327.             : hours + ":") +
  328.         (minutes.toString().length < 2 ? "0" + minutes : minutes) +
  329.         ":" +
  330.         (seconds.toString().length < 2 ? "0" + seconds : seconds)
  331.       );
  332.     },
  333.     adjustVolume: function(e) {
  334.       var theRealEvent = isTouch ? e.originalEvent.touches[0] : e;
  335.       this.song.volume = Math.abs(
  336.         (theRealEvent.pageX - this.volumeAdjuster.offset().left) /
  337.           this.volumeAdjuster.width()
  338.       );
  339.     },
  340.     adjustCurrentTime: function(e) {
  341.       var theRealEvent = isTouch ? e.originalEvent.touches[0] : e;
  342.       this.song.currentTime = Math.round(
  343.         (this.song.duration *
  344.           (theRealEvent.pageX - this.theBar.offset().left)) /
  345.           this.theBar.width()
  346.       );
  347.     },
  348.  
  349.     initAudio: function(elem) {
  350.       var url = elem.children("a:first-child").attr("href"),
  351.         title = elem.text(),
  352.         cover = elem.attr("data-cover"),
  353.         artist = elem.attr("data-artist"),
  354.         playerInstance = this;
  355.  
  356.       //Set the title of the song  on the player
  357.       $(this.trackInfo)
  358.         .children(".title")
  359.         .text(title);
  360.       //Set the artist name on the player
  361.       $(this.trackInfo)
  362.         .children(".artist")
  363.         .text(artist);
  364.  
  365.       //Set the cover image for the player
  366.       $(this.coverInfo).css("background-image", "url(" + cover + ")");
  367.  
  368.       this.song = new Audio(url);
  369.  
  370.       //Force load
  371.       this.song.load();
  372.  
  373.       //set the song time duration on player
  374.       this.song.addEventListener(
  375.         "loadeddata",
  376.         function() {
  377.           $(playerInstance.timeDuration).html(
  378.             playerInstance.secondsToTime(this.duration)
  379.           );
  380.           $(playerInstance.volumeAdjuster)
  381.             .find("div")
  382.             .width(this.volume * 100 + "%");
  383.           playerInstance.volumeDefault = this.volume;
  384.         },
  385.         false
  386.       );
  387.  
  388.       //update bar loader
  389.       this.song.addEventListener("progress", function() {
  390.         $(playerInstance.barLoaded).width(
  391.           (this.buffered.end(0) / this.duration) * 100 + "%"
  392.         );
  393.       });
  394.  
  395.       //timeupdate event listener (timeupdate used together with the current Time Property to return
  396.       // the current position of the audio playback in seconds)
  397.       this.song.addEventListener("timeupdate", function() {
  398.         $(playerInstance.timeCurrent).text(
  399.           playerInstance.secondsToTime(this.currentTime)
  400.         );
  401.         $(playerInstance.barPlayed).width(
  402.           (this.currentTime / this.duration) * 100 + "%"
  403.         );
  404.       });
  405.  
  406.       this.song.addEventListener("volumechange", function() {
  407.         if (Number(Math.round(this.volume * 100 + "e" + 1) + "e-" + 1) <= 0.4) {
  408.           this.volume = 0;
  409.         }
  410.         $(playerInstance.volumeAdjuster)
  411.           .find("div")
  412.           .width(this.volume * 100 + "%");
  413.         if (
  414.           this.volume > 0 &&
  415.           playerInstance.playerHolder.hasClass(playerInstance.cssClass.mute)
  416.         )
  417.           playerInstance.playerHolder.removeClass(playerInstance.cssClass.mute);
  418.         if (
  419.           this.volume <= 0 &&
  420.           !playerInstance.playerHolder.hasClass(playerInstance.cssClass.mute)
  421.         )
  422.           playerInstance.playerHolder.addClass(playerInstance.cssClass.mute);
  423.  
  424.         playerInstance.volumeValue = this.volume;
  425.       });
  426.  
  427.       this.song.addEventListener("ended", function() {
  428.         //Play the loaded song when autoplay is activated
  429.         //$('.fwd').click();
  430.         if (playerInstance.settings.autoPlay) {
  431.           playerInstance.autoPlayNext();
  432.         } else {
  433.           //Hide playing class
  434.           playerInstance.playerHolder.removeClass(
  435.             playerInstance.cssClass.playing
  436.           );
  437.           //Hide pause Icon and show play
  438.           $(playerInstance.controlPlay).removeClass("hidden");
  439.           $(playerInstance.controlPause).removeClass("visible");
  440.         }
  441.       });
  442.  
  443.       //Toggle Mute icon and reset Volume
  444.       $(this.volumeButton).on("click", function() {
  445.         if (
  446.           $(playerInstance.playerHolder).hasClass(playerInstance.cssClass.mute)
  447.         ) {
  448.           $(playerInstance.playerHolder).removeClass(
  449.             playerInstance.cssClass.mute
  450.           );
  451.           playerInstance.song.volume = playerInstance.volumeDefault;
  452.         } else {
  453.           $(playerInstance.playerHolder).addClass(playerInstance.cssClass.mute);
  454.           playerInstance.volumeDefault = playerInstance.song.volume;
  455.           playerInstance.song.volume = 0;
  456.           //issue callback to track mute action.
  457.           playerInstance.settings.onMute();
  458.         }
  459.         return false;
  460.       });
  461.  
  462.       //when volume bar is clicked
  463.       $(this.volumeAdjuster)
  464.         .on(eStart, function(e) {
  465.           playerInstance.adjustVolume(e);
  466.           playerInstance.volumeAdjuster.on(eMove, function(e) {
  467.             playerInstance.adjustVolume(e);
  468.           });
  469.           //issue callback
  470.           playerInstance.settings.volumeChanged();
  471.         })
  472.         .on(eCancel, function() {
  473.           playerInstance.volumeAdjuster.unbind(eMove);
  474.         });
  475.  
  476.       //when trackbar is click
  477.       $(this.theBar)
  478.         .on(eStart, function(e) {
  479.           playerInstance.adjustCurrentTime(e);
  480.           playerInstance.theBar.on(eMove, function(e) {
  481.             playerInstance.adjustCurrentTime(e);
  482.           });
  483.         })
  484.         .on(eCancel, function() {
  485.           playerInstance.theBar.unbind(eMove);
  486.           //issue callback
  487.           playerInstance.settings.seeked();
  488.         });
  489.  
  490.       $(this.playlistHolder)
  491.         .find(playerInstance.playlistItemSelector)
  492.         .removeClass("active");
  493.       elem.addClass("active");
  494.  
  495.       //issue Callback
  496.       this.settings.onLoad();
  497.  
  498.       //Play the loaded song when autoplay is activated
  499.       if (this.settings.autoPlay) this.playAudio();
  500.     },
  501.  
  502.     playAudio: function() {
  503.       this.song.play();
  504.  
  505.       //Add playing class
  506.       this.playerHolder.addClass(this.cssClass.playing);
  507.  
  508.       //Hide pause Icon and show play if they exist
  509.       if (
  510.         $.inArray("controls", this.settings.elements) != "-1" &&
  511.         $.inArray("play", this.settings.controlElements) != "-1"
  512.       ) {
  513.         $(this.controlPlay).addClass("hidden");
  514.         $(this.controlPause).addClass("visible");
  515.       }
  516.       this.settings.onPlay();
  517.     },
  518.  
  519.     stopAudio: function() {
  520.       this.song.pause();
  521.       //Remove playing class
  522.       this.playerHolder.removeClass(this.cssClass.playing);
  523.  
  524.       //Hide pause Icon and show play if they exist
  525.       if (
  526.         $.inArray("controls", this.settings.elements) != "-1" &&
  527.         $.inArray("play", this.settings.controlElements) != "-1"
  528.       ) {
  529.         $(this.controlPlay).removeClass("hidden");
  530.         $(this.controlPause).removeClass("visible");
  531.       }
  532.     },
  533.     // Auto Play the next track and loop if loop is activated
  534.     autoPlayNext: function() {
  535.       this.stopAudio();
  536.       var next = this.getSong(true);
  537.       //Looping Activated : play the first item on the playlist if there is no next item with(looping)
  538.       if (next.length == 0 && this.settings.loop) {
  539.         next = $(this.playlistHolder).find(
  540.           this.playlistItemSelector + ":first"
  541.         );
  542.         this.loadNewSong(next);
  543.         this.playAudio();
  544.       } else if (!next.length == 0) {
  545.         this.loadNewSong(next);
  546.         this.playAudio();
  547.       }
  548.     },
  549.     //nextSong: is Boolean to get next or previous song.
  550.     getSong: function(nextSong) {
  551.       var $x = $(this.playlistHolder).find(this.playlistItemSelector);
  552.       var curSong = $(this.playlistItemSelector + ".active");
  553.       if (nextSong) {
  554.         return $x.eq($x.index(curSong) + 1);
  555.       } else {
  556.         return $x.eq($x.index(curSong) - 1);
  557.       }
  558.     },
  559.     //initiate the give song maintaining current settings
  560.     loadNewSong: function(elem) {
  561.       //save current volume  level
  562.       this.volumeValue = this.song.volume;
  563.       //set up the next song to be played
  564.       this.initAudio(elem);
  565.       //set song volume to the previous track's volume to ensure consistency
  566.       this.song.volume = this.volumeValue;
  567.       this.volumeAdjuster.find("div").width(this.volumeValue * 100 + "%");
  568.       //reset progress & loaded bar indicator to begin
  569.       this.barPlayed.width(0);
  570.       this.barLoaded.width(0);
  571.     }
  572.   });
  573.  
  574.   $.fn[pluginName] = function(options) {
  575.     return this.each(function() {
  576.       if (!$.data(this, "plugin_" + pluginName)) {
  577.         $.data(this, "plugin_" + pluginName, new Plugin(this, options));
  578.       }
  579.     });
  580.   };
  581. })(jQuery, window, document);

Paste-bin is for source code and general debugging text.

Login or Register to edit, delete and keep track of your pastes and more.

Raw Paste

Login or Register to edit or fork this paste. It's free.