Nyaa.si Batch downloader

Batch download torrents from nyaa.si

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

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

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

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

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

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

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name        Nyaa.si Batch downloader
// @namespace   Autodownload
// @author      Victorique
// @description Batch download torrents from nyaa.si
// @include     *://nyaa.si/user/*?q=*
// @include     *://nyaa.si/user/*?f=*&c=*&q=*
// @version     7.1.7
// @icon        https://i.imgur.com/nx5ejHb.png
// @license     MIT
// @run-at      document-idle
// @grant       none
// @require     https://greasyfork.org/scripts/19117-jsutils/code/JsUtils.js
// @require     https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.8/FileSaver.min.js
// @require     https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.5/jszip.min.js
// ==/UserScript==
"use strict";

var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();

var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var AbstractEps = function () {
    function AbstractEps() {
        _classCallCheck(this, AbstractEps);
    }

    _createClass(AbstractEps, null, [{
        key: 'abstractGetEps',
        value: function abstractGetEps(skipSeedLimit) {
            var minSeeds = Number.parseInt(Localstore.getMinSeedsFromStore());
            if (minSeeds > -1 && skipSeedLimit === false) {
                var arrayOfEps = [];
                for (var i = 0, len = AbstractEps.eps.length; i < len; i++) {
                    var currentEp = AbstractEps.eps[i];
                    if (currentEp.seeds < minSeeds) {
                        continue;
                    }
                    arrayOfEps.push(currentEp);
                }
                return arrayOfEps;
            } else {
                return AbstractEps.eps;
            }
        }
    }, {
        key: 'addEp',
        value: function addEp(ep) {
            if (Anime.isValidRes(ep.res) === false) {
                throw new TypeError('The Episode supplied does not have a valid resolution');
            }
            for (var i = 0, len = AbstractEps.eps.length; i < len; i++) {
                var epi = AbstractEps.eps[i];
                if (epi.equals(ep)) {
                    console.warn('The episode supplied already exsists, this episode has been ignored');
                    return;
                }
            }
            AbstractEps.eps.push(ep);
        }
    }, {
        key: 'removeEpisodeFromAnime',
        value: function removeEpisodeFromAnime(obj) {
            var arr = AbstractEps.eps;
            var i = arr.length;
            while (i--) {
                if (arr[i] === obj) {
                    arr.splice(i, 1);
                }
            }
        }
    }]);

    return AbstractEps;
}();

AbstractEps.eps = [];
var Anime = function (_AbstractEps) {
    _inherits(Anime, _AbstractEps);

    function Anime() {
        _classCallCheck(this, Anime);

        return _possibleConstructorReturn(this, (Anime.__proto__ || Object.getPrototypeOf(Anime)).call(this));
    }

    _createClass(Anime, null, [{
        key: 'addSupportedRes',
        value: function addSupportedRes(res) {
            Anime._supportedRes.push(res);
        }
    }, {
        key: 'addAvailableResolutions',
        value: function addAvailableResolutions(res, fullRes) {
            if (Anime._resExists(res)) {
                return;
            }
            Anime._availableRes.push({ 'res': res, 'fullRes': fullRes });
        }
    }, {
        key: 'removeAvailableResolutions',
        value: function removeAvailableResolutions(resToRemove) {
            for (var i = 0; i < Anime._availableRes.length; i++) {
                var currentRes = Anime._availableRes[i];
                if (currentRes.res === resToRemove || currentRes.fullRes === resToRemove) {
                    Anime._availableRes.splice(i, 1);
                }
            }
        }
    }, {
        key: '_resExists',
        value: function _resExists(_res) {
            for (var i = 0; i < Anime._availableRes.length; i++) {
                var currentRes = Anime._availableRes[i];
                if (currentRes.res === _res || currentRes.fullRes === _res) {
                    return true;
                }
            }
            return false;
        }
    }, {
        key: 'getTdFromTable',
        value: function getTdFromTable(table, index) {
            return table.find('td:nth-child(' + index + ')');
        }
    }, {
        key: 'avgSeedsForRes',
        value: function avgSeedsForRes(res, skipSeedLimit) {
            var seedCount = 0;
            var epCount = Anime.getAmountOfEpsFromRes(res, skipSeedLimit);
            if (epCount === 0) {
                return 0;
            }
            var eps = _get(Anime.__proto__ || Object.getPrototypeOf(Anime), 'abstractGetEps', this).call(this, skipSeedLimit);
            for (var i = 0, len = eps.length; i < len; i++) {
                var currentEp = eps[i];
                if (currentEp.res === res) {
                    seedCount += currentEp.seeds;
                }
            }
            return Math.round(seedCount / epCount);
        }
    }, {
        key: 'avgPeersForRes',
        value: function avgPeersForRes(res, skipSeedLimit) {
            var leechCount = 0;
            var epCount = Anime.getAmountOfEpsFromRes(res, skipSeedLimit);
            if (epCount === 0) {
                return 0;
            }
            var eps = _get(Anime.__proto__ || Object.getPrototypeOf(Anime), 'abstractGetEps', this).call(this, skipSeedLimit);
            for (var i = 0, len = eps.length; i < len; i++) {
                var currentEp = eps[i];
                if (currentEp.res === res) {
                    leechCount += currentEp.leechers;
                }
            }
            return Math.round(leechCount / epCount);
        }
    }, {
        key: 'getTotalSizeForRes',
        value: function getTotalSizeForRes(res, skipSeedLimit) {
            var decimals = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 3;

            var eps = Anime.getEpsForRes(res, skipSeedLimit);
            return Utils.getHumanReadableSize(eps, decimals);
        }
    }, {
        key: 'getAmountOfEpsFromRes',
        value: function getAmountOfEpsFromRes(res, skipSeedLimit) {
            return Anime.getEpsForRes(res, skipSeedLimit).length;
        }
    }, {
        key: 'getEpsForRes',
        value: function getEpsForRes(res, skipSeedLimit) {
            var arrayOfEps = [];
            var eps = _get(Anime.__proto__ || Object.getPrototypeOf(Anime), 'abstractGetEps', this).call(this, skipSeedLimit);
            for (var i = 0, len = eps.length; i < len; i++) {
                var currentEp = eps[i];
                if (currentEp.res === res) {
                    arrayOfEps.push(currentEp);
                }
            }
            return arrayOfEps;
        }
    }, {
        key: 'isValidRes',
        value: function isValidRes(res) {
            return Anime._resExists(res);
        }
    }, {
        key: 'addAllEps',
        value: function addAllEps(eps) {
            for (var i = 0; i < eps.length; i++) {
                _get(Anime.__proto__ || Object.getPrototypeOf(Anime), 'addEp', this).call(this, eps[i]);
            }
        }
    }, {
        key: 'getUidFromJqueryObject',
        value: function getUidFromJqueryObject(obj) {
            if (obj.is('tr')) {
                return function () {
                    var currectTd = Anime.getNameTr(obj);
                    var tableRows = currectTd.find('a:not(a.comments)');
                    if (tableRows.length > 1) {
                        throw 'Object must be unique';
                    }
                    return Anime._getUidFromAnchor(tableRows.get(0));
                }();
            }
            return null;
        }
    }, {
        key: 'getNameTr',
        value: function getNameTr(obj) {
            return obj.find('td:nth-child(2)');
        }
    }, {
        key: 'getEpisodeFromAnchor',
        value: function getEpisodeFromAnchor(anchor) {
            var link = function () {
                if (Utils.isjQueryObject(anchor)) {
                    return anchor.get(0);
                }
                return anchor;
            }();
            var uid = Anime._getUidFromAnchor(link);
            return Anime.getEpisodeFromUid(uid, true);
        }
    }, {
        key: 'getEpisodeFromUid',
        value: function getEpisodeFromUid(uid, skipSeedLimit) {
            var eps = _get(Anime.__proto__ || Object.getPrototypeOf(Anime), 'abstractGetEps', this).call(this, skipSeedLimit);
            for (var i = 0, len = eps.length; i < len; i++) {
                var currentEp = eps[i];
                if (currentEp.uid === uid) {
                    return currentEp;
                }
            }
            return null;
        }
    }, {
        key: '_getUidFromAnchor',
        value: function _getUidFromAnchor(anchor) {
            if (typeof anchor === 'string') {
                if (anchor.indexOf(".torrent") > -1) {
                    return anchor.replace(".torrent", "").split("/").pop();
                }
                return anchor.split("/").pop();
            }
            return anchor.href.split("/").pop();
        }
    }, {
        key: 'getEpisodesFromResidence',
        value: function getEpisodesFromResidence(resides, exclude, skipSeedLimit) {
            var arrayOfEps = [];
            var eps = _get(Anime.__proto__ || Object.getPrototypeOf(Anime), 'abstractGetEps', this).call(this, skipSeedLimit);
            for (var i = 0, len = eps.length; i < len; i++) {
                var currentEp = eps[i];
                if (exclude === true) {
                    if (currentEp.resides !== resides) {
                        arrayOfEps.push(currentEp);
                    }
                } else {
                    if (currentEp.resides === resides) {
                        arrayOfEps.push(currentEp);
                    }
                }
            }
            return arrayOfEps;
        }
    }, {
        key: 'getPageUrls',
        value: function getPageUrls() {
            function range(start, end) {
                return Array(end - start + 1).fill().map(function (_, idx) {
                    return start + idx;
                });
            }
            var pages = $(".center > ul.pagination a");
            if (pages.length === 0) {
                return [];
            }
            var firstPage = Utils.getElementFromJqueryArray(pages, 1);
            var lastPage = Utils.getElementFromJqueryArray(pages, pages.length - 2);
            var firstPageNumber = Number.parseInt(firstPage.text());
            var lastPageNumber = Number.parseInt(lastPage.text());
            var rangeBetween = range(firstPageNumber, lastPageNumber);
            var baseUrl = window.location.href;
            var urls = [];
            var currentPage = QueryString.p === undefined ? 1 : QueryString.p;
            for (var i = 0; i < rangeBetween.length; i++) {
                var num = String(rangeBetween[i]);
                if (num == currentPage) {
                    continue;
                }
                var newUrl = Utils.addParameter(baseUrl, "p", num.toString());
                urls.push(newUrl);
            }
            return urls;
        }
    }, {
        key: 'removeEpisodesFromUid',
        value: function removeEpisodesFromUid(uid) {
            var episode = Anime.getEpisodeFromUid(uid, true);
            _get(Anime.__proto__ || Object.getPrototypeOf(Anime), 'removeEpisodeFromAnime', this).call(this, episode);
        }
    }, {
        key: 'removeEpisodesFromResidence',
        value: function removeEpisodesFromResidence(resides, exclude) {
            var eps = Anime.getEpisodesFromResidence(resides, exclude, true);
            for (var i = 0, len = eps.length; i < len; i++) {
                var currentEp = eps[i];
                this.removeEpisodeFromAnime(currentEp);
            }
        }
    }, {
        key: 'getAmountOfEps',
        value: function getAmountOfEps() {
            return _get(Anime.__proto__ || Object.getPrototypeOf(Anime), 'abstractGetEps', this).call(this, true).length;
        }
    }, {
        key: 'getEpisodeFromUrl',
        value: function getEpisodeFromUrl(url) {
            var eps = _get(Anime.__proto__ || Object.getPrototypeOf(Anime), 'abstractGetEps', this).call(this, true);
            for (var i = 0, len = eps.length; i < len; i++) {
                var ep = eps[i];
                if (ep.downloadLink === url) {
                    return ep;
                }
            }
            return null;
        }
    }, {
        key: 'currentAnime',
        get: function get() {
            return Anime._currentAnime;
        },
        set: function set(value) {
            Anime._currentAnime = value;
        }
    }, {
        key: 'currentSubber',
        get: function get() {
            return Anime._currentSubber;
        },
        set: function set(value) {
            Anime._currentSubber = value;
        }
    }, {
        key: 'supportedRes',
        get: function get() {
            return Anime._supportedRes;
        }
    }, {
        key: 'availableRes',
        get: function get() {
            return Anime._availableRes;
        }
    }]);

    return Anime;
}(AbstractEps);

Anime._availableRes = [];
Anime._supportedRes = [{ "res": 1080, "fullRes": "1920x1080" }, {
    "res": 720,
    "fullRes": "1280x720"
}, { "res": 480, "fullRes": "640x480" }, { "res": 360, "fullRes": "640x360" }];

var Episode = function () {
    function Episode(res, downloadLink, seeds, leechers, uid, resides, title, size) {
        _classCallCheck(this, Episode);

        this._res = res;
        this._downloadLink = downloadLink;
        this._seeds = seeds;
        this._leechers = leechers;
        this._uid = uid;
        this._resides = resides;
        this._title = title;
        this._size = size;
    }

    _createClass(Episode, [{
        key: 'equals',
        value: function equals(ep) {
            return this.uid === ep.uid;
        }
    }, {
        key: 'res',
        get: function get() {
            return this._res;
        }
    }, {
        key: 'downloadLink',
        get: function get() {
            return this._downloadLink;
        }
    }, {
        key: 'seeds',
        get: function get() {
            return this._seeds;
        }
    }, {
        key: 'leechers',
        get: function get() {
            return this._leechers;
        }
    }, {
        key: 'uid',
        get: function get() {
            return this._uid;
        }
    }, {
        key: 'resides',
        get: function get() {
            return this._resides;
        }
    }, {
        key: 'title',
        get: function get() {
            return this._title;
        }
    }, {
        key: 'size',
        get: function get() {
            return this._size;
        }
    }]);

    return Episode;
}();

var QueryString = function () {
    if (typeof window == "undefined") {
        return {};
    }
    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") {
            query_string[pair[0]] = [query_string[pair[0]], pair[1]];
        } else {
            query_string[pair[0]].push(pair[1]);
        }
    }
    return query_string;
}();

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);
};

var Main = function () {
    function Main() {
        _classCallCheck(this, Main);
    }

    _createClass(Main, null, [{
        key: 'main',
        value: function main() {
            Main.setAnimeObj();
            Main.buildUi();
            Main.bindListeners();
        }
    }, {
        key: 'setAnimeObj',
        value: function setAnimeObj() {
            if (QueryString.q !== '') {
                Anime.currentAnime = decodeURIComponent(QueryString.q).split('+').join(' ');
            } else {
                Anime.currentAnime = "unknown";
            }
            var paths = window.location.pathname.split("/");
            Anime.currentSubber = paths[2];
            var instance = new DataParser(Utils.getTable());
            var eps = instance.parseTable(Utils.getCurrentPageOffset());
            Anime.addAllEps(eps);
        }
    }, {
        key: 'buildUi',
        value: function buildUi() {
            makeStyles();
            buildPanel();
            afterBuild();
            function makeStyles() {
                var styles = '';
                styles += '.collapsem{cursor: pointer; position: absolute; right: 4px; top: 2px;}';
                styles += '.panel-success > .panel-heading {position: relative;}';
                styles += '.avgSeeds{floar:left; padding-right:10px; color:#3c763d;}';
                styles += '.checkboxes{left:1px; margin:0; padding:0; position: relative; top: 1px; z-index: 1;}';
                styles += '#topbar{z-index: 2 !important;}';
                styles += 'label[for=\'MinSeeds\']{ display: block; margin-top: 10px;}';
                styles += '.filterLabel{margin-right: 10px;}';
                styles += '.alert {position:relative;}';
                styles += '#alertUser, #parseErrors{margin-top: 15px;}';
                styles += ".downloadButton {position:absolute; bottom:5px;}";
                styles += '#alertButton{right:78px;}';
                styles += '#alertButtonCancel{right: 5px;}';
                styles += '#downloadZip{right: 140px;}';
                styles += '#errorClose{position:absolute; bottom:5px; right: 11px;}';
                styles += '#animeSelection{width: 100%;}';
                styles += '#clearResOptions{margin-left: 10px; margin-right: 10px ;cursor: pointer;}';
                styles += '#selectAllFromControl{cursor: pointer;}';
                styles += '#downloadCustomButton{float:right;}';
                styles += '#findEp{float: right; position: relative; bottom: 20px; width: 180px;}';
                styles += "#loadingContainer{margin-top: 15px; margin-bottom: 45px;}";
                Utils.injectCss(styles);
            }
            function buildPanel() {
                var html = '';
                html += '<div class="panel panel-success">';
                html += '<div class="panel-heading">';
                html += '<h3 id="panel-title" class="panel-title"></h3>';
                html += '<i class="glyphicon glyphicon-minus collapsem" id="collapseToggle" title="Hide"></i>';
                html += '</div>';
                html += '<div class="panel-body" id="pannelContent"></div>';
                html += '</div>';
                $('.container > .row > h3').after(html);
                buildPanelContent();
                function buildPanelContent() {
                    var html = '';
                    html += '<div>';
                    $('#panel-title').html('<span> Download "' + Anime.currentAnime + ' (' + Anime.currentSubber + ')"</span>');
                    if (Anime.getAmountOfEps() === 0) {
                        html += '<span> No translated anime found or error occured</span>';
                        html += '</div>';
                        $('#pannelContent').html(html);
                        return;
                    }
                    html += '<span>Pick a resolution: </span>';
                    html += '<span id=\'selectDownload\'>';
                    html += UI.buildDropdownSelections();
                    html += '</span>';
                    html += '<button class="btn btn-default" type="button" data-type=\'downloadAll\' id="downloadAll">Download all</button>';
                    html += '<button class="btn btn-default" type=\'button\' id=\'downloadCustomButton\' data-type=\'downloadSelected\' >download your selected items</button>';
                    html += '</div>';
                    html += '<div id=\'options\'>';
                    html += '<div class="checkbox">';
                    html += "<label>";
                    html += '<input type=\'checkbox\' id=\'crossPage\' /> ';
                    html += "include Cross pages";
                    html += "</label>";
                    html += "</div>";
                    html += '<div class="input-group">';
                    html += '<input placeholder="Minimum seeders" class="form-control" type=\'number\' min=\'0\' id=\'MinSeeds\' title=\'Any episode that is below this limit will be excluded from the download.\'/>';
                    html += '<span class="input-group-btn">';
                    html += '<button class="btn btn-default" type=\'button\' id=\'SaveMinSeeds\'>Save</button>';
                    html += "</span>";
                    html += "</div>";
                    html += '<div id=\'tableInfo\'>';
                    html += UI.buildTable();
                    html += '</div>';
                    html += '<div id=\'alertUser\' class=\'hide\'></div>';
                    html += '<div class=\'selectAnime\' id=\'selectAnime\'>';
                    html += UI.buildSelect();
                    html += '</div>';
                    html += '<input class="form-control" type=\'text\' id=\'findEp\' placeholder=\'Search Select (or use regex) \' />';
                    html += '<button class="btn btn-default" disabled id=\'acceptSelect\' data-type=\'downloadSelects\'>Select for download</button>';
                    html += '<div id=\'parseErrors\' class =\'hide\'></div>';
                    $('#pannelContent').html(html);
                }
            }
            function afterBuild() {
                makeCheckBoxes();
                sortLists();
                function makeCheckBoxes() {
                    $('.tlistdownload > a').after('<input class=\'checkboxes\' type=\'checkbox\'/>');
                }
                function sortLists() {
                    Utils.sortAllControls();
                }
            }
        }
    }, {
        key: 'bindListeners',
        value: function bindListeners() {
            Utils.reBindSelectFilters();
            $('#downloadAll').on('click', function (e) {
                Utils.doDownloads(e);
            });
            $('.checkboxes').on('click', function (e) {
                if (Utils.checkBoxValid($('.checkboxes'))) {
                    Utils.enableButton($('#downloadCustomButton'));
                } else {
                    Utils.disableButton($('#downloadCustomButton'));
                }
            });
            $('#crossPage').on('click', function (e) {
                preformParsing(Anime.getPageUrls());
                function preformParsing(urls) {
                    if (urls.length === 0) {
                        return;
                    }
                    if (Utils.checkBoxValid($('#crossPage'))) {
                        (function () {
                            $('#tableInfo').html('<p>Please wait while we parse each page...</p>');
                            $('#selectAnime').html('');
                            $('#acceptSelect').hide();
                            $('#crossPage, #downloadAll').prop('disabled', true);
                            $('#parseErrors').slideUp('fast', function () {
                                $(this).html('');
                            });
                            var AjaxInfo = {
                                error: {
                                    pageAtError: null
                                },
                                currentPage: null
                            };
                            var ajaxPromiseMap = new Map();
                            var arrayd = [];
                            for (var i = 0; i < urls.length; i++) {
                                var d = $.Deferred();
                                ajaxPromiseMap.set(urls[i], d);
                                arrayd.push(d);
                            }
                            $.when.apply($, arrayd).done(function () {
                                if (AjaxInfo.error.pageAtError !== null) {
                                    UI.showAjaxErrorAlert(AjaxInfo);
                                }
                                $('#tableInfo').html(UI.buildTable());
                                $('#downloadRes').html(UI.buildDropdownSelections());
                                $('#selectAnime').html(UI.buildSelect());
                                Utils.sortAllControls();
                                $('#acceptSelect').show();
                                Utils.reBindSelectFilters();
                                $('#crossPage, #downloadAll').prop('disabled', false);
                            });
                            var timeOut = 0;

                            var _loop = function _loop(cur, deferr) {
                                var currentPage = 0;
                                var queryObjet = Utils.getQueryFromUrl(cur);
                                if (queryObjet.p) {
                                    currentPage = queryObjet.p;
                                } else {
                                    currentPage = 1;
                                }
                                setTimeout(function () {
                                    var ajax = $.ajax(cur);
                                    ajax.done(function (data) {
                                        AjaxInfo.currentPage = currentPage;
                                        var table = $(data).find("table");
                                        var parser = new DataParser(table);
                                        $('#tableInfo').append('<div>Page ' + currentPage + ' Done </div>');
                                        Anime.addAllEps(parser.parseTable(currentPage));
                                    }).fail(function () {
                                        AjaxInfo.error.pageAtError = Number.parseInt(cur.split('=').pop());
                                        $('#tableInfo').append('<div>Page ' + currentPage + ' Done </div>');
                                    }).always(function () {
                                        deferr.resolve();
                                    });
                                }, timeOut);
                                timeOut += 350;
                            };

                            var _iteratorNormalCompletion = true;
                            var _didIteratorError = false;
                            var _iteratorError = undefined;

                            try {
                                for (var _iterator = ajaxPromiseMap[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
                                    var _ref = _step.value;

                                    var _ref2 = _slicedToArray(_ref, 2);

                                    var cur = _ref2[0];
                                    var deferr = _ref2[1];

                                    _loop(cur, deferr);
                                }
                            } catch (err) {
                                _didIteratorError = true;
                                _iteratorError = err;
                            } finally {
                                try {
                                    if (!_iteratorNormalCompletion && _iterator.return) {
                                        _iterator.return();
                                    }
                                } finally {
                                    if (_didIteratorError) {
                                        throw _iteratorError;
                                    }
                                }
                            }
                        })();
                    } else {
                        var tableInfoElm = $('#tableInfo');
                        tableInfoElm.html('<p>Please wait while we re-calculate the Episodes</p>');
                        var _currentPage = Utils.getCurrentPageOffset();
                        Anime.removeEpisodesFromResidence(_currentPage, true);
                        Utils.cleanAvailableResolutions();
                        $('#downloadRes').html(UI.buildDropdownSelections());
                        tableInfoElm.html(UI.buildTable());
                        $('#selectAnime').html(UI.buildSelect());
                        Utils.reBindSelectFilters();
                        Utils.sortAllControls();
                    }
                }
            });
            $('#SaveMinSeeds').on('click', function (e) {
                if (parseInt($('#MinSeeds').val()) < 0) {
                    alert('number cannot be negative');
                    return;
                }
                var value = void 0;
                value = $('#MinSeeds').val() === '' ? parseInt("-1") : parseInt($('#MinSeeds').val());
                Localstore.setMinSeedsFromStore(value);
                if (value === -1) {
                    alert('Minimum seeds have been cleared');
                } else {
                    alert('Minimum seeds now set to: ' + value);
                }
                $('#selectAnime').html(UI.buildSelect());
                Utils.sortAllControls();
                Utils.reBindSelectFilters();
            });
            $('#collapseToggle').on('click', function () {
                $('#pannelContent').stop(true, true).slideToggle('slow', function () {
                    var elm = $('#collapseToggle');
                    if ($(this).is(':hidden')) {
                        elm.removeClass('glyphicon-minus').addClass('glyphicon-plus');
                        elm.attr('title', 'Show');
                    } else {
                        elm.addClass('glyphicon-minus').removeClass('glyphicon-plus');
                        elm.attr('title', 'Hide');
                    }
                });
            });
            $('#acceptSelect').on('click', function (e) {
                Utils.doDownloads(e);
            });
            $('#findEp').on('keyup', function () {
                UI.applySearch($(this).val());
            });
        }
    }]);

    return Main;
}();

var UI = function () {
    function UI() {
        _classCallCheck(this, UI);
    }

    _createClass(UI, null, [{
        key: 'buildTable',
        value: function buildTable() {
            var html = '';
            html += '<table class="table table-bordered table-hover table-striped torrent-list" style=\'width: 100%\' id=\'info\'>';
            html += '<caption>Download infomation</caption>';
            html += '<thead>';
            html += '<tr>';
            html += '<th>resolution</th>';
            html += '<th>Episode count</th>';
            html += '<th>Average seeds</th>';
            html += '<th>Average leechers</th>';
            html += '<th>Total size</th>';
            html += '</tr>';
            html += '</thead>';
            html += '<tbody>';
            var allRes = Anime.availableRes;
            for (var i = 0; i < allRes.length; i++) {
                var currRes = allRes[i];
                var localRes = currRes.res;
                html += '<tr>';
                html += '<td>' + (localRes === -1 ? 'Others' : localRes + 'p') + '</td>';
                html += '<td>' + Anime.getAmountOfEpsFromRes(localRes, true) + '</td>';
                html += '<td>' + Anime.avgSeedsForRes(localRes, true) + '</td>';
                html += '<td>' + Anime.avgPeersForRes(localRes, true) + '</td>';
                html += '<td>' + Anime.getTotalSizeForRes(localRes, true) + ' (aprox)</td>';
                html += '</tr>';
            }
            html += '</tbody>';
            html += '</table>';
            return html;
        }
    }, {
        key: 'stateChangeAcceptSelect',
        value: function stateChangeAcceptSelect(state) {
            $("#acceptSelect").enableButton(state);
        }
    }, {
        key: 'autoEnableAcceptSelect',
        value: function autoEnableAcceptSelect() {
            var selection = $("#animeSelection option:selected");
            UI.stateChangeAcceptSelect(selection.length > 0);
        }
    }, {
        key: 'buildDropdownSelections',
        value: function buildDropdownSelections() {
            var html = '';
            html += '<select class="form-control" style="margin-right:5px;display: inline;width: auto;" id="downloadRes">';
            var allRes = Anime.availableRes;
            for (var i = 0; i < allRes.length; i++) {
                var currRes = allRes[i];
                var localRes = currRes.res;
                html += '<option value=' + localRes + '>' + (localRes === -1 ? 'Others' : localRes + 'p') + '</option>';
            }
            html += '</select>';
            return html;
        }
    }, {
        key: 'builDownloadAlert',
        value: function builDownloadAlert(type) {
            var amountOfAnime = 0;
            var selectedRes = Number.parseInt($('#downloadRes').val());
            var res = null;
            var totalSize = null;
            if (type === 'downloadSelected') {
                amountOfAnime = $('.checkboxes:checked').length;
                res = 'custom';
            } else if (type === 'downloadSelects') {
                amountOfAnime = $('#animeSelection option:selected').length;
                totalSize = Utils.getHumanReadableSize(function () {
                    var localSize = 0;
                    $('#animeSelection option:selected').each(function () {
                        var url = this.dataset.url;
                        localSize += Anime.getEpisodeFromAnchor(url).size;
                    });
                    return localSize;
                }());
                res = 'custom';
            } else {
                amountOfAnime = Anime.getAmountOfEpsFromRes(selectedRes, false);
                res = selectedRes === -1 ? 'Others' : selectedRes + 'p';
                totalSize = Anime.getTotalSizeForRes(parseInt(res), false);
            }
            var seedLimit = Localstore.getMinSeedsFromStore();
            if (seedLimit === "-1") {
                seedLimit = "none";
            }
            var html = '';
            html += '<div class=\'alert alert-success\'>';
            html += '<div><strong>Download: ' + res + '</strong></div> <br />';
            html += '<div><strong>Seed Limit: ' + seedLimit + '</strong></div>';
            if (totalSize !== null) {
                html += '<br /><div><strong>Total size: ' + totalSize + ' (aprox)</strong></div>';
            }
            html += '<p>You are about to download ' + amountOfAnime + ' ep(s)</p>';
            html += '<p>This will cause ' + amountOfAnime + ' download pop-up(s) Are you sure you want to continue?</p>';
            html += '<p>If there are a lot of eps, your browser might stop responding for a while. This is normal. If you are on Google Chrome, it will ask you to allow multiple-downloads</p>';
            html += '<button type="button" class="btn btn-warning downloadButton" id=\'alertButtonCancel\'>Cancel</button>';
            html += '<button type="button" class="btn btn-success downloadButton" id=\'alertButton\'>Okay</button>';
            html += '<button type="button" class="btn btn-success downloadButton" id=\'downloadZip\'>Download as zip</button>';
            html += "<div class='hidden' id='loadingContainer'>";
            html += "<hr />";
            html += "<div class=\"progress\">";
            html += "<div id='progressBarForZip' class=\"progress-bar progress-bar-striped active\" role=\"progressbar\" aria-valuenow=\"45\" aria-valuemin=\"0\" aria-valuemax=\"100\" style='width: 100%;'>Current status: <span id='progressStatus'></span></div>";
            html += "</div>";
            html += "</div>";
            html += '</div>';
            return html;
        }
    }, {
        key: 'showAjaxErrorAlert',
        value: function showAjaxErrorAlert(ajaxInfo) {
            var parseError = $('#parseErrors');
            if (!parseError.is(':hidden')) {
                return null;
            }
            parseError.html('');
            var html = '';
            html += '<div class=\'alert alert-danger\'>';
            html += '<p>There was an error in getting the information from page: \'' + ajaxInfo.error.pageAtError + '\'</p>';
            html += '<button id=\'errorClose\' class="btn btn-primary"> close </button>';
            html += '</div>';
            parseError.show();
            parseError.html(html);
            $('#errorClose').off('click').on('click', function () {
                $('#parseErrors').slideUp('slow', function () {
                    $(this).html('');
                });
            });
        }
    }, {
        key: 'buildSelect',
        value: function buildSelect() {
            var resTOFilter = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "none";

            var html = '';
            UI.epsInSelect = [];
            var minSeeds = Number.parseInt(Localstore.getMinSeedsFromStore());
            html += '<div id=\'selectWrapper\'>';
            html += '<div id=\'selectContainer\'>';
            html += '<p>Or you can select episodes here:</p>';
            html += '<p>Seed limit: ' + (minSeeds === -1 ? 'None' : minSeeds) + '</p>';
            html += '<select class="form-control" id=\'animeSelection\' multiple size=\'20\'>';
            var allRes = Anime.availableRes;
            for (var i = 0; i < allRes.length; i++) {
                var currRes = allRes[i];
                var localRes = currRes.res;
                var eps = Anime.getEpsForRes(localRes, false);
                for (var j = 0, len = eps.length; j < len; j++) {
                    var currentEp = eps[j];
                    if (resTOFilter == 'none' || currentEp.res == resTOFilter) {
                        html += '<option data-url=\'' + currentEp.downloadLink + '\'>';
                        html += currentEp.title + ' - Seeders: ' + currentEp.seeds;
                        UI.epsInSelect.push(currentEp);
                        html += '</option>';
                    } else {
                        break;
                    }
                }
            }
            html += '</select>';
            html += '<span>Filter select control: </span>';
            var checked = false;
            for (var _i = 0; _i < allRes.length; _i++) {
                if (resTOFilter == allRes[_i].res) {
                    checked = true;
                }
                html += '<input type=\'radio\' ' + (checked ? 'checked' : '') + ' data-set= \'' + allRes[_i].res + '\' name=\'filterSelect\'/>' + '<label class="filterLabel">' + (allRes[_i].res === -1 ? 'Others' : allRes[_i].res + 'p') + '</label>';
                checked = false;
            }
            html += '<a id=\'clearResOptions\' data-set=\'none\' >clear resolution filter</a>';
            html += '<a id=\'selectAllFromControl\'>Select all</a>';
            html += '</div>';
            html += '</div>';

            $("#acceptSelect").enableButton(false);
            return html;
        }
    }, {
        key: 'applySearch',
        value: function applySearch(textToFilter) {
            var opts = UI.epsInSelect;
            var rxp = new RegExp(textToFilter);
            var optlist = $('#animeSelection').empty();
            for (var i = 0, len = opts.length; i < len; i++) {
                var ep = opts[i];
                if (rxp.test(ep.title)) {
                    optlist.append('<option data-url=\'' + ep.downloadLink + '\'>' + ep.title + ' - Seeders: ' + ep.seeds + '</option>');
                }
            }
            UI.searchApplied = textToFilter;
            Utils.sortSelect(document.getElementById("animeSelection"));
            UI.autoEnableAcceptSelect();
        }
    }, {
        key: 'getAppliedSearch',
        value: function getAppliedSearch() {
            return UI.searchApplied;
        }
    }, {
        key: 'getEpsInSelect',
        value: function getEpsInSelect() {
            return UI.epsInSelect;
        }
    }]);

    return UI;
}();

UI.epsInSelect = [];
UI.searchApplied = '';

var Utils = function () {
    function Utils() {
        _classCallCheck(this, Utils);
    }

    _createClass(Utils, null, [{
        key: 'downloadViaJavaScript',
        value: function downloadViaJavaScript(url, data, callBack) {
            var _type = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "POST";

            var fileName = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;

            var xhr = new XMLHttpRequest();
            xhr.open(_type, url, true);
            xhr.responseType = "blob";
            xhr.withCredentials = true;
            if (_type == "POST") {
                xhr.setRequestHeader("Content-type", "application/json");
            }
            var hasError = false;
            var mediaType = null;
            xhr.onreadystatechange = function () {
                var error = null;
                if (xhr.readyState === XMLHttpRequest.DONE) {
                    if (hasError) {
                        if (xhr.response != null && xhr.response.length > 0) {
                            error = xhr.response;
                        } else {
                            error = "internal server error";
                        }
                    }
                    var contentDispositionHeader = xhr.getResponseHeader("Content-Disposition");
                    if (fileName == null && contentDispositionHeader != null && contentDispositionHeader.indexOf("filename") > -1) {
                        fileName = contentDispositionHeader.split("filename").pop();
                        fileName = fileName.replace("=", "");
                        fileName = fileName.trim();
                        fileName = fileName.replace(/"/g, "");
                    }
                    var mediaTypeHeader = xhr.getResponseHeader("Content-Type");
                    if (mediaTypeHeader != null) {
                        mediaType = mediaTypeHeader;
                    } else {
                        mediaType = "application/octet-stream";
                    }
                    var blob = xhr.response;

                    var saveAsFunc = saveAs.bind(this, blob, fileName, true);
                    callBack.call(this, blob, fileName, hasError, error, saveAsFunc);
                } else if (xhr.readyState === XMLHttpRequest.HEADERS_RECEIVED) {
                    if (xhr.status !== 200) {
                        xhr.responseType = "text";
                        hasError = true;
                    }
                }
            };
            if (_type === "POST") {
                xhr.send(JSON.stringify(data));
            } else {
                xhr.send();
            }
        }
    }, {
        key: 'sortSelect',
        value: function sortSelect(selElem) {
            var tmpAry = [];
            for (var i = 0, length = selElem.options.length; i < length; i++) {
                tmpAry[i] = [];
                tmpAry[i][0] = selElem.options[i].text;
                tmpAry[i][1] = selElem.options[i].dataset.url;
            }
            tmpAry.sort(function (a, b) {
                return a[0].toUpperCase().localeCompare(b[0].toUpperCase());
            });
            selElem.innerHTML = "";
            for (var _i2 = 0, len = tmpAry.length; _i2 < len; _i2++) {
                var op = new Option(tmpAry[_i2][0]);
                op.dataset.url = tmpAry[_i2][1];
                selElem.options[_i2] = op;
            }
        }
    }, {
        key: 'injectCss',
        value: function injectCss(css) {
            function _isUrl(url) {
                var matcher = new RegExp(/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/);
                return matcher.test(url);
            }
            if (_isUrl(css)) {
                $("<link>").prop({
                    "type": "text/css",
                    "rel": "stylesheet"
                }).attr("href", css).appendTo("head");
            } else {
                $("<style>").prop("type", "text/css").html(css).appendTo("head");
            }
        }
    }, {
        key: 'addParameter',
        value: function addParameter(url, parameterName, parameterValue) {
            var atStart = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;

            var replaceDuplicates = true;
            var urlhash = void 0;
            var cl = void 0;
            if (url.indexOf('#') > 0) {
                cl = url.indexOf('#');
                urlhash = url.substring(url.indexOf('#'), url.length);
            } else {
                urlhash = '';
                cl = url.length;
            }
            var sourceUrl = url.substring(0, cl);
            var urlParts = sourceUrl.split("?");
            var newQueryString = "";
            if (urlParts.length > 1) {
                var parameters = urlParts[1].split("&");
                for (var i = 0; i < parameters.length; i++) {
                    var parameterParts = parameters[i].split("=");
                    if (!(replaceDuplicates && parameterParts[0] == parameterName)) {
                        if (newQueryString == "") {
                            newQueryString = "?";
                        } else {
                            newQueryString += "&";
                        }
                        newQueryString += parameterParts[0] + "=" + (parameterParts[1] ? parameterParts[1] : '');
                    }
                }
            }
            if (newQueryString == "") {
                newQueryString = "?";
            }
            if (atStart) {
                newQueryString = '?' + parameterName + "=" + parameterValue + (newQueryString.length > 1 ? '&' + newQueryString.substring(1) : '');
            } else {
                if (newQueryString !== "" && newQueryString != '?') newQueryString += "&";
                newQueryString += parameterName + "=" + (parameterValue ? parameterValue : '');
            }
            return urlParts[0] + newQueryString + urlhash;
        }
    }, {
        key: 'getElementFromJqueryArray',
        value: function getElementFromJqueryArray(elm, index) {
            return elm.filter(function (i) {
                return i === index;
            });
        }
    }, {
        key: 'getTable',
        value: function getTable() {
            return $('table');
        }
    }, {
        key: 'getQueryFromUrl',
        value: function getQueryFromUrl(url) {
            return url.split("&").reduce(function (prev, curr, i, arr) {
                var p = curr.split("=");
                prev[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
                return prev;
            }, {});
        }
    }, {
        key: 'isjQueryObject',
        value: function isjQueryObject(obj) {
            return obj instanceof jQuery || 'jquery' in Object(obj);
        }
    }, {
        key: 'disableButton',
        value: function disableButton(button) {
            button.prop('disabled', true);
        }
    }, {
        key: 'enableButton',
        value: function enableButton(button) {
            button.prop('disabled', false);
        }
    }, {
        key: 'doDownloads',
        value: function doDownloads(event) {
            $('#crossPage').prop('disabled', true);
            var type = $(event.target).data('type');
            var html = UI.builDownloadAlert(type);
            var urlsToDownload = [];
            $('#alertUser').html(html).slideDown("slow").show();
            if (type === 'downloadSelected') {
                $.each($('.checkboxes:checked').prev('a'), function () {
                    var ep = Anime.getEpisodeFromAnchor(this);
                    urlsToDownload.push(ep.downloadLink);
                });
            } else if (type === 'downloadSelects') {
                $.each($('#animeSelection option:selected'), function () {
                    var url = this.dataset.url;
                    urlsToDownload.push(url);
                });
            } else {
                var eps = Anime.getEpsForRes(parseInt($('#downloadRes').val()), false);
                for (var i = 0, len = eps.length; i < len; i++) {
                    urlsToDownload.push(eps[i].downloadLink);
                }
            }
            bindAlertControls();
            function bindAlertControls() {
                $('#alertButtonCancel').on('click', function () {
                    $('#alertUser').slideUp('slow');
                    $('#crossPage').prop('disabled', false);
                });
                $('#alertButton').on('click', function () {
                    doIt(urlsToDownload, false);
                });
                $("#downloadZip").on("click", function () {
                    doIt(urlsToDownload, true);
                });
            }
            function doIt(urls, asZip) {
                var ajaxPromiseMap = new Map();
                var arrayd = [];
                for (var _i3 = 0; _i3 < urls.length; _i3++) {
                    var d = $.Deferred();
                    ajaxPromiseMap.set(urls[_i3], d);
                    arrayd.push(d);
                }
                $.when.apply($, arrayd).done(function () {
                    if (!asZip) {
                        return;
                    }

                    var zip = new JSZip();
                    var errors = [];
                    if (arrayd.length === 1) {
                        var blob = arguments[0];
                        var fileName = arguments[1];
                        var error = arguments[2];
                        if (error !== null) {
                            errors.push(fileName);
                        } else {
                            zip.file(fileName, blob);
                        }
                    } else {
                        for (var _i4 = 0; _i4 < arguments.length; _i4++) {
                            var arg = arguments[_i4];
                            var _blob = arg[0];
                            var _fileName = arg[1];
                            var _error = arg[2];
                            if (_error !== null) {
                                errors.push(_fileName);
                            } else {
                                zip.file(_fileName, _blob);
                            }
                        }
                    }
                    if (errors.length > 0) {
                        var errorMessage = "Unable to download the following files: \n" + errors.join("\n") + "\n Please download these files manually";
                        alert(errorMessage);
                    }
                    $("#progressStatus").text("Generating zip file...");
                    zip.generateAsync({ type: "blob" }).then(function (blob) {
                        saveAs(blob, Anime.currentAnime + ".zip");
                        $("#loadingContainer").hide();
                        $("#progressStatus").text(null);
                        $("#progressBarForZip").width(0);
                        $('#alertUser').slideUp('slow');
                    }, function (err) {
                        alert(err);
                    });
                });
                var timerOffset = 0;
                if (asZip) {
                    $("#loadingContainer").show();
                }
                var count = 0;

                var _loop2 = function _loop2(currentUrl, deferr) {
                    var ep = Anime.getEpisodeFromUrl(currentUrl);
                    var fileName = ep.title.replace(/ /g, "_") + ".torrent";
                    setTimeout(function () {
                        count++;
                        Utils.downloadViaJavaScript(currentUrl, undefined, function (blob, fileName, hasError, error, saveFunc) {
                            if (!asZip) {
                                saveFunc();
                            } else {
                                var percent = Math.floor(100 * count / ajaxPromiseMap.size);
                                var doneAsString = percent + "%";
                                $("#progressStatus").text("Downloading torrents: " + doneAsString);
                                $("#progressBarForZip").width(doneAsString);
                            }
                            if (hasError) {
                                deferr.resolve(blob, fileName, error);
                            } else {
                                deferr.resolve(blob, fileName, null);
                            }
                        }, "GET", fileName);
                    }, timerOffset);
                    timerOffset += 450;
                };

                var _iteratorNormalCompletion2 = true;
                var _didIteratorError2 = false;
                var _iteratorError2 = undefined;

                try {
                    for (var _iterator2 = ajaxPromiseMap[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
                        var _ref3 = _step2.value;

                        var _ref4 = _slicedToArray(_ref3, 2);

                        var currentUrl = _ref4[0];
                        var deferr = _ref4[1];

                        _loop2(currentUrl, deferr);
                    }
                } catch (err) {
                    _didIteratorError2 = true;
                    _iteratorError2 = err;
                } finally {
                    try {
                        if (!_iteratorNormalCompletion2 && _iterator2.return) {
                            _iterator2.return();
                        }
                    } finally {
                        if (_didIteratorError2) {
                            throw _iteratorError2;
                        }
                    }
                }

                if (!asZip) {
                    $('#alertUser').slideUp('slow');
                }
                $('#crossPage').prop('disabled', false);
            }
        }
    }, {
        key: 'checkBoxValid',
        value: function checkBoxValid(checkbox) {
            return checkbox.is(':checked');
        }
    }, {
        key: '_minSeedsSet',
        value: function _minSeedsSet() {
            var seeds = Localstore.getMinSeedsFromStore();
            if (seeds !== null && seeds.length > 0) {
                return Number.parseInt(seeds) !== 1;
            }
            return false;
        }
    }, {
        key: 'getCurrentPageOffset',
        value: function getCurrentPageOffset() {
            return parseInt(typeof QueryString.p === 'undefined' ? 1 : QueryString.p);
        }
    }, {
        key: 'arrayCopy',
        value: function arrayCopy(array) {
            var deep = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;

            return $.extend(deep, [], array);
        }
    }, {
        key: 'cleanAvailableResolutions',
        value: function cleanAvailableResolutions() {
            var avRes = Utils.arrayCopy(Anime.availableRes, true);
            for (var i = 0, len = avRes.length; i < len; i++) {
                var currentRes = avRes[i].res;
                if (Anime.getAmountOfEpsFromRes(currentRes, true) === 0) {
                    Anime.removeAvailableResolutions(currentRes);
                }
            }
        }
    }, {
        key: 'sortAllControls',
        value: function sortAllControls() {
            Utils.sortSelect(document.getElementById('animeSelection'));
            Utils.sortSelect(document.getElementById('downloadRes'));

            $('#info').sortTable(0);
        }
    }, {
        key: 'reBindSelectFilters',
        value: function reBindSelectFilters() {
            $('input[name=\'filterSelect\']').offOn('change', handleSelect);

            $('#clearResOptions').offOn('click', handleSelect);

            $("#animeSelection").offOn("click", function () {
                UI.autoEnableAcceptSelect();
            });

            $("#selectAllFromControl").offOn("click", function () {
                var allSelected = $("#animeSelection option:selected").length === $("#animeSelection option").length;
                if (allSelected) {
                    $(this).text("Select all");
                    $("#animeSelection option").prop("selected", false);
                } else {
                    $(this).text("deselect all");
                    $("#animeSelection option").prop("selected", true);
                }
                UI.autoEnableAcceptSelect();
            });
            function handleSelect(event) {
                var resTOFilter = $(event.target).data('set');
                $('#selectAnime').html(UI.buildSelect(resTOFilter));
                Utils.sortAllControls();
                var searchApplied = UI.getAppliedSearch();
                if (searchApplied !== '') {
                    UI.applySearch(searchApplied);
                }
                Utils.reBindSelectFilters();
            }
        }
    }, {
        key: 'getHumanReadableSize',
        value: function getHumanReadableSize(from) {
            var decimals = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 3;

            var bits = 0;
            if (Array.isArray(from)) {
                for (var i = 0; i < from.length; i++) {
                    var ep = from[i];
                    bits += ep.size;
                }
            } else if (typeof from === 'number') {
                bits = from;
            } else {
                bits += from.size;
            }
            function formatBytes(bytes, decimals) {
                if (bytes == 0) {
                    return '0 Byte';
                }
                var k = 1024;
                var dm = decimals + 1 || 3;
                var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
                var i = Math.floor(Math.log(bytes) / Math.log(k));
                return (bytes / Math.pow(k, i)).toPrecision(dm) + ' ' + sizes[i];
            }
            return formatBytes(bits, decimals);
        }
    }]);

    return Utils;
}();

var DataParser = function () {
    function DataParser(table) {
        _classCallCheck(this, DataParser);

        this.table = null;
        this.table = table;
    }

    _createClass(DataParser, [{
        key: 'parseTable',
        value: function parseTable(currentPage) {
            var trRow = this.table.find('img[src*=\'/static/img/icons/nyaa/1_2.png\']').closest('tr');
            var eps = [];
            $.each($(trRow), function () {
                var resInfo = parseRes(this);
                if (resInfo == null) {
                    Anime.addAvailableResolutions(-1, null);
                } else {
                    Anime.addAvailableResolutions(resInfo.res, resInfo.fullRes);
                }
                var info = getEpisodeInfo(this);
                if(resInfo == null){
                   eps.push(new Episode( -1 , info.currentDownloadLink, info.seeds, info.leech, info.uid, currentPage, info.title, info.size));
                }else{
                  eps.push(new Episode(typeof resInfo.res === 'undefined' ? -1 : resInfo.res, info.currentDownloadLink, info.seeds, info.leech, info.uid, currentPage, info.title, info.size));
                }
            });
            return eps;
            function parseRes(eventContent) {
                var supportedRes = Anime.supportedRes;
                for (var i = 0; i < supportedRes.length; i++) {
                    var currRes = supportedRes[i].res;
                    var currFullRes = supportedRes[i].fullRes;
                    if ($(eventContent).children('td:nth-child(2)').text().indexOf(currRes + 'p') > -1 || $(eventContent).children('td:nth-child(2)').text().indexOf(currFullRes) > -1) {
                        return supportedRes[i];
                    }
                }
            }
            function getEpisodeInfo(eventContent) {
                var _eventContent = $(eventContent);
                var currentDownloadLink = Anime.getTdFromTable(_eventContent, 3).find("a")[0].href;
                function getTextContent(idx) {
                    return isNaN(parseInt(Anime.getTdFromTable(_eventContent, idx).text())) ? 0 : parseInt(Anime.getTdFromTable(_eventContent, idx).text());
                }
                function convertToString(ev) {
                    var sizeValue = Anime.getTdFromTable(ev, 4).text();
                    var sizeText = $.trim(sizeValue.split(' ').pop());
                    var intValue = parseInt(sizeValue);
                    switch (sizeText) {
                        case "MiB":
                            return Math.pow(2, 20) * intValue;
                        case "GiB":
                            return intValue * 1073741824;
                        default:
                            return 0;
                    }
                }
                var seeds = getTextContent(6);
                var leech = getTextContent(7);
                var title = Anime.getTdFromTable(_eventContent, 2).text().trim().substring(1).trim();
                var uid = Anime.getUidFromJqueryObject(_eventContent);
                var size = convertToString(_eventContent);
                return {
                    'currentDownloadLink': currentDownloadLink,
                    'seeds': seeds,
                    'leech': leech,
                    'title': title,
                    'uid': uid,
                    "size": size
                };
            }
        }
    }]);

    return DataParser;
}();

var Localstore = function () {
    function Localstore() {
        _classCallCheck(this, Localstore);
    }

    _createClass(Localstore, null, [{
        key: 'getMinSeedsFromStore',
        value: function getMinSeedsFromStore() {
            var lo = localStorage.getItem('minSeeds');
            return lo === null ? "-1" : lo;
        }
    }, {
        key: 'setMinSeedsFromStore',
        value: function setMinSeedsFromStore(seeds) {
            localStorage.setItem('minSeeds', seeds.toString());
        }
    }, {
        key: 'removeMinSeedsFromStore',
        value: function removeMinSeedsFromStore() {
            localStorage.removeItem('minSeeds');
        }
    }]);

    return Localstore;
}();

Main.main();