hybridsong / Enhanced Image Boards

// ==UserScript==
// %genload_req%
// @name           Enhanced Image Boards
// @namespace      https://github.com/hybridsong/imageboards
// @version        2018.12.12.2017-9-19
// @author         hybridsong
// @license        GPL-3.0-only
// @icon           https://secure.gravatar.com/avatar/187e65a2ca69335f7483a4f19812050a
// @match          *://danbooru.donmai.us/*
// @match          *://www.pixiv.net/*
// @run-at         document-idle
// ==/UserScript==

/*
 *  Enhanced Image Boards
 *  \hybridsong/
 */

(function (global, factory) {
  if (typeof define === "function" && define.amd) {
    define([], factory);
  } else if (typeof exports !== "undefined") {
    factory();
  } else {
    var mod = {
      exports: {}
    };
    factory();
    global.FileSaver = mod.exports;
  }
})(this, function () {
  "use strict";

  /*
  * FileSaver.js
  * A saveAs() FileSaver implementation.
  *
  * By Eli Grey, http://eligrey.com
  *
  * License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT)
  * source  : http://purl.eligrey.com/github/FileSaver.js
  */
  // The one and only way of getting global scope in all environments
  // https://stackoverflow.com/q/3277182/1008999
  var _global = typeof window === 'object' && window.window === window ? window : typeof self === 'object' && self.self === self ? self : typeof global === 'object' && global.global === global ? global : void 0;

  function bom(blob, opts) {
    if (typeof opts === 'undefined') opts = {
      autoBom: false
    };else if (typeof opts !== 'object') {
      console.warn('Depricated: Expected third argument to be a object');
      opts = {
        autoBom: !opts
      };
    } // prepend BOM for UTF-8 XML and text/* types (including HTML)
    // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF

    if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
      return new Blob([String.fromCharCode(0xFEFF), blob], {
        type: blob.type
      });
    }

    return blob;
  }

  function download(url, name, opts) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.responseType = 'blob';

    xhr.onload = function () {
      saveAs(xhr.response, name, opts);
    };

    xhr.onerror = function () {
      console.error('could not download file');
    };

    xhr.send();
  }

  function corsEnabled(url) {
    var xhr = new XMLHttpRequest(); // use sync to avoid popup blocker

    xhr.open('HEAD', url, false);
    xhr.send();
    return xhr.status >= 200 && xhr.status <= 299;
  } // `a.click()` doesn't work for all browsers (#465)


  function click(node) {
    try {
      node.dispatchEvent(new MouseEvent('click'));
    } catch (e) {
      var evt = document.createEvent('MouseEvents');
      evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null);
      node.dispatchEvent(evt);
    }
  }

  var saveAs = _global.saveAs || // probably in some web worker
  typeof window !== 'object' || window !== _global ? function saveAs() {}
  /* noop */
  // Use download attribute first if possible (#193 Lumia mobile)
  : 'download' in HTMLAnchorElement.prototype ? function saveAs(blob, name, opts) {
    var URL = _global.URL || _global.webkitURL;
    var a = document.createElement('a');
    name = name || blob.name || 'download';
    a.download = name;
    a.rel = 'noopener'; // tabnabbing
    // TODO: detect chrome extensions & packaged apps
    // a.target = '_blank'

    if (typeof blob === 'string') {
      // Support regular links
      a.href = blob;

      if (a.origin !== location.origin) {
        corsEnabled(a.href) ? download(blob, name, opts) : click(a, a.target = '_blank');
      } else {
        click(a);
      }
    } else {
      // Support blobs
      a.href = URL.createObjectURL(blob);
      setTimeout(function () {
        URL.revokeObjectURL(a.href);
      }, 4E4); // 40s

      setTimeout(function () {
        click(a);
      }, 0);
    }
  } // Use msSaveOrOpenBlob as a second approach
  : 'msSaveOrOpenBlob' in navigator ? function saveAs(blob, name, opts) {
    name = name || blob.name || 'download';

    if (typeof blob === 'string') {
      if (corsEnabled(blob)) {
        download(blob, name, opts);
      } else {
        var a = document.createElement('a');
        a.href = blob;
        a.target = '_blank';
        setTimeout(function () {
          click(a);
        });
      }
    } else {
      navigator.msSaveOrOpenBlob(bom(blob, opts), name);
    }
  } // Fallback to using FileReader and a popup
  : function saveAs(blob, name, opts, popup) {
    // Open a popup immediately do go around popup blocker
    // Mostly only avalible on user interaction and the fileReader is async so...
    popup = popup || open('', '_blank');

    if (popup) {
      popup.document.title = popup.document.body.innerText = 'downloading...';
    }

    if (typeof blob === 'string') return download(blob, name, opts);
    var force = blob.type === 'application/octet-stream';

    var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari;

    var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent);

    if ((isChromeIOS || force && isSafari) && typeof FileReader === 'object') {
      // Safari doesn't allow downloading of blob urls
      var reader = new FileReader();

      reader.onloadend = function () {
        var url = reader.result;
        url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;');
        if (popup) popup.location.href = url;else location = url;
        popup = null; // reverse-tabnabbing #460
      };

      reader.readAsDataURL(blob);
    } else {
      var URL = _global.URL || _global.webkitURL;
      var url = URL.createObjectURL(blob);
      if (popup) popup.location = url;else location.href = url;
      popup = null; // reverse-tabnabbing #460

      setTimeout(function () {
        URL.revokeObjectURL(url);
      }, 4E4); // 40s
    }
  };
  _global.saveAs = saveAs.saveAs = saveAs;

  if (typeof module !== 'undefined') {
    module.exports = saveAs;
  }
});

(function() {
  'use strict';

  var globals = typeof global === 'undefined' ? self : global;
  if (typeof globals.require === 'function') return;

  var modules = {};
  var cache = {};
  var aliases = {};
  var has = {}.hasOwnProperty;

  var expRe = /^\.\.?(\/|$)/;
  var expand = function(root, name) {
    var results = [], part;
    var parts = (expRe.test(name) ? root + '/' + name : name).split('/');
    for (var i = 0, length = parts.length; i < length; i++) {
      part = parts[i];
      if (part === '..') {
        results.pop();
      } else if (part !== '.' && part !== '') {
        results.push(part);
      }
    }
    return results.join('/');
  };

  var dirname = function(path) {
    return path.split('/').slice(0, -1).join('/');
  };

  var localRequire = function(path) {
    return function expanded(name) {
      var absolute = expand(dirname(path), name);
      return globals.require(absolute, path);
    };
  };

  var initModule = function(name, definition) {
    var hot = hmr && hmr.createHot(name);
    var module = {id: name, exports: {}, hot: hot};
    cache[name] = module;
    definition(module.exports, localRequire(name), module);
    return module.exports;
  };

  var expandAlias = function(name) {
    return aliases[name] ? expandAlias(aliases[name]) : name;
  };

  var _resolve = function(name, dep) {
    return expandAlias(expand(dirname(name), dep));
  };

  var require = function(name, loaderPath) {
    if (loaderPath == null) loaderPath = '/';
    var path = expandAlias(name);

    if (has.call(cache, path)) return cache[path].exports;
    if (has.call(modules, path)) return initModule(path, modules[path]);

    throw new Error("Cannot find module '" + name + "' from '" + loaderPath + "'");
  };

  require.alias = function(from, to) {
    aliases[to] = from;
  };

  var extRe = /\.[^.\/]+$/;
  var indexRe = /\/index(\.[^\/]+)?$/;
  var addExtensions = function(bundle) {
    if (extRe.test(bundle)) {
      var alias = bundle.replace(extRe, '');
      if (!has.call(aliases, alias) || aliases[alias].replace(extRe, '') === alias + '/index') {
        aliases[alias] = bundle;
      }
    }

    if (indexRe.test(bundle)) {
      var iAlias = bundle.replace(indexRe, '');
      if (!has.call(aliases, iAlias)) {
        aliases[iAlias] = bundle;
      }
    }
  };

  require.register = require.define = function(bundle, fn) {
    if (bundle && typeof bundle === 'object') {
      for (var key in bundle) {
        if (has.call(bundle, key)) {
          require.register(key, bundle[key]);
        }
      }
    } else {
      modules[bundle] = fn;
      delete cache[bundle];
      addExtensions(bundle);
    }
  };

  require.list = function() {
    var list = [];
    for (var item in modules) {
      if (has.call(modules, item)) {
        list.push(item);
      }
    }
    return list;
  };

  var hmr = globals._hmr && new globals._hmr(_resolve, require, modules, cache);
  require._cache = cache;
  require.hmr = hmr && hmr.wrap;
  require.brunch = true;
  globals.require = require;
})();

'use strict';

(function () {
    'use strict';

    var BASE_64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 'abcdefghijklmnopqrstuvwxyz0123456789+/';

    // Namespace
    var Rand = {
        // Function to use for random values, available to overwrite
        randomGenerator: Math.random,

        // This is seen as a random number dependent on the distribution
        seed: function seed() {
            var distribution = arguments.length <= 0 || arguments[0] === undefined ? 'constant' : arguments[0];

            switch (distribution) {
                // Constant distribution (random) -> .:.:..:..:
                case 'constant':case 'random':
                    return Rand.randomGenerator();

                // Stable distribution -> ..:|:..
                // Sharp edge in the middle
                case 'double-exponential':case 'stable':
                    return (Rand.randomGenerator() - 0.5) * Rand.randomGenerator() + 0.5;

                // Like the stable distribution but
                // only in one direction (outdying) -> |:....
                case 'exponential':
                    return Rand.randomGenerator() * Rand.randomGenerator();

                // Linear curve decresing
                case 'linear-decrease':
                    return 1 - Math.sqrt(Rand.randomGenerator());

                // Linear curve incresing
                case 'linear-increase':
                    return Math.sqrt(Rand.randomGenerator());

                // Birnbaum-Saunders survival function ish
                case 'survival':
                    var r = Rand.randomGenerator();
                    return Math.pow(r, 2);

                case 'normal':

                    var u = Rand.randomGenerator();
                    var v = Rand.randomGenerator();

                    return Math.sqrt(-2 * Math.log(u)) * (Math.cos(2 * Math.PI * v) / 8) + 0.5;
            }
        },

        // Check that value is between min and max
        sanitize: function sanitize(value) {
            var min = arguments.length <= 1 || arguments[1] === undefined ? 0 : arguments[1];
            var max = arguments.length <= 2 || arguments[2] === undefined ? 1 : arguments[2];

            if (value < min) {
                return min;
            }

            if (value > max) {
                return max;
            }

            return value;
        },

        // Return a random value between min and max
        random: function random() {
            var min = arguments.length <= 0 || arguments[0] === undefined ? 0 : arguments[0];
            var max = arguments.length <= 1 || arguments[1] === undefined ? 1 : arguments[1];
            var distribution = arguments.length <= 2 || arguments[2] === undefined ? 'constant' : arguments[2];

            var interval = max - min;

            // There are some different distributions
            var seed = Rand.seed(distribution);

            return Rand.sanitize(min + seed * interval, min, max);
        },

        // Return a boolean depending on the probability
        // returns false with probability
        bool: function bool() {
            var probability = arguments.length <= 0 || arguments[0] === undefined ? 0.5 : arguments[0];

            return Rand.randomGenerator() >= probability;
        },

        // Return random int between min and max
        // Just an alias for parseInt(random())
        int: function int() {
            return parseInt(Rand.random.apply(Rand, arguments));
        },

        // A hash string values 0-f
        hash: function hash() {
            var length = arguments.length <= 0 || arguments[0] === undefined ? 40 : arguments[0];

            var str = '';

            while (str.length < length) {
                str += Rand.int(0, 16).toString(16);
            }

            return str.substr(0, length);
        },

        // Return a base36 string
        base36: function base36() {
            var length = arguments.length <= 0 || arguments[0] === undefined ? 40 : arguments[0];

            var str = '';

            while (str.length < length) {
                str += Rand.int(0, 36 * length).toString(36);
            }

            return str.substr(0, length);
        },

        // Return a base64 string
        base64: function base64() {
            var length = arguments.length <= 0 || arguments[0] === undefined ? 40 : arguments[0];

            var str = '';
            var b = BASE_64_CHARS;

            while (str.length < length) {
                str += b[Rand.int(0, 64)];
            }

            return str.substr(0, length);
        },

        // Return random character
        char: function char() {
            return Rand.int(10, 36).toString(36);
        },

        // Return random hexadecimal color
        color: function color() {
            return '#' + Rand.hash(6);
        },

        // Return random rgba color
        rgba: function rgba() {
            var int = Rand.int;
            return 'rgba(' + int(0, 255) + ', ' + int(0, 255) + ', ' + int(0, 255) + (', ' + Rand.randomGenerator() + ')');
        },

        // Return random date between min and max (1 year)
        date: function date() {
            var min = arguments.length <= 0 || arguments[0] === undefined ? new Date() : arguments[0];
            var max = arguments[1];

            // Check if min is object or not
            if (typeof min === 'number') {
                min = new Date(min);
            }

            if (!max) {
                // One year
                max = new Date();
                max.setFullYear(min.getFullYear() + 1);
            }

            return new Date(Rand.int(min.getTime(), max.getTime()));
        },

        // Return random item from array
        choose: function choose() {
            var arr = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0];
            var distribution = arguments.length <= 1 || arguments[1] === undefined ? 'constant' : arguments[1];

            if (arr.length > 0) {
                return arr[Rand.int(0, arr.length, distribution)];
            }

            return null;
        },

        // Generate password
        password: function password() {
            var length = arguments.length <= 0 || arguments[0] === undefined ? 8 : arguments[0];
            var numbers = arguments.length <= 1 || arguments[1] === undefined ? 2 : arguments[1];

            var str = '';

            while (str.length < length) {

                if (str.length % Math.floor(length / numbers) === 0) {
                    str += Rand.int(0, 9);
                    continue;
                }

                if (Rand.bool(0.3)) {
                    str += Rand.char().toUpperCase();
                } else {
                    str += Rand.char();
                }
            }

            return str;
        }
    };

    // Export
    /* eslint no-undef: [0] */
    if (typeof module !== "undefined" && module !== null && module.exports != null) {

        module.exports = Rand;
    } else {
        window.Rand = Rand;
    }
})();

require.register("common.js", function(exports, require, module){
  exports.clean_array = function (arr) {
    let tmp = []
    for (let idx in arr) {
        let val = arr[idx]
        if (val != undefined)
            tmp.push(val)
    }
    return tmp
}

exports.index_array = function (arr) {
    let tmp = {}
    for (let idx = 0; idx < arr.length; idx++) {
        let val = arr[idx]
        if (!tmp[val])
            tmp[val] = []
        tmp[val].push(idx)
    }
    return tmp
}

exports.get_index = function (object, key, idx) {
    if (object[key] && object[key][idx] !== undefined) {
        return object[key][idx]
    }
}

exports.rename = function (basename) {
    let name = basename[0].split('_'),
        ext = basename[1],
        idx = index_array(name)

    if (debug_rename)
        console.log(name, idx, ext)

    name[get_index(idx, '', 2)] = ['danbooru', postid].join(' ')
    name[get_index(idx, 'original', 0)] = undefined
    name[get_index(idx, '', 2) + 1] = undefined

    if (debug_rename)
        console.log(name)

    return clean_array(name).join(' ').replace(/ +/, '') + '.' + ext
}

exports.get_name = function (doc) {
    const
        tags = (list, { unwanted, prepend = '', excludes } = {}) => {
            const
                tags = [],
                isneeded = str => {
                        for (let i in unwanted)
                            if (str == unwanted[i])
                                return false
                        return true
                    }

            for (let i=0; i<list.length; i++) {
                let tag = list[i].textContent

                for (let i in excludes)
                    tag = tag.replace(excludes[i], '')

                tag = tag
                    .trim()
                    .replace(/,/g, '+')
                    .replace(/\//g, '-')
                    .replace(/ /g, '_')

                if (isneeded(tag) && tag)
                    tags.push(prepend + tag)
            }

            return tags.length ? tags.join(' ') : '0'
        }

    const
        brackets = /\(.+\)/,
        name = [
            tags(doc.querySelectorAll('#tag-list .category-4 .search-tag'), { excludes: [brackets]  }), // characters
            tags(doc.querySelectorAll('#tag-list .category-3 .search-tag'), { unwanted: ['original'] }), // copyrights
            tags(doc.querySelectorAll('#tag-list .category-1 .search-tag')), // artists
            ['danbooru', doc.querySelector('meta[name="post-id"]').content].join(' ')
        ].join(', ')

    if (debug_get_name)
        console.log(name)

    return name
}

  
});


let main_style = "\
        #ES-images { position: fixed; top: 0; right: 5px; width: 125px; height: 100%; overflow-y: auto; z-index:1; display:none }\
        #ES-total { position: fixed; bottom: 5; right: 50px; background: #1d1d1d; padding: 0 5px; opacity: 0.5; z-index:1 }\
        #ES-namefix { position: fixed; bottom: 25; right: 50px; background: #1d1d1d; padding: 0 5px; opacity: 0.5; z-index:1 }\
        #ES-results { position: absolute; top:0; height: 100%; background: #1d1d1d; display: none }\
    "

let head = document.querySelector('head'),
    style = document.createElement("style")

style.type = "text/css"
style.append(main_style)

head.append(style)

'use strict'

let doc_url = new URL(document.location.href),
    debug_rename = 0,
    debug_get_name = 0

function filename (str)
{
   var name = new String(str).substring(str.lastIndexOf('/') + 1);
   return name;
}

function extname (path) {
    var filename = path.split('\\').pop().split('/').pop();
    return filename.substr(( Math.max(0, filename.lastIndexOf(".")) || Infinity) + 1);
}

function insert (target, el, after) {
    let insert = (el) => {
        if (el) {
            if (after) {
                if (target.nextElementSibling)
                    target.parentElement.insertBefore(el, target.nextElementSibling)
                else
                    target.parentElement.append(el)
            } else
                target.parentElement.insertBefore(el, target)
        }
    }

    if (Array.isArray(el))
        for (let i=0; i<el.length; ++i)
            insert(el[i])
    else
        insert(el)
}

function check (fn, success) {
    let t = setInterval(() => {
        if (fn()) {
            clearInterval(t)
            success()
        }
    }, 2000)
}

const
    common = require('common.js')

for (let name in common)
    window[name] = common[name]

// Danbooru Sector
function danbooru () {

function part_posts_id () { // posts id

let options = document.getElementById("post-options").getElementsByTagName("ul")[0],
    image = document.getElementById("image-container").querySelector("#image"),
    image_src = image.src,
    original_src = null,
    postid = document.getElementsByName("post-id")[0].content

let save = function (original, el) {
    let url = original ? original_src : image_src,
        action = el.parentElement.childNodes[1],
        improved_name = get_name(document) + '.' + extname(url)

    var xhr = new XMLHttpRequest()
    xhr.open('GET', url, true)
    xhr.responseType = 'arraybuffer'
    xhr.onprogress = function (evt) {
        let percentComplete = (evt.loaded / evt.total) * 100
        action.innerText = `${Math.floor(percentComplete)}%`
    }
    xhr.onload = function () {
        if (this.status === 200) {
            var blob = new Blob([this.response], { type: xhr.getResponseHeader('Content-Type') })
            var URL = window.URL || window.webkitURL
            var downloadUrl = URL.createObjectURL(blob)

            // use HTML5 a[download] attribute to specify filename
            var a = document.createElement("a")
            a.href = downloadUrl
            a.download = improved_name
            document.body.appendChild(a)
            a.click()

            action.innerText = null
            setTimeout(function () { URL.revokeObjectURL(downloadUrl); }, 100); // cleanup
        }
    }
    xhr.send()

    action.onclick = function () {
        xhr.abort()
        action.innerText = null
    }
}

let info = document.querySelector('#post-information ul li:last-child')

let download = document.createElement('li'),
    download_a = document.createElement('a'),
    download_action = document.createElement('a')

download_action.style.marginLeft = '5px'

download_a.append("Download")
download_a.href = "javascript:"
download_a.onclick = function () {
    save(false, this)
}
download.append(download_a)
download.append(download_action)

let download_original = document.createElement('li'),
    download_original_a = document.createElement('a'),
    download_original_action = document.createElement('a')

download_original_action.style.marginLeft = '5px'

download_original_a.append("Download-Original")
download_original_a.href = "javascript:"
download_original_a.onclick = function () {
    save(true, this)
}
download_original.append(download_original_a)
download_original.append(download_original_action)

insert(info, download_original, true)
insert(info, download, true)

;(() => {
    let list = options.getElementsByTagName("li")
    setTimeout(() => {
        for (idx in list) {
            if ('View original' === list[idx].innerText)
                original_src = list[idx].getElementsByTagName('a')[0].href
        }

        if (!original_src) {
            download_original.remove()
        }

        let image = document.getElementById("image-container").querySelector("#image")
        image.onmouseup = function () {
            window.open(image_src)
        }
    }, 0)
})()

} // part posts id

if (document.location.pathname.match(/posts\/\d+/)) part_posts_id()

function part_posts () {
    let sidebar = document.querySelector('#a-index #sidebar'),
        sidebar_style = sidebar.style

    sidebar_style.cssFloat = 'right'
    document.querySelector('#a-index #content').style.marginLeft = '0px'

    let show = document.createElement('div')
    show.innerHTML = '<h1>Sidebar</h1>'

    sidebar.append(show)

    let sections = document.querySelectorAll('#a-index #sidebar section')

    for (let i=0; i<sections.length; i++) sections[i].style.display = 'none'

    sidebar.onmouseover = () => {
        for (let i=0; i<sections.length; i++) sections[i].style.display = 'block'
    }

    sidebar.onmouseout = () => {
        for (let i=0; i<sections.length; i++) sections[i].style.display = 'none'
    }

    let more = document.querySelector('.paginator menu .more'),
        num = 0
    if (more) {
        num = more.nextElementSibling.querySelector('a').innerText
        if (num == '>>') num = '...'
    } else {
        num = document.querySelector('.paginator menu').lastChild.previousElementSibling.querySelector('a').innerText
    }

    let floatbar = document.createElement('div')
    floatbar.style.position = 'fixed'
    floatbar.style.top = '50%'
    floatbar.style.listStyleType = 'none'
    floatbar.style.color = '#111'

    let li = document.createElement('li'),
        a = document.createElement('a')

    li.append(a)
    a.append('Top')
    a.onclick = () => {
        window.scroll(0,0)
    }
    floatbar.append(li)
    floatbar.append("Pgc " + num)

    document.body.append(floatbar)

} // part posts

if (document.location.pathname == '/posts') part_posts()

function part_artists () { // Find Artists

let tr = document.getElementsByTagName('table')[0].querySelector('tbody').querySelectorAll('tr')

let add_links = () => {
    for (let i=0; i<tr.length; i++) {
        let td = tr[i].querySelector('td')
        let tag = td.querySelector('a').innerText

        let list = document.createElement('a')
        list.append('(posts)')
        list.href = 'https://danbooru.donmai.us/posts?tags=' + tag

        td.append(list)
    }
}

if (doc_url.searchParams.get('listposts') == '✓') {
    if (tr.length == 1) {
        let tag = tr[0].querySelector('td').querySelector('a').innerText
        window.location.replace('https://danbooru.donmai.us/posts?tags=' + tag)
    } else if (tr.length > 1) add_links ()
} else if (tr.length > 0)
    add_links()

} // part artists

if (document.location.pathname.match(/artists$/)) part_artists()

} // danbooru

// Danbooru main()
if (window.location.host == 'danbooru.donmai.us') danbooru()
// End of Danbooru Sector

// Pixiv Sector
var pixiv_li

function pixiv () {

let check_timer
doc_url = new URL(document.location.href)

// clean
if (pixiv_li) pixiv_li.remove()

function danbooru_posts () {

// Test index used
// var i=0; for (let a of document.querySelectorAll("a")) { if (a.href.match(/\/member.php\?id\=/)) { console.log (i,a)} ++i}

// Condition Artist.
let skip = 0, all = document.querySelectorAll("a"), artist
for (let a of all) {
    if (a.href.match(/\/member.php\?id\=/)) ++skip
    // Use a skip(number) to select a target link element in all links.
    if ( document.location.pathname == '/member_illust.php' && skip == 2 ) {
        artist = a // We just need a username to modify.
        break
    }
    if ( document.location.pathname == '/member.php' && skip == 1 ) {
        artist = a.parentNode.nextSibling.firstElementChild.firstElementChild
        break
    }
}

if (!artist) return
// Passed! Cancel timer.
clearInterval(check_timer)

let username = artist.innerText

let li = document.createElement('li'),
    a = document.createElement('a')

li.append(a)
a.append('Danbooru Posts')
a.target = '_blank'
insert(artist, li, true)
pixiv_li = li

// Member.php needed.
a.href = 'https://danbooru.donmai.us/artists'
    + encodeURI("?commit=Search&search[is_active]=true&search[any_name_matches]="
    + username
    + "&utf8=✓&listposts=✓")

// Using Pixiv Url to search on Member_illust.php.
if (document.location.pathname == '/member_illust.php' && doc_url.searchParams.get('illust_id')) {
    // Change URL.
    a.href =
        'https://danbooru.donmai.us/artists' +
        encodeURI("?commit=Search&search[is_active]=true&search[url_matches]=") +
        encodeURIComponent(document.location.href) +
        encodeURI("&utf8=✓&listposts=✓")
}

} // part danbooru_posts

if (document.location.pathname.match(/member_illust.php|member.php/))
    // A check used to test some condition of each second before doing something.
    check_timer = setInterval(danbooru_posts, 1000)
} // pixiv

// Pixiv main()
if (window.location.host == 'www.pixiv.net') {
    let current_page = window.location.href
    // Back, Forward
    window.onpopstate = history.onpushstate = pixiv
    // On url changed
    window.onclick = () => {
        setTimeout(() => {
            if (current_page != window.location.href) {
                current_page = window.location.href
                pixiv()
            }
        }, 1000)
    }
    // Idle
    pixiv()
}
// End of Pixiv Sector