MediaWiki:Gadget-sound.js
Jump to navigation
Jump to search
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
- Opera: Press Ctrl-F5.
mw.hook('wikipage.content').add(function ($content) {
var i18n = {
playTitle: 'Click to play',
stopTitle: 'Click to stop',
};
var $sound = $content.find('.sound');
$sound.prop('title', i18n.playTitle);
// for MW 1.40
$sound.each(function(){
if($(this).find("audio").attr("disabled")){
var $audio = $(this).find("audio");
var mwtitle = $audio.attr("data-mwtitle");
getInfo( mwtitle ).then( function( info ){
var attr = {};
if( !info ) {
attr.src = "/w/Special:FilePath/" + mwtitle.replaceAll(" ", "_");
} else {
var metadata = meta2obj(info.metadata);
attr.src = info.url;
try {
attr.type = info.mime.replace(/application/, "audio") + "; codecs='" + metadata.streams[0].data.type + "'";
} catch(error){}
}
$audio.removeAttr('disabled')
.attr("preload", "metadata")
.attr("role", "application")
.attr("src", attr.src)
.append(
$("<source />", attr)
);
});
}
});
$sound.on('click', function (e) {
// Ignore links
if (e.target.tagName === 'A') {
return;
}
var audio = $(this).find('audio')[0];
if (audio) {
audio.paused ? audio.play() : audio.pause();
}
});
$sound.find("audio").on('play', function () {
// Stop any already playing sounds
var playing = $('.sound-playing audio')[0];
playing && playing.pause();
$(this).closest('.sound')
.addClass('sound-playing').prop('title', i18n.stopTitle);
}).on('pause', function () {
// Reset back to the start
this.currentTime = 0;
$(this).closest('.sound')
.removeClass('sound-playing').prop('title', i18n.playTitle);
});
});
/**
* Retries a request once if it fails
*
* Always returns an abortable promise, even if the request itself isn't abortable.
*
* "request" is a function which will run the request,
* and should return the request's promise.
* "delay" is the amount of milliseconds to wait before retrying.
* "retries" is the amount of times to retry
*/
function retryableRequest(request, delay, retries) {
var deferred = $.Deferred();
var curRequest;
var timeout;
retries = retries || 1;
var attemptRequest = function (attempt) {
(curRequest = request()).then(deferred.resolve, function (code, data) {
if (attempt <= retries) {
timeout = setTimeout(function () {
attemptRequest(++attempt);
}, delay || 1000);
} else {
deferred.reject(code, data);
}
});
};
attemptRequest(1);
return deferred.promise({
abort: function () {
if (curRequest.abort) {
curRequest.abort();
}
clearTimeout(timeout);
}
});
}
/*****************************
* Request audio info
*/
function getInfo(filename) {
filename = filename.replaceAll(" ", "_");
if (filename.indexOf("File:") != 0) {
filename = "File:" + filename;
}
return retryableRequest(function () {
return new mw.Api().get({
action: 'query',
titles: filename,
prop: 'videoinfo',
viprop: 'url|mime|metadata'
});
}).then(function (data) {
if (data) {
var pageid = Object.keys(data.query.pages)[0];
if (pageid > -1) {
return data.query.pages[pageid].videoinfo[0];
}
}
return "";
}).fail(function () {
return "";
});
}
function meta2obj(value){
if(typeof value === 'object' && Array.isArray(value)){
var obj = {}, idx = 0;
value.forEach( function( v, i ){
if(v.hasOwnProperty("name") && v.hasOwnProperty("value")){
if(typeof v.name === 'number'){
obj[idx++] = {
id: v.name,
data: meta2obj(v.value)
};
} else {
obj[v.name] = meta2obj(v.value);
}
}
});
return obj;
}
return value;
}