thomper / Lernu English HTML5 Audio

// ==UserScript==
// @name            Lernu English HTML5 Audio
// @namespace       http://www.ontbee.com/gmscripts
// @description     Alter en.lernu.net to use HTML5 sound instead of Flash
// @license         MIT
// @version         0.1
// @include         http://en.lernu.net/*
// @grant           none
// @noframes
// ==/UserScript==

// This script finds 'click to play this sound' links and changes the
// onclick function to use a HTML5 Audio object instead of their
// flash player.
//
// An example of a link is:
// <a href="javascript:void(0);" onclick="sendiAlFlash('/sonoj/prononcoj/alfabeto/a.mp3');" class="SuperBibl LARGHO 20" title="Listen to the sound with the sound player.">A</a>
//
// We first grab all elements of that class. The 'click to download'
// links have the same class though so we then filter based on the
// 'enhavo' property.  For some reason the title for all these
// elements is '' in javascript but the enhavo property has the title.
//
// Once we have all the click-to-play links, we get the sound file
// URL for each link and set its onclick function to play that URL.

var SOUND_LINK_CLASS_NAME = 'SuperBibl LARGHO 20';
var PLAY_LINK_ENHAVO = 'Listen to the sound with the sound player.';
var SOUND_LINK_RE = /sendiAlFlash\((?:'(.+\.mp3)'|"(.+\.mp3)")/;

// For some reason calling [].filter.call(arr, etc.) gives an error:
// this.each is not a function.  So we have to write our own filter.
function filterArray(arr, condFunc) {
    var results = [];

    // arr won't be an array in this script, but an array-like object,
    // so we can't just call arr.forEach.
    Array.prototype.forEach.call(arr, function(element) {
        if (condFunc(element)) {
            results.push(element);
        }
    });

    return results;
}

function getSoundLinks() {
    var links = document.getElementsByClassName(SOUND_LINK_CLASS_NAME);
    return filterArray(links, function(link) {
        return link.enhavo === PLAY_LINK_ENHAVO;
    });
}

function getSoundUrl(link) {
    var onclickText = link.onclick.toString();
    return SOUND_LINK_RE.exec(onclickText)[1];
}

function buildPlayFunc(url) {
    var audio = new Audio(url);

    return function() {
        audio.pause();
        audio.currentTime = 0;
        audio.play();
    };
}

function fixLinks() {
    getSoundLinks().forEach(function(link) {
        link.onclick = buildPlayFunc(getSoundUrl(link));
    });
}

window.addEventListener('load', function() {
    fixLinks();
});