Fantastic Frontier Roblox Wiki
Advertisement

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.
$(function() {
    // Define utility functionality.
    function str_pad_left(string,pad,length) {
        return (new Array(length + 1).join(pad) + string).slice(-length);
    }
    
    function pretty_print_time(time) {
        return Math.floor(time / 60) + ':' + str_pad_left(Math.floor(time % 60), '0', 2);
    }
    
    // Loop all found audio players on the article.
    $(".audio-player").each(function() {
        var ap = $(this); // Current audio player tag.
        
        // Get widget stats.
        var id = ap.attr("data-id");
        var title = ap.attr("data-title");
        var authors = ap.attr("data-authors");
        var notes = ap.attr("data-notes");
        var aType = ap.attr("data-type");
        if (aType === "" || aType === undefined)
            aType = "youtube";
        
        // Replacement widget.
        var widget = $("<div class=\"audio-player\"><div class=\"icon missing\"></div><span class=\"aplayer-title\"></span><span class=\"aplayer-timer\"><span class=\"aplayer-timer-text\">[-:-- / -:--]</span><span class=\"aplayer-tslider\"><span class=\"aplayer-tslider-curr\" style=\"width:0%\"></span></span></span><span class=\"aplayer-notes\"></span></div>");
        var icon = widget.find(".icon");
        
        widget.find(".aplayer-title").text(title + " - " + authors);
        widget.find(".aplayer-notes").text(notes);
        
        // Visual display of time & duration of audio.
        var timer = widget.find(".aplayer-timer-text");
        var slider = widget.find(".aplayer-tslider");
        var slider_curr = slider.find(".aplayer-tslider-curr");
        
        ap.replaceWith(widget);
        
        // Check, because we don't allow playing if there's no audio specified.
        if (id.length > 0 && (id != "Youtube video id" && id != "Video/audio id")) {
            if (aType == "apm") {
                if (!id.endsWith(".mp3"))
                    id += ".mp3";
                // Refer to https://www.apmmusic.com/legal - hopefully no issues as far as I can see.
                var audio = new Audio("https://audio.prod.apmmusic.com/mp3_128/" + id);
                audio.type = "audio/mp3";
                
                var updateTimer = function(ended) {
                    var curr = ended ? duration : playerTarget.getCurrentTime();
                    timer.text("[" + pretty_print_time(curr) + " / " + pretty_print_time(duration) + "]");
                    slider_curr.css({"width": ((curr / duration) * 100) + "%"});
                };
                
                var duration;
                
                audio.loadedmetadata = function() {
                    duration = audio.duration;
                    console.log(duration);
                    timer.text("[0:00 / " + pretty_print_time(duration) + "]"); // Init timer.
                };
                audio.preload = true;
                console.log([audio], audio.duration);
                setTimeout(function() {
                    audio.play(); // test.
                }, 4000);
            } else {
                // This code loads the Youtube IFrame Player API code asynchronously. Wikia only supports OGG audio files, unfortunately.
                var tag = document.createElement('script');
                tag.src = "https://www.youtube.com/iframe_api";
                var firstScriptTag = document.getElementsByTagName('script')[0];
                firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
                
                // Placeholder <div> to store the video. The id is random.
                var videoPlaceholderTag = $("<div id='yt-player-" + Math.floor(1000 + Math.random() * 1999000) + "'></div>");
                videoPlaceholderTag.css({"display": "none"});
                $("body").append(videoPlaceholderTag);
                
                // This is a bit of a hack, but we use this async loop to wait for YT (Youtube API) to become available.
                var loadTimerVar, player, playerTarget, duration;
                
                var updateTimer = function(ended) {
                    var curr = ended ? duration : playerTarget.getCurrentTime();
                    timer.text("[" + pretty_print_time(curr) + " / " + pretty_print_time(duration) + "]");
                    slider_curr.css({"width": ((curr / duration) * 100) + "%"});
                };
                
                var playerIsPlaying = false; // To use outside of our code below.
                loadTimerVar = setInterval(function() {
                    if (("YT" in window) && YT.loaded) { // The Youtube API has loaded.
                        clearInterval(loadTimerVar);
                        var playTimer;
                        // Load in the Youtube video element, to prepare playing.
                        player = new YT.Player(videoPlaceholderTag.attr("id"), {
                            height: '0',
                            width: '0',
                            videoId: id,
                            suggestedQuality: "small",
                            events: {
                                'onReady': function(event) {
                                    playerTarget = event.target; // Grabs the player instance for later use.
                                    duration = playerTarget.getDuration();
                                    timer.text("[0:00 / " + pretty_print_time(duration) + "]"); // Init timer.
                                    // To save bandwidth, since we don't need any video.
                                    playerTarget.setPlaybackQuality("small");
                                    // The video is ready, so we show the play icon.
                                    icon.removeClass("missing").removeClass("pause").addClass("play");
                                    icon.css({"cursor": "pointer"}); // The button can now be clicked.
                                    slider.css({"cursor": "pointer"}); // The slider can now be clicked.
                                },
                                'onStateChange': function(event) {
                                    var isPlaying = event.data == YT.PlayerState.PLAYING || event.data == YT.PlayerState.BUFFERING; // Either playing or buffering is good to show the pause icon.
                                    if (isPlaying != playerIsPlaying) { // Playing state was changed.
                                        playerIsPlaying = isPlaying;
                                        icon.removeClass(!playerIsPlaying ? "pause" : "play").addClass(!playerIsPlaying ? "play" : "pause");
                                        
                                        // Update the timer display loop.
                                        if (isPlaying && playTimer === undefined) {
                                            playTimer = setInterval(updateTimer, 100);
                                        } else if (!isPlaying && playTimer !== undefined) {
                                            clearInterval(playTimer);
                                            playTimer = undefined;
                                        }
                                    }
                                    if (event.data == YT.PlayerState.ENDED) // Move to end.
                                        updateTimer(true);
                                }
                            }
                        });
                    }
                }, 100);
                
                // Click listener to toggle playing the audio.
                icon.click(function() {
                    if (playerTarget !== undefined) {
                        if (playerIsPlaying) {
                            playerTarget.pauseVideo();
                        } else {
                            playerTarget.playVideo();
                        }
                    }
                });
                
                slider.click(function(e) {
                    var posX = e.pageX - slider.offset().left;
                    var p = posX / slider.width();
                    
                    if (playerTarget !== undefined) {
                        playerTarget.seekTo(p * duration);
                        updateTimer();
                    }
                });
            }
        }
    });
});
Advertisement