Nyaa.se_AutoDownloader

Automatically download anime torrents

当前为 2015-06-28 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        Nyaa.se_AutoDownloader
// @namespace   Autodownload
// @author      Victorique
// @description Automatically download anime torrents
// @include     http://www.nyaa.se/?page=search&cats=*&filter=*&term=*&user=*
// @include     http://www.nyaa.se/?page=search&filter=*&term=*&user=*
// @include     http://www.nyaa.se/?page=search&term=*&user=*
// @version     4.0.1
// @grant       none
// @license     http://opensource.org/licenses/MIT
// @run-at      document-start
// @require     https://code.jquery.com/jquery-2.1.4.min.js
// ==/UserScript==

/*
var e = document.createElement("script");

e.src = 'http://localhost/userScripts/AutoDownloader.user.js';
e.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(e);
*/

"use strict";

/* OBJECT CREATION START */
var Episode = (function () {
    /**
     * An Episode represents an table row in the current page
     * @param   {Number} res          The resolution used for this episode
     * @param   {String} downloadLink The download link for this episode
     * @param   {Number} seeds        The seed count for this episode
     * @param   {Number} leechers     The leech count for this episode
     * @param   {String} uid          The ID of this episode
     * @param   {Number} resides      The page that this Episode resides in
     * @returns {Object} the proto of itself
     */
    function Episode(res, downloadLink, seeds, leechers, uid, resides) {

        if (typeof res !== "number") {
            throw "res must be a number";
        }

        if (typeof downloadLink !== "string") {
            throw "downloadLink must be a string";
        }

        if (typeof seeds !== "number") {
            throw "seeds must be a number";
        }

        if (typeof leechers !== "number") {
            throw "leechers must be a number";
        }

        if (typeof uid !== "string") {
            throw "uid must be a string";
        }

        if (typeof resides !== "number") {
            throw "resides must be a number";
        }
        var _res = res;

        var _downloadLink = downloadLink;

        var _seeds = seeds;

        var _leechers = leechers;

        var _uid = uid;

        var _resides = resides;

        this.getRes = function () {
            return _res;
        };

        this.getDownloadLink = function () {
            return _downloadLink;
        };

        this.getSeeds = function () {
            return _seeds;
        };

        this.getLeechers = function () {
            return _leechers;
        };

        this.getUid = function () {
            return _uid;
        };

        this.getResides = function () {
            return _resides;
        };
        return this;
    }
    Episode.prototype = {
        constructor: Episode
    }
    return Episode;
}());

var Anime = (function () {

    var currentAnime = null;
    var currentSubber = null;
    /**
     * Array of Episode Objects
     */
    var eps = [];

    /**
     * Set the current Anime name
     * @param {String} anime The of the Anime
     */
    var setCurrentAnime = function (anime) {
        currentAnime = anime;
    };

    /**
     * Set the name of the current subber
     * @param {String} sub Name of the current subber
     */
    var setCurrentSubber = function (sub) {
        currentSubber = sub;
    };

    /**
     * Get the current Subber
     * @returns {String} The name of the Subber for this anime
     */
    var getCurrentSubber = function () {
        return currentSubber;
    };

    /**
     * Get the current anime name
     * @returns {String} Name of the anime
     */
    var getCurrentAnime = function () {
        return currentAnime;
    };


    /**
     * Get the avrage seeds for a specified res
     * @param   {Number} res The res to get the avg seeds for
     * @returns {Number} The avg seeds
     */
    var avgSeedsForRes = function (res) {
        if (typeof res !== "number") {
            throw "res Must be an int";
        }
        var seedCount = 0;
        if (getamountOfEpsFromRes(res) === 0) {
            return 0;
        }
        for (var i = 0; i < eps.length; i++) {
            var currentEp = eps[i];
            if (currentEp.getRes() === res) {
                seedCount += currentEp.getSeeds();
            }
        }
        return Math.round(seedCount = seedCount / getamountOfEpsFromRes(res));
    };

    /**
     * Get the avrage leechers for a specified res
     * @param   {Number} res The res to get the avg seeds for
     * @returns {Number} The avg leechers
     */
    var avgPeersForRes = function (res) {
        if (typeof res !== "number") {
            throw "res Must be an int";
        }
        var leechCount = 0;
        if (getamountOfEpsFromRes(res) === 0) {
            return 0;
        }
        for (var i = 0; i < eps.length; i++) {
            var currentEp = eps[i];
            if (currentEp.getRes() === res) {
                leechCount += currentEp.getLeechers();
            }
        }
        return Math.round(leechCount = leechCount / getamountOfEpsFromRes(res));
    };

    /**
     * Get the total amount of eps for a res
     * @param   {Number} res res
     * @returns {Number} The amount of eps for the res
     */
    var getamountOfEpsFromRes = function (res) {
        if (typeof res !== "number") {
            throw "res must be of type 'number'";
        }
        return getEpsForRes(res).length;
    };


    var _isjQueryObject = function (obj) {
        if (obj instanceof jQuery || 'jquery' in Object(obj)) {
            return true;
        } else {
            return false;
        }
    };

    /**
     * Add Episodes to the array
     * @param {Episode} ep The Anime object to add
     */
    var addEps = function (ep) {
        if (typeof ep !== "object" && !ep instanceof Episode) {
            throw "addEps must take an Episode object";
        }
        eps.push(ep);
    };


    /**
     * Add an array of Episode object to the Anime object
     * @param {Array} episode Array of Episode objects to add
     */
    var addAllEps = function (episode) {
        for (var i = 0; i < episode.length; i++) {
            var currEp = episode[i];
            if (typeof currEp !== "object" && !currEp instanceof Episode) {
                throw "addEps must take an Episode object";
            }
            eps.push(currEp);
        }
    };

    /**
     * Get the Anime objects for a specified res
     * @param   {Number}  res res to use
     * @returns {Episode} Array of Episodes that match the specified res
     */
    var getEpsForRes = function (res) {
        if (typeof res !== "number") {
            throw "res Must be an int";
        }
        var arrayOfEps = [];
        for (var i = 0; i < eps.length; i++) {
            var currentEp = eps[i];
            if (currentEp.getRes() === res) {
                arrayOfEps.push(currentEp);
            }
        }
        return arrayOfEps;
    };

    /**
     * Given a JQuery object that represents a "tr" of the table, this will return that Episode's UID
     * @param   {Object} obj The Jquery representation of a tr (table row)
     * @returns {String} The UID of that Episode
     */
    var getUidFromJqueryObject = function (obj) {
        if (!_isjQueryObject(obj)) {
            throw "Object must be of type 'Jquery'";
        }
        if (obj.is("tr")) {
            var anchor = (function () {
                var tableRows = obj.find("td.tlistdownload > a");
                if (tableRows.length > 1) {
                    throw "Object must be unique";
                }
                return _getUidFromAnchor(tableRows.get(0))
            }());
        } else {
            return null;
        }
        return anchor;
    };

    /**
     * Get the Episode from a given anchor tag
     * @param   {Object}  anchor Jquery or pure JS anchor dom element
     * @returns {Episode} The eipside that matches the Anchor
     */
    var getEpisodeFromAnchor = function (anchor) {
        var link = (function () {
            if (_isjQueryObject(anchor)) {
                return anchor.get(0);
            }
            return anchor;
        }());
        var uid = _getUidFromAnchor(link);
        return getEpisodeFromUid(uid);
    };

    /**
     * Get the Episode object given a UID
     * @param   {String}  uid The Episode UID
     * @returns {Episode} The Episode that matches the UID
     */
    var getEpisodeFromUid = function (uid) {
        if (typeof uid !== "string") {
            throw "uid must be of type String";
        }
        for (var i = 0; i < eps.length; i++) {
            var currentEp = eps[i];
            if (currentEp.getUid() === uid) {
                return currentEp;
            }
        }
        return null;
    };

    var getEpisodesFromResidence = function (resides, exclude) {
        if (typeof resides !== "number") {
            throw "resides must be a number";
        }
        var arrayOfEps = [];
        for (var i = 0; i < eps.length; i++) {
            var currentEp = eps[i];
            if (exclude === true) {
                if (currentEp.getResides() !== resides) {
                    arrayOfEps.push(currentEp);
                }
            } else {
                if (currentEp.getResides() === resides) {
                    arrayOfEps.push(currentEp);
                }
            }
        }
        return arrayOfEps;
    };

    var _getUidFromAnchor = function (anchor) {
        return anchor.href.split("=").pop();
    };

    var _removeObjectFromArray = function (arr, obj) {
        var i = arr.length;
        while (i--) {
            if (arr[i] === obj) {
                arr.splice(i, 1);
            }
        }
    }

    var getPageUrls = function () {
        var urls = [];
        $.each($('div.pages').filter(function (i) {
            return i === 0;
        }).find('a'), function (k, v) {
            urls.push(this.href);
        });
        return urls;
    };

    var removeEpisodesFromUid = function (uid) {
        var episodes = getEpisodeFromUid(uid);
        for (var i = 0; i < episodes.length; i++) {
            var currentEp = episodes[i];
            _removeObjectFromArray(eps, currentEp);
        }
    };

    var removeEpisodesFromResidence = function (resides, exclude) {
        if (typeof exclude !== "boolean") {
            throw "excluse must be true or false";
        }

        var episodes = getEpisodesFromResidence(resides, exclude);
        for (var i = 0; i < episodes.length; i++) {
            var currentEp = episodes[i];
            _removeObjectFromArray(eps, currentEp);
        }
    };


    return {
        setCurrentAnime: setCurrentAnime,
        getCurrentAnime: getCurrentAnime,
        addEps: addEps,
        getEpsForRes: getEpsForRes,
        getamountOfEpsFromRes: getamountOfEpsFromRes,
        setCurrentSubber: setCurrentSubber,
        getCurrentSubber: getCurrentSubber,
        avgSeedsForRes: avgSeedsForRes,
        getUidFromJqueryObject: getUidFromJqueryObject,
        getEpisodeFromUid: getEpisodeFromUid,
        getEpisodeFromAnchor: getEpisodeFromAnchor,
        getPageUrls: getPageUrls,
        addAllEps: addAllEps,
        getEpisodesFromResidence: getEpisodesFromResidence,
        removeEpisodesFromUid: removeEpisodesFromUid,
        removeEpisodesFromResidence: removeEpisodesFromResidence,
        avgPeersForRes: avgPeersForRes
    };
}());


/** Utility functions ***/
var Utils = (function () {
    var displayMessage = function (message, confirmMsg) {
        if (typeof confirmMsg === "boolean") {
            if (confirmMsg === true) {
                return confirm(message);
            }
        }
        alert(message);
        return true;
    };

    var disableButton = function (button) {
        button.prop('disabled', true);
    };

    var enableButton = function (button) {
        button.prop('disabled', false);
    };

    var doDownloads = function (event) {
        var type = $(event.target).data("type");
        var amountOfAnime;
        var collectionOfAnime;
        var userSelect;
        if (type === "downloadAll") {
            var selectedRes = parseInt($("#downloadRes").val());
            amountOfAnime = Anime.getamountOfEpsFromRes(selectedRes);
            collectionOfAnime = Anime.getEpsForRes(selectedRes);
            userSelect = displayMessage("You are about to download " + amountOfAnime + " eps.\nThis will cause " + amountOfAnime + " download pop-ups\nAre you sure you want to continue?\nIf there are a lot of eps, your browser might stop responding for a while. This is normal\nIf you are on Google Chrome, it will ask you to allow multiple-downloads", true);
        } else if (type === "downloadSelected") {
            amountOfAnime = $(".checkboxes:checked").length;
            collectionOfAnime = [];
            $.each($('.checkboxes:checked').prev('a'), function (k, v) {
                var episode = Anime.getEpisodeFromAnchor(this);
                collectionOfAnime.push(episode);
            });
            userSelect = displayMessage("You are about to download " + amountOfAnime + " items. if there are a lot of itmes, it might make your browser stop responding for a while This is normal\n Chrome will ask you to accept multiple downloads ", true);
        } else {
            throw "Unexpected Error";
        }
        if (userSelect === false) {
            return;
        }
        for (var i = 0; i < collectionOfAnime.length; i++) {
            var currentEp = collectionOfAnime[i];
            var currentDownloadLink = currentEp.getDownloadLink();
            var link = document.createElement("a");
            link.download = "";
            link.href = currentDownloadLink;
            link.click();
        }
    };

    var checkBoxValid = function (checkbox) {
        return checkbox.is(":checked");
    };

    var buildTable = function () {
        var html = "";
        html += "<table style='width: 100%' id='info'>";

        html += "<caption>Download infomation</caption>";

        html += "<tr>";
        html += "<th>resolution</th>";
        html += "<th>Episode count</th>";
        html += "<th>Average seeds</th>";
        html += "<th>Average leechers</th>";
        html += "</tr>";

        html += "<tr>";
        html += "<td>1080p</td>";
        html += "<td>" + Anime.getamountOfEpsFromRes(1080) + "</td>";
        html += "<td>" + Anime.avgSeedsForRes(1080) + "</td>";
        html += "<td>" + Anime.avgPeersForRes(1080) + "</td>";
        html += "</tr>";

        html += "<tr>";
        html += "<td>720p</td>";
        html += "<td>" + Anime.getamountOfEpsFromRes(720) + "</td>";
        html += "<td>" + Anime.avgSeedsForRes(720) + "</td>";
        html += "<td>" + Anime.avgPeersForRes(720) + "</td>";
        html += "</tr>";


        html += "<tr>";
        html += "<td>480p</td>";
        html += "<td>" + Anime.getamountOfEpsFromRes(480) + "</td>";
        html += "<td>" + Anime.avgSeedsForRes(480) + "</td>";
        html += "<td>" + Anime.avgPeersForRes(480) + "</td>";
        html += "</tr>";

        html += "</table>";


        return html;
    };

    var getCurrentPageOffset = function () {
        return parseInt((typeof QueryString.offset === "undefined") ? 1 : QueryString.offset);
    };

    return {
        displayMessage: displayMessage,
        disableButton: disableButton,
        enableButton: enableButton,
        doDownloads: doDownloads,
        checkBoxValid: checkBoxValid,
        buildTable: buildTable,
        getCurrentPageOffset: getCurrentPageOffset
    };
}());

var DataParser = (function () {

    /**
     * Parses a table and returns an array of Episodes from it
     * @param   {Object}  table Jquery representation of the anime table
     * @returns {Episode} Array of Episodes
     */
    var parseTable = function (table, currentPage) {
        var trRow = table.find("img[src='http://files.nyaa.se/www-37.png']").closest("tr");
        var p1080Only = $(trRow).filter(function (e) {
            return ($(this).children("td:nth-child(2)").text().indexOf("1080p") > -1 || $(this).children("td:nth-child(2)").text().indexOf("1920x1080") > -1);
        });

        var p720nly = $(trRow).filter(function (e) {
            return ($(this).children("td:nth-child(2)").text().indexOf("720p") > -1 || $(this).children("td:nth-child(2)").text().indexOf("1280x720")) > -1;
        });

        var p480nly = $(trRow).filter(function (e) {
            return ($(this).children("td:nth-child(2)").text().indexOf("480p") > -1 || $(this).children("td:nth-child(2)").text().indexOf("640x480") > -1);
        });
        var eps = [];
        $.each($(p1080Only), function (k, v) {
            var currentDownloadLink = $(this).find('td:nth-child(3) >a').attr('href');
            var seeds = parseInt($(this).find("td.tlistsn").text());
            var leech = parseInt($(this).find('td.tlistln').text());
            var uid = Anime.getUidFromJqueryObject($(this));
            eps.push(new Episode(1080, currentDownloadLink, seeds, leech, uid, currentPage));
        });

        $.each($(p720nly), function (k, v) {
            var currentDownloadLink = $(this).find('td:nth-child(3) >a').attr('href');
            var seeds = parseInt($(this).find("td.tlistsn").text());
            var leech = parseInt($(this).find('td.tlistln').text());
            var uid = Anime.getUidFromJqueryObject($(this));
            eps.push(new Episode(720, currentDownloadLink, seeds, leech, uid, currentPage));
        });


        $.each($(p480nly), function (k, v) {
            var currentDownloadLink = $(this).find('td:nth-child(3) >a').attr('href');
            var seeds = parseInt($(this).find("td.tlistsn").text());
            var leech = parseInt($(this).find('td.tlistln').text());
            var uid = Anime.getUidFromJqueryObject($(this));
            eps.push(new Episode(480, currentDownloadLink, seeds, leech, uid, currentPage));
        });

        return eps;
    };

    return {
        parseTable: parseTable
    };
}());

var QueryString = function () {
    var query_string = {};
    var query = window.location.search.substring(1);
    var vars = query.split('&');
    for (var i = 0; i < vars.length; i++) {
        var pair = vars[i].split('=');
        if (typeof query_string[pair[0]] === 'undefined') {
            query_string[pair[0]] = pair[1];
        } else if (typeof query_string[pair[0]] === 'string') {
            var arr = [
        query_string[pair[0]],
        pair[1]
      ];
            query_string[pair[0]] = arr;
        } else {
            query_string[pair[0]].push(pair[1]);
        }
    }
    return query_string;
}();


// Download fix for firefox
HTMLElement.prototype.click = function () {
    var evt = this.ownerDocument.createEvent('MouseEvents');
    evt.initMouseEvent('click', true, true, this.ownerDocument.defaultView, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
    this.dispatchEvent(evt);
};

/* OBJECT CREATION END */

$(document).ready(function () {
    init(); // init the pannel and set up objects and listeners
    if (Utils.checkBoxValid($(".checkboxes"))) {
        Utils.enableButton($("#downloadCustomButton"));
    } else {
        Utils.disableButton($("#downloadCustomButton"));
    }
});

function init() {
    var doDownload = true;
    setAnimeObj();
    buildUi();
    bindListeners();

    function setAnimeObj() {
        // Set currentAnime
        if (QueryString.term !== "") {
            Anime.setCurrentAnime(decodeURIComponent(QueryString.term).split("+").join(" "));
        } else {
            Anime.setCurrentAnime("Unknown");
        }

        // set subber
        Anime.setCurrentSubber($(".notice > a > span").html());

        // Set eps

        var eps = DataParser.parseTable($("table.tlist"), Utils.getCurrentPageOffset());

        Anime.addAllEps(eps);

    }

    function buildUi() {
        makeStyles();
        buildPanel();
        makeCheckBoxes();

        function makeStyles() {
            var styles = "";
            styles += ".panel{background-color: #fff; border: 1px solid transparent; border-radius: 4px; box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); margin-bottom: 20px;}";
            styles += ".panel-success {border-color: #d6e9c6;}";
            styles += ".panel-heading{   border-bottom: 1px solid transparent; border-top-left-radius: 3px; border-top-right-radius: 3px; padding: 4px 15px; text-align:center}";
            styles += ".panel-success > .panel-heading {background-color: #dff0d8; border-color: #d6e9c6; color: #3c763d;}";
            styles += ".panel-success > .panel-footer + .panel-collapse > .panel-body {border-bottom-color: #d6e9c6;}";
            styles += ".panel-footer {background-color: #f5f5f5; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; border-top: 1px solid #ddd; padding: 10px 15px;}";
            styles += ".panel-title {color: inherit; margin-bottom: 0; margin-top: 0; padding: 6px;}";
            styles += ".panel-body {padding: 15px;}";
            styles += ".epinfoInner{float:right; padding-left:10px; color:#3c763d;}";
            styles += ".epInfo{height: 15px;}";
            styles += ".avgSeeds{floar:left; padding-right:10px; color:#3c763d;}";
            styles += ".checkboxes{left:1px; margin:0; padding:0; position: relative; top: 1px;}";

            styles += "#info, #info th, #info td {border: 1px solid black;border-collapse: collapse;}";
            styles += "#info th, #info td {padding: 5px;text-align: left;}";

            styles += "#downloadCustomButton{float:right;}";
            $("<style>").prop("type", "text/css").html(styles).appendTo("head");
        }

        function buildPanel() {
            var html = "";
            html += '<div class="panel panel-success" style="margin-left: 9px; margin-top: 19px; width: 851px;">';

            html += '<div class="panel-heading">';
            html += '<h3 id="panel-title" class="panel-title"></h3>';
            html += "</div>";

            html += '<div class="panel-body" id="pannelContent"></div>';
            html += '<div class="panel-footer" id="panelFooter">';

            html += '<div class="epInfo"></div>';
            html += '</div>';

            html += '</div>';
            $(".content > .notice").after(html);
            buildPanelContent();

            function buildPanelContent() {
                var html = "";
                html += "<div>";
                $("#panel-title").html("<span> Download \"" + Anime.getCurrentAnime() + " (" + Anime.getCurrentSubber() + ")\"</span>");
                if (Anime.getamountOfEpsFromRes(480) === 0 && Anime.getamountOfEpsFromRes(720) === 0 && Anime.getamountOfEpsFromRes(1080) === 0) {
                    html += "<span> No translated anime found or error occured</span>";
                    html += "</div>";
                    $("#pannelContent").html(html);
                    doDownload = false;
                    return;
                }
                html += "<span>Pick a resolution: </span>";
                html += "<select style=\"margin-right:5px;\" id=\"downloadRes\">";
                if (Anime.getamountOfEpsFromRes(1080) >= 1) {
                    html += "<option value=\"1080\">1080p</option>";
                }
                if (Anime.getamountOfEpsFromRes(720) >= 1) {
                    html += "<option value=\"720\">720p</option>";
                }
                if (Anime.getamountOfEpsFromRes(480) >= 1) {
                    html += "<option value=\"480\">480p</option>";
                }
                html += "</select>";
                html += "<button type=\"button\" data-type='downloadAll' id=\"downloadAll\">Download all</button>";

                html += "<button type='button' id='downloadCustomButton' data-type='downloadSelected' >download your selected items</button>";

                html += "</div>";

                html += "<div id='options'>";

                html += "<label for='crossPage'> include Cross pages</label>";
                html += "<input type='checkbox' id='crossPage' /> ";

                html += "</div>";

                html += "<div id='tableInfo'>";
                html += Utils.buildTable();
                html += "</div>";

                $("#pannelContent").html(html);
            }
        }

        function makeCheckBoxes() {
            $(".tlistdownload > a").after("<input class='checkboxes' type='checkbox'/>");
        }
    }

    function bindListeners() {
        $("#downloadAll").on("click", function (e) {
            if (doDownload === true) {
                Utils.doDownloads(e);
            }
        });

        $("#downloadCustomButton").on("click", function (e) {
            if (doDownload === true) {
                Utils.doDownloads(e);
            }
        });

        $(".checkboxes").on("click", function (e) {
            if (Utils.checkBoxValid($(".checkboxes"))) {
                Utils.enableButton($("#downloadCustomButton"));
            } else {
                Utils.disableButton($("#downloadCustomButton"));
            }
        });

        $("#crossPage").on("click", function (e) {
            if (Utils.checkBoxValid($("#crossPage"))) {
                $("#tableInfo").html("<p>Please wait while we parse each page...</p>");
                Anime.getPageUrls().reduce(function (prev, cur, index) {
                    return prev.then(function (data) {
                        return $.ajax(cur).then(function (data) {
                            var currentPage = cur.split("=").pop();
                            if (cur.indexOf("offset") === -1) {
                                currentPage = 1;
                            }
                            var table = $(data).find("table.tlist");

                            Anime.addAllEps(DataParser.parseTable(table, parseInt(currentPage)));
                            $("#tableInfo").append("<div>Page " + currentPage + " Done </div>")
                        });
                    })
                }, $().promise()).done(function () {
                    $("#tableInfo").html(Utils.buildTable());
                });
            } else { // when un-chekced, clear the Episodes of all eps that are not of the current page
                $("#tableInfo").html("<p>Please wait while we re-calculate the Episodes</p>");
                var currentPage = Utils.getCurrentPageOffset();
                Anime.removeEpisodesFromResidence(currentPage, true);
                $("#tableInfo").html(Utils.buildTable());
            }
        });
    }
}