Greasy Fork is available in English.

Reddit Downloader

Download your saved posts or directly posts from your feed with support for Direct links (png, jpg, gif, mp4...), (Gypcat kinda), Redgify, Imgur (Only when supplied with an API key)

// ==UserScript==
// @name         Reddit Downloader
// @namespace    https://github.com/felixire/Reddit-Downloader
// @version      0.2.4
// @description  Download your saved posts or directly posts from your feed with support for Direct links (png, jpg, gif, mp4...), (Gypcat kinda), Redgify, Imgur (Only when supplied with an API key)
// @author       felixire
// @match        https://www.reddit.com/*
// @match        https://reddit.com/*
// @match        https://www.old.reddit.com/*
// @match        https://old.reddit.com/*
// @match        https://www.new.reddit.com/*
// @match        https://new.reddit.com/*
// @require      https://greasyfork.org/scripts/28536-gm-config/code/GM_config.js?version=184529
// @grant        GM_download
// @grant        GM_notification
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// ==/UserScript==

const DEBUG = false;
let _LastDownloadedID = GM_getValue('LastDownloaded', '');

let _IsOnUserPage = false;

//#region Helpers
function wait(ms) {
    return new Promise(res => setTimeout(res, ms));
}

function randomName(length = 16) {
    let chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    let name = '';
    for (let index = 0; index < length; index++) {
        let ind = Math.floor(Math.random() * chars.length);
        name += chars.charAt(ind);
    }
    return name;
}

function waitForElements(selectors, timeout = 1000) {
    return new Promise(async (res, rej) => {
        let time = 0;
        if (!Array.isArray(selectors))
            selectors = [selectors];

        let eles = [];

        selectors.forEach(async (sel, i) => {
            let ele = document.querySelector(sel.trim());
            while (ele == null || ele == undefined) {
                if (time >= timeout) {
                    //console.error("Timed out while waiting for: " + sel);
                    rej("Timed out while waiting for: " + sel);
                    return;
                }

                time += 10;
                await wait(10);
                ele = document.querySelector(sel);
            }
            eles.push(ele);
            if (i == (selectors.length - 1))
                res(eles);
            return;
        });
    })
}

function createNotification(title, text) {
    GM_notification({
        title,
        text,
        timeout: 5000
    })
}

function isOldReddit(){
    return new Promise((res) => {
        if (window.location.href.includes('old.reddit.com')){
            res(true);
            return true;
        }
        if (window.location.href.includes('new.reddit.com')){
            res(false);
            return false;
        }

        //Old page
        waitForElements('.redesign-beta-optin', 5000)
        .then(() => {
            res(true);
            return true;
        }).catch(() => {})

        //New page
        waitForElements('#SHORTCUT_FOCUSABLE_DIV', 5000)
        .then(() => {
            res(false);
            return false;
        }).catch(() => {})
    })
}

//#endregion

//#region Supported Downloaders
class DownloadSite {
    constructor() {

    }

    checkSupport(href) {
        throw new Error('NOT IMPLEMENTD!');
    }

    async downloadImages(info, folder = '') {
        return new Promise(async res => {
            let url = this._removeParams(info.url);
            let links = await this.getDownloadLinks(url);
            if (!Array.isArray(links)) links = [links];
            if (links.length > 1)
                await this._downloadBulk(links, folder, `${randomName()}`);
            else
                await this._downloadBulk(links, folder);
            // if(links.length > 1)
            // else
            //     this._download(links[0], folder);

            res();
        });
    }

    /**
     * @return {Promise<Array<string>>}
     */
    getDownloadLinks(href) {
        throw new Error('NOT IMPLEMENTD!');
    }

    _getExtension(href) {
        return href.replace(/.*\./, '');
    }

    _getParams(href) {
        return href.match(/\?.*/gim);
    }

    _removeAmpSymbols(href) {
        return href.replace(/amp;/gim, '');
    }

    _removeParams(href) {
        return href.replace(/\?.*/gim, '');
    }

    async _downloadBulk(links, folder = '', locationAppend = '') {
        return new Promise(async res => {
            for (let index = 0; index < links.length; index++) {
                const url = links[index];
                const params = this._getParams(url);
                const pureUrl = this._removeParams(url);
                const name = (links.length > 1 ? `[${index}]` : '') + `${randomName()}`;

                this._download({
                    url: url,
                    folder,
                    locationAppend,
                    name,
                    extension: this._getExtension(pureUrl)
                });
                await wait(100);
            }

            res();
        })
    }

    //_download(url, folder='', name=randomName(), locationAppend=''){
    _download(infos) {
        let folder = ((infos.folder != '' && infos.folder != null && infos.folder != undefined && infos.folder != '') ? `/${infos.folder}` : '');
        let locationAppend = ((infos.locationAppend != null && infos.locationAppend != undefined && infos.locationAppend != '') ? `/${infos.locationAppend}` : '');
        let name = (infos.name != '' && infos.name != null && infos.name != undefined) ? `/${infos.name}` : '/' + randomName();
        let downloadLocation = GM_config.get('download_location').substr(-1) == '/' ? GM_config.get('download_location').slice(0, -1) : GM_config.get('download_location');

        let details = {
            url: infos.url,
            name: downloadLocation + folder + locationAppend + name + '.' + infos.extension,
            saveAs: false
        }

        GM_download(details);
    }
}

class DirectDownload extends DownloadSite {
    constructor() {
        super();
        this.supportedExtensions = ['png', 'jpg', 'jpeg', 'gif', 'gifv', 'mp4', 'mp3'];
    }

    checkSupport(href) {
        return this.supportedExtensions.includes(this._getExtension(href));
    }

    getDownloadLinks(href) {
        if (href.endsWith('.gifv')) href = href.replace('gifv', 'mp4');
        return [href];
    }
}

class RedditGallery extends DownloadSite {
    constructor() {
        super();
    }

    async downloadImages(info, folder) {
        return new Promise(async res => {
            let postJSON = await window.RedditDownloader._getPostData(info.og_url);
            let media_metadata = postJSON[0].data.children[0].data.media_metadata;
            if (media_metadata == null || media_metadata == undefined) {
                media_metadata = postJSON[0].data.children[0].data.crosspost_parent_list[0].media_metadata;
            }

            let media_keys = Object.keys(media_metadata);
            let links = [];

            for (let i = 0; i < media_keys.length; i++) {
                const key = media_keys[i];
                const url = media_metadata[key].s.u;

                links.push(this._removeAmpSymbols(url));
            }

            if (!Array.isArray(links)) links = [links];
            if (links.length > 1)
                await this._downloadBulk(links, folder, `${randomName()}`);
            else
                await this._downloadBulk(links, folder);
            // if(links.length > 1)
            // else{
            //     let infos = {}
            //     this._download(links[0], folder);
            // }

            res();
        });
    }

    checkSupport(href) {
        console.log('-----------------')
        console.log(href.includes('reddit.com/gallery/'));
        return (href.includes('reddit.com/gallery/'));
    }
}

class Imgur extends DownloadSite {
    constructor() {
        super();

        this._ApiEndpoint = 'https://api.imgur.com/3/';
    }

    checkSupport(href) {
        return (href.includes('imgur.com/') && !href.includes('i.imgur.com/'));
    }

    getDownloadLinks(href) {
        let id = href.replace(/.*\//igm, '');
        let isAlbum = href.replace(/.*imgur.com\//igm, '').startsWith('a');
        return isAlbum ? this.getAlbumLinks(id) : this.getGalleryLinks(id);
    }

    getGalleryLinks(galleryID) {
        return new Promise((res, rej) => {
            if (!GM_config.get('imgur_client_id')) {
                rej('NO CLIENT ID!');
                return;
            }
            fetch(this._ApiEndpoint + `gallery/${galleryID}/images?client_id=${GM_config.get('imgur_client_id')}`)
                .then(body => body.text())
                .then(text => {
                    let data = JSON.parse(text);
                    if (data.data.images == undefined) {
                        res([]);
                        return;
                    }
                    let links = data.data.images.reduce((a, c) => {
                        console.log(a, c);
                        a.push(c.link);
                        return a;
                    }, []);


                    console.log(links)
                    res(links);
                });
        })
    }

    getAlbumLinks(albumID) {
        return new Promise((res, rej) => {
            if (!GM_config.get('imgur_client_id')) {
                rej('NO CLIENT ID!');
                return;
            }
            fetch(this._ApiEndpoint + `album/${albumID}/images?client_id=${GM_config.get('imgur_client_id')}`)
                .then(body => body.text())
                .then(text => {
                    let data = JSON.parse(text);
                    let links = data.data.reduce((a, c) => {
                        a.push(c.link);
                        return a;
                    }, []);

                    res(links);
                });
        })
    }
}

class Gfycat extends DownloadSite {
    constructor() {
        super();
    }

    checkSupport(href) {
        return (href.includes('//gfycat.com/') || href.includes('www.gfycat.com/'));
    }

    getDownloadLinks(href) {
        //media => oembed => thumbnail_url
        //https://thumbs.gfycat.com/<ID>-size_restricted.gif

        return href.replace('thumbs', 'giant').replace('-size_restricted.gif', '.mp4');
    }
}

class Redgifs extends DownloadSite {
    constructor() {
        super();

        this.gypcatList = [
            'aardvark',
            'aardwolf',
            'abalone',
            'abyssiniancat',
            'abyssiniangroundhornbill',
            'acaciarat',
            'achillestang',
            'acornbarnacle',
            'acornweevil',
            'acornwoodpecker',
            'acouchi',
            'adamsstaghornedbeetle',
            'addax',
            'adder',
            'adeliepenguin',
            'admiralbutterfly',
            'adouri',
            'aegeancat',
            'affenpinscher',
            'afghanhound',
            'africanaugurbuzzard',
            'africanbushviper',
            'africancivet',
            'africanclawedfrog',
            'africanelephant',
            'africanfisheagle',
            'africangoldencat',
            'africangroundhornbill',
            'africanharrierhawk',
            'africanhornbill',
            'africanjacana',
            'africanmolesnake',
            'africanparadiseflycatcher',
            'africanpiedkingfisher',
            'africanporcupine',
            'africanrockpython',
            'africanwildcat',
            'africanwilddog',
            'agama',
            'agouti',
            'aidi',
            'airedale',
            'airedaleterrier',
            'akitainu',
            'alabamamapturtle',
            'alaskajingle',
            'alaskanhusky',
            'alaskankleekai',
            'alaskanmalamute',
            'albacoretuna',
            'albatross',
            'albertosaurus',
            'albino',
            'aldabratortoise',
            'allensbigearedbat',
            'alleycat',
            'alligator',
            'alligatorgar',
            'alligatorsnappingturtle',
            'allosaurus',
            'alpaca',
            'alpinegoat',
            'alpineroadguidetigerbeetle',
            'altiplanochinchillamouse',
            'amazondolphin',
            'amazonparrot',
            'amazontreeboa',
            'amberpenshell',
            'ambushbug',
            'americanalligator',
            'americanavocet',
            'americanbadger',
            'americanbittern',
            'americanblackvulture',
            'americanbobtail',
            'americanbulldog',
            'americancicada',
            'americancrayfish',
            'americancreamdraft',
            'americancrocodile',
            'americancrow',
            'americancurl',
            'americangoldfinch',
            'americanindianhorse',
            'americankestrel',
            'americanlobster',
            'americanmarten',
            'americanpainthorse',
            'americanquarterhorse',
            'americanratsnake',
            'americanredsquirrel',
            'americanriverotter',
            'americanrobin',
            'americansaddlebred',
            'americanshorthair',
            'americantoad',
            'americanwarmblood',
            'americanwigeon',
            'americanwirehair',
            'amethystgemclam',
            'amethystinepython',
            'amethystsunbird',
            'ammonite',
            'amoeba',
            'amphibian',
            'amphiuma',
            'amurminnow',
            'amurratsnake',
            'amurstarfish',
            'anaconda',
            'anchovy',
            'andalusianhorse',
            'andeancat',
            'andeancockoftherock',
            'andeancondor',
            'anemone',
            'anemonecrab',
            'anemoneshrimp',
            'angelfish',
            'angelwingmussel',
            'anglerfish',
            'angora',
            'angwantibo',
            'anhinga',
            'ankole',
            'ankolewatusi',
            'annashummingbird',
            'annelid',
            'annelida',
            'anole',
            'anophelesmosquito',
            'ant',
            'antarcticfurseal',
            'antarcticgiantpetrel',
            'antbear',
            'anteater',
            'antelope',
            'antelopegroundsquirrel',
            'antipodesgreenparakeet',
            'antlion',
            'anura',
            'aoudad',
            'apatosaur',
            'ape',
            'aphid',
            'apisdorsatalaboriosa',
            'aplomadofalcon',
            'appaloosa',
            'aquaticleech',
            'arabianhorse',
            'arabianoryx',
            'arabianwildcat',
            'aracari',
            'arachnid',
            'arawana',
            'archaeocete',
            'archaeopteryx',
            'archerfish',
            'arcticduck',
            'arcticfox',
            'arctichare',
            'arcticseal',
            'arcticwolf',
            'argali',
            'argentinehornedfrog',
            'argentineruddyduck',
            'argusfish',
            'arieltoucan',
            'arizonaalligatorlizard',
            'arkshell',
            'armadillo',
            'armedcrab',
            'armednylonshrimp',
            'armyant',
            'armyworm',
            'arrowana',
            'arrowcrab',
            'arrowworm',
            'arthropods',
            'aruanas',
            'asianconstablebutterfly',
            'asiandamselfly',
            'asianelephant',
            'asianlion',
            'asianpiedstarling',
            'asianporcupine',
            'asiansmallclawedotter',
            'asiantrumpetfish',
            'asianwaterbuffalo',
            'asiaticgreaterfreshwaterclam',
            'asiaticlesserfreshwaterclam',
            'asiaticmouflon',
            'asiaticwildass',
            'asp',
            'ass',
            'assassinbug',
            'astarte',
            'astrangiacoral',
            'atlanticblackgoby',
            'atlanticbluetang',
            'atlanticridleyturtle',
            'atlanticsharpnosepuffer',
            'atlanticspadefish',
            'atlasmoth',
            'attwatersprairiechicken',
            'auk',
            'auklet',
            'aurochs',
            'australiancattledog',
            'australiancurlew',
            'australianfreshwatercrocodile',
            'australianfurseal',
            'australiankelpie',
            'australiankestrel',
            'australianshelduck',
            'australiansilkyterrier',
            'austrianpinscher',
            'avians',
            'avocet',
            'axisdeer',
            'axolotl',
            'ayeaye',
            'aztecant',
            'azurevase',
            'azurevasesponge',
            'azurewingedmagpie',
            'babirusa',
            'baboon',
            'backswimmer',
            'bactrian',
            'badger',
            'bagworm',
            'baiji',
            'baldeagle',
            'baleenwhale',
            'balloonfish',
            'ballpython',
            'bandicoot',
            'bangeltiger',
            'bantamrooster',
            'banteng',
            'barasinga',
            'barasingha',
            'barb',
            'barbet',
            'barebirdbat',
            'barnacle',
            'barnowl',
            'barnswallow',
            'barracuda',
            'basenji',
            'basil',
            'basilisk',
            'bass',
            'bassethound',
            'bat',
            'bats',
            'beagle',
            'bear',
            'beardedcollie',
            'beardeddragon',
            'beauceron',
            'beaver',
            'bedbug',
            'bedlingtonterrier',
            'bee',
            'beetle',
            'bellfrog',
            'bellsnake',
            'belugawhale',
            'bengaltiger',
            'bergerpicard',
            'bernesemountaindog',
            'betafish',
            'bettong',
            'bichonfrise',
            'bighorn',
            'bighornedsheep',
            'bighornsheep',
            'bigmouthbass',
            'bilby',
            'billygoat',
            'binturong',
            'bird',
            'birdofparadise',
            'bison',
            'bittern',
            'blackandtancoonhound',
            'blackbear',
            'blackbird',
            'blackbuck',
            'blackcrappie',
            'blackfish',
            'blackfly',
            'blackfootedferret',
            'blacklab',
            'blacklemur',
            'blackmamba',
            'blacknorwegianelkhound',
            'blackpanther',
            'blackrhino',
            'blackrussianterrier',
            'blackwidowspider',
            'blesbok',
            'blobfish',
            'blowfish',
            'blueandgoldmackaw',
            'bluebird',
            'bluebottle',
            'bluebottlejellyfish',
            'bluebreastedkookaburra',
            'bluefintuna',
            'bluefish',
            'bluegill',
            'bluejay',
            'bluemorphobutterfly',
            'blueshark',
            'bluet',
            'bluetickcoonhound',
            'bluetonguelizard',
            'bluewhale',
            'boa',
            'boaconstrictor',
            'boar',
            'bobcat',
            'bobolink',
            'bobwhite',
            'boilweevil',
            'bongo',
            'bonobo',
            'booby',
            'bordercollie',
            'borderterrier',
            'borer',
            'borzoi',
            'boto',
            'boubou',
            'boutu',
            'bovine',
            'brahmanbull',
            'brahmancow',
            'brant',
            'bream',
            'brocketdeer',
            'bronco',
            'brontosaurus',
            'brownbear',
            'brownbutterfly',
            'bubblefish',
            'buck',
            'buckeyebutterfly',
            'budgie',
            'bufeo',
            'buffalo',
            'bufflehead',
            'bug',
            'bull',
            'bullfrog',
            'bullmastiff',
            'bumblebee',
            'bunny',
            'bunting',
            'burro',
            'bushbaby',
            'bushsqueaker',
            'bustard',
            'butterfly',
            'buzzard',
            'caecilian',
            'caiman',
            'caimanlizard',
            'calf',
            'camel',
            'canadagoose',
            'canary',
            'canine',
            'canvasback',
            'capeghostfrog',
            'capybara',
            'caracal',
            'cardinal',
            'caribou',
            'carp',
            'carpenterant',
            'cassowary',
            'cat',
            'catbird',
            'caterpillar',
            'catfish',
            'cats',
            'cattle',
            'caudata',
            'cavy',
            'centipede',
            'cero',
            'chafer',
            'chameleon',
            'chamois',
            'chanticleer',
            'cheetah',
            'chevrotain',
            'chick',
            'chickadee',
            'chicken',
            'chihuahua',
            'chimneyswift',
            'chimpanzee',
            'chinchilla',
            'chinesecrocodilelizard',
            'chipmunk',
            'chital',
            'chrysalis',
            'chrysomelid',
            'chuckwalla',
            'chupacabra',
            'cicada',
            'cirriped',
            'civet',
            'clam',
            'cleanerwrasse',
            'clingfish',
            'clownanemonefish',
            'clumber',
            'coati',
            'cob',
            'cobra',
            'cock',
            'cockatiel',
            'cockatoo',
            'cockerspaniel',
            'cockroach',
            'cod',
            'coelacanth',
            'collardlizard',
            'collie',
            'colt',
            'comet',
            'commabutterfly',
            'commongonolek',
            'conch',
            'condor',
            'coney',
            'conure',
            'cony',
            'coot',
            'cooter',
            'copepod',
            'copperbutterfly',
            'copperhead',
            'coqui',
            'coral',
            'cormorant',
            'cornsnake',
            'corydorascatfish',
            'cottonmouth',
            'cottontail',
            'cougar',
            'cow',
            'cowbird',
            'cowrie',
            'coyote',
            'coypu',
            'crab',
            'crane',
            'cranefly',
            'crayfish',
            'creature',
            'cricket',
            'crocodile',
            'crocodileskink',
            'crossbill',
            'crow',
            'crownofthornsstarfish',
            'crustacean',
            'cub',
            'cuckoo',
            'cur',
            'curassow',
            'curlew',
            'cuscus',
            'cusimanse',
            'cuttlefish',
            'cutworm',
            'cygnet',
            'dachshund',
            'daddylonglegs',
            'dairycow',
            'dalmatian',
            'damselfly',
            'danishswedishfarmdog',
            'darklingbeetle',
            'dartfrog',
            'darwinsfox',
            'dassie',
            'dassierat',
            'davidstiger',
            'deer',
            'deermouse',
            'degu',
            'degus',
            'deinonychus',
            'desertpupfish',
            'devilfish',
            'deviltasmanian',
            'diamondbackrattlesnake',
            'dikdik',
            'dikkops',
            'dingo',
            'dinosaur',
            'diplodocus',
            'dipper',
            'discus',
            'dobermanpinscher',
            'doctorfish',
            'dodo',
            'dodobird',
            'doe',
            'dog',
            'dogfish',
            'dogwoodclubgall',
            'dogwoodtwigborer',
            'dolphin',
            'donkey',
            'dorado',
            'dore',
            'dorking',
            'dormouse',
            'dotterel',
            'douglasfirbarkbeetle',
            'dove',
            'dowitcher',
            'drafthorse',
            'dragon',
            'dragonfly',
            'drake',
            'drever',
            'dromaeosaur',
            'dromedary',
            'drongo',
            'duck',
            'duckbillcat',
            'duckbillplatypus',
            'duckling',
            'dugong',
            'duiker',
            'dungbeetle',
            'dungenesscrab',
            'dunlin',
            'dunnart',
            'dutchshepherddog',
            'dutchsmoushond',
            'dwarfmongoose',
            'dwarfrabbit',
            'eagle',
            'earthworm',
            'earwig',
            'easternglasslizard',
            'easternnewt',
            'easteuropeanshepherd',
            'eastrussiancoursinghounds',
            'eastsiberianlaika',
            'echidna',
            'eel',
            'eelelephant',
            'eeve',
            'eft',
            'egg',
            'egret',
            'eider',
            'eidolonhelvum',
            'ekaltadeta',
            'eland',
            'electriceel',
            'elephant',
            'elephantbeetle',
            'elephantseal',
            'elk',
            'elkhound',
            'elver',
            'emeraldtreeskink',
            'emperorpenguin',
            'emperorshrimp',
            'emu',
            'englishpointer',
            'englishsetter',
            'equestrian',
            'equine',
            'erin',
            'ermine',
            'erne',
            'eskimodog',
            'esok',
            'estuarinecrocodile',
            'ethiopianwolf',
            'europeanfiresalamander',
            'europeanpolecat',
            'ewe',
            'eyas',
            'eyelashpitviper',
            'eyra',
            'fairybluebird',
            'fairyfly',
            'falcon',
            'fallowdeer',
            'fantail',
            'fanworms',
            'fattaileddunnart',
            'fawn',
            'feline',
            'fennecfox',
            'ferret',
            'fiddlercrab',
            'fieldmouse',
            'fieldspaniel',
            'finch',
            'finnishspitz',
            'finwhale',
            'fireant',
            'firebelliedtoad',
            'firecrest',
            'firefly',
            'fish',
            'fishingcat',
            'flamingo',
            'flatcoatretriever',
            'flatfish',
            'flea',
            'flee',
            'flicker',
            'flickertailsquirrel',
            'flies',
            'flounder',
            'fluke',
            'fly',
            'flycatcher',
            'flyingfish',
            'flyingfox',
            'flyinglemur',
            'flyingsquirrel',
            'foal',
            'fossa',
            'fowl',
            'fox',
            'foxhound',
            'foxterrier',
            'frenchbulldog',
            'freshwatereel',
            'frigatebird',
            'frilledlizard',
            'frillneckedlizard',
            'fritillarybutterfly',
            'frog',
            'frogmouth',
            'fruitbat',
            'fruitfly',
            'fugu',
            'fulmar',
            'funnelweaverspider',
            'furseal',
            'gadwall',
            'galago',
            'galah',
            'galapagosalbatross',
            'galapagosdove',
            'galapagoshawk',
            'galapagosmockingbird',
            'galapagospenguin',
            'galapagossealion',
            'galapagostortoise',
            'gallinule',
            'gallowaycow',
            'gander',
            'gangesdolphin',
            'gannet',
            'gar',
            'gardensnake',
            'garpike',
            'gartersnake',
            'gaur',
            'gavial',
            'gazelle',
            'gecko',
            'geese',
            'gelada',
            'gelding',
            'gemsbok',
            'gemsbuck',
            'genet',
            'gentoopenguin',
            'gerbil',
            'gerenuk',
            'germanpinscher',
            'germanshepherd',
            'germanshorthairedpointer',
            'germanspaniel',
            'germanspitz',
            'germanwirehairedpointer',
            'gharial',
            'ghostshrimp',
            'giantschnauzer',
            'gibbon',
            'gilamonster',
            'giraffe',
            'glassfrog',
            'globefish',
            'glowworm',
            'gnat',
            'gnatcatcher',
            'gnu',
            'goa',
            'goat',
            'godwit',
            'goitered',
            'goldeneye',
            'goldenmantledgroundsquirrel',
            'goldenretriever',
            'goldfinch',
            'goldfish',
            'gonolek',
            'goose',
            'goosefish',
            'gopher',
            'goral',
            'gordonsetter',
            'gorilla',
            'goshawk',
            'gosling',
            'gossamerwingedbutterfly',
            'gourami',
            'grackle',
            'grasshopper',
            'grassspider',
            'grayfox',
            'grayling',
            'grayreefshark',
            'graysquirrel',
            'graywolf',
            'greatargus',
            'greatdane',
            'greathornedowl',
            'greatwhiteshark',
            'grebe',
            'greendarnerdragonfly',
            'greyhounddog',
            'grison',
            'grizzlybear',
            'grosbeak',
            'groundbeetle',
            'groundhog',
            'grouper',
            'grouse',
            'grub',
            'grunion',
            'guanaco',
            'guernseycow',
            'guillemot',
            'guineafowl',
            'guineapig',
            'gull',
            'guppy',
            'gypsymoth',
            'gyrfalcon',
            'hackee',
            'haddock',
            'hadrosaurus',
            'hagfish',
            'hairstreak',
            'hairstreakbutterfly',
            'hake',
            'halcyon',
            'halibut',
            'halicore',
            'hamadryad',
            'hamadryas',
            'hammerheadbird',
            'hammerheadshark',
            'hammerkop',
            'hamster',
            'hanumanmonkey',
            'hapuka',
            'hapuku',
            'harborporpoise',
            'harborseal',
            'hare',
            'harlequinbug',
            'harpseal',
            'harpyeagle',
            'harrier',
            'harrierhawk',
            'hart',
            'hartebeest',
            'harvestmen',
            'harvestmouse',
            'hatchetfish',
            'hawaiianmonkseal',
            'hawk',
            'hectorsdolphin',
            'hedgehog',
            'heifer',
            'hellbender',
            'hen',
            'herald',
            'herculesbeetle',
            'hermitcrab',
            'heron',
            'herring',
            'heterodontosaurus',
            'hind',
            'hippopotamus',
            'hoatzin',
            'hochstettersfrog',
            'hog',
            'hogget',
            'hoiho',
            'hoki',
            'homalocephale',
            'honeybadger',
            'honeybee',
            'honeycreeper',
            'honeyeater',
            'hookersealion',
            'hoopoe',
            'hornbill',
            'hornedtoad',
            'hornedviper',
            'hornet',
            'hornshark',
            'horse',
            'horsechestnutleafminer',
            'horsefly',
            'horsemouse',
            'horseshoebat',
            'horseshoecrab',
            'hound',
            'housefly',
            'hoverfly',
            'howlermonkey',
            'huemul',
            'huia',
            'human',
            'hummingbird',
            'humpbackwhale',
            'husky',
            'hydatidtapeworm',
            'hydra',
            'hyena',
            'hylaeosaurus',
            'hypacrosaurus',
            'hypsilophodon',
            'hyracotherium',
            'hyrax',
            'iaerismetalmark',
            'ibadanmalimbe',
            'iberianbarbel',
            'iberianchiffchaff',
            'iberianemeraldlizard',
            'iberianlynx',
            'iberianmidwifetoad',
            'iberianmole',
            'iberiannase',
            'ibex',
            'ibis',
            'ibisbill',
            'ibizanhound',
            'iceblueredtopzebra',
            'icefish',
            'icelandgull',
            'icelandichorse',
            'icelandicsheepdog',
            'ichidna',
            'ichneumonfly',
            'ichthyosaurs',
            'ichthyostega',
            'icterinewarbler',
            'iggypops',
            'iguana',
            'iguanodon',
            'illadopsis',
            'ilsamochadegu',
            'imago',
            'impala',
            'imperatorangel',
            'imperialeagle',
            'incatern',
            'inchworm',
            'indianabat',
            'indiancow',
            'indianelephant',
            'indianglassfish',
            'indianhare',
            'indianjackal',
            'indianpalmsquirrel',
            'indianpangolin',
            'indianrhinoceros',
            'indianringneckparakeet',
            'indianrockpython',
            'indianskimmer',
            'indianspinyloach',
            'indigobunting',
            'indigowingedparrot',
            'indochinahogdeer',
            'indochinesetiger',
            'indri',
            'indusriverdolphin',
            'inexpectatumpleco',
            'inganue',
            'insect',
            'intermediateegret',
            'invisiblerail',
            'iraniangroundjay',
            'iridescentshark',
            'iriomotecat',
            'irishdraughthorse',
            'irishredandwhitesetter',
            'irishsetter',
            'irishterrier',
            'irishwaterspaniel',
            'irishwolfhound',
            'irrawaddydolphin',
            'irukandjijellyfish',
            'isabellineshrike',
            'isabellinewheatear',
            'islandcanary',
            'islandwhistler',
            'isopod',
            'italianbrownbear',
            'italiangreyhound',
            'ivorybackedwoodswallow',
            'ivorybilledwoodpecker',
            'ivorygull',
            'izuthrush',
            'jabiru',
            'jackal',
            'jackrabbit',
            'jaeger',
            'jaguar',
            'jaguarundi',
            'janenschia',
            'japanesebeetle',
            'javalina',
            'jay',
            'jellyfish',
            'jenny',
            'jerboa',
            'joey',
            'johndory',
            'juliabutterfly',
            'jumpingbean',
            'junco',
            'junebug',
            'kagu',
            'kakapo',
            'kakarikis',
            'kangaroo',
            'karakul',
            'katydid',
            'kawala',
            'kentrosaurus',
            'kestrel',
            'kid',
            'killdeer',
            'killerwhale',
            'killifish',
            'kingbird',
            'kingfisher',
            'kinglet',
            'kingsnake',
            'kinkajou',
            'kiskadee',
            'kissingbug',
            'kite',
            'kitfox',
            'kitten',
            'kittiwake',
            'kitty',
            'kiwi',
            'koala',
            'koalabear',
            'kob',
            'kodiakbear',
            'koi',
            'komododragon',
            'koodoo',
            'kookaburra',
            'kouprey',
            'krill',
            'kronosaurus',
            'kudu',
            'kusimanse',
            'labradorretriever',
            'lacewing',
            'ladybird',
            'ladybug',
            'lamb',
            'lamprey',
            'langur',
            'lark',
            'larva',
            'laughingthrush',
            'lcont',
            'leafbird',
            'leafcutterant',
            'leafhopper',
            'leafwing',
            'leech',
            'lemming',
            'lemur',
            'leonberger',
            'leopard',
            'leopardseal',
            'leveret',
            'lhasaapso',
            'lice',
            'liger',
            'lightningbug',
            'limpet',
            'limpkin',
            'ling',
            'lion',
            'lionfish',
            'littlenightmonkeys',
            'lizard',
            'llama',
            'lobo',
            'lobster',
            'locust',
            'loggerheadturtle',
            'longhorn',
            'longhornbeetle',
            'longspur',
            'loon',
            'lorikeet',
            'loris',
            'louse',
            'lovebird',
            'lowchen',
            'lunamoth',
            'lungfish',
            'lynx',
            'lynxÂ',
            'macaque',
            'macaw',
            'macropod',
            'madagascarhissingroach',
            'maggot',
            'magpie',
            'maiasaura',
            'majungatholus',
            'malamute',
            'mallard',
            'maltesedog',
            'mamba',
            'mamenchisaurus',
            'mammal',
            'mammoth',
            'manatee',
            'mandrill',
            'mangabey',
            'manta',
            'mantaray',
            'mantid',
            'mantis',
            'mantisray',
            'manxcat',
            'mara',
            'marabou',
            'marbledmurrelet',
            'mare',
            'marlin',
            'marmoset',
            'marmot',
            'marten',
            'martin',
            'massasauga',
            'massospondylus',
            'mastiff',
            'mastodon',
            'mayfly',
            'meadowhawk',
            'meadowlark',
            'mealworm',
            'meerkat',
            'megalosaurus',
            'megalotomusquinquespinosus',
            'megaraptor',
            'merganser',
            'merlin',
            'metalmarkbutterfly',
            'metamorphosis',
            'mice',
            'microvenator',
            'midge',
            'milksnake',
            'milkweedbug',
            'millipede',
            'minibeast',
            'mink',
            'minnow',
            'mite',
            'moa',
            'mockingbird',
            'mole',
            'mollies',
            'mollusk',
            'molly',
            'monarch',
            'mongoose',
            'mongrel',
            'monkey',
            'monkfishÂ',
            'monoclonius',
            'montanoceratops',
            'moorhen',
            'moose',
            'moray',
            'morayeel',
            'morpho',
            'mosasaur',
            'mosquito',
            'moth',
            'motmot',
            'mouflon',
            'mountaincat',
            'mountainlion',
            'mouse',
            'mouse / mice',
            'mousebird',
            'mudpuppy',
            'mule',
            'mullet',
            'muntjac',
            'murrelet',
            'muskox',
            'muskrat',
            'mussaurus',
            'mussel',
            'mustang',
            'mutt',
            'myna',
            'mynah',
            'myotisÂ',
            'nabarlek',
            'nag',
            'naga',
            'nagapies',
            'nakedmolerat',
            'nandine',
            'nandoo',
            'nandu',
            'narwhal',
            'narwhale',
            'natterjacktoad',
            'nauplius',
            'nautilus',
            'needlefish',
            'needletail',
            'nematode',
            'nene',
            'neonblueguppy',
            'neonbluehermitcrab',
            'neondwarfgourami',
            'neonrainbowfish',
            'neonredguppy',
            'neontetra',
            'nerka',
            'nettlefish',
            'newfoundlanddog',
            'newt',
            'newtnutria',
            'nightcrawler',
            'nighthawk',
            'nightheron',
            'nightingale',
            'nightjar',
            'nijssenissdwarfchihlid',
            'nilgai',
            'ninebandedarmadillo',
            'noctilio',
            'noctule',
            'noddy',
            'noolbenger',
            'northerncardinals',
            'northernelephantseal',
            'northernflyingsquirrel',
            'northernfurseal',
            'northernhairynosedwombat',
            'northernpike',
            'northernseahorse',
            'northernspottedowl',
            'norwaylobster',
            'norwayrat',
            'nubiangoat',
            'nudibranch',
            'numbat',
            'nurseshark',
            'nutcracker',
            'nuthatch',
            'nutria',
            'nyala',
            'nymph',
            'ocelot',
            'octopus',
            'okapi',
            'olingo',
            'olm',
            'opossum',
            'orangutan',
            'orca',
            'oregonsilverspotbutterfly',
            'oriole',
            'oropendola',
            'oropendula',
            'oryx',
            'osprey',
            'ostracod',
            'ostrich',
            'otter',
            'ovenbird',
            'owl',
            'owlbutterfly',
            'ox',
            'oxen',
            'oxpecker',
            'oyster',
            'ozarkbigearedbat',
            'pacaÂ',
            'pachyderm',
            'pacificparrotlet',
            'paddlefish',
            'paintedladybutterfly',
            'panda',
            'pangolin',
            'panther',
            'paperwasp',
            'papillon',
            'parakeet',
            'parrot',
            'partridge',
            'peacock',
            'peafowl',
            'peccary',
            'pekingese',
            'pelican',
            'pelicinuspetrel',
            'penguin',
            'perch',
            'peregrinefalcon',
            'pewee',
            'phalarope',
            'pharaohhound',
            'pheasant',
            'phoebe',
            'phoenix',
            'pig',
            'pigeon',
            'piglet',
            'pika',
            'pike',
            'pikeperchÂ',
            'pilchard',
            'pinemarten',
            'pinkriverdolphin',
            'pinniped',
            'pintail',
            'pipistrelle',
            'pipit',
            'piranha',
            'pitbull',
            'pittabird',
            'plainsqueaker',
            'plankton',
            'planthopper',
            'platypus',
            'plover',
            'polarbear',
            'polecat',
            'polliwog',
            'polyp',
            'polyturator',
            'pomeranian',
            'pondskater',
            'pony',
            'pooch',
            'poodle',
            'porcupine',
            'porpoise',
            'portuguesemanofwar',
            'possum',
            'prairiedog',
            'prawn',
            'prayingmantid',
            'prayingmantis',
            'primate',
            'pronghorn',
            'pseudodynerusquadrisectus',
            'ptarmigan',
            'pterodactyls',
            'pterosaurs',
            'puffer',
            'pufferfish',
            'puffin',
            'pug',
            'pullet',
            'puma',
            'pupa',
            'pupfish',
            'puppy',
            'purplemarten',
            'pussycat',
            'pygmy',
            'python',
            'quadrisectus',
            'quagga',
            'quahog',
            'quail',
            'queenalexandrasbirdwing',
            'queenalexandrasbirdwingbutterfly',
            'queenant',
            'queenbee',
            'queenconch',
            'queenslandgrouper',
            'queenslandheeler',
            'queensnake',
            'quelea',
            'quetzal',
            'quetzalcoatlus',
            'quillback',
            'quinquespinosus',
            'quokka',
            'quoll',
            'rabbit',
            'rabidsquirrel',
            'raccoon',
            'racer',
            'racerunner',
            'ragfish',
            'rail',
            'rainbowfish',
            'rainbowlorikeet',
            'rainbowtrout',
            'ram',
            'raptors',
            'rasbora',
            'rat',
            'ratfish',
            'rattail',
            'rattlesnake',
            'raven',
            'ray',
            'redhead',
            'redheadedwoodpecker',
            'redpoll',
            'redstart',
            'redtailedhawk',
            'reindeer',
            'reptile',
            'reynard',
            'rhea',
            'rhesusmonkey',
            'rhino',
            'rhinoceros',
            'rhinocerosbeetle',
            'rhodesianridgeback',
            'ringtailedlemur',
            'ringworm',
            'riograndeescuerzo',
            'roach',
            'roadrunner',
            'roan',
            'robberfly',
            'robin',
            'rockrat',
            'rodent',
            'roebuck',
            'roller',
            'rook',
            'rooster',
            'rottweiler',
            'sable',
            'sableantelope',
            'sablefishÂ',
            'saiga',
            'sakimonkey',
            'salamander',
            'salmon',
            'saltwatercrocodile',
            'sambar',
            'samoyeddog',
            'sandbarshark',
            'sanddollar',
            'sanderling',
            'sandpiper',
            'sapsucker',
            'sardine',
            'sawfish',
            'scallop',
            'scarab',
            'scarletibis',
            'scaup',
            'schapendoes',
            'schipperke',
            'schnauzer',
            'scorpion',
            'scoter',
            'screamer',
            'seabird',
            'seagull',
            'seahog',
            'seahorse',
            'seal',
            'sealion',
            'seamonkey',
            'seaslug',
            'seaurchin',
            'senegalpython',
            'seriema',
            'serpent',
            'serval',
            'shark',
            'shearwater',
            'sheep',
            'sheldrake',
            'shelduck',
            'shibainu',
            'shihtzu',
            'shorebird',
            'shoveler',
            'shrew',
            'shrike',
            'shrimp',
            'siamang',
            'siamesecat',
            'siberiantiger',
            'sidewinder',
            'sifaka',
            'silkworm',
            'silverfish',
            'silverfox',
            'silversidefish',
            'siskin',
            'skimmer',
            'skink',
            'skipper',
            'skua',
            'skunk',
            'skylark',
            'sloth',
            'slothbear',
            'slug',
            'smelts',
            'smew',
            'snail',
            'snake',
            'snipe',
            'snoutbutterfly',
            'snowdog',
            'snowgeese',
            'snowleopard',
            'snowmonkey',
            'snowyowl',
            'sockeyesalmon',
            'solenodon',
            'solitaire',
            'songbird',
            'sora',
            'southernhairnosedwombat',
            'sow',
            'spadefoot',
            'sparrow',
            'sphinx',
            'spider',
            'spidermonkey',
            'spiketail',
            'spittlebug',
            'sponge',
            'spoonbill',
            'spotteddolphin',
            'spreadwing',
            'springbok',
            'springpeeper',
            'springtail',
            'squab',
            'squamata',
            'squeaker',
            'squid',
            'squirrel',
            'stag',
            'stagbeetle',
            'stallion',
            'starfish',
            'starling',
            'steed',
            'steer',
            'stegosaurus',
            'stickinsect',
            'stickleback',
            'stilt',
            'stingray',
            'stinkbug',
            'stinkpot',
            'stoat',
            'stonefly',
            'stork',
            'stud',
            'sturgeon',
            'sugarglider',
            'sulphurbutterfly',
            'sunbear',
            'sunbittern',
            'sunfish',
            'swallow',
            'swallowtail',
            'swallowtailbutterfly',
            'swan',
            'swellfish',
            'swift',
            'swordfish',
            'tadpole',
            'tahr',
            'takin',
            'tamarin',
            'tanager',
            'tapaculo',
            'tapeworm',
            'tapir',
            'tarantula',
            'tarpan',
            'tarsier',
            'taruca',
            'tasmaniandevil',
            'tasmaniantiger',
            'tattler',
            'tayra',
            'teal',
            'tegus',
            'teledu',
            'tench',
            'tenrec',
            'termite',
            'tern',
            'terrapin',
            'terrier',
            'thoroughbred',
            'thrasher',
            'thrip',
            'thrush',
            'thunderbird',
            'thylacine',
            'tick',
            'tiger',
            'tigerbeetle',
            'tigermoth',
            'tigershark',
            'tilefish',
            'tinamou',
            'titi',
            'titmouse',
            'toad',
            'toadfish',
            'tomtitÂ',
            'topi',
            'tortoise',
            'toucan',
            'towhee',
            'tragopan',
            'treecreeper',
            'trex',
            'triceratops',
            'trogon',
            'trout',
            'trumpeterbird',
            'trumpeterswan',
            'tsetsefly',
            'tuatara',
            'tuna',
            'turaco',
            'turkey',
            'turnstone',
            'turtle',
            'turtledove',
            'uakari',
            'ugandakob',
            'uintagroundsquirrel',
            'ulyssesbutterfly',
            'umbrellabird',
            'umbrette',
            'unau',
            'ungulate',
            'unicorn',
            'upupa',
            'urchin',
            'urial',
            'uromastyxmaliensis',
            'uromastyxspinipes',
            'urson',
            'urubu',
            'urus',
            'urutu',
            'urva',
            'utahprairiedog',
            'vampirebat',
            'vaquita',
            'veery',
            'velociraptor',
            'velvetcrab',
            'velvetworm',
            'venomoussnake',
            'verdin',
            'vervet',
            'viceroybutterfly',
            'vicuna',
            'viper',
            'viperfish',
            'vipersquid',
            'vireo',
            'virginiaopossum',
            'vixen',
            'vole',
            'volvox',
            'vulpesvelox',
            'vulpesvulpes',
            'vulture',
            'walkingstick',
            'wallaby',
            'wallaroo',
            'walleye',
            'walrus',
            'warbler',
            'warthog',
            'wasp',
            'waterboatman',
            'waterbuck',
            'waterbuffalo',
            'waterbug',
            'waterdogs',
            'waterdragons',
            'watermoccasin',
            'waterstrider',
            'waterthrush',
            'wattlebird',
            'watussi',
            'waxwing',
            'weasel',
            'weaverbird',
            'weevil',
            'westafricanantelope',
            'whale',
            'whapuku',
            'whelp',
            'whimbrel',
            'whippet',
            'whippoorwill',
            'whitebeakeddolphin',
            'whiteeye',
            'whitepelican',
            'whiterhino',
            'whitetaileddeer',
            'whitetippedreefshark',
            'whooper',
            'whoopingcrane',
            'widgeon',
            'widowspider',
            'wildcat',
            'wildebeast',
            'wildebeest',
            'willet',
            'wireworm',
            'wisent',
            'wobbegongshark',
            'wolf',
            'wolfspider',
            'wolverine',
            'wombat',
            'woodborer',
            'woodchuck',
            'woodcock',
            'woodnymphbutterfly',
            'woodpecker',
            'woodstorks',
            'woollybearcaterpillar',
            'worm',
            'wrasse',
            'wreckfish',
            'wren',
            'wrenchbird',
            'wryneck',
            'wuerhosaurus',
            'wyvern',
            'xanclomys',
            'xanthareel',
            'xantus',
            'xantusmurrelet',
            'xeme',
            'xenarthra',
            'xenoposeidon',
            'xenops',
            'xenopterygii',
            'xenopus',
            'xenotarsosaurus',
            'xenurine',
            'xenurusunicinctus',
            'xerus',
            'xiaosaurus',
            'xinjiangovenator',
            'xiphias',
            'xiphiasgladius',
            'xiphosuran',
            'xoloitzcuintli',
            'xoni',
            'xrayfish',
            'xraytetra',
            'xuanhanosaurus',
            'xuanhuaceratops',
            'xuanhuasaurus',
            'yaffle',
            'yak',
            'yapok',
            'yardant',
            'yearling',
            'yellowbelliedmarmot',
            'yellowbellylizard',
            'yellowhammer',
            'yellowjacket',
            'yellowlegs',
            'yellowthroat',
            'yellowwhitebutterfly',
            'yeti',
            'ynambu',
            'yorkshireterrier',
            'yosemitetoad',
            'yucker',
            'zander',
            'zanzibardaygecko',
            'zebra',
            'zebradove',
            'zebrafinch',
            'zebrafish',
            'zebralongwingbutterfly',
            'zebraswallowtailbutterfly',
            'zebratailedlizard',
            'zebu',
            'zenaida',
            'zeren',
            'zethusspinipes',
            'zethuswasp',
            'zigzagsalamander',
            'zonetailedpigeon',
            'zooplankton',
            'zopilote',
            'zorilla',
            'abandoned',
            'able',
            'absolute',
            'academic',
            'acceptable',
            'acclaimed',
            'accomplished',
            'accurate',
            'aching',
            'acidic',
            'acrobatic',
            'adorable',
            'adventurous',
            'babyish',
            'back',
            'bad',
            'baggy',
            'bare',
            'barren',
            'basic',
            'beautiful',
            'belated',
            'beloved',
            'calculating',
            'calm',
            'candid',
            'canine',
            'capital',
            'carefree',
            'careful',
            'careless',
            'caring',
            'cautious',
            'cavernous',
            'celebrated',
            'charming',
            'damaged',
            'damp',
            'dangerous',
            'dapper',
            'daring',
            'dark',
            'darling',
            'dazzling',
            'dead',
            'deadly',
            'deafening',
            'dear',
            'dearest',
            'each',
            'eager',
            'early',
            'earnest',
            'easy',
            'easygoing',
            'ecstatic',
            'edible',
            'educated',
            'fabulous',
            'failing',
            'faint',
            'fair',
            'faithful',
            'fake',
            'familiar',
            'famous',
            'fancy',
            'fantastic',
            'far',
            'faraway',
            'farflung',
            'faroff',
            'gargantuan',
            'gaseous',
            'general',
            'generous',
            'gentle',
            'genuine',
            'giant',
            'giddy',
            'gigantic',
            'hairy',
            'half',
            'handmade',
            'handsome',
            'handy',
            'happy',
            'happygolucky',
            'hard',
            'icky',
            'icy',
            'ideal',
            'idealistic',
            'identical',
            'idiotic',
            'idle',
            'idolized',
            'ignorant',
            'ill',
            'illegal',
            'jaded',
            'jagged',
            'jampacked',
            'kaleidoscopic',
            'keen',
            'lame',
            'lanky',
            'large',
            'last',
            'lasting',
            'late',
            'lavish',
            'lawful',
            'mad',
            'madeup',
            'magnificent',
            'majestic',
            'major',
            'male',
            'mammoth',
            'married',
            'marvelous',
            'naive',
            'narrow',
            'nasty',
            'natural',
            'naughty',
            'obedient',
            'obese',
            'oblong',
            'oblong',
            'obvious',
            'occasional',
            'oily',
            'palatable',
            'pale',
            'paltry',
            'parallel',
            'parched',
            'partial',
            'passionate',
            'past',
            'pastel',
            'peaceful',
            'peppery',
            'perfect',
            'perfumed',
            'quaint',
            'qualified',
            'radiant',
            'ragged',
            'rapid',
            'rare',
            'rash',
            'raw',
            'recent',
            'reckless',
            'rectangular',
            'sad',
            'safe',
            'salty',
            'same',
            'sandy',
            'sane',
            'sarcastic',
            'sardonic',
            'satisfied',
            'scaly',
            'scarce',
            'scared',
            'scary',
            'scented',
            'scholarly',
            'scientific',
            'scornful',
            'scratchy',
            'scrawny',
            'second',
            'secondary',
            'secondhand',
            'secret',
            'selfassured',
            'selfish',
            'selfreliant',
            'sentimental',
            'talkative',
            'tall',
            'tame',
            'tan',
            'tangible',
            'tart',
            'tasty',
            'tattered',
            'taut',
            'tedious',
            'teeming',
            'ugly',
            'ultimate',
            'unacceptable',
            'unaware',
            'uncomfortable',
            'uncommon',
            'unconscious',
            'understated',
            'unequaled',
            'vacant',
            'vague',
            'vain',
            'valid',
            'wan',
            'warlike',
            'warm',
            'warmhearted',
            'warped',
            'wary',
            'wasteful',
            'watchful',
            'waterlogged',
            'watery',
            'wavy',
            'yawning',
            'yearly',
            'zany',
            'false',
            'active',
            'actual',
            'adept',
            'admirable',
            'admired',
            'adolescent',
            'adorable',
            'adored',
            'advanced',
            'affectionate',
            'afraid',
            'aged',
            'aggravating',
            'beneficial',
            'best',
            'better',
            'bewitched',
            'big',
            'bighearted',
            'biodegradable',
            'bitesized',
            'bitter',
            'black',
            'cheap',
            'cheerful',
            'cheery',
            'chief',
            'chilly',
            'chubby',
            'circular',
            'classic',
            'clean',
            'clear',
            'clearcut',
            'clever',
            'close',
            'closed',
            'decent',
            'decimal',
            'decisive',
            'deep',
            'defenseless',
            'defensive',
            'defiant',
            'deficient',
            'definite',
            'definitive',
            'delayed',
            'delectable',
            'delicious',
            'elaborate',
            'elastic',
            'elated',
            'elderly',
            'electric',
            'elegant',
            'elementary',
            'elliptical',
            'embarrassed',
            'fast',
            'fat',
            'fatal',
            'fatherly',
            'favorable',
            'favorite',
            'fearful',
            'fearless',
            'feisty',
            'feline',
            'female',
            'feminine',
            'few',
            'fickle',
            'gifted',
            'giving',
            'glamorous',
            'glaring',
            'glass',
            'gleaming',
            'gleeful',
            'glistening',
            'glittering',
            'hardtofind',
            'harmful',
            'harmless',
            'harmonious',
            'harsh',
            'hasty',
            'hateful',
            'haunting',
            'illfated',
            'illinformed',
            'illiterate',
            'illustrious',
            'imaginary',
            'imaginative',
            'immaculate',
            'immaterial',
            'immediate',
            'immense',
            'impassioned',
            'jaunty',
            'jealous',
            'jittery',
            'key',
            'kind',
            'lazy',
            'leading',
            'leafy',
            'lean',
            'left',
            'legal',
            'legitimate',
            'light',
            'masculine',
            'massive',
            'mature',
            'meager',
            'mealy',
            'mean',
            'measly',
            'meaty',
            'medical',
            'mediocre',
            'nautical',
            'near',
            'neat',
            'necessary',
            'needy',
            'odd',
            'oddball',
            'offbeat',
            'offensive',
            'official',
            'old',
            'periodic',
            'perky',
            'personal',
            'pertinent',
            'pesky',
            'pessimistic',
            'petty',
            'phony',
            'physical',
            'piercing',
            'pink',
            'pitiful',
            'plain',
            'quarrelsome',
            'quarterly',
            'ready',
            'real',
            'realistic',
            'reasonable',
            'red',
            'reflecting',
            'regal',
            'regular',
            'separate',
            'serene',
            'serious',
            'serpentine',
            'several',
            'severe',
            'shabby',
            'shadowy',
            'shady',
            'shallow',
            'shameful',
            'shameless',
            'sharp',
            'shimmering',
            'shiny',
            'shocked',
            'shocking',
            'shoddy',
            'short',
            'shortterm',
            'showy',
            'shrill',
            'shy',
            'sick',
            'silent',
            'silky',
            'tempting',
            'tender',
            'tense',
            'tepid',
            'terrible',
            'terrific',
            'testy',
            'thankful',
            'that',
            'these',
            'uneven',
            'unfinished',
            'unfit',
            'unfolded',
            'unfortunate',
            'unhappy',
            'unhealthy',
            'uniform',
            'unimportant',
            'unique',
            'valuable',
            'vapid',
            'variable',
            'vast',
            'velvety',
            'weak',
            'wealthy',
            'weary',
            'webbed',
            'wee',
            'weekly',
            'weepy',
            'weighty',
            'weird',
            'welcome',
            'welldocumented',
            'yellow',
            'zealous',
            'aggressive',
            'agile',
            'agitated',
            'agonizing',
            'agreeable',
            'ajar',
            'alarmed',
            'alarming',
            'alert',
            'alienated',
            'alive',
            'all',
            'altruistic',
            'blackandwhite',
            'bland',
            'blank',
            'blaring',
            'bleak',
            'blind',
            'blissful',
            'blond',
            'blue',
            'blushing',
            'cloudy',
            'clueless',
            'clumsy',
            'cluttered',
            'coarse',
            'cold',
            'colorful',
            'colorless',
            'colossal',
            'comfortable',
            'common',
            'compassionate',
            'competent',
            'complete',
            'delightful',
            'delirious',
            'demanding',
            'dense',
            'dental',
            'dependable',
            'dependent',
            'descriptive',
            'deserted',
            'detailed',
            'determined',
            'devoted',
            'different',
            'embellished',
            'eminent',
            'emotional',
            'empty',
            'enchanted',
            'enchanting',
            'energetic',
            'enlightened',
            'enormous',
            'filthy',
            'fine',
            'finished',
            'firm',
            'first',
            'firsthand',
            'fitting',
            'fixed',
            'flaky',
            'flamboyant',
            'flashy',
            'flat',
            'flawed',
            'flawless',
            'flickering',
            'gloomy',
            'glorious',
            'glossy',
            'glum',
            'golden',
            'good',
            'goodnatured',
            'gorgeous',
            'graceful',
            'healthy',
            'heartfelt',
            'hearty',
            'heavenly',
            'heavy',
            'hefty',
            'helpful',
            'helpless',
            'impartial',
            'impeccable',
            'imperfect',
            'imperturbable',
            'impish',
            'impolite',
            'important',
            'impossible',
            'impractical',
            'impressionable',
            'impressive',
            'improbable',
            'joint',
            'jolly',
            'jovial',
            'kindhearted',
            'kindly',
            'lighthearted',
            'likable',
            'likely',
            'limited',
            'limp',
            'limping',
            'linear',
            'lined',
            'liquid',
            'medium',
            'meek',
            'mellow',
            'melodic',
            'memorable',
            'menacing',
            'merry',
            'messy',
            'metallic',
            'mild',
            'negative',
            'neglected',
            'negligible',
            'neighboring',
            'nervous',
            'new',
            'oldfashioned',
            'only',
            'open',
            'optimal',
            'optimistic',
            'opulent',
            'plaintive',
            'plastic',
            'playful',
            'pleasant',
            'pleased',
            'pleasing',
            'plump',
            'plush',
            'pointed',
            'pointless',
            'poised',
            'polished',
            'polite',
            'political',
            'queasy',
            'querulous',
            'reliable',
            'relieved',
            'remarkable',
            'remorseful',
            'remote',
            'repentant',
            'required',
            'respectful',
            'responsible',
            'silly',
            'silver',
            'similar',
            'simple',
            'simplistic',
            'sinful',
            'single',
            'sizzling',
            'skeletal',
            'skinny',
            'sleepy',
            'slight',
            'slim',
            'slimy',
            'slippery',
            'slow',
            'slushy',
            'small',
            'smart',
            'smoggy',
            'smooth',
            'smug',
            'snappy',
            'snarling',
            'sneaky',
            'sniveling',
            'snoopy',
            'thick',
            'thin',
            'third',
            'thirsty',
            'this',
            'thorny',
            'thorough',
            'those',
            'thoughtful',
            'threadbare',
            'united',
            'unkempt',
            'unknown',
            'unlawful',
            'unlined',
            'unlucky',
            'unnatural',
            'unpleasant',
            'unrealistic',
            'venerated',
            'vengeful',
            'verifiable',
            'vibrant',
            'vicious',
            'wellgroomed',
            'wellinformed',
            'welllit',
            'wellmade',
            'welloff',
            'welltodo',
            'wellworn',
            'wet',
            'which',
            'whimsical',
            'whirlwind',
            'whispered',
            'yellowish',
            'zesty',
            'amazing',
            'ambitious',
            'ample',
            'amused',
            'amusing',
            'anchored',
            'ancient',
            'angelic',
            'angry',
            'anguished',
            'animated',
            'annual',
            'another',
            'antique',
            'bogus',
            'boiling',
            'bold',
            'bony',
            'boring',
            'bossy',
            'both',
            'bouncy',
            'bountiful',
            'bowed',
            'complex',
            'complicated',
            'composed',
            'concerned',
            'concrete',
            'confused',
            'conscious',
            'considerate',
            'constant',
            'content',
            'conventional',
            'cooked',
            'cool',
            'cooperative',
            'difficult',
            'digital',
            'diligent',
            'dim',
            'dimpled',
            'dimwitted',
            'direct',
            'disastrous',
            'discrete',
            'disfigured',
            'disgusting',
            'disloyal',
            'dismal',
            'enraged',
            'entire',
            'envious',
            'equal',
            'equatorial',
            'essential',
            'esteemed',
            'ethical',
            'euphoric',
            'flimsy',
            'flippant',
            'flowery',
            'fluffy',
            'fluid',
            'flustered',
            'focused',
            'fond',
            'foolhardy',
            'foolish',
            'forceful',
            'forked',
            'formal',
            'forsaken',
            'gracious',
            'grand',
            'grandiose',
            'granular',
            'grateful',
            'grave',
            'gray',
            'great',
            'greedy',
            'green',
            'hidden',
            'hideous',
            'high',
            'highlevel',
            'hilarious',
            'hoarse',
            'hollow',
            'homely',
            'impure',
            'inborn',
            'incomparable',
            'incompatible',
            'incomplete',
            'inconsequential',
            'incredible',
            'indelible',
            'indolent',
            'inexperienced',
            'infamous',
            'infantile',
            'joyful',
            'joyous',
            'jubilant',
            'klutzy',
            'knobby',
            'little',
            'live',
            'lively',
            'livid',
            'loathsome',
            'lone',
            'lonely',
            'long',
            'milky',
            'mindless',
            'miniature',
            'minor',
            'minty',
            'miserable',
            'miserly',
            'misguided',
            'misty',
            'mixed',
            'next',
            'nice',
            'nifty',
            'nimble',
            'nippy',
            'orange',
            'orderly',
            'ordinary',
            'organic',
            'ornate',
            'ornery',
            'poor',
            'popular',
            'portly',
            'posh',
            'positive',
            'possible',
            'potable',
            'powerful',
            'powerless',
            'practical',
            'precious',
            'present',
            'prestigious',
            'questionable',
            'quick',
            'repulsive',
            'revolving',
            'rewarding',
            'rich',
            'right',
            'rigid',
            'ringed',
            'ripe',
            'sociable',
            'soft',
            'soggy',
            'solid',
            'somber',
            'some',
            'sophisticated',
            'sore',
            'sorrowful',
            'soulful',
            'soupy',
            'sour',
            'spanish',
            'sparkling',
            'sparse',
            'specific',
            'spectacular',
            'speedy',
            'spherical',
            'spicy',
            'spiffy',
            'spirited',
            'spiteful',
            'splendid',
            'spotless',
            'spotted',
            'spry',
            'thrifty',
            'thunderous',
            'tidy',
            'tight',
            'timely',
            'tinted',
            'tiny',
            'tired',
            'torn',
            'total',
            'unripe',
            'unruly',
            'unselfish',
            'unsightly',
            'unsteady',
            'unsung',
            'untidy',
            'untimely',
            'untried',
            'victorious',
            'vigilant',
            'vigorous',
            'villainous',
            'violet',
            'white',
            'whole',
            'whopping',
            'wicked',
            'wide',
            'wideeyed',
            'wiggly',
            'wild',
            'willing',
            'wilted',
            'winding',
            'windy',
            'young',
            'zigzag',
            'anxious',
            'any',
            'apprehensive',
            'appropriate',
            'apt',
            'arctic',
            'arid',
            'aromatic',
            'artistic',
            'ashamed',
            'assured',
            'astonishing',
            'athletic',
            'brave',
            'breakable',
            'brief',
            'bright',
            'brilliant',
            'brisk',
            'broken',
            'bronze',
            'brown',
            'bruised',
            'coordinated',
            'corny',
            'corrupt',
            'costly',
            'courageous',
            'courteous',
            'crafty',
            'crazy',
            'creamy',
            'creative',
            'creepy',
            'criminal',
            'crisp',
            'dirty',
            'disguised',
            'dishonest',
            'dismal',
            'distant',
            'distant',
            'distinct',
            'distorted',
            'dizzy',
            'dopey',
            'downright',
            'dreary',
            'even',
            'evergreen',
            'everlasting',
            'every',
            'evil',
            'exalted',
            'excellent',
            'excitable',
            'exemplary',
            'exhausted',
            'forthright',
            'fortunate',
            'fragrant',
            'frail',
            'frank',
            'frayed',
            'free',
            'french',
            'frequent',
            'fresh',
            'friendly',
            'frightened',
            'frightening',
            'frigid',
            'gregarious',
            'grim',
            'grimy',
            'gripping',
            'grizzled',
            'gross',
            'grotesque',
            'grouchy',
            'grounded',
            'honest',
            'honorable',
            'honored',
            'hopeful',
            'horrible',
            'hospitable',
            'hot',
            'huge',
            'infatuated',
            'inferior',
            'infinite',
            'informal',
            'innocent',
            'insecure',
            'insidious',
            'insignificant',
            'insistent',
            'instructive',
            'insubstantial',
            'judicious',
            'juicy',
            'jumbo',
            'knotty',
            'knowing',
            'knowledgeable',
            'longterm',
            'loose',
            'lopsided',
            'lost',
            'loud',
            'lovable',
            'lovely',
            'loving',
            'modern',
            'modest',
            'moist',
            'monstrous',
            'monthly',
            'monumental',
            'moral',
            'mortified',
            'motherly',
            'motionless',
            'nocturnal',
            'noisy',
            'nonstop',
            'normal',
            'notable',
            'noted',
            'original',
            'other',
            'our',
            'outgoing',
            'outlandish',
            'outlying',
            'precious',
            'pretty',
            'previous',
            'pricey',
            'prickly',
            'primary',
            'prime',
            'pristine',
            'private',
            'prize',
            'probable',
            'productive',
            'profitable',
            'quickwitted',
            'quiet',
            'quintessential',
            'roasted',
            'robust',
            'rosy',
            'rotating',
            'rotten',
            'rough',
            'round',
            'rowdy',
            'square',
            'squeaky',
            'squiggly',
            'stable',
            'staid',
            'stained',
            'stale',
            'standard',
            'starchy',
            'stark',
            'starry',
            'steel',
            'steep',
            'sticky',
            'stiff',
            'stimulating',
            'stingy',
            'stormy',
            'straight',
            'strange',
            'strict',
            'strident',
            'striking',
            'striped',
            'strong',
            'studious',
            'stunning',
            'tough',
            'tragic',
            'trained',
            'traumatic',
            'treasured',
            'tremendous',
            'tremendous',
            'triangular',
            'tricky',
            'trifling',
            'trim',
            'untrue',
            'unused',
            'unusual',
            'unwelcome',
            'unwieldy',
            'unwilling',
            'unwitting',
            'unwritten',
            'upbeat',
            'violent',
            'virtual',
            'virtuous',
            'visible',
            'winged',
            'wiry',
            'wise',
            'witty',
            'wobbly',
            'woeful',
            'wonderful',
            'wooden',
            'woozy',
            'wordy',
            'worldly',
            'worn',
            'youthful',
            'attached',
            'attentive',
            'attractive',
            'austere',
            'authentic',
            'authorized',
            'automatic',
            'avaricious',
            'average',
            'aware',
            'awesome',
            'awful',
            'awkward',
            'bubbly',
            'bulky',
            'bumpy',
            'buoyant',
            'burdensome',
            'burly',
            'bustling',
            'busy',
            'buttery',
            'buzzing',
            'critical',
            'crooked',
            'crowded',
            'cruel',
            'crushing',
            'cuddly',
            'cultivated',
            'cultured',
            'cumbersome',
            'curly',
            'curvy',
            'cute',
            'cylindrical',
            'doting',
            'double',
            'downright',
            'drab',
            'drafty',
            'dramatic',
            'dreary',
            'droopy',
            'dry',
            'dual',
            'dull',
            'dutiful',
            'excited',
            'exciting',
            'exotic',
            'expensive',
            'experienced',
            'expert',
            'extralarge',
            'extraneous',
            'extrasmall',
            'extroverted',
            'frilly',
            'frivolous',
            'frizzy',
            'front',
            'frosty',
            'frozen',
            'frugal',
            'fruitful',
            'full',
            'fumbling',
            'functional',
            'funny',
            'fussy',
            'fuzzy',
            'growing',
            'growling',
            'grown',
            'grubby',
            'gruesome',
            'grumpy',
            'guilty',
            'gullible',
            'gummy',
            'humble',
            'humiliating',
            'humming',
            'humongous',
            'hungry',
            'hurtful',
            'husky',
            'intelligent',
            'intent',
            'intentional',
            'interesting',
            'internal',
            'international',
            'intrepid',
            'ironclad',
            'irresponsible',
            'irritating',
            'itchy',
            'jumpy',
            'junior',
            'juvenile',
            'known',
            'kooky',
            'kosher',
            'low',
            'loyal',
            'lucky',
            'lumbering',
            'luminous',
            'lumpy',
            'lustrous',
            'luxurious',
            'mountainous',
            'muddy',
            'muffled',
            'multicolored',
            'mundane',
            'murky',
            'mushy',
            'musty',
            'muted',
            'mysterious',
            'noteworthy',
            'novel',
            'noxious',
            'numb',
            'nutritious',
            'nutty',
            'onerlooked',
            'outrageous',
            'outstanding',
            'oval',
            'overcooked',
            'overdue',
            'overjoyed',
            'profuse',
            'proper',
            'proud',
            'prudent',
            'punctual',
            'pungent',
            'puny',
            'pure',
            'purple',
            'pushy',
            'putrid',
            'puzzled',
            'puzzling',
            'quirky',
            'quixotic',
            'quizzical',
            'royal',
            'rubbery',
            'ruddy',
            'rude',
            'rundown',
            'runny',
            'rural',
            'rusty',
            'stupendous',
            'stupid',
            'sturdy',
            'stylish',
            'subdued',
            'submissive',
            'substantial',
            'subtle',
            'suburban',
            'sudden',
            'sugary',
            'sunny',
            'super',
            'superb',
            'superficial',
            'superior',
            'supportive',
            'surefooted',
            'surprised',
            'suspicious',
            'svelte',
            'sweaty',
            'sweet',
            'sweltering',
            'swift',
            'sympathetic',
            'trivial',
            'troubled',
            'trusting',
            'trustworthy',
            'trusty',
            'truthful',
            'tubby',
            'turbulent',
            'twin',
            'upright',
            'upset',
            'urban',
            'usable',
            'used',
            'useful',
            'useless',
            'utilized',
            'utter',
            'vital',
            'vivacious',
            'vivid',
            'voluminous',
            'worried',
            'worrisome',
            'worse',
            'worst',
            'worthless',
            'worthwhile',
            'worthy',
            'wrathful',
            'wretched',
            'writhing',
            'wrong',
            'wry',
            'yummy',
            'true',
            'aliceblue',
            'antiquewhite',
            'aqua',
            'aquamarine',
            'azure',
            'beige',
            'bisque',
            'black',
            'blanchedalmond',
            'blue',
            'blueviolet',
            'brown',
            'burlywood',
            'cadetblue',
            'chartreuse',
            'chocolate',
            'coral',
            'cornflowerblue',
            'cornsilk',
            'crimson',
            'cyan',
            'darkblue',
            'darkcyan',
            'darkgoldenrod',
            'darkgray',
            'darkgreen',
            'darkgrey',
            'darkkhaki',
            'darkmagenta',
            'darkolivegreen',
            'darkorange',
            'darkorchid',
            'darkred',
            'darksalmon',
            'darkseagreen',
            'darkslateblue',
            'darkslategray',
            'darkslategrey',
            'darkturquoise',
            'darkviolet',
            'deeppink',
            'deepskyblue',
            'dimgray',
            'dimgrey',
            'dodgerblue',
            'firebrick',
            'floralwhite',
            'forestgreen',
            'fractal',
            'fuchsia',
            'gainsboro',
            'ghostwhite',
            'gold',
            'goldenrod',
            'gray',
            'green',
            'greenyellow',
            'honeydew',
            'hotpink',
            'indianred',
            'indigo',
            'ivory',
            'khaki',
            'lavender',
            'lavenderblush',
            'lawngreen',
            'lemonchiffon',
            'lightblue',
            'lightcoral',
            'lightcyan',
            'lightgoldenrod',
            'lightgoldenrodyellow',
            'lightgray',
            'lightgreen',
            'lightgrey',
            'lightpink',
            'lightsalmon',
            'lightseagreen',
            'lightskyblue',
            'lightslateblue',
            'lightslategray',
            'lightsteelblue',
            'lightyellow',
            'lime',
            'limegreen',
            'linen',
            'magenta',
            'maroon',
            'mediumaquamarine',
            'mediumblue',
            'mediumforestgreen',
            'mediumgoldenrod',
            'mediumorchid',
            'mediumpurple',
            'mediumseagreen',
            'mediumslateblue',
            'mediumspringgreen',
            'mediumturquoise',
            'mediumvioletred',
            'midnightblue',
            'mintcream',
            'mistyrose',
            'moccasin',
            'navajowhite',
            'navy',
            'navyblue',
            'oldlace',
            'olive',
            'olivedrab',
            'opaque',
            'orange',
            'orangered',
            'orchid',
            'palegoldenrod',
            'palegreen',
            'paleturquoise',
            'palevioletred',
            'papayawhip',
            'peachpuff',
            'peru',
            'pink',
            'plum',
            'powderblue',
            'purple',
            'red',
            'rosybrown',
            'royalblue',
            'saddlebrown',
            'salmon',
            'sandybrown',
            'seagreen',
            'seashell',
            'sienna',
            'silver',
            'skyblue',
            'slateblue',
            'slategray',
            'slategrey',
            'snow',
            'springgreen',
            'steelblue',
            'tan',
            'teal',
            'thistle',
            'tomato',
            'transparent',
            'turquoise',
            'violet',
            'violetred',
            'wheat',
            'white',
            'whitesmoke',
            'yellow',
            'yellowgreen'
        ]
    }

    checkSupport(href) {
        return (href.includes('//redgifs.com/') || href.includes('www.redgifs.com/'));
    }

    capatilizeWords(word) {
        let words = [];
        let remaing = word;
        let ind = 0;
        while (remaing.length > 0 && ind <= remaing.length) {
            let word = remaing.slice(0, ++ind);
            if (this.gypcatList.includes(word)) {
                remaing = remaing.slice(ind);
                words.push(word);
                ind = 0;
            }
        }

        return words.map(val => val[0].toUpperCase() + val.slice(1)).join('');
    }

    getDownloadLinks(href) {
        //media => oembed => thumbnail_url
        //https://thcf2.redgifs.com/<ID>.mp4
        //https://redgifs.com/watch/<ID>

        let words = href.split('/');
        let cWords = this.capatilizeWords(words[words.length - 1]);
        let url = words.slice(0, words.length - 1);
        url = url.join('/').replace('www.', '').replace('/watch', '').replace('redgifs', 'thcf2.redgifs') + '/' + cWords + '.mp4'
        return url;
    }
}

const _SupportedSites = [new DirectDownload(), new RedditGallery(), new Imgur(), new Gfycat(), new Redgifs()];
//#endregion

//#region Downloader Class
class BaseRedditClass {
    constructor() {

    }

    _getSavedPostsData(after = null) {
        return new Promise((res, rej) => {
            let username;
            if (_IsOnUserPage) {
                username = document.location.href.split('/');
                username = username[username.indexOf('user') + 1];
            } else if (GM_config.get('reddit_username') != '') {
                username = _RedditUsername;
            }

            fetch(`${window.location.origin}/user/${username}/saved/.json?limit=20${after != null ? '&after=' + after : ''}`)
                .then(resp => resp.text())
                .then(text => res(JSON.parse(text)));
        })
    }

    _getPostData(url) {
        return new Promise((res, rej) => {
            fetch(`${url}/.json`)
                .then(resp => resp.text())
                .then(text => res(JSON.parse(text)));
        })
    }

    _parseData(data) {
        return {
            id: data.data.name,
            url: data.data.url,
            og_url: `https://www.reddit.com${data.data.permalink}`,
            subreddit: data.data.subreddit
        }
    }

    _getFilterArray() {
        return new Promise((res, rej) => {
            let str = GM_config.get('create_for_filter');
            let arr = str.split(',').map(val => val.trim());
            res(arr);
        });
    }

    async downloadSingle(info, filter = null) {
        return new Promise(async (res, rej) => {
            if (filter == null) filter = await this._getFilterArray();
            const url = info.url;

            if (url == undefined) {
                rej();
                return;
            };

            for (let index = 0; index < _SupportedSites.length; index++) {
                const site = _SupportedSites[index];
                if (site.checkSupport(url)) {
                    let folder = null;
                    if (GM_config.get('create_subreddit_folder')) {
                        if (!GM_config.get('create_only_for_selected') || filter.includes(info.subreddit)) {
                            folder = info.subreddit;
                        }
                    }
                    await site.downloadImages(info, folder);
                    await wait(20);
                    break;
                }
            }
            res();
        })
    }

    async downloadAll() {
        console.log('DOWNLOADING!');
        //_SupportedSites.forEach(downloader => {
        //    downloader.checkSupport()
        //})

        //Before = newly added to page so page 1 => when using an id you go up the list
        //Thats why you use Before as Paramter

        //^^^ Screw that shit am i right

        //resp.data.after => Pagnation
        //resp.data.children[].data.name => ID
        //resp.data.children[].data.url => url
        //resp.data.children[].data.subreddit => subreddit

        let running = true;
        let after = null;
        let postInfos = [];
        let first = true;
        let stopAt = _LastDownloadedID;
        let filter = await this._getFilterArray();
        while (running) {
            let data = (await this._getSavedPostsData(after)).data;
            after = data.after;
            if (after == null || after == 'null') running = false;
            for (let index = 0; index < data.children.length; index++) {
                const postData = data.children[index];
                const info = this._parseData(postData);

                if (info.id == stopAt) {
                    running = false;
                    break;
                }

                if (first) {
                    first = false;
                    _LastDownloadedID = info.id;
                    GM_setValue('LastDownloaded', info.id);
                }

                postInfos.push(info);
            }
        }

        let tmp_title = document.title;

        for (let index = 0; index < postInfos.length; index++) {
            document.title = `${index+1}/${postInfos.length}`;
            const info = postInfos[index];
            await this.downloadSingle(info, filter).catch(() => {
                console.error("Failed to download image!")
            });
            /*const url = info.url;
            //console.log(`Downloading ${index+1}/${links.length}  -  ${url}`);

            if(url == undefined) continue;

            for (let index = 0; index < _SupportedSites.length; index++) {
                const site = _SupportedSites[index];
                if(site.checkSupport(url)){
                    let folder = null;
                    if(GM_config.get('create_subreddit_folder')){
                        if(!GM_config.get('create_only_for_selected') || filter.includes(info.subreddit)){
                            folder = info.subreddit;
                        }
                    }
                    await site.downloadImages(url, folder);
                    await wait(20);
                    break;
                }
            }*/
        }

        createNotification('Reddit Downloader', `Finished downloading ${postInfos.length} Posts!`);

        document.title = tmp_title;
    }
}

class RedditDownloader extends BaseRedditClass {
    constructor() {
        super();

        //this.addSavedDownloadButton();
        //this.addSettingsButton();
        this.pageUpdateChecker();
    }

    addSavedDownloadButton() {
        let aEles = document.querySelectorAll('a');
        for (let index = 0; index < aEles.length; index++) {
            const x = aEles[index];
            if (x.innerText.toLowerCase().indexOf('overview') > -1) {
                console.log(x);

                let className = x.className;

                let btn = document.createElement('a');
                btn.className = className + ' download';
                btn.innerText = 'DOWNLOAD';
                btn.onclick = () => {
                    this.downloadAll()
                };
                x.parentNode.appendChild(btn);

                return true;
            }
        }

        return false;
    }

    async addPostDownloadButton() {
        return new Promise(async (res, rej) => {
            let postEles = [...document.querySelectorAll('.Post')];
            let commentButton = document.querySelector('.icon-comment');
            if (commentButton == null || commentButton == undefined) {
                rej();
                return;
            }
            let buttonClassName = commentButton.parentElement.parentElement.className;

            for (let i = 0; i < postEles.length; i++) {
                const post = postEles[i];
                if (post.classList.contains('TMP_DOWNLOAD_ADDED') || post.querySelector('a[Reddit_Downloader="download"]') != null || post.classList.contains('promotedvideolink') || post == undefined) continue;
                //console.log(post);
                const link = post.querySelector('a[data-click-id="body"]');
                let url;
                if (link == undefined || link == null) {
                    if (window.location.href.includes('comments')) {
                        url = window.location.href;

                        if (post.children.length < 1 || post.children[0].getAttribute('data-test-id') != 'post-content') continue;

                    } else {
                        continue;
                    }

                } else {
                    url = link.href
                }
                post.classList.add('TMP_DOWNLOAD_ADDED')

                //TODO clean this shit up
                let dwnBTN = document.createElement('a');
                dwnBTN.className = buttonClassName;
                dwnBTN.innerText = 'DOWNLOAD';
                dwnBTN.setAttribute('Reddit_Downloader', 'download')
                dwnBTN.onclick = () => {
                    console.log(`Getting Data from post: ${url}`);
                    this._getPostData(url)
                        .then(data => {
                            if (!document.body.contains(post)) {
                                rej();
                                return;
                            }
                            const info = this._parseData(data[0].data.children[0]);
                            this.downloadSingle(info);
                        })
                };
                post.querySelector('.icon-comment').parentElement.parentElement.parentNode.appendChild(dwnBTN);

                // promises.push(this._getPostData(url)
                //     .then(data => {
                //         if(!document.body.contains(post)){
                //             rej();
                //             return;
                //         }
                //         const info = this._parseData(data[0].data.children[0]);

                //         // TODO clean this shit up
                //         let dwnBTN = document.createElement('a');
                //         dwnBTN.className = buttonClassName;
                //         dwnBTN.innerText = 'DOWNLOAD';
                //         dwnBTN.setAttribute('Reddit_Downloader', 'download')
                //         dwnBTN.onclick = () => this.downloadSingle(info);
                //         post.querySelector('.icon-comment').parentElement.parentElement.parentNode.appendChild(dwnBTN);
                //     }).catch(() => {}));
            }

            res();

            // Promise.all(promises).then(values => {
            //     res();
            // })
        })
    }

    async addSettingsButton() {
        waitForElements('#change-username-tooltip-id', 5000)
            .then(parent => {
                let chatButton = parent[0].children[0];
                let settingsButton = chatButton.cloneNode(true);

                settingsButton.setAttribute('title', 'Reddit Downloader Settings');
                settingsButton.querySelector('a').href = '#';
                settingsButton.querySelector('a').onclick = () => {
                    GM_config.open();
                };
                //settingsButton.querySelector('svg').setAttribute('viewBox', '0 0 24 24');
                settingsButton.querySelector('i').className = "icon icon-settings"
                //Icon link: https://iconmonstr.com/gear-1-svg/
                //settingsButton.querySelector('path').setAttribute('d', 'M24 13.616v-3.232c-1.651-.587-2.694-.752-3.219-2.019v-.001c-.527-1.271.1-2.134.847-3.707l-2.285-2.285c-1.561.742-2.433 1.375-3.707.847h-.001c-1.269-.526-1.435-1.576-2.019-3.219h-3.232c-.582 1.635-.749 2.692-2.019 3.219h-.001c-1.271.528-2.132-.098-3.707-.847l-2.285 2.285c.745 1.568 1.375 2.434.847 3.707-.527 1.271-1.584 1.438-3.219 2.02v3.232c1.632.58 2.692.749 3.219 2.019.53 1.282-.114 2.166-.847 3.707l2.285 2.286c1.562-.743 2.434-1.375 3.707-.847h.001c1.27.526 1.436 1.579 2.019 3.219h3.232c.582-1.636.75-2.69 2.027-3.222h.001c1.262-.524 2.12.101 3.698.851l2.285-2.286c-.744-1.563-1.375-2.433-.848-3.706.527-1.271 1.588-1.44 3.221-2.021zm-12 2.384c-2.209 0-4-1.791-4-4s1.791-4 4-4 4 1.791 4 4-1.791 4-4 4z');
                parent[0].appendChild(settingsButton);
            })
            .catch(err => {
                this.addSettingsButton();
            });
    }

    async pageUpdateChecker() {
        let isAdded = false;
        let username = await this.getUsername();

        while (true) {
            await wait(50);
            _IsOnUserPage = window.location.href.includes('reddit.com/user/' + username);

            if (true) {
                if(!_IsOnUserPage)
                    isAdded = false;
                if (window.RedditDownloader != undefined) await window.RedditDownloader.addPostDownloadButton().catch(() => {});
            }
            if (!isAdded && _IsOnUserPage) {
                if (window.RedditDownloader != undefined) {
                    await wait(50);
                    isAdded = window.RedditDownloader.addSavedDownloadButton();
                }
            }
        }
    }

    async getUsername() {
        return new Promise(async (res, rej) => {
            let usernameEle = [];
            while (usernameEle == undefined || usernameEle == null || usernameEle.length == 0) {
                usernameEle = await waitForElements('#email-collection-tooltip-id', 5000);
                console.log("CALLED", usernameEle);
            }

            res(usernameEle[0].innerText.split('\n')[0]);
        })
    }
}

class OldRedditDownloader extends BaseRedditClass {
    constructor() {
        super();

        //this.addSavedDownloadButton();
        this.addSettingsButton();
        this.pageUpdateChecker();
    }

    async addSavedDownloadButton() {
        return new Promise(async (res) => {
            waitForElements('.tabmenu')
            .then(ele => {
                let tabmenu = ele[0];

                let downloadLi = document.createElement('li');
                let downloadA = document.createElement('a');
                downloadA.classList.add('choice');
                downloadA.innerHTML = 'Download';
                downloadA.style.cursor = 'pointer';
                downloadA.onclick = () => {
                    this.downloadAll();
                }

                downloadLi.appendChild(downloadA);
                tabmenu.appendChild(downloadLi);
            })
            .catch(() => {
                res(false);
            })
        })
    }

    async addPostDownloadButton() {
        return new Promise(async (res, rej) => {
            let postEles = [...document.querySelectorAll('.thing[data-subreddit-prefixed]')];

            for (let index = 0; index < postEles.length; index++) {
                const post = postEles[index];

                if (post.classList.contains('TMP_DOWNLOAD_ADDED') || post.querySelector('a[Reddit_Downloader="download"]') != null || post.classList.contains('promotedvideolink') || post == undefined) continue;

                const link = post.querySelector('a[data-event-action="comments"]');
                let url = link;
                post.classList.add('TMP_DOWNLOAD_ADDED')

                const buttons = post.querySelector('.flat-list.buttons');

                const downloadButtonLi = document.createElement('li');
                downloadButtonLi.classList.add('download-button');

                const downloadButtonA = document.createElement('a');
                downloadButtonA.innerHTML = 'Download';
                downloadButtonA.setAttribute('Reddit_Downloader', 'download');

                downloadButtonA.onclick = () => {
                    console.log(`Getting Data from post: ${url}`);
                    this._getPostData(url)
                        .then(data => {
                            if (!document.body.contains(post)) {
                                rej();
                                return;
                            }
                            const info = this._parseData(data[0].data.children[0]);
                            this.downloadSingle(info);
                        })
                }

                downloadButtonLi.appendChild(downloadButtonA);
                buttons.appendChild(downloadButtonLi);


            }

            res();
        })
    }

    async addSettingsButton() {
        waitForElements('.tabmenu', 5000)
        .then(parent => {
            let tabmenu = parent[0];

            let downloadLi = document.createElement('li');
            let downloadA = document.createElement('a');
            downloadA.classList.add('choice');
            downloadA.innerHTML = 'RD-Settings';
            downloadA.style.cursor = 'pointer';
            downloadA.onclick = () => {
                GM_config.open();
            }

            downloadLi.appendChild(downloadA);
            tabmenu.appendChild(downloadLi);
        })
        .catch(() => {
            this.addSettingsButton();
        })
    }

    async pageUpdateChecker() {
        let isAdded = false;
        let username = await this.getUsername();

        while (true) {
            await wait(50);
            _IsOnUserPage = window.location.href.includes('reddit.com/user/' + username);

            if (!_IsOnUserPage) {
                isAdded = false;
                if (window.RedditDownloader != undefined) await window.RedditDownloader.addPostDownloadButton().catch(() => {});
            }
            if (!isAdded && _IsOnUserPage) {
                if (window.RedditDownloader != undefined) {
                    await wait(50);
                    isAdded = await window.RedditDownloader.addSavedDownloadButton();
                }
            }
        }
    }

    async getUsername() {
        return new Promise(async (res, rej) => {
            let usernameEle = [];
            while (usernameEle == undefined || usernameEle == null || usernameEle.length == 0) {
                usernameEle = await waitForElements('.user', 5000);
                console.log("CALLED", usernameEle);
            }

            res(usernameEle[0].children[0].innerText.trim());
        })
    }
}
//#endregion


(async () => {
    if (DEBUG) {
        //let imgur = new Imgur();
        //await imgur.downloadImages('https://imgur.com/a/w0ouO');

        //let direct = new DirectDownload();
        //await direct.downloadImages('')

        //let redgif = new Redgifs();
        //await redgif.downloadImages('');
    }
})()

window.addEventListener('load', async () => {
    if (window.top != window.self) {
        return;
    }

    await wait(100);
    let oldReddit = await isOldReddit();

    if (oldReddit)
        window.RedditDownloader = new OldRedditDownloader();
    else{
        window.RedditDownloader = new RedditDownloader();
    }

    GM_config.init({
        'id': 'Reddit_Downloader',
        'fields': {
            'create_subreddit_folder': {
                'label': 'Create a subreddit folder which stores all subreddit entries.',
                'type': 'checkbox',
                'default': false
            },
            'create_only_for_selected': {
                'label': 'Create a folder only if it passes the filter.',
                'type': 'checkbox',
                'default': false
            },
            'create_for_filter': {
                'label': 'The names of the subreddits to create a folder for. (comma seperated)',
                'type': 'text',
                'size': 9999999,
                'default': ''
            },
            'reddit_username': {
                'label': 'Your Reddit username. Not actually needed right now.',
                'type': 'text',
                'size': 9999999,
                'default': ''
            },
            'imgur_client_id': {
                'label': 'Your imgur Client ID. Incase you want to download imgur images/albums.',
                'type': 'text',
                'size': 9999999,
                'default': ''
            },
            'download_location': {
                'label': 'The download location of the files. Inside of your Downloads folder.',
                'type': 'text',
                'size': 9999999,
                'default': 'Reddit/Stuff/Stuff/'
            }
        }
    });

    GM_registerMenuCommand('Manage Settings', (() => {
        GM_config.open();
    }));
})