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 - он представляет собой массив объектов (мелодий), содержащих четыре поля:
* name - название песни.
* artist - исполнитель.
* src - путь к мелодии.
* duration - длительность.
Надо сразу оговориться, что длительность и 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-блока:
* Графическое отображение плеера.
* Объект содержащий сам flesh плеер.
* Плейлист.
Для создания html представления мы воспользуемся jQuery, не зря же мы пишем плагин для jQuery - давате использовать и его возможности.
=== Графическое отображение ===
JavaScript:
//обертка для нашего плеера, которая будет помещена в родительский элемент (смотри выше - var player = $(this))
var player_wrapper = $('');
//часть для управления
var player_control = $('');
//стандартные кнопки
var player_control_prev = $('');
var player_control_play = $('');
var player_control_pause = $('');
var player_control_stop = $('');
var player_control_next = $('');
//звук
var player_control_volume = $('');
var player_control_volume_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 = $('');
var player_control_progress_position = $('');
var player_control_progress_track = $('');
var player_control_progress_track_slider = $('');
player_control_progress_track.append(player_control_progress_track_slider);
var player_control_progress_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 = $('');
var player_control_repeat = $('');
//название и исполнитель
var player_control_title = $('');
var player_control_title_artist = $('');
var player_control_title_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);
=== Объект содержащий сам flesh плеер ===
Теперь мы создадим html-объект и передадим ему наши настройки:
JavaScript:
var player_swf = $('');
//передаем ссылку к flesh
var player_swf_object = $('');
//параметры объекта
var player_swf_object_param1 = $('');
var player_swf_object_param2 = $('');
//передаем управляющие параметры - интервал обновления данных и название объекта которуму передавать эти данные
var player_swf_object_param3 = $('');
//собираем объект
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");
=== Плейлист ===
Как вы уже видели, плейлист передается в виде массива мелодий, представляющих собой объекты с полями:
* name - название песни.
* artist - исполнитель.
* src - путь к мелодии.
* duration - длительность.
В принципе если вы не хотите отображать плейлист, то можете этот блок не создавать вообще.
JavaScript:
var player_playlist = $('');
//формируем плейлист
for(var i = 0; i < options.playlist.length; i++) {
var song = options.playlist[i];
var player_playlist_song = $('');
var player_playlist_song_name = $('').html(song.name);
var player_playlist_song_artist = $('').html(song.artist);
var player_playlist_song_duartion = $('').html(song.duartion);
var player_playlist_song_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);
};
=== Формирование HTML структуры плеера ===
Основные блоки, отвечающие за внешнее представление, готовы и остается только собрать их воедино:
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:
song1
artist
01:20
/mp3/song1.mp3
song2
artist
01:38
/mp3/song2.mp3
==== JS-объект (listener) ====
Cам объект мы уже определили, осталось только добавить обработчики двух событий, генерируемых flesh.
=== Событие onInit ===
При вызове этого события мы зададим первоначальные параметры нашего объекта, а так же добавим несколько полей, которые пригодятся нам в будущем:
* track - номер играющей мелодии.
* isShuffle - определяет включено ли перемешанное воспроизведение.
* isRepeat - определяет включено ли цикличное воспроизведение мелодии.
* isPaused - определяет нажата ли пауза.
Вы спросите, для чего нам 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;
}
}
=== Событие onUpdate ===
На это событие приходится основная нагрузка по обновлению графического представления нашего проигрывателя.
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));
}
==== Управляющие функции ====
Давайте рассмотрим все функции, которые нам потребуются для управления проигрывателем.
=== apTrackSet() ===
Эта функция определяет номер выбранной песни в списке и передает его функции 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);
}
=== apTrackSetNum() ===
Эта функция будет останавливать проигрыватель и запускать выбранную мелодию из плейлиста по ее номеру. Согласно описанию нашего плагина, эта функция доступна из-вне.
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");
}
}
=== apPlay() ===
Запускает воспроизведение мелодии.
JavaScript:
function apPlay() {
if(_audioplayer_listener.url) {
swf.SetVariable("method:play", "");
swf.SetVariable("enabled", "true");
_audioplayer_listener.isPaused = false;
}
}
=== apPause() ===
Ставим мелодию на паузу.
JavaScript:
function apPause() {
if(_audioplayer_listener.url) {
swf.SetVariable("method:pause", "");
_audioplayer_listener.isPaused = true;
}
}
=== apStop() ===
Останавливаем проигрыватель.
JavaScript:
function apStop() {
swf.SetVariable("method:stop", "");
swf.SetVariable("enabled", "false");
player_control_progress_track_slider.slider("value", 0);
}
=== apNext() ===
Запускаем следующую песню. Если установлен флаг 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);
}
=== apPrev() ===
Запускаем предыдущую песню.
Все аналогично 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);
}
=== apVolumeSet() ===
Устанавливаем уровень громкости. Напоминаю, что запуск этой функции осуществляется обработчиком событий бегунка уровня звука (slider).
JavaScript:
function apVolumeSet(volume) {
swf.SetVariable("method:setVolume", volume);
}
=== apPositionSet() ===
Устанавливаем место воспроизведения мелодии. Напоминаю, что запуск этой функции осуществляется обработчиком событий бегунка времени (slider).
Не забываем, что обработчик передает значение от 0 до 100.
JavaScript:
function apPositionSet(position) {
//переводим проценты в миллисекунды
position = Math.round(position * _audioplayer_listener.duration / 100);
swf.SetVariable("method:setPosition", position);
}
=== apPlaylistSet() ===
Устанавливаем новый плейлист. По сути нам нужно проделать тоже самое, что мы делали при инициализации нашего плагина.
JavaScript:
function apPlaylistSet(playlist) {
//очищаем текущий плейлист
player_playlist.html('');
//формируем новый
for(var i = 0; i < playlist.length; i++) {
var song = playlist[i];
var player_playlist_song = $('');
var player_playlist_song_name = $('').html(song.name);
var player_playlist_song_artist = $('').html(song.artist);
var player_playlist_song_src = $('').html(song.src);
var player_playlist_song_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 варианта стандартного дизайна с очень гибкой системой настройки цветового решения.
Но если вы столкнулись с необходимостью или просто хотите создать уникальный дизайн аудио плеера, то рекомендую обратить внимания на представленное решение. Оно полностью развязывает вам руки - единственные ограничения это мастерство дизайнера, создающего внешнее представление плеера и мастерство программиста, который описывает внутреннее представление.
Причем мастерство обоих ограничено их воображением и практическим опытом.