Заставлять пользователей слушать музыку на вашем сайте это плохая идея (подгружать фоновую мелодию).
А вот если им дать возможность формировать свои плейлисты и возможность управлять прослушиванием (регулировать громкость, переключать и «перематывать» мелодии, и т.д.), то это может стать фишкой вашего сайта.
Если вы уже копались в сети, то наверняка уже находили множество аудиоплееров. Некоторые из них простые, некоторые навороченные, но что объединяет большинство из них, это уже готовый дизайн - один стандартный шаблон или несколько из которых можно выбрать.
В одном из своих проектов я столкнулся с необходимостью разместить музыкальный проигрыватель дизайн, которого был разработан специально для этого проекта. Тут я уже не мог взять какое-то стандартное решение, которое максимально подходило бы под общий дизайн.
Поэтому я начал искать плеер у которого изначально нет отображения, или это отображение можно легко менять (т. е. не зашито во flash). И такие тоже встречаются.
Свой выбор я остановил на MP3 Player JS. В чем прелесть этого проигрывателя - разработчик предоставляет flash файл, который не имеет внешнего отображения на странице и небольшую документацию по API этого проигрывателя. Все.
На основе документации предлагается разработать свой управляющий js-объект. Ну а так как мы имеем дело с JavaScript, то мы легко сможем настроить и необходимый нам внешний вид проигрывателя.
Сайт разработчиков: flash-mp3-player.net
Полная документация по типу JS: MP3 Player JS documentation
На сайте разработчика представлено несколько типов плееров. Некоторые типы с уже имеющемся визуальным отображением, для которых вы можете прямо на сайте разработчика настроить цветовое решение и параметры объекта.
Но нас интересует тип JS - данный вариант изначально не имеет графического отображения.
Для работы с плеером нам потребуются следующие файлы:
player_mp3_js.swf
- собственно сам проигрыватель.audioplayer.js
- управляющие скрипты (полностью разрабатываются нами).audioplayer.css
- стили нашего плеера (в этой статье не рассматриваются).Прежде чем мы начнем создавать свой управляющий объект, давайте рассмотрим что же нам дает проигрыватель.
Если вы ожидает тонну документации по работе с плеером, то я вас хочу огорчить, а может и порадовать - вся документация по проигрывателю типа JS помещается на одном листе А4.
На мой взгляд это очень здорово, т.к. работа плеера теперь зависит только от нашего воображения.
Параметров всего пять:
Эти параметры передаются при создании html-объекта. Однако их можно изменять в процессе работы - особенно это актуально для параметра enabled. К примеру, если вы остановите мелодию, то данные от flash все равно будут приходить, хотя ни чего и не играется. Поэтому есть резон передать значение false параметру endbled, а при запуске следующей мелодии снова вернуть ему значение true.
Эти методы предназначены для управления flash:
Это основные свойства, которые присущи js-объекту, и которые обновляет flash.
У нашего объекта будет всего лишь два события, которые вызывает flash:
Здесь я расскажу как реализовать основные возможности проигрывателя. Мы рассмотрим:
Я буду рассматривать создание плагина для jQuery, но вы вольны разработать объект на чистом JavaScript.
Со следующих строчек начнется полет моей фантазии, поэтому не стоит воспринимать это решение как что-то должное. Это скорее одна реализация из бесконечного числа возможных.
Итак что же будет делать наш плагин. Внутри указанного html-элемента (предполагается что это div), плагин передаст инициализирующие параметры нашему объекту и построит html представление плеера.
В качестве параметров предлагаю передавать следующее:
Итак у нас получится примерно следующее:
JavaScript: //объект получающий события от flash var _audioplayer_listener = new Object(); //плагин (function($) { $.fn.audioplayer = function(options) { //передаем данные по-умолчанию (плейлист, путь до flash, интервал обновления данных) options = $.extend({ playlist: [{name: "Test", artist: "Tester", src:"test.mp3", duration:"00:00"}], flash_url: "playermp3_js.swf", interval: 400 }, options || {}); //элемент родитель плеера var player = $(this); if(!player.data("audioplayer")) { var plugin = function() { //тут будет весь наш управляющий скрипт //параметры и функции, которые будут доступны из-вне return { flash_url:options.flash_url, interval:options.interval, listener:_audioplayer_listener, playlist:options.playlist, track:player_track, trackSet:function(track) { apTrackSetNum(track); }, prev:function() { apPrev(); }, play:function() { apPlay(); }, pause:function() { apPause(); }, stop:function() { apStop(); }, next:function() { apNext(); }, playlistSet:function(playlist) { apPlaylistSet(playlist); } } } player.data("audioplayer", plugin()); } else { return player.data("audioplayer"); } } })(jQuery);
Обратите внимание на параметр playlist - он представляет собой массив объектов (мелодий), содержащих четыре поля:
Надо сразу оговориться, что длительность и ID3-теги (хотя это и не описано в документации) можно получить при загрузке мелодии во flesh, но есть одна маленькая деталь, что точное время определяется только после полной загрузки файла. А при получении русских названий из ID3-тегов они ломаются (используется какая-то хитрая кодировка) - тут можете конечно поколдовать и написать определитель кодировки, который вы будете вызывать через AJAX (на сколько мне известно в JavaScript не предусмотрено работа с кодировкой и все строки он хранит в utf-8).
Представьте, запускаете вы файл, а его продолжительность изменяется по мере его загрузки во flesh и вместо русских букв каракули - не очень хорошо, на мой взгляд. Именно для избежания этого мы и передаем данные из вне, а не получаем от flesh.
Оформление наших скриптов в форме плагина, позволяет организовать очень простую инициализацию и управление нашим плеером:
JavaScript: //создаем плеер внутри элемента с классом myaudioplayer $('.myaudioplayer').audiopleyer({ interval: 500, playlist: [{name:"song1", artist:"artist", src:"/mp3/song1.mp3", duration:"01:20"}, {name:"song2", artist:"artist", src:"/mp3/song2.mp3", duration:"01:38"}] }); //переопределяем плейлист $('.myaudioplayer').audiopleyer().playlistSet([ {name:"song10", artist:"artist", src:"/mp3/song10.mp3", duration:"02:20"}, {name:"song20", artist:"artist", src:"/mp3/song20.mp3", duration:"02:38"}, {name:"song30", artist:"artist", src:"/mp3/song30.mp3", duration:"02:19"} ]);
Мы создадим три основных html-блока:
Для создания html представления мы воспользуемся jQuery, не зря же мы пишем плагин для jQuery - давате использовать и его возможности.
JavaScript: //обертка для нашего плеера, которая будет помещена в родительский элемент (смотри выше - var player = $(this)) var player_wrapper = $('<div class="audioplayer"/>'); //часть для управления var player_control = $('<div class="control"/>'); //стандартные кнопки var player_control_prev = $('<div class="prev" title="Prev"/>'); var player_control_play = $('<div class="play" title="Play"/>'); var player_control_pause = $('<div class="pause" title="Pause"/>'); var player_control_stop = $('<div class="stop" title="Stop"/>'); var player_control_next = $('<div class="next" title="Next"/>'); //звук var player_control_volume = $('<div class="volume"/>'); var player_control_volume_slider = $('<div class="slider"/>'); player_control_volume.append(player_control_volume_slider); //сделаем наш бегунок в виде slider предоставляемого jQueryUI //зададим первоначальное значение уровня громкости 50% player_control_volume_slider.slider({ range: "min", value:50, slide:function(event, ui){ //зададим обработчик перемещения слайдера, функция apSetVolume рассматривается далее apVolumeSet(ui.value); } }); //прогресс бар (панель отображающая бегунок времени, текущее время и длительность мелодии) var player_control_progress = $('<div class="progress"/>'); var player_control_progress_position = $('<div class="position"/>'); var player_control_progress_track = $('<div class="track"/>'); var player_control_progress_track_slider = $('<div class="slider"/>'); player_control_progress_track.append(player_control_progress_track_slider); var player_control_progress_duration = $('<div class="duration"/>'); player_control_progress.append(player_control_progress_position, player_control_progress_track, player_control_progress_duration); //сделаем бегунок времени в виде slider предоставляемого jQueryUI player_control_progress_track_slider.slider({ range: "min", slide:function(event, ui) { //зададим обработчик перемещения слайдера, функция apSetPosition рассматривается далее apPositionSet(ui.value); } }); //кнопки shuffle и repeat var player_control_shuffle = $('<div class="shuffle" title="Shuffle"/>'); var player_control_repeat = $('<div class="repeat" title="Repeat"/>'); //название и исполнитель var player_control_title = $('<div class="title"/>'); var player_control_title_artist = $('<p class="artist"/>'); var player_control_title_name = $('<p class="name"/>'); player_control_title.append(var player_control_title_artist, var player_control_title_name); //собираем все в player_control player_control.append(player_control_prev, player_control_play, player_control_pause, player_control_stop, player_control_next, player_control_volume, player_control_progress, player_control_shuffle, player_control_repeat, player_control_title);
Теперь мы создадим html-объект и передадим ему наши настройки:
JavaScript: var player_swf = $('<div class="swf"/>'); //передаем ссылку к flesh var player_swf_object = $('<object id="swf_audioplayer" type="application/x-shockwave-flash" data="' + options.flash_url + '" width="1" height="1"/>'); //параметры объекта var player_swf_object_param1 = $('<param name="movie" value="' + options.flash_url + '"/>'); var player_swf_object_param2 = $('<param name="AllowScriptAccess" value="always"/>'); //передаем управляющие параметры - интервал обновления данных и название объекта которуму передавать эти данные var player_swf_object_param3 = $('<param name="FlashVars" value="listener=_audioplayer_listener&interval=' + options.interval + '"/>'); //собираем объект player_swf_object.append(player_swf_object_param1, player_swf_object_param2, player_swf_object_param3); player_swf.append(player_swf_object); //создаем привязку к flash объекту, по которой мы будем передавать управляющие параметры. //тут мы должны получить сам объект, а не объект в обертке jQuery, поэтому используем классический метод JavaScript var swf = document.getElementById("swf_audioplayer");
Как вы уже видели, плейлист передается в виде массива мелодий, представляющих собой объекты с полями:
В принципе если вы не хотите отображать плейлист, то можете этот блок не создавать вообще.
JavaScript: var player_playlist = $('<div class="playlist"/>'); //формируем плейлист for(var i = 0; i < options.playlist.length; i++) { var song = options.playlist[i]; var player_playlist_song = $('<div class="song"/>'); var player_playlist_song_name = $('<p class="name"/>').html(song.name); var player_playlist_song_artist = $('<p class="artist"/>').html(song.artist); var player_playlist_song_duartion = $('<p class="duartion"/>').html(song.duartion); var player_playlist_song_src = $('<p class="src"/>').html(song.src); player_playlist_song.click(function(){ apTrackSet(this); }); player_playlist_song.append(player_playlist_song_name, player_playlist_song_artist, player_playlist_song_duartion, player_playlist_song_src); player_playlist.append(player_playlist_song); };
Основные блоки, отвечающие за внешнее представление, готовы и остается только собрать их воедино:
JavaScript: player_wrapper.append(player_control, player_swf, player_playlist); //помещаем полученный блок в элемент-родитель, предварительно очистив все его содержимое player.html('').append(player_wrapper);
В результате для инициализации:
JavaScript: $('.myaudioplayer').audiopleyer({ interval: 500, playlist: [{name:"song1", artist:"artist", src:"/mp3/song1.mp3", duration:"01:20"}, {name:"song2", artist:"artist", src:"/mp3/song2.mp3", duration:"01:38"}] });
Мы должны получить следующий HTML код:
HTML: <div class="myaudioplayer"> <div class="audioplayer"> <div class="control"> <div class="prev" title="Prev"></div> <div class="play" title="Play"></div> <div class="pause" title="Pause"></div> <div class="stop" title="Stop"></div> <div class="next" title="Next"></div> <div class="volume"> <div class="slider ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all"> <div class="ui-slider-range ui-widget-header ui-slider-range-min" style="width:50%;"></div> <a class="ui-slider-handle ui-state-default ui-corner-all" href="#" style="left:50%;"></a> </div> </div> <div class="progress"> <div class="position"></div> <div class="track"> <div class="slider ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all"> <div class="ui-slider-range ui-widget-header ui-slider-range-min" style="width:0%;"></div> <a class="ui-slider-handle ui-state-default ui-corner-all" href="#" style="left:0%;"></a> </div> </div> <div class="duration"></div> </div> <div class="shuffle" title="Shuffle"></div> <div class="repeat" title="Repeat"></div> <div class="title"> <p class="artist"></p> <p class="name"></p> </div> </div> <div class="swf"> <object id="swf_audioplayer" type="application/x-shockwave-flash" data="playermp3_js.swf" width="1" height="1"> <param name="movie" value="playermp3_js.swf"/> <param name="AllowScriptAccess" value="always"/> <param name="FlashVars" value="listener=_audioplayer_listener&interval=500"/> </object> </div> <div class="playlist"> <div class="song"> <p class="name">song1</p> <p class="artist">artist</p> <p class="duration">01:20</p> <p class="src">/mp3/song1.mp3</p> </div> <div class="song"> <p class="name">song2</p> <p class="artist">artist</p> <p class="duration">01:38</p> <p class="src">/mp3/song2.mp3</p> </div> </div> </div> </div>
Cам объект мы уже определили, осталось только добавить обработчики двух событий, генерируемых flesh.
При вызове этого события мы зададим первоначальные параметры нашего объекта, а так же добавим несколько полей, которые пригодятся нам в будущем:
Вы спросите, для чего нам isPaused если есть стандартный флаг isPlaying? Параметр isPlaying показывает играет или нет мелодия в конкретный момент. Но мелодия может не играть по двум причинам - ее поставили на паузу или ее остановили совсем, что эквивалентно тому что мелодия доиграла до конца. Именно для различения этих состояний нам и нужен флаг isPaused.
В качестве начальных параметров зададим уровень громкости 50%, загрузим в плеер первую мелодию
JavaScript: _audioplayer_listener.onInit = function() { this.track = 0; this.isPaused = false; this.isRepeat = false; this.isShuffle = false; swf.SetVariable("method:setVolume", 50); if(options.playlist.length > 0) { swf.SetVariable("method:setUrl", options.playlist[0].src); player_control_duration.html(options.playlist[0].duration); player_control_artist.html(options.playlist[0].artist); player_control_name.html(options.playlist[0].name); } else { this.url = false; } }
На это событие приходится основная нагрузка по обновлению графического представления нашего проигрывателя.
JavaScript: _audioplayer_listener.onUpdate = function() { //параметр isPlaying приходит из flesh в виде строки, а для нас представляет интерес логический параметр this.isPlaying = (this.isPlaying == "true") ? true : false; //если у нас мелодия остановилась, но пауза не нажата, это значит что она доиграла до конца и следует запустить следубщую if(!this.isPlaying && !this.isPaused) { swf.SetVariable("enabled", "false"); apNext(); } //обновляем счетчик прошедшего времени var time = Math.round(this.position / 1000); var minutes = Math.flour(time / 60); var seconds = time - minutes * 60; player_control_progress_position.html(minutes + ":" + seconds); //передвигаем бегунок времени //я уже отмечал, что полное время показывается только после полной загрузки файла //поэтому, чтобы наш бегунок не скакал туда-сюда при загрузке файла, будем учитывать процент загрузки player_control_progress_track_slider.slider("value", Math.round((this.position / this.duration) * this.bytesPercent)); }
Давайте рассмотрим все функции, которые нам потребуются для управления проигрывателем.
Эта функция определяет номер выбранной песни в списке и передает его функции apPlaylistSetNum(). Как вы помните мы повесили обработчик onclick на каждую песню плейлиста, который передает елемент по которому произошел щелчок мыши.
JavaScript: function apTrackSet(element) { //определяем номер песни в списке var song_src = $('.src', element).html(); var song_number = 0; for(var i = 0; i < options.playlist.length; i++) { if(options.playlist[i].src == song_src) { song_number = i; break; } } //устанавливаем песню apTrackSetNum(song_number); }
Эта функция будет останавливать проигрыватель и запускать выбранную мелодию из плейлиста по ее номеру. Согласно описанию нашего плагина, эта функция доступна из-вне.
JavaScript: function apTrackSetNum(num) { if(num > 0 && num < options.playlist.length) { //получаем URL установленно песни var url = options.playlist[num].src; //обновляем данные графической части player_control_duration.html(options.playlist[num].duration); player_control_artist.html(options.playlist[num].artist); player_control_name.html(options.playlist[num].name); //обновляем поля объекта _audioplayer_listener.track = num; //останавливаем проигрыватель swf.SetVariable("method:stop", ""); swf.SetVariable("enabled", "false"); //запускаем выбранную песню swf.SetVariable("method:setUrl", url); swf.SetVariable("method:play", ""); swf.SetVariable("enabled", "true"); } }
Запускает воспроизведение мелодии.
JavaScript: function apPlay() { if(_audioplayer_listener.url) { swf.SetVariable("method:play", ""); swf.SetVariable("enabled", "true"); _audioplayer_listener.isPaused = false; } }
Ставим мелодию на паузу.
JavaScript: function apPause() { if(_audioplayer_listener.url) { swf.SetVariable("method:pause", ""); _audioplayer_listener.isPaused = true; } }
Останавливаем проигрыватель.
JavaScript: function apStop() { swf.SetVariable("method:stop", ""); swf.SetVariable("enabled", "false"); player_control_progress_track_slider.slider("value", 0); }
Запускаем следующую песню. Если установлен флаг isRepeat, то повторяем текущую еще раз.
В данном случаи если стоит флаг isShuffle, то мы выбираем песню случайным образом. Но в целом я бы посоветовал формировать второй список воспроизведения путем перемешивания основного списка воспроизведения и в зависимости от isShuffle брать песню из первого или из второго списка.
JavaScript: function apNext() { if(!_audioplayer_listener.isRepeat) { if(_audioplayer_listener.isShuffle) { _audioplayer_listener.track = Math.floor(Math.random() * (options.playlist.length + 1)) } else { _audioplayer_listener.track++; if(_audioplayer_listener.track >= options.playlist.length) { _audioplayer_listener.track = 0; } } } apTruckSetNum(_audioplayer_listener.track); }
Запускаем предыдущую песню.
Все аналогично apNext().
JavaScript: function apPrev() { if(!_audioplayer_listener.isRepeat) { if(_audioplayer_listener.isShuffle) { _audioplayer_listener.track = Math.floor(Math.random() * (options.playlist.length + 1)) } else { _audioplayer_listener.track--; if(_audioplayer_listener.track < 0) { _audioplayer_listener.track = options.playlist.length - 1; } } } apTruckSetNum(_audioplayer_listener.track); }
Устанавливаем уровень громкости. Напоминаю, что запуск этой функции осуществляется обработчиком событий бегунка уровня звука (slider).
JavaScript: function apVolumeSet(volume) { swf.SetVariable("method:setVolume", volume); }
Устанавливаем место воспроизведения мелодии. Напоминаю, что запуск этой функции осуществляется обработчиком событий бегунка времени (slider).
Не забываем, что обработчик передает значение от 0 до 100.
JavaScript: function apPositionSet(position) { //переводим проценты в миллисекунды position = Math.round(position * _audioplayer_listener.duration / 100); swf.SetVariable("method:setPosition", position); }
Устанавливаем новый плейлист. По сути нам нужно проделать тоже самое, что мы делали при инициализации нашего плагина.
JavaScript: function apPlaylistSet(playlist) { //очищаем текущий плейлист player_playlist.html(''); //формируем новый for(var i = 0; i < playlist.length; i++) { var song = playlist[i]; var player_playlist_song = $('<div class="song"/>'); var player_playlist_song_name = $('<p class="name"/>').html(song.name); var player_playlist_song_artist = $('<p class="artist"/>').html(song.artist); var player_playlist_song_src = $('<p class="src"/>').html(song.src); var player_playlist_song_duration = $('<p class="duration"/>').html(song.duration); player_playlist_song.click(function(){ apTrackSet(this); }); player_playlist_song.append(player_playlist_song_name, player_playlist_song_artist, player_playlist_song_duartion, player_playlist_song_src); player_playlist.append(player_playlist_song); } }
Как вы понимает основной функционал уже описан и остается привязать выполнение тех или иных функций при нажатии на управляющие кнопки плеера.
Обработчики бегунков уже были описаны, а остальные описываются буквально парой строк, поэтому я приведу их единым блоком:
JavaScript: //нажатие на кнопку play player_control_play.click(function() { apPlay(); }); //нажатие на кнопку pause player_control_pause.click(function() { apPause(); }); //нажатие на кнопку stop player_control_stop.click(function() { apStop(); }); //нажатие на кнопку prev player_control_prev.click(function() { apPrev(); }); //нажатие на кнопку next player_control_next.click(function() { apNext(); }); //нажатие на кнопку shuffle player_control_shuffle.click(function() { if(_audioplayer_listener.isShuffle) { _audioplayer_listener.isShuffle = false; } else { _audioplayer_listener.isShuffle = true; } }); //нажатие на кнопку repeat player_control_repeat.click(function() { if(_audioplayer_listener.isRepeat) { _audioplayer_listener.isRepeat = false; } else { _audioplayer_listener.isRepeat = true; } });
Плеер готов к работе.
Как показывает практика, чем больше ограничений разработчик накладывает на свое приложение - тем проще с ним работать. Однако не надо забывать, что вам придется работать в рамках этих ограничений и если вы захотите большого, то придется поменять приложение.
С другой стороны, чем меньше ограничений у приложения, тем более квалифицированного подхода оно требует.
Не совсем подходящая, но тем не менее аналогия из области разработки дизайна. Давно известно, что заказчику нужно показывать два, максимум три варианта макета. В этом случаи он быстро примет решение. Если же ему показать 10 вариантов, то принятие решения может затянутся на месяца.
Понятно, что в большинстве случаев подойдет стандартный дизайн аудио плеера с возможностью кастомизации цветового решения. Даже в данном случаи разработчик flesh предлагает целых 4 варианта стандартного дизайна с очень гибкой системой настройки цветового решения.
Но если вы столкнулись с необходимостью или просто хотите создать уникальный дизайн аудио плеера, то рекомендую обратить внимания на представленное решение. Оно полностью развязывает вам руки - единственные ограничения это мастерство дизайнера, создающего внешнее представление плеера и мастерство программиста, который описывает внутреннее представление.
Причем мастерство обоих ограничено их воображением и практическим опытом.