448 lines
15 KiB
JavaScript
448 lines
15 KiB
JavaScript
/* Copyright (C) 2013, 2014 Tilman Kranz <tilt@linuxfoo.de>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person
|
|
* obtaining a copy of this software and associated documentation
|
|
* files (the "Software"), to deal in the Software without
|
|
* restriction, including without limitation the rights to use, copy,
|
|
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
* of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
|
* KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
|
* OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
|
|
* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
|
* THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE */
|
|
|
|
var MyPlayer = function(_args) {
|
|
var failed = false,
|
|
detached = false,
|
|
player = null,
|
|
args_default = {
|
|
autoplay: false,
|
|
css: { "height": "500px" },
|
|
detachable: true,
|
|
element: "body",
|
|
id3: false,
|
|
list: [],
|
|
loop: true,
|
|
mode: "mp3url",
|
|
shuffle: false,
|
|
waveform: false
|
|
},
|
|
args = (_args===undefined) ? args_default : $.extend({}, args_default, _args),
|
|
mimeTypeFromSrc = function(src) {
|
|
var extension = src.split(".").pop().toLowerCase();
|
|
|
|
var types = {
|
|
"3g2": "video/3gpp2",
|
|
"3gp": "video/3gpp",
|
|
"7z": "application/x-7z-compressed",
|
|
"aac": "audio/aac",
|
|
"abw": "application/x-abiword",
|
|
"arc": "application/x-freearc",
|
|
"avi": "video/x-msvideo",
|
|
"azw": "application/vnd.amazon.ebook",
|
|
"bin": "application/octet-stream",
|
|
"bmp": "image/bmp",
|
|
"bz": "application/x-bzip",
|
|
"bz2": "application/x-bzip2",
|
|
"cda": "application/x-cdf",
|
|
"csh": "application/x-csh",
|
|
"css": "text/css",
|
|
"csv": "text/csv",
|
|
"doc": "application/msword",
|
|
"eot": "application/vnd.ms-fontobject",
|
|
"epub": "application/epub+zip",
|
|
"gif": "image/gif",
|
|
"gz": "application/gzip",
|
|
"htm": "text/html",
|
|
"html": "text/html",
|
|
"ico": "image/vnd.microsoft.icon",
|
|
"ics": "text/calendar",
|
|
"jar": "application/java-archive",
|
|
"jpeg": "image/jpeg",
|
|
"jpg": "image/jpeg",
|
|
"js": "text/javascript",
|
|
"json": "application/json",
|
|
"jsonld": "application/ld+json",
|
|
"mid": "audio/midi audio/x-midi",
|
|
"midi": "audio/midi audio/x-midi",
|
|
"mjs": "text/javascript",
|
|
"mp3": "audio/mpeg",
|
|
"mp4": "video/mp4",
|
|
"mpeg": "video/mpeg",
|
|
"mpkg": "application/vnd.apple.installer+xml",
|
|
"odp": "application/vnd.oasis.opendocument.presentation",
|
|
"ods": "application/vnd.oasis.opendocument.spreadsheet",
|
|
"odt": "application/vnd.oasis.opendocument.text",
|
|
"oga": "audio/ogg",
|
|
"ogv": "video/ogg",
|
|
"ogx": "application/ogg",
|
|
"opus": "audio/opus",
|
|
"otf": "font/otf",
|
|
"pdf": "application/pdf",
|
|
"php": "application/x-httpd-php",
|
|
"png": "image/png",
|
|
"ppt": "application/vnd.ms-powerpoint",
|
|
"rar": "application/vnd.rar",
|
|
"rtf": "application/rtf",
|
|
"sh": "application/x-sh",
|
|
"svg": "image/svg+xml",
|
|
"swf": "application/x-shockwave-flash",
|
|
"tar": "application/x-tar",
|
|
"tif": "image/tiff",
|
|
"tiff": "image/tiff",
|
|
"ts": "video/mp2t",
|
|
"ttf": "font/ttf",
|
|
"txt": "text/plain",
|
|
"vsd": "application/vnd.visio",
|
|
"wav": "audio/wav",
|
|
"weba": "audio/webm",
|
|
"webm": "video/webm",
|
|
"webp": "image/webp",
|
|
"woff": "font/woff",
|
|
"woff2": "font/woff2",
|
|
"xhtml": "application/xhtml+xml",
|
|
"xls": "application/vnd.ms-excel",
|
|
"xml": "application/xml",
|
|
"xul": "application/vnd.mozilla.xul+xml",
|
|
"zip": "application/zip"
|
|
};
|
|
|
|
return types[extension] || "application/octet-stream";
|
|
},
|
|
createAudio = function() {
|
|
var autoplay = args.autoplay ? 'autoplay="true"' : '';
|
|
var styles = [];
|
|
var style;
|
|
var key;
|
|
|
|
for (key in args.css) {
|
|
var value = args.css[key];
|
|
styles.push(`${key}: ${value}`);
|
|
}
|
|
|
|
style = styles.join(" ");
|
|
args.audio = $(`<audio id="myplayer" controls="controls" style="${style}" ${autoplay}></audio>`);
|
|
console.log("DEBUG: appending audio=", args.audio, " to element=", args.element, " ...");
|
|
$(args.element).append(args.audio);
|
|
},
|
|
readId3 = function() {
|
|
$(args.element).find('ul.mejs li').each(function(i, track){
|
|
var url = $(track).attr('data-url');
|
|
|
|
$(track).prepend('<span class="ajaxLoader"> </span> ');
|
|
|
|
jsmediatags.read(url, {
|
|
onSuccess: function(tag) {
|
|
var tags = tag.tags;
|
|
var track_title;
|
|
|
|
if(typeof(tags.title)!='undefined') {
|
|
track_title = tags.title;
|
|
}
|
|
else {
|
|
track_title = url;
|
|
}
|
|
|
|
if(typeof(tags.artist)!='undefined') {
|
|
track_title = tags.artist + ' - ' + track_title;
|
|
}
|
|
|
|
$(args.element).find('ul.mejs li').each(function(j, _track){
|
|
if(i==j) {
|
|
$(_track).html(track_title);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
});
|
|
},
|
|
playerCreated = function(mediaElement, originalNode, instance) {
|
|
restoreParams();
|
|
|
|
if(args.shuffle) {
|
|
instance.shuffleCallback();
|
|
}
|
|
|
|
if(args.loop) {
|
|
instance.loopCallback();
|
|
}
|
|
|
|
if(args.id3) {
|
|
readId3();
|
|
}
|
|
},
|
|
createPlayer = function() {
|
|
player = new MediaElementPlayer(
|
|
"myplayer", {
|
|
success: playerCreated,
|
|
features: [
|
|
'playpause',
|
|
'current',
|
|
'progress',
|
|
'duration',
|
|
'volume',
|
|
'playlist',
|
|
'prevtrack',
|
|
'nexttrack',
|
|
'shuffle',
|
|
'loop'
|
|
]
|
|
});
|
|
|
|
$(args.element).append(
|
|
'<p class="playerDetached" style="display: none;">'+
|
|
'The player is currently detached.'+
|
|
'</p>'
|
|
);
|
|
},
|
|
param = function(name) {
|
|
var query = window.location.search.substring(1);
|
|
var vars = query.split("&");
|
|
|
|
for(i=0; i<vars.length; i++) {
|
|
var pair = vars[i].split("=");
|
|
|
|
if(pair[0] == name) {
|
|
return pair[1];
|
|
}
|
|
}
|
|
|
|
return false;
|
|
},
|
|
setupDetach = function() {
|
|
if(!args.detachable) {
|
|
return;
|
|
}
|
|
|
|
var popup = function(url) {
|
|
player.pause();
|
|
$('.mejs-audio').hide();
|
|
$('.playerDetached').show();
|
|
|
|
var playerWindow = window.open(
|
|
url, 'myplayer',
|
|
'height='+ Math.max($(args.element).height(), 298)+','+
|
|
'width='+408+','+
|
|
'resizable=false'
|
|
);
|
|
|
|
if(window.focus) {
|
|
playerWindow.focus();
|
|
}
|
|
|
|
$("iframe",top.document).height(20);
|
|
|
|
return false;
|
|
};
|
|
|
|
if(param('popup')==false) {
|
|
$('.mejs-controls').append(
|
|
'<div id="popupButton" '+
|
|
'class="popupButton">'+
|
|
'<button '+
|
|
'title="Open in separate window" '+
|
|
'type="button">'+
|
|
'</button>'+
|
|
'</div>'
|
|
);
|
|
|
|
$('.popupButton button').click(function(){
|
|
var currentTime = player.getCurrentTime();
|
|
var volume = player.getVolume();
|
|
var paused = player.media.paused;
|
|
var trackNo = 0;
|
|
|
|
$(args.element).find('ul.mejs li').each(function(i){
|
|
if($(this).hasClass('current')) {
|
|
trackNo = i;
|
|
}
|
|
});
|
|
|
|
popup(
|
|
$(location).attr('href')+'?'+
|
|
'popup&'+
|
|
'paused='+paused+'&'+
|
|
'currentTime='+currentTime+'&'+
|
|
'volume='+volume+'&'+
|
|
'trackNo='+trackNo
|
|
);
|
|
});
|
|
}
|
|
else {
|
|
var windowHeight = $(window).height();
|
|
|
|
window.onbeforeunload = function(){
|
|
$("iframe", opener.top.document).height(windowHeight);
|
|
$('.mejs-audio', opener.document).show();
|
|
$('.playerDetached', opener.document).hide();
|
|
};
|
|
}
|
|
},
|
|
restoreParams = function() {
|
|
if(!detached) {
|
|
return;
|
|
}
|
|
|
|
var paused = (param('paused') && param('paused')=='true');
|
|
var currentTime = param('currentTime') ? parseFloat(param('currentTime')) : 0.0;
|
|
var volume = param('volume') ? parseFloat(param('volume')) : 1.0;
|
|
var trackNo = param('trackNo') ? parseInt(param('trackNo')) : 0;
|
|
|
|
player.setVolume(volume);
|
|
|
|
$(args.element).find('ul.mejs li').each(function(i){
|
|
if(i==trackNo) {
|
|
player.playTrack($(this));
|
|
player.setCurrentTime(currentTime);
|
|
}
|
|
});
|
|
|
|
if(paused) {
|
|
player.pause();
|
|
}
|
|
};
|
|
|
|
if(param('popup')!==false) {
|
|
detached = true;
|
|
|
|
$('body').html(
|
|
'<div ' +
|
|
'id="myplayer" ' +
|
|
'style="' +
|
|
'width: ' + $(args.element).width() + 'px; '+
|
|
'height: ' + $(args.element).height() + ' px;'+
|
|
'"></div>'
|
|
);
|
|
|
|
args.element = '#myplayer';
|
|
}
|
|
|
|
if(args.mode=='mp3url') {
|
|
console.log("args.mode=", args.mode);
|
|
var mp3url = (typeof args.mp3url === "undefined")
|
|
? $(location).attr('href').replace(/\?.*/, '').replace(/\/[^\/]+\/?$/, '')
|
|
: args.mp3url;
|
|
|
|
$.ajax({
|
|
url: mp3url,
|
|
type: 'GET',
|
|
success: function(res) {
|
|
var doc;
|
|
var head;
|
|
|
|
doc = document.createElement('html');
|
|
|
|
createAudio();
|
|
doc.innerHTML = res;
|
|
|
|
head = $(doc).find('a').each(function(idx,item) {
|
|
var src = $(item).attr('href');
|
|
|
|
if(src.match(/\.mp3$/)) {
|
|
var url = mp3url+'/'+src;
|
|
var title = item.innerHTML;
|
|
var type = "audio/mpeg";
|
|
|
|
args.audio.append(`<source src="${url}" type="${type}" title="${title}"/>`);
|
|
}
|
|
});
|
|
|
|
createPlayer();
|
|
setupDetach();
|
|
}
|
|
});
|
|
}
|
|
else if(args.mode=='m3u') {
|
|
var m3u = (typeof args.m3u === "undefined")
|
|
? $(location).attr('href').replace(/\?.*/, '').replace(/\/[^\/]+\/?$/, '/play.m3u')
|
|
: args.m3u;
|
|
|
|
createAudio();
|
|
|
|
$.get(m3u, function(txt){
|
|
var lines = txt.split("\n");
|
|
var len = lines.length;
|
|
var i = 0;
|
|
|
|
while(i < len) {
|
|
if(!lines[i].match(/^[ \t]*#/) && lines[i].match(/\.mp3$/)) {
|
|
var mp3 = lines[i];
|
|
var title = unescape(mp3.split('/').pop());
|
|
var type = "audio/mpeg";
|
|
|
|
args.audio.append(`<source src="${mp3}" type="${type}" title="${title}"/>`);
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
createPlayer();
|
|
setupDetach();
|
|
});
|
|
}
|
|
else if(args.mode=='list') {
|
|
var len = args.list.length;
|
|
var i = 0;
|
|
|
|
createAudio();
|
|
|
|
while(i < len) {
|
|
var item = args.list[i];
|
|
var type = typeof item;
|
|
var src = '';
|
|
var title = '';
|
|
var type;
|
|
|
|
if(item !== null && type === 'object') {
|
|
if(item.url) {
|
|
src = item.url;
|
|
}
|
|
else {
|
|
alert(`MyPlayer: item[${i}]: property "url" is missing.`);
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
if(item.title) {
|
|
title = item.title;
|
|
}
|
|
else {
|
|
title = url.replace(/(.*\/)?([^\/]+)/, '$2');
|
|
}
|
|
}
|
|
else if(type === 'string') {
|
|
src = item;
|
|
title = src;
|
|
}
|
|
else {
|
|
alert(`MyPlayer: item[${i}]: unsupported type=${type}.`);
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
type = mimeTypeFromSrc(src);
|
|
|
|
args.audio.append(`<source src="${src}" type="${type}" title="${type}"/>`);
|
|
|
|
i++;
|
|
}
|
|
|
|
createPlayer();
|
|
setupDetach();
|
|
}
|
|
else {
|
|
$(args.element).append(`<p>Unsupported mode ${args.mode}"</p>`);
|
|
failed = true;
|
|
}
|
|
};
|
|
|