Nyaa.se_AutoDownloader

Automatically download anime torrents

目前為 2015-06-28 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 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());
            }
        });
    }
}