script.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. // Creating everything
  2. var ap_apwp, apwp_audio, apwp_album, apwp_cover, apwp_title, apwp_artist, apwp_controls, apwp_progress, apwp_volume, apwp_v_slider, apwp_v_num, apwp_others;
  3. // Multiple events to a listener
  4. function addEventListener_multi(element, eventNames, handler) {
  5. var events = eventNames.split(' ');
  6. events.forEach(e => element.addEventListener(e, handler, false));
  7. }
  8. // Random numbers in a specific range
  9. function getRandom(min, max) {
  10. min = Math.ceil(min);
  11. max = Math.floor(max);
  12. return Math.floor(Math.random() * (max - min + 1)) + min;
  13. }
  14. // Position element inside element
  15. function getRelativePos(elm) {
  16. var pPos = elm.parentNode.getBoundingClientRect(); // Parent pos
  17. var cPos = elm.getBoundingClientRect(); // ... and Target pos
  18. var pos = {};
  19. pos.top = cPos.top - pPos.top + elm.parentNode.scrollTop,
  20. pos.right = cPos.right - pPos.right,
  21. pos.bottom = cPos.bottom - pPos.bottom,
  22. pos.left = cPos.left - pPos.left;
  23. return pos;
  24. }
  25. function formatTime(val) {
  26. var h = 0, m = 0, s;
  27. val = parseInt(val, 10);
  28. if (val > 60 * 60) {
  29. h = parseInt(val / (60 * 60), 10);
  30. val -= h * 60 * 60;
  31. }
  32. if (val > 60) {
  33. m = parseInt(val / 60, 10);
  34. val -= m * 60;
  35. }
  36. s = val;
  37. val = (h > 0)? h + ':' : '';
  38. val += (m > 0)? ((m < 10 && h > 0)? '0' : '') + m + ':' : '0:';
  39. val += ((s < 10)? '0' : '') + s;
  40. return val;
  41. }
  42. function apwp_initTime() {
  43. apwp_controls.querySelector('.start-time').innerHTML = formatTime(apwp_audio.currentTime); // Calculate current value time
  44. if (!apwp_isStream) {
  45. apwp_controls.querySelector('.end-time').innerHTML = formatTime(apwp_audio.duration); // Calculate total value time
  46. apwp_progress.value = apwp_audio.currentTime / apwp_audio.duration * 100; // Progress bar
  47. }
  48. // Ended of the audio
  49. if (apwp_audio.currentTime == apwp_audio.duration) {
  50. apwp_controls.querySelector('.apwp-plause').classList.remove('fa-pause');
  51. apwp_controls.querySelector('.apwp-plause').classList.add('fa-play');
  52. apwp_audio.removeEventListener('timeupdate', apwp_initTime);
  53. if (apwp_isNext) { // Autoload next audio
  54. var elem;
  55. apwp_a_index++;
  56. if (apwp_a_index == apwp_a_url.length) { // Repeat all audio
  57. apwp_a_index = 0;
  58. elem = apwp_a_url[0];
  59. } else {
  60. elem = apwp_a_url[apwp_a_index];
  61. }
  62. apwp_changeAudio(elem);
  63. apwp_setAlbum(apwp_a_index);
  64. } else {
  65. apwp_isPlaying = false;
  66. }
  67. }
  68. }
  69. function apwp_initAudio() {
  70. // If readyState more than 2, audio file has loaded
  71. apwp_isLoaded = apwp_audio.readyState == 4 ? true : false;
  72. apwp_isStream = apwp_audio.duration == 'Infinity' ? true : false;
  73. apwp_controls.querySelector('.apwp-plause').disabled = false;
  74. apwp_progress.disabled = apwp_isStream ? true : false;
  75. if (!apwp_isStream) {
  76. apwp_progress.parentNode.classList.remove('apwp-load', 'apwp-loading');
  77. apwp_controls.querySelector('.end-time').innerHTML = formatTime(apwp_audio.duration);
  78. }
  79. apwp_audio.addEventListener('timeupdate', apwp_initTime); // Tracking load progress
  80. if (apwp_isLoaded && apwp_isPlaying) apwp_audio.play();
  81. // Progress bar click event
  82. addEventListener_multi(apwp_progress, 'touchstart mousedown', function (e) {
  83. if (apwp_isStream) {
  84. e.stopPropagation();
  85. return false;
  86. }
  87. if (apwp_audio.readyState == 4) {
  88. apwp_audio.removeEventListener('timeupdate', apwp_initTime);
  89. apwp_audio.pause();
  90. }
  91. });
  92. addEventListener_multi(apwp_progress, 'touchend mouseup', function (e) {
  93. if (apwp_isStream) {
  94. e.stopPropagation();
  95. return false;
  96. }
  97. if (apwp_audio.readyState == 4) {
  98. apwp_audio.currentTime = apwp_progress.value * apwp_audio.duration / 100;
  99. apwp_audio.addEventListener('timeupdate', apwp_initTime);
  100. if (apwp_isPlaying) apwp_audio.play();
  101. }
  102. });
  103. // Add event listener for next track
  104. apwp_audio.addEventListener('ended', playNextTrack);
  105. }
  106. function playNextTrack() {
  107. apwp_a_index++;
  108. if (apwp_a_index >= apwp_a_url.length) {
  109. apwp_a_index = 0; // Repeat playlist from the beginning
  110. }
  111. // Load next track
  112. apwp_changeAudio(apwp_a_url[apwp_a_index]);
  113. apwp_setAlbum(apwp_a_index);
  114. // Replay next track
  115. apwp_audio.play();
  116. apwp_isPlaying = true;
  117. apwp_controls.querySelector('.apwp-plause').classList.remove('fa-play');
  118. apwp_controls.querySelector('.apwp-plause').classList.add('fa-pause');
  119. }
  120. function apwp_changeAudio(elem) {
  121. apwp_isLoaded = false;
  122. apwp_controls.querySelector('.apwp-prev').disabled = apwp_a_index == 0 ? true : false;
  123. apwp_controls.querySelector('.apwp-plause').disabled = apwp_auto_load ? true : false;
  124. apwp_controls.querySelector('.apwp-next').disabled = apwp_a_index == apwp_a_url.length - 1 ? true : false;
  125. apwp_progress.parentNode.classList.add('apwp-load');
  126. apwp_progress.disabled = true;
  127. apwp_progress.value = 0;
  128. apwp_controls.querySelector('.start-time').innerHTML = '00:00';
  129. apwp_controls.querySelector('.end-time').innerHTML = '00:00';
  130. elem = apwp_isRandom && apwp_isNext ? apwp_a_url[getRandom(0, apwp_a_url.length - 1)] : elem;
  131. // Playlist, audio is running
  132. for (var i = 0; i < apwp_a_url.length; i++) {
  133. apwp_a_url[i].parentNode.classList.remove('apwp-active');
  134. if (apwp_a_url[i] == elem) {
  135. apwp_a_index = i;
  136. apwp_a_url[i].parentNode.classList.add('apwp-active');
  137. }
  138. }
  139. // Scrolling to element inside element
  140. var apwp_active = getRelativePos(apwp_source[apwp_a_index]);
  141. apwp_source[apwp_a_index].parentNode.scrollTop = apwp_active.top;
  142. // Load the new track
  143. apwp_loadAudio(elem);
  144. if (apwp_isPlaying) {
  145. apwp_controls.querySelector('.apwp-plause').classList.remove('fa-play');
  146. apwp_controls.querySelector('.apwp-plause').classList.add('fa-pause');
  147. }
  148. }
  149. function apwp_loadAudio(elem) {
  150. apwp_progress.parentNode.classList.add('apwp-loading');
  151. apwp_controls.querySelector('.apwp-plause').disabled = true;
  152. apwp_audio.querySelector('source').src = elem.dataset.src;
  153. apwp_audio.load();
  154. apwp_audio.volume = parseFloat(apwp_v_num / 100); // Based on volume input value
  155. apwp_audio.addEventListener('canplaythrough', apwp_initAudio); // Play audio without stop for buffering
  156. // If audio fails to load, only IE/Edge 9.0 or above
  157. apwp_audio.addEventListener('error', function() {
  158. alert('Please reload the page.');
  159. });
  160. }
  161. function apwp_setAlbum(index) {
  162. apwp_cover.innerHTML = apwp_a_url[index].dataset.cover ? '<div style="background:url(' + apwp_a_url[index].dataset.cover + ') no-repeat;background-size:cover;width:80px;height:80px;"></div>' : '<i class="fa fa-music fa-5x"></i>';
  163. apwp_title.innerHTML = apwp_source[index].querySelector('.apwp-source').innerHTML;
  164. apwp_artist.innerHTML = apwp_source[index].querySelector('.apwp-desc') ? apwp_source[index].querySelector('.apwp-desc').innerHTML : '';
  165. }
  166. function apwp_startScript() {
  167. ap_apwp = document.querySelector('#apwp');
  168. apwp_audio = ap_apwp.querySelector('#audio');
  169. apwp_album = ap_apwp.querySelector('.apwp-album');
  170. apwp_cover = apwp_album.querySelector('.apwp-cover');
  171. apwp_title = apwp_album.querySelector('.apwp-title');
  172. apwp_artist = apwp_album.querySelector('.apwp-artist');
  173. apwp_controls = ap_apwp.querySelector('.apwp-controls');
  174. apwp_progress = apwp_controls.querySelector('.apwp-progress');
  175. apwp_volume = apwp_controls.querySelector('.apwp-volume');
  176. apwp_v_slider = apwp_volume.querySelector('.apwp-v-slider');
  177. apwp_v_num = apwp_v_slider.value; // Default volume
  178. apwp_others = apwp_controls.querySelector('.apwp-others');
  179. apwp_auto_load = apwp_config.auto_load; // Autoload audio file
  180. if (apwp_config.shide_top) apwp_album.parentNode.classList.toggle('apwp-hide');
  181. if (apwp_config.shide_btm) {
  182. apwp_playlist.classList.add('apwp-display');
  183. apwp_playlist.classList.toggle('apwp-hide');
  184. }
  185. if (apwp_a_url.length <= 1) {
  186. apwp_controls.querySelector('.apwp-prev').style.display = 'none';
  187. apwp_controls.querySelector('.apwp-next').style.display = 'none';
  188. apwp_others.querySelector('.apwp-plext').style.display = 'none';
  189. apwp_others.querySelector('.apwp-random').style.display = 'none';
  190. }
  191. // Playlist listeners
  192. apwp_source.forEach(function(item, index) {
  193. if (item.classList.contains('apwp-active')) apwp_a_index = index; // Playlist contains '.apwp-active'
  194. item.addEventListener('click', function() {
  195. apwp_audio.removeEventListener('timeupdate', apwp_initTime);
  196. apwp_a_index = index;
  197. apwp_changeAudio(this.querySelector('.apwp-source'));
  198. apwp_setAlbum(apwp_a_index);
  199. });
  200. });
  201. // FIRST AUDIO LOAD =======
  202. apwp_changeAudio(apwp_a_url[apwp_a_index]);
  203. apwp_setAlbum(apwp_a_index);
  204. // FIRST AUDIO LOAD =======
  205. // Controls listeners
  206. apwp_controls.querySelector('.apwp-plauseward').addEventListener('click', function(e) {
  207. var eles = e.target.classList;
  208. if (eles.contains('apwp-plause')) {
  209. if (apwp_audio.paused) {
  210. if (!apwp_isLoaded) apwp_loadAudio(apwp_a_url[apwp_a_index]);
  211. apwp_audio.play();
  212. apwp_isPlaying = true;
  213. eles.remove('fa-play');
  214. eles.add('fa-pause');
  215. } else {
  216. apwp_audio.pause();
  217. apwp_isPlaying = false;
  218. eles.remove('fa-pause');
  219. eles.add('fa-play');
  220. }
  221. } else {
  222. if (eles.contains('apwp-prev') && apwp_a_index != 0) {
  223. apwp_a_index = apwp_a_index-1;
  224. e.target.disabled = apwp_a_index == 0 ? true : false;
  225. } else if (eles.contains('apwp-next') && apwp_a_index != apwp_a_url.length-1) {
  226. apwp_a_index = apwp_a_index+1;
  227. e.target.disabled = apwp_a_index == apwp_a_url.length-1 ? true : false;
  228. }
  229. apwp_audio.removeEventListener('timeupdate', apwp_initTime);
  230. apwp_changeAudio(apwp_a_url[apwp_a_index]);
  231. apwp_setAlbum(apwp_a_index);
  232. }
  233. });
  234. // Audio volume
  235. apwp_volume.addEventListener('click', function(e) {
  236. var eles = e.target.classList;
  237. if (eles.contains('apwp-mute')) {
  238. if (eles.contains('fa-volume-up')) {
  239. eles.remove('fa-volume-up');
  240. eles.add('fa-volume-off');
  241. apwp_v_slider.value = 0;
  242. } else {
  243. eles.remove('fa-volume-off');
  244. eles.add('fa-volume-up');
  245. apwp_v_slider.value = apwp_v_num;
  246. }
  247. } else {
  248. apwp_v_num = apwp_v_slider.value;
  249. if (apwp_v_num != 0) {
  250. apwp_controls.querySelector('.apwp-mute').classList.remove('fa-volume-off');
  251. apwp_controls.querySelector('.apwp-mute').classList.add('fa-volume-up');
  252. }
  253. }
  254. apwp_audio.volume = parseFloat(apwp_v_slider.value / 100);
  255. });
  256. // Others
  257. apwp_others.addEventListener('click', function(e) {
  258. var eles = e.target.classList;
  259. if (eles.contains('apwp-plext')) {
  260. apwp_isNext = apwp_isNext && !apwp_isRandom ? false : true;
  261. if (!apwp_isRandom) apwp_isRanext = apwp_isRanext ? false : true;
  262. eles.contains('apwp-active') && !apwp_isRandom ? eles.remove('apwp-active') : eles.add('apwp-active');
  263. } else if (eles.contains('apwp-random')) {
  264. apwp_isRandom = apwp_isRandom ? false : true;
  265. if (apwp_isNext && !apwp_isRanext) {
  266. apwp_isNext = false;
  267. apwp_others.querySelector('.apwp-plext').classList.remove('apwp-active');
  268. } else {
  269. apwp_isNext = true;
  270. apwp_others.querySelector('.apwp-plext').classList.add('apwp-active');
  271. }
  272. eles.contains('apwp-active') ? eles.remove('apwp-active') : eles.add('apwp-active');
  273. } else if (eles.contains('apwp-shide-top')) {
  274. apwp_album.parentNode.classList.toggle('apwp-hide');
  275. } else if (eles.contains('apwp-shide-bottom')) {
  276. apwp_playlist.classList.add('apwp-display');
  277. apwp_playlist.classList.toggle('apwp-hide');
  278. }
  279. });
  280. }
  281. // Start apwple player
  282. if (document.querySelector('#apwp')) {
  283. var apwp_auto_load, apwp_audio, apwp_album, apwp_cover, apwp_title, apwp_artist, apwp_controls, apwp_progress, apwp_volume, apwp_v_slider, apwp_v_num, apwp_others;
  284. var ap_apwp = document.querySelector('#apwp');
  285. var apwp_playlist = ap_apwp.querySelector('.apwp-playlist');
  286. var apwp_source = apwp_playlist.querySelectorAll('li');
  287. var apwp_a_url = apwp_playlist.querySelectorAll('[data-src]');
  288. var apwp_a_index = 0;
  289. var apwp_isPlaying = false;
  290. var apwp_isNext = false; // Auto play
  291. var apwp_isRandom = false; // Play random
  292. var apwp_isRanext = false; // Check if before random starts, apwp_isNext value is true
  293. var apwp_isStream = false; // Radio streaming
  294. var apwp_isLoaded = false; // Audio file has loaded
  295. var apwp_config = ap_apwp.dataset.config ? JSON.parse(ap_apwp.dataset.config) : {
  296. shide_top: false, // Show/hide album
  297. shide_btm: false, // Show/hide playlist
  298. auto_load: false // Autoload audio file
  299. };
  300. var apwp_elem = '';
  301. apwp_elem += '<audio id="audio" preload><source src="" type="audio/mpeg"></audio>';
  302. apwp_elem += '<div class="apwp-display"><div class="apwp-album w-full flex-wrap"><div class="apwp-cover"><i class="fa fa-music fa-5x"></i></div><div class="apwp-info"><div class="apwp-title">Title</div><div class="apwp-artist">Artist</div></div></div></div>';
  303. apwp_elem += '<div class="apwp-controls flex-wrap flex-align">';
  304. apwp_elem += '<div class="apwp-plauseward flex flex-align"><button type="button" class="apwp-prev fa fa-backward" disabled></button><button type="button" class="apwp-plause fa fa-play" disabled></button><button type="button" class="apwp-next fa fa-forward" disabled></button></div>';
  305. apwp_elem += '<div class="apwp-tracker apwp-load"><input class="apwp-progress" type="range" min="0" max="100" value="0" disabled/><div class="apwp-buffer"></div></div>';
  306. apwp_elem += '<div class="apwp-time flex flex-align"><span class="start-time">00:00</span><span class="apwp-slash">&#160;/&#160;</span><span class="end-time">00:00</span></div>';
  307. apwp_elem += '<div class="apwp-volume flex flex-align"><button type="button" class="apwp-mute fa fa-volume-up"></button><input class="apwp-v-slider" type="range" min="0" max="100" value="100"/></div>';
  308. apwp_elem += '<div class="apwp-others flex flex-align"><button type="button" class="apwp-plext fa fa-play-circle" title="Auto Play"></button><button type="button" class="apwp-random fa fa-random" title="Random"></button><div class="apwp-shide"><button type="button" class="apwp-shide-top fa fa-caret-up" title="Show/Hide Album"></button><button type="button" class="apwp-shide-bottom fa fa-caret-down" title="Show/Hide Playlist"></button></div></div>';
  309. apwp_elem += '</div>'; //apwp-controls
  310. var apwp_player = document.createElement('div');
  311. apwp_player.classList.add('apwp-player');
  312. apwp_player.innerHTML = apwp_elem;
  313. ap_apwp.insertBefore(apwp_player, apwp_playlist);
  314. apwp_startScript();
  315. }