akuma06 / Sky Animes Radio

// ==UserScript==
// @name         Sky Animes Radio
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  Transform the skyanime radio in a html5 one!
// @author       akuma06
// @match        http://radio.sky-animes.com/
// @require      http://code.jquery.com/jquery-latest.js
// @grant        none
// ==/UserScript==

(function() {
    'use strict';
    var lastIndex = 0; var library = []; var params = {}; var radioState = { selectedAlbum :0, selectedSong: 0, playing: false, shuffle: false, startTime: 0};
    function loadParamsUrl () {
        params = {};
        var hash = window.location.hash.slice(1);
        if (hash != "") {
            var hashTable = hash.split("&");
            for (var h = 0; h < hashTable.length; h++) {
                var hashItem = hashTable[h].split("=");
                params[hashItem[0]] = hashItem[1];
            }
            console.log(params);
        }
    }
    loadParamsUrl();
    
   $("<link />").attr("rel", "stylesheet").attr("href", "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css").attr("integrity", "sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u").attr("crossorigin", "anonymous").appendTo("head");
   $("<link />").attr("rel", "stylesheet").attr("href", "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css").attr("integrity", "sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp").attr("crossorigin", "anonymous").appendTo("head");
   $("<script></script>").attr("src", "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js").attr("integrity", "sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa").attr("crossorigin", "anonymous").appendTo("head");
   $('<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">').appendTo("head");
    $(window).on("hashchange", function (e) {
        $("#list").html("");
        Templates.flush();
        loadParamsUrl();
        progressBar.show();
        progressBar.start(function () {
            load_links(true);
        });
    });
    if (localStorage.getItem("lastIndex") !== null) {
        lastIndex = JSON.parse(localStorage.getItem("lastIndex"));
    }
    if (sessionStorage.getItem("radioState") !== null) radioState = JSON.parse(sessionStorage.getItem("radioState"));

    var indexedDB = window.indexedDB || window.webkitIndexedDB || 
        window.mozIndexedDB || window.msIndexedDB;
    var IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction;
    var db;
    function initDb(callback) {
        var request = indexedDB.open("SkyAnimeDB", 3);  
        request.onsuccess = function (evt) {
            db = request.result;
            callback();
        };

        request.onerror = function (evt) {
            console.log("IndexedDB error: " + evt.target.errorCode);
        };

        request.onupgradeneeded = function (e) {
            var thisDb = e.target.result;

            //Create objectStore
            if(!thisDb.objectStoreNames.contains("library")) {					
                var objectStore = thisDb.createObjectStore("library", { keyPath: "id", autoIncrement:true }); 

                objectStore.createIndex("album", "album", { unique: false });
                objectStore.createIndex("url", "url", { unique: false });
                objectStore.createIndex("mp3", "mp3", { unique: false });
                objectStore.createIndex("cat", "cat", { unique: false });
                objectStore.createIndex("index", "index", { unique: true });

            }
        };
    }

    function addData(itemLib, key, callback) {

        var transaction = db.transaction(["library"], "readwrite");
        var objectStore = transaction.objectStore("library");
        itemLib.id = key;
        console.log(itemLib);
        var req = objectStore.put(itemLib);
        req.onsuccess = function() {
            callback();
        };

        req.onerror = function(e) {
            console.log("Error",e.target.error.name);
            //some type of error handler
        };
    }
    var i = 0;

    var getMp3 = function(url, id, callback) {
        i++;
        if (id < library.length) {
            $.get(url, function (data) {
                $(data).find("a").each(function(el) {
                    if (($(this).attr("href").match(/mp3$/i))&&($.inArray($(this).text(), library[id].songTitles) == -1)) {
                        var urlSong = url + $(this).attr("href");
                        library[id].mp3.push({url:urlSong, text: $(this).text()});
                        library[id].songTitles.push($(this).text());
                        Templates.link(urlSong, id, (library[id].mp3.length-1));
                    } else if ((!$(this).attr("href").match(/hq\/$/i)) && ($(this).text() != "Parent Directory") && (!url.match(escape($(this).attr("href")))) && (!$(this).attr("href").match(/[a-z]=[a-z]$/i)) && (!$(this).attr("href").match(/\/[0-9]{4,5}\/$/i)) && (!$(this).attr("href").match(/scan\/$/i)) && (!$(this).attr("href").match(/scans\/$/i)) && (!$(this).attr("href").match(/cover\/$/i)) && (!$(this).attr("href").match(/covers\/$/i)) && ($(this).attr("href").match(/\/$/i))) {
                        getMp3(url+$(this).attr("href"), id, callback);

                    }

                });
                i--;
                if ((library[id].mp3.length > 0)&&(lastIndex <= id)) addData(library[id], library[id].id, function () {
                    lastIndex = id;
                    //localStorage.setItem("library", JSON.stringify(library));
                    localStorage.setItem("lastIndex", lastIndex);
                    localStorage.setItem("date", Date.now());
                    id++;
                    if (library[id] == undefined) {
                        // Determine last better Index
                        for (var f = id; f < library.length; f++) {
                            id = f;
                            if (library[id] != undefined) f = library.length;
                        }
                    }
                    if (id < library.length) callback(library[id].url, id, getMp3);
                    else console.log("No more songs to get");
                });
                else if (i == 0) {
                    if (lastIndex > id) id = lastIndex;
                    //localStorage.setItem("library", JSON.stringify(library));
                    localStorage.setItem("lastIndex", lastIndex);
                    localStorage.setItem("date", Date.now());
                    id++;
                    callback(library[id].url, id, getMp3);
                }
            }).fail(function (jqXHR, err) {
                console.log(err);
                // library.splice(id, 1);
                id++;
                //localStorage.setItem("library", JSON.stringify(library));
                callback(library[id].url, id, getMp3);
            });
        }
    };

    var Playlist = {
        list: [],
        idActif: 0,
        history: [],
        previous: function () {
            $("a[data-id='"+radioState.selectedSong+"'][data-album='"+radioState.selectedAlbum+"']").css({fontWeight: "normal", backgroundColor:"#CCCCCC"});
            radioState.startTime = 0;
            var histItem = false;
            if (this.history.length > 1) {
                histItem = this.history.splice(-2, 2)[0];
                radioState.selectedSong = histItem.idSong;
                radioState.selectedAlbum = histItem.idAlbum;
            } else console.log("Nothing left in history");
            return histItem;
        },
        next: function () { 
            var id;
            $("a[data-id='"+radioState.selectedSong+"'][data-album='"+radioState.selectedAlbum+"']").css({fontWeight: "normal", backgroundColor:"#CCCCCC"});
            radioState.startTime = 0;
            if (radioState.shuffle) {
                this.idActif = Math.floor(Math.random() * (this.list.length - 1 - 0 + 1)) + 0;
            } else {
                this.idActif++;
                if (this.idActif >= this.list.length) this.idActif = 0;
            }
            var keys = this.list[this.idActif].split(":");
            radioState.selectedSong = keys[1];
            radioState.selectedAlbum = keys[0];

            return {idAlbum: keys[0], idSong: keys[1] }; },
        toggleShuffle: function(){
            if (radioState.shuffle) {
                radioState.shuffle = false;
                $("#randomButton").attr("class", "btn btn-default");
            } else {
                radioState.shuffle = true;
                $("#randomButton").attr("class", "btn btn-primary");
            }

            sessionStorage.setItem("radioState", JSON.stringify(radioState));
        },
        setActiveSong: function(idAlbum, idSong) {
            var listItem = $.inArray(idAlbum+":"+idSong, this.list);
            if (listItem > -1) this.idActif = listItem;
            else this.idActif = 0;
            this.history.push({idAlbum: idAlbum, idSong: idSong });
        },
        init: function() {
            if (radioState.selectedSong !== null) {
                var listItem = $.inArray(radioState.selectedAlbum+":"+radioState.selectedSong, this.list);
                if (listItem > -1)
                    play_song(radioState.selectedAlbum, radioState.selectedSong);
                else {
                    var keys = this.list[0].split(":");
                    radioState.selectedSong = keys[1];
                    radioState.selectedAlbum = keys[0];
                    play_song(radioState.selectedAlbum, radioState.selectedSong);
                }
            }
        }
    };

    var Templates = {
        indexes: [],
        flush: function () {
            this.indexes = [];
            Playlist.list = [];
            Playlist.history = [];
        },
        link: function (urlSong, idAlbum, idSong) { 
            if (((params.cat != undefined)&&(library[idAlbum].cat == params.cat)) || (params.cat == undefined)) {
                if (((params.firstonly != undefined)&&(idSong == 0)) || (params.firstonly == undefined)) {
                    if (((params.q != undefined)&&(library[idAlbum].album.match(params.q))) || (params.q == undefined)) {
                        if ($.inArray(library[idAlbum].album, this.indexes) == -1) {
                            $("#list").append($("<div id='album_"+idAlbum+"'><div class='alist' style='display:none;margin:0 0.4rem 0.4rem;' id='alist_"+idAlbum+"'></div></div>").prepend($("<h3 style='padding:0.2rem 0;cursor:pointer;color:white;overflow-wrap: break-word;text-overflow: ellipsis;white-space: nowrap;overflow: hidden;'>"+ library[idAlbum].album +"</h3>").css({margin:0}).click(function(e){ $(this).next().toggle(); }))
                                              .css({padding: "0.2em",
                                                    backgroundColor: ((this.indexes.length%2 == 0) ? "#AAAAAA" : "#CCCCCC"),
                                                    marginTop: "0.2rem"})); 
                            this.indexes.push(library[idAlbum].album);
                        }
                        $("#album_"+idAlbum+" .alist").append($("<a></a>").attr("href", urlSong).html(library[idAlbum].mp3[idSong].text).attr("data-id", idSong).attr("data-album", idAlbum).click(function(e) {
                            e.preventDefault();
                            select_song($(this).attr("data-album"), $(this).attr("data-id"));
                        }).css({display:"block", color:"black", textDecoration:"none", backgroundColor:"#CCCCCC", borderBottom:"1px solid black", padding:"3px"}));
                        Playlist.list.push(idAlbum+":"+idSong);
                    }
                }
            }
        }
    };
    var suivieLoading = 0;

    var loopLoadLinks = function (l, next) {
        if (l < lastIndex) {
            if ((library[l] != undefined)&&(library[l].mp3.length > 0)) {
                for (var t = 0; t < library[l].mp3.length; t++) {
                    var lien = library[l].mp3[t];
                    Templates.link(lien.url, l, t);
                }
                progressBar.update(l);
            }
            if (Number.isInteger(l/Math.round(lastIndex*0.01)))
                setTimeout(function () { loopLoadLinks(++l, next); }, 50);
            else loopLoadLinks(++l, next);
        } else next();
    };

    var load_links = function () {
        console.log("Regenerer a partir du cache");
        loopLoadLinks(0, function () {
            if (lastIndex > 0) {
                if (library[lastIndex].mp3.length == 0) {
                    // Determine last better Index
                    for (var f = lastIndex; f > 0; f--) {
                        lastIndex = f;
                        if (library[lastIndex].mp3.length > 0) f =0;
                    }
                    console.log(lastIndex);
                }
                console.log(library[lastIndex].mp3[0].text);
            }
            progressBar.hide();
            console.log("Recuperation de la suite");
            getMp3(library[(lastIndex)].url, (lastIndex), getMp3);
            Playlist.init();
        });
    };
    var audio;

    var select_song = function (album, song) {
        console.log("Play :"+ album + " - " + song);
        radioState.startTime = 0;
        radioState.playing = true;
        play_song(album, song);
    };

    var play_song = function (album, song) {
        console.log("Play :"+ album + " - " + song);
        if (library[album].mp3[song]) {
            $("a[data-id='"+radioState.selectedSong+"'][data-album='"+radioState.selectedAlbum+"']").css({fontWeight: "normal", backgroundColor:"#CCCCCC"});
            $("a[data-id='"+song+"'][data-album='"+album+"']").css({fontWeight: "bold", backgroundColor:"#AAAAAA"});
            audio[0].src = library[album].mp3[song].url;
            audio[0].currentTime = radioState.startTime;
            if (radioState.playing) audio[0].play();
            $("#radio_title").html(library[album].mp3[song].text);
            $("head title").html(library[album].album + " - " +library[album].mp3[song].text + " - Radio Sky Anime by akuma06");
            radioState.selectedAlbum = album;
            radioState.selectedSong = song;
            Playlist.setActiveSong(album, song);
        } else {
            console.log("erreur");   
        }
        sessionStorage.setItem("radioState", JSON.stringify(radioState));
    };
    var changeDom = function () {
        $("body").css("margin", 0)
            .html("<div class='container'><div style='background-color: rgb(250, 250, 250);' class='row'><div id='radio' class='col-md-12' style='height:15%; min-height:180px;text-align: center;'>"+
                  "<a href='#previous' id='previousSong' style='display: block;float: left;height: 100%;line-height: 16rem;text-decoration: none;color: grey;font-size: 3rem;font-family: monospace;'><<</a>"+
                  "<a href='#next' id='nextSong' style='display: block;float: right;height: 100%;line-height: 16rem;text-decoration: none;color: grey;font-size: 3rem;font-family: monospace;margin-left:1rem;'>>></a>"+
                  "<div style='margin:auto;'><h2 id='radio_title' style='color: grey; overflow-wrap: break-word;height: 1.2em;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;margin-left: 8rem;margin-right: 8rem;'></h2>"+
                  "<audio id='player_song' style='width:60%;' controls></audio></div></div></div><div class='row'>"+
                  "<div id='list' class='col-md-12' style='height:85%; overflow-y:auto;background: #CCCCCC;padding: 0.5rem 0.5rem;'></div></div></div>");
        $("#previousSong").click(function (e) {
            e.preventDefault();
            radioState.playing = true;
            if (Playlist.previous())
                play_song(radioState.selectedAlbum, radioState.selectedSong);
        });
        $("#nextSong").click(function (e) {
            e.preventDefault();
            radioState.playing = true;
            Playlist.next();
            play_song(radioState.selectedAlbum, radioState.selectedSong);
        });
        audio = $("#player_song").on('ended', function() {
            radioState.playing = true;
            Playlist.next();
            play_song(radioState.selectedAlbum, radioState.selectedSong);
        }).on('timeupdate',function() {
            radioState.startTime = $(this)[0].currentTime;
            sessionStorage.setItem("radioState", JSON.stringify(radioState));
        }).on('pause', function () {
            radioState.playing = false;
            sessionStorage.setItem("radioState", JSON.stringify(radioState));
        }).on('playing', function () {
            radioState.playing = true;
            sessionStorage.setItem("radioState", JSON.stringify(radioState));
        });
        $($("#radio div")[0]).append(
            $("<a href='#cat=oped&firstonly=1' class='btn btn-primary' style='float:right' data-toggle='tooltip' data-placement='top' title='Lire uniquement les openings et endings' id='opedButton'>OP/ED</a>").on("click", function(e) {
                if (!progressBar.ended) {
                    e.preventDefault();
                    alert("Vous devez attendre la fin du chargement :/");
                }
            })
        ).append(
            $("<a href='#shuffle=true' class='btn btn-default' style='float:right' data-toggle='tooltip' data-placement='left' title='Lecture aléatoire' id='randomButton'><span class='glyphicon glyphicon-random'></span>&nbsp;</a>").on("click", function(e) {
                e.preventDefault();
                Playlist.toggleShuffle();
            })
        );
        if (radioState.shuffle)
            $("#randomButton").attr("class", "btn btn-primary");
        $('[data-toggle="tooltip"]').tooltip();

    };

    var progressBar = {
        first: 0,
        ended: true,
        myDiv: $("<div></div>").append(
            $("<div></div>").append(
                $("<div></div>").css({ backgroundColor: "#CCCCCC", width: "100%", height:"100%"})
            ).append(
                $("<div class='verte'></div>").css({ backgroundImage: "repeating-linear-gradient(to right bottom, rgb(0, 152, 133) 0%, rgb(21, 243, 73) 100%)", width: "0%", height:"100%", position: "relative", zIndex:"4", top: "-30px"})
            ).css({margin: "3px", height:"30px", width:"300px", overflow: "hidden"})
        ).append("<p style='text-align:center'>Chargement en cours...</p>").css({ position: "fixed", top:"50%", left:"50%", marginTop:"-18px", marginLeft:"-153px", zIndex:2, backgroundColor:'white'}),
        update: function (suivieLoading) {
            console.log((suivieLoading/lastIndex)*100);
            $(this.myDiv).find(".verte").css({width: (suivieLoading/lastIndex)*100+"%"});
        },
        show: function () {
            this.myDiv.appendTo("body");
            this.myDiv.show();
        },
        hide: function () {
            this.myDiv.fadeOut("slow", function () { 
                $(this).find("verte").css({width: "0%"});
                $(this).hide(); 
            });
            this.ended = true;
        },
        start: function (next) {
            this.update(0);
            this.ended = false;
            setTimeout(next, 30);
        }
    };
    $(document).ready(function () {
        initDb(function () {
            if (lastIndex == 0) {
                library = $("option").map(function (ind, val, tab) {
                    var item = { url: "http://radio.sky-animes.com/HQ/"+$(val).val()+"/", 
                                album: (($(val).attr("title") != undefined) ? $(val).attr("title").replace(/^ /i, "") : $(val).text().replace(/^ /i, "")), 
                                index: encodeURIComponent((($(val).attr("title") != undefined) ? $(val).attr("title").replace(/^ /i, "") : $(val).text().replace(/^ /i, ""))), 
                                cat: (($(val).parent().attr("id") == "id_ost") ? "ost" : "oped" ), 
                                mp3: [],
                                songTitles: []
                               };
                    addData(item, ind, function () {});
                    return item; 
                });
                console.log(library);
                changeDom();
                progressBar.show();
                progressBar.start(function () {
                    load_links();
                });            } else {

                    var transaction = db.transaction(["library"], "readonly");
                    var objectStore = transaction.objectStore("library");
                    var request = objectStore.openCursor();

                    request.onsuccess = function(event) {
                        var cursor = event.target.result;
                        if(cursor) {
                            library[cursor.key] = cursor.value;
                            cursor.continue();
                        } else {
                            console.log(library);
                            changeDom();
                            progressBar.show();
                            progressBar.start(function () {
                                load_links(true);
                            });
                        }
                    };
                }
        });
    });
})();