Image Board Enhancer (Rule34, Gelbooru, e621, and more)

Auto Resize images and video on multiple image boards and enlarges thumbnails on mouse hover and adds content type icons to them.

As of 2021-01-30. See the latest version.

// ==UserScript==
// @name        Image Board Enhancer (Rule34, Gelbooru, e621, and more)
// @namespace   ImageBoardEnhancer
// @version     1.3.1
// @description Auto Resize images and video on multiple image boards and enlarges thumbnails on mouse hover and adds content type icons to them.
// @author      DanDanDan
// @match       *://rule34.xxx/*
// @match       *://chan.sankakucomplex.com/*
// @match       *://idol.sankakucomplex.com/*
// @match       *://gelbooru.com/*
// @match       *://danbooru.donmai.us/*
// @match       *://konachan.com/*
// @match       *://konachan.net/*
// @match       *://yande.re/*
// @match       *://safebooru.org/*
// @match       *://rule34.paheal.net/*
// @match       *://rule34hentai.net/*
// @match       *://e621.net/*
// @match       *://e926.net/*
// @match       *://tbib.org/*
// @match       *://behoimi.org/*
// @require     https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js
// @require     https://greasyfork.org/scripts/420841-image-board-enhancer-icons/code/Image%20Board%20Enhancer%20Icons.js?version=895618
// @require     https://greasyfork.org/scripts/420842-vanilla-js-wheel-zoom/code/vanilla-js-wheel-zoom.js?version=895198
// @grant       GM.setValue
// @grant       GM.getValue
// ==/UserScript==

(async () => {
  'use strict';

  try {

    var resizeImageToFit = await GM.getValue('resizeImageToFit', true);
    var resizeVideoToFit = await GM.getValue('resizeVideoToFit', true);
    var autoplayVideos = await GM.getValue('autoplayVideos', true);
    var autoScrollToContent = await GM.getValue('autoScrollToContent', true);
    var updateWithWindowResize = await GM.getValue('updateWithWindowResize', true);
    var updateScrollOnWindowResize = await GM.getValue('updateScrollOnWindowResize', true);
    var showFitButton = await GM.getValue('showFitButton', true);
    var showScrollButton = await GM.getValue('showScrollButton', true);
    var showR34XXXLikeAndFavoriteButtons = await GM.getValue('showR34XXXLikeAndFavoriteButtons', true);
    var removeFluid = await GM.getValue('removeFluid', false);
    var videoVolume = await GM.getValue('videoVolume', 0);
    var enableEnhancedThumbnails = await GM.getValue('enableEnhancedThumbnails', true);
    var alwaysShowScrollbars = await GM.getValue('alwaysShowScrollbars', false);
    var enableZoomableImage = await GM.getValue('enableZoomableImage', true);
    var maxZoom = await GM.getValue('maxZoom', 1);
    var zoomSpeed = await GM.getValue('zoomSpeed', 7);
    var resizeButton = await GM.getValue('resizeButton', 'BracketLeft');
    var scrollButton = await GM.getValue('scrollButton', 'BracketRight');

    var hiddenIcons = await GM.getValue('hiddenIcons', []);

    var customSites = await GM.getValue('customSites', {});

    // Create variables.
    var currentWindowWidth = 0;
    var currentWindowHeight = 0;
    var currentWindowAspect = 0;
    var contentTrueWidth = 0;
    var contentTrueHeight = 0;
    var contentTrueAspect = 0;
    var resizeReady = false;
    var debugMode = false;
    var r34buttons = false;
    var toolbarDOM = '.sidebar form';
    var containerDOM = '#content';
    var imageDOM = '#image';
    var playerDOM;
    var changeKeyboardShortcut = false;
    var containerAlignment = '';
    var thumbnailDOM = '.thumb';
    var thumbnails = [];
    var animationTagIsGif = false;
    var urlParams = new URLSearchParams(window.location.search);
    var unsupportedThumbnailPage = false//(document.location.hostname.toLowerCase() == 'chan.sankakucomplex.com' || document.location.hostname.toLowerCase() == 'idol.sankakucomplex.com');
    var waitingForZoom = false;
    var wzoom;

    // Per-site DOM selection.
    if (document.location.hostname.toLowerCase() == 'rule34.xxx') { toolbarDOM = '.space'; r34buttons = showR34XXXLikeAndFavoriteButtons; playerDOM = '#gelcomVideoContainer'; animationTagIsGif = true; }
    else if (document.location.hostname.toLowerCase() == 'chan.sankakucomplex.com' || document.location.hostname.toLowerCase() == 'idol.sankakucomplex.com') { toolbarDOM = '#search-form'; }
    else if (document.location.hostname.toLowerCase() == 'gelbooru.com') { toolbarDOM = '#tag-list'; containerDOM = '#container'; thumbnailDOM = '.thumbnail-preview'; }
    else if (document.location.hostname.toLowerCase() == 'danbooru.donmai.us') { toolbarDOM = '#search-box'; thumbnailDOM = '.post-preview'; }
    else if (document.location.hostname.toLowerCase() == 'konachan.com' || document.location.hostname.toLowerCase() == 'konachan.net') { animationTagIsGif = true; }
    else if (document.location.hostname.toLowerCase() == 'yande.re') { }
    else if (document.location.hostname.toLowerCase() == 'safebooru.org') { }
    else if (document.location.hostname.toLowerCase() == 'tbib.org') { }
    else if (document.location.hostname.toLowerCase() == 'behoimi.org') { }
    else if (document.location.hostname.toLowerCase() == 'rule34.paheal.net') { toolbarDOM = '#Navigationleft'; containerDOM = 'article'; imageDOM = '#main_image'; containerAlignment = 'margin-left: auto;'; }
    else if (document.location.hostname.toLowerCase() == 'rule34hentai.net') { toolbarDOM = '#Navigationleft'; containerDOM = 'article'; imageDOM = '#main_image'; playerDOM = '#fluid_video_wrapper_video-id'; containerAlignment = 'margin-left: auto;'; }
    else if (document.location.hostname.toLowerCase() == 'e621.net' || document.location.hostname.toLowerCase() == 'e926.net') { toolbarDOM = '#search-box'; thumbnailDOM = '.post-preview'; animationTagIsGif = true; }
    // Custom site DOM selection.
    else if (customSites[document.location.hostname.toLowerCase()]) {
      var obj = customSites[document.location.hostname.toLowerCase()];
      if (debugMode) console.log(obj, 'obj')
      if (obj.toolbarDOM) toolbarDOM = obj.toolbarDOM;
      if (obj.containerDOM) containerDOM = obj.containerDOM;
      if (obj.imageDOM) imageDOM = obj.imageDOM;
      if (obj.thumbnailDOM) thumbnailDOM = obj.thumbnailDOM
      $("body").append("<button id='ibenhancerDeleteConfigButton' style='position: absolute; top: 0px; right: 0px; z-index: 9999999; color: black; background-color: whitesmoke; font-size: 12px;'>Delete site config.</button>");
      $("#ibenhancerDeleteConfigButton").click(deleteSiteConfig);
    }
    // Default site DOM and add setup button.
    else {
      // Add setup button to websites wihtout a config.
      $("body").append("<button id='ibenhancerSetupButton' style='position: absolute; top: 0px; right: 0px; z-index: 9999999; color: black; background-color: whitesmoke; font-size: 12px;'>Setup Image Board Enhancer</button>");
      $("#ibenhancerSetupButton").click(addSiteConfig);
      console.warn('This site is not supported, but may still work.');
    }

    // Add site config.
    function addSiteConfig() {
      var config = JSON.parse(prompt("Enter config in JSON format.", '{"toolbarDOM": ".sidebar form", "containerDOM": "#content", "imageDOM": "#image", "thumbnailDOM": ".thumb" }'));

      if (config === null || !config || config == {}) {
        alert('Config not valid.');
      } else {
        customSites[document.location.hostname.toLowerCase()] = config;
        if (debugMode) console.log(customSites);
        GM.setValue('customSites', customSites);
        alert('Config saved.')
        location.reload();
      }
    }

    // Delete site config.
    function deleteSiteConfig() {
      delete customSites[document.location.hostname.toLowerCase()];
      GM.setValue('customSites', customSites);
      alert('Config deleted.')
      location.reload();
    }

    // Remove the Gelcom Video player.
    function removeFluidPlayer() {
      if (debugMode) console.log('removeFluidPlayer');
      $(playerDOM).replaceWith($(containerDOM + ' video'));
      $(containerDOM + ' video').attr('id', 'image');
      document.querySelector(imageDOM).outerHTML = document.querySelector(imageDOM).outerHTML; // This removes all event listeners, it seems jquery tries to maintain  them.
      $(containerDOM + ' video').removeAttr('style');
      $(containerDOM + ' video').removeAttr('playsinline');
      $(containerDOM + ' video').removeAttr('webkit-playsinline');
      $(containerDOM + ' video').attr('controls', 'true');
      $(containerDOM + ' video').attr('autoplay', autoplayVideos);
    }

    // Get window size and aspect ratio.
    function getWindowProps() {
      if (debugMode) console.log('getWindowProps');
      currentWindowWidth = document.documentElement.clientWidth;
      currentWindowHeight = document.documentElement.clientHeight;
      if (currentWindowWidth !== 0 && currentWindowHeight !== 0)
        currentWindowAspect = currentWindowWidth / currentWindowHeight;
    }

    // Get the real size of the video or image.
    function getContentProps() {
      if (debugMode) console.log('getContentProps');

      if ($(containerDOM + ' video').length) {
        contentTrueWidth = $(containerDOM + ' video')[0].videoWidth;
        contentTrueHeight = $(containerDOM + ' video')[0].videoHeight;
      }

      else if ($(containerDOM + ' ' + imageDOM).length) {
        var screenImage = $(containerDOM + ' ' + imageDOM);
        var theImage = new Image();
        theImage.src = screenImage.attr("src");
        contentTrueWidth = theImage.width;
        contentTrueHeight = theImage.height;
      }

      if (contentTrueWidth !== 0 && contentTrueHeight !== 0)
        contentTrueAspect = contentTrueWidth / contentTrueHeight;
      resizeReady = true;
    }

    // Resize the image (This resizes the video on some sites eg. sankakucomplex.com)
    function resizeImage() {
      if (debugMode) console.log('resizeImage');

      $(containerDOM + ' ' + imageDOM).css('max-width', '');

      if (currentWindowAspect > contentTrueAspect) {
        $(containerDOM + ' ' + imageDOM)[0].width = currentWindowHeight * contentTrueAspect;
        $(containerDOM + ' ' + imageDOM)[0].height = currentWindowHeight;
      }

      else {
        $(containerDOM + ' ' + imageDOM)[0].width = currentWindowWidth;
        $(containerDOM + ' ' + imageDOM)[0].height = currentWindowWidth / contentTrueAspect;
      }

      // Remove css from images.
      $(containerDOM + ' ' + imageDOM).removeAttr('style');
      if (enableZoomableImage && !$(containerDOM + ' video').length) $(containerDOM + ' ' + imageDOM).css({ cursor: 'zoom-in' });
    }

    // Resize Fluid video player.
    function resizeFluidVideo() {
      if (debugMode) console.log('resizeFluidVideo');

      $(containerDOM + ' ' + playerDOM).css('max-width', '');

      if (currentWindowAspect > contentTrueAspect) {
        $(containerDOM + ' ' + playerDOM).css('width', currentWindowHeight * contentTrueAspect);
        $(containerDOM + ' ' + playerDOM).css('height', currentWindowHeight);
      }

      else {
        $(containerDOM + ' ' + playerDOM).css('width', currentWindowWidth);
        $(containerDOM + ' ' + playerDOM).css('height', currentWindowWidth / contentTrueAspect);
      }
    }

    // Resize default video.
    function resizeVideo() {
      if (debugMode) console.log('resizeVideo');

      $(containerDOM + ' video').css('max-width', '');

      if (currentWindowAspect > contentTrueAspect) {
        $(containerDOM + ' video')[0].width = currentWindowHeight * contentTrueAspect;
        $(containerDOM + ' video')[0].height = currentWindowHeight;
      }

      else {
        $(containerDOM + ' video')[0].width = currentWindowWidth;
        $(containerDOM + ' video').height = currentWindowWidth / contentTrueAspect;
      }
    }

    // Scroll the window to the video or image.
    function scrollToContent(delay) {
      if (debugMode) console.log('scrollToContent');

      setTimeout(function () {
        var contentID;

        if ($(containerDOM + ' ' + imageDOM).length) contentID = containerDOM + ' ' + imageDOM;
        else if ($(containerDOM + ' ' + playerDOM).length) contentID = containerDOM + ' ' + playerDOM;
        else if ($(containerDOM + ' video').length) contentID = containerDOM + ' video';

        $([document.documentElement, document.body]).animate({
          scrollTop: $(contentID).offset().top + 1
        }, 0);
        $([document.documentElement, document.body]).animate({
          scrollLeft: $(contentID).offset().left + 1
        }, 0);
      }, delay);

    }

    // Check if resize is ready and what type of content to resize. 
    function fitContent(delay) {
      if (debugMode) console.log('fitContent');
      setTimeout(function () {
        if (resizeReady) {
          getWindowProps();
          if ($(containerDOM + ' ' + imageDOM).length) {
            resizeImage();
          }

          else if ($(containerDOM + ' ' + playerDOM).length) {
            resizeFluidVideo();
          }

          else if ($(containerDOM + ' video').length) {
            resizeVideo();
          }
        }
      }, delay);


    }

    // Set the video auto play and volume settings.
    function videoSettings() {
      if (debugMode) console.log('videoSettings');

      $(containerDOM + ' video').prop('autoplay', autoplayVideos);
      $(containerDOM + ' video').prop('volume', videoVolume);
      $(containerDOM + ' video').prop('loop', true);
      if (autoplayVideos) $(containerDOM + ' video')[0].play(); else $(containerDOM + ' video')[0].pause();
    }

    // Remove the Gelcom player if present.
    if (removeFluid && $(playerDOM).length) removeFluidPlayer();

    // Get the image properties, resize, and scroll as the page is loading. 
    // If the image loads too quickly it wont fire the event.
    if ($(containerDOM + ' video').length || $(containerDOM + ' ' + imageDOM).length) {

      // Show Scrollbars
      if (alwaysShowScrollbars) $('html').css({ overflow: 'scroll' });

      getContentProps();
      if (resizeImageToFit) fitContent(200);
      if (autoScrollToContent) scrollToContent(200);
    }

    // Add event listener to the image or video.
    if ($(containerDOM + ' video').length) {
      if (debugMode) console.log('Create video event listener');

      videoSettings();
      $(containerDOM + ' video').on('loadedmetadata', function () { //NOTE: replaced 'loadedmetadata' with 'canplay'
        getContentProps();
        if (resizeVideoToFit) fitContent(200);
        if (autoScrollToContent) scrollToContent(200);
        $(containerDOM + ' video').play();

      });
    }

    else if ($(containerDOM + ' ' + imageDOM).length) {
      if (debugMode) console.log('Create image event listener');

      $(containerDOM + ' ' + imageDOM).on('load', function () {
        if (waitingForZoom) {
          console.log('Waited for zoom');
          setTimeout(openZoom, 16);
          waitingForZoom = false;
        }
        getContentProps();
        if (resizeImageToFit) fitContent(200);
        if (autoScrollToContent) scrollToContent(200);
      });
    }

    // Add the event listener to the window.
    if (updateWithWindowResize) {
      $(window).resize(function () {
        fitContent(0);
        if (updateScrollOnWindowResize) scrollToContent(0);
      });
    }

    // Setting Functions
    function showSettings() {
      $("#ibenhancerSettings").addClass('show');
      $("#ibenhancerSettings-blocker").addClass('show');
      $("html").addClass('ibenhancerSettingVisible');
    }
    function hideSettings() {
      $("#ibenhancerSettings").removeClass('show');
      $("#ibenhancerSettings-blocker").removeClass('show');
      $("html").removeClass('ibenhancerSettingVisible');

      $("#resizeImageToFitCheckbox").prop('checked', resizeImageToFit);
      $("#resizeVideoToFitCheckbox").prop('checked', resizeVideoToFit);
      $("#autoplayVideosCheckbox").prop('checked', autoplayVideos);
      $("#autoScrollToContentCheckbox").prop('checked', autoScrollToContent);
      $("#updateWithWindowResizeCheckbox").prop('checked', updateWithWindowResize);
      $("#updateScrollOnWindowResizeCheckbox").prop('checked', updateScrollOnWindowResize);
      $("#showFitButtonCheckbox").prop('checked', showFitButton);
      $("#showScrollButtonCheckbox").prop('checked', showScrollButton);
      $("#showR34XXXLikeAndFavoriteButtonsCheckbox").prop('checked', showR34XXXLikeAndFavoriteButtons);
      $("#removeFluidCheckbox").prop('checked', removeFluid);
      $("#enableEnhancedThumbnailsCheckbox").prop('checked', enableEnhancedThumbnails);
      $("#alwaysShowScrollbarsCheckbox").prop('checked', alwaysShowScrollbars);
      $("#enableZoomableImageCheckbox").prop('checked', enableZoomableImage);

      $("#maxZoomInput").val(maxZoom);
      $("#zoomSpeedInput").val(zoomSpeed);
      $("#videoVolumeInput").val(videoVolume);

      $("#hideIconGifCheckbox").prop('checked', hiddenIcons.includes("gif"));
      $("#hideIconVideoCheckbox").prop('checked', hiddenIcons.includes("video"));
      $("#hideIconSoundCheckbox").prop('checked', hiddenIcons.includes("sound"));
      $("#hideIconFlashCheckbox").prop('checked', hiddenIcons.includes("flash"));
      $("#hideIconStraightCheckbox").prop('checked', hiddenIcons.includes("straight"));
      $("#hideIconGayCheckbox").prop('checked', hiddenIcons.includes("gay"));
      $("#hideIconLesbianCheckbox").prop('checked', hiddenIcons.includes("lesbian"));
      $("#hideIconTransCheckbox").prop('checked', hiddenIcons.includes("trans"));
      $("#hideIconTrapCheckbox").prop('checked', hiddenIcons.includes("trap"));
      $("#hideIconThreeDCheckbox").prop('checked', hiddenIcons.includes("threeD"));
      $("#hideIconLoliShotaCheckbox").prop('checked', hiddenIcons.includes("loliShota"));
      $("#hideIconGoreDeathCheckbox").prop('checked', hiddenIcons.includes("goreDeath"));
      $("#hideIconPregnantCheckbox").prop('checked', hiddenIcons.includes("pregnant"));
      $("#hideIconBestialityCheckbox").prop('checked', hiddenIcons.includes("bestiality"));
      $("#hideIconFeetCheckbox").prop('checked', hiddenIcons.includes("feet"));
      $("#hideIconBondageCheckbox").prop('checked', hiddenIcons.includes("bondage"));
      $("#hideIconPoopCheckbox").prop('checked', hiddenIcons.includes("poop"));
      $("#hideIconPissCheckbox").prop('checked', hiddenIcons.includes("piss"));
      $("#hideIconGroupCheckbox").prop('checked', hiddenIcons.includes("group"));
      $("#hideIconIncestCheckbox").prop('checked', hiddenIcons.includes("incest"));
      $("#hideIconSafeCheckbox").prop('checked', hiddenIcons.includes("safe"));
      $("#hideIconQuestionableCheckbox").prop('checked', hiddenIcons.includes("questionable"));
      $("#hideIconExplicitCheckbox").prop('checked', hiddenIcons.includes("explicit"));

    }
    function changeResizeButtonClicked() {
      $('#resizeButton').html('?');
      changeKeyboardShortcut = 'resizeButton';
    }
    function changeScrollButtonClicked() {
      $('#scrollButton').html('?');
      changeKeyboardShortcut = 'scrollButton';
    }
    function saveSettings() {
      GM.setValue('resizeImageToFit', $('#resizeImageToFitCheckbox').is(':checked'));

      GM.setValue('resizeVideoToFit', $('#resizeVideoToFitCheckbox').is(':checked'));

      GM.setValue('autoplayVideos', $('#autoplayVideosCheckbox').is(':checked'));

      GM.setValue('autoScrollToContent', $('#autoScrollToContentCheckbox').is(':checked'));

      GM.setValue('updateScrollOnWindowResize', $('#updateScrollOnWindowResizeCheckbox').is(':checked'));

      GM.setValue('updateWithWindowResize', $('#updateWithWindowResizeCheckbox').is(':checked'));

      GM.setValue('showFitButton', $('#showFitButtonCheckbox').is(':checked'));

      GM.setValue('showScrollButton', $('#showScrollButtonCheckbox').is(':checked'));

      GM.setValue('showR34XXXLikeAndFavoriteButtons', $('#showR34XXXLikeAndFavoriteButtonsCheckbox').is(':checked'));

      GM.setValue('removeFluid', $('#removeFluidCheckbox').is(':checked'));

      GM.setValue('videoVolume', $('#videoVolumeInput').val());

      GM.setValue('enableEnhancedThumbnails', $('#enableEnhancedThumbnailsCheckbox').is(':checked'));

      GM.setValue('alwaysShowScrollbars', $('#alwaysShowScrollbarsCheckbox').is(':checked'));

      GM.setValue('enableZoomableImage', $('#enableZoomableImageCheckbox').is(':checked'));

      GM.setValue('maxZoom', $('#maxZoomInput').val());
      GM.setValue('zoomSpeed', $('#zoomSpeedInput').val());

      GM.setValue('resizeButton', resizeButton);
      GM.setValue('scrollButton', scrollButton);

      var newHiddenIcons = [];

      if($('#hideIconGifCheckbox').is(':checked')) newHiddenIcons.push('gif');
      if($('#hideIconVideoCheckbox').is(':checked')) newHiddenIcons.push('video');
      if($('#hideIconSoundCheckbox').is(':checked')) newHiddenIcons.push('sound');
      if($('#hideIconFlashCheckbox').is(':checked')) newHiddenIcons.push('flash');
      if($('#hideIconStraightCheckbox').is(':checked')) newHiddenIcons.push('straight');
      if($('#hideIconGayCheckbox').is(':checked')) newHiddenIcons.push('gay');
      if($('#hideIconLesbianCheckbox').is(':checked')) newHiddenIcons.push('lesbian');
      if($('#hideIconTransCheckbox').is(':checked')) newHiddenIcons.push('trans');
      if($('#hideIconTrapCheckbox').is(':checked')) newHiddenIcons.push('trap');
      if($('#hideIconThreeDCheckbox').is(':checked')) newHiddenIcons.push('threeD');
      if($('#hideIconLoliShotaCheckbox').is(':checked')) newHiddenIcons.push('loliShota');
      if($('#hideIconGoreDeathCheckbox').is(':checked')) newHiddenIcons.push('goreDeath');
      if($('#hideIconPregnantCheckbox').is(':checked')) newHiddenIcons.push('pregnant');
      if($('#hideIconBestialityCheckbox').is(':checked')) newHiddenIcons.push('bestiality');
      if($('#hideIconFeetCheckbox').is(':checked')) newHiddenIcons.push('feet');
      if($('#hideIconBondageCheckbox').is(':checked')) newHiddenIcons.push('bondage');
      if($('#hideIconPoopCheckbox').is(':checked')) newHiddenIcons.push('poop');
      if($('#hideIconPissCheckbox').is(':checked')) newHiddenIcons.push('piss');
      if($('#hideIconGroupCheckbox').is(':checked')) newHiddenIcons.push('group');
      if($('#hideIconIncestCheckbox').is(':checked')) newHiddenIcons.push('incest');
      if($('#hideIconSafeCheckbox').is(':checked')) newHiddenIcons.push('safe');
      if($('#hideIconQuestionableCheckbox').is(':checked')) newHiddenIcons.push('questionable');
      if($('#hideIconExplicitCheckbox').is(':checked')) newHiddenIcons.push('explicit');

      GM.setValue('hiddenIcons', newHiddenIcons);

      location.reload();
    }

    function hideAllIcons() {
      $("#hideIconGifCheckbox").prop('checked', true);
      $("#hideIconVideoCheckbox").prop('checked', true);
      $("#hideIconSoundCheckbox").prop('checked', true);
      $("#hideIconFlashCheckbox").prop('checked', true);
      $("#hideIconStraightCheckbox").prop('checked', true);
      $("#hideIconGayCheckbox").prop('checked', true);
      $("#hideIconLesbianCheckbox").prop('checked', true);
      $("#hideIconTransCheckbox").prop('checked', true);
      $("#hideIconTrapCheckbox").prop('checked', true);
      $("#hideIconThreeDCheckbox").prop('checked', true);
      $("#hideIconLoliShotaCheckbox").prop('checked', true);
      $("#hideIconGoreDeathCheckbox").prop('checked', true);
      $("#hideIconPregnantCheckbox").prop('checked', true);
      $("#hideIconBestialityCheckbox").prop('checked', true);
      $("#hideIconFeetCheckbox").prop('checked', true);
      $("#hideIconBondageCheckbox").prop('checked', true);
      $("#hideIconPoopCheckbox").prop('checked', true);
      $("#hideIconPissCheckbox").prop('checked', true);
      $("#hideIconGroupCheckbox").prop('checked', true);
      $("#hideIconIncestCheckbox").prop('checked', true);
      $("#hideIconSafeCheckbox").prop('checked', true);
      $("#hideIconQuestionableCheckbox").prop('checked', true);
      $("#hideIconExplicitCheckbox").prop('checked', true);
    }
    function unhideAllIcons() {
      $("#hideIconGifCheckbox").prop('checked', false);
      $("#hideIconVideoCheckbox").prop('checked', false);
      $("#hideIconSoundCheckbox").prop('checked', false);
      $("#hideIconFlashCheckbox").prop('checked', false);
      $("#hideIconStraightCheckbox").prop('checked', false);
      $("#hideIconGayCheckbox").prop('checked', false);
      $("#hideIconLesbianCheckbox").prop('checked', false);
      $("#hideIconTransCheckbox").prop('checked', false);
      $("#hideIconTrapCheckbox").prop('checked', false);
      $("#hideIconThreeDCheckbox").prop('checked', false);
      $("#hideIconLoliShotaCheckbox").prop('checked', false);
      $("#hideIconGoreDeathCheckbox").prop('checked', false);
      $("#hideIconPregnantCheckbox").prop('checked', false);
      $("#hideIconBestialityCheckbox").prop('checked', false);
      $("#hideIconFeetCheckbox").prop('checked', false);
      $("#hideIconBondageCheckbox").prop('checked', false);
      $("#hideIconPoopCheckbox").prop('checked', false);
      $("#hideIconPissCheckbox").prop('checked', false);
      $("#hideIconGroupCheckbox").prop('checked', false);
      $("#hideIconIncestCheckbox").prop('checked', false);
      $("#hideIconSafeCheckbox").prop('checked', false);
      $("#hideIconQuestionableCheckbox").prop('checked', false);
      $("#hideIconExplicitCheckbox").prop('checked', false);
    }

    // Create the toolbar.
    if ($(containerDOM + ' ' + imageDOM).length || $(containerDOM + ' video').length) {
      if (debugMode) console.log('Create toolbar');

      $(toolbarDOM).after("<div id='ibenhancer'>Image Board Enhancer<br></div>");

      if (showFitButton) {
        $("#ibenhancer").append("<button id='fitContentButton' style='margin-top: 3px;'>Fit</button>");
        $("#fitContentButton").click(function () { getContentProps(); fitContent(0); });
      }

      if (showScrollButton) {
        $("#ibenhancer").append("<button id='scrollContentButton' style='margin-top: 3px;'>Scroll</button>");
        $("#scrollContentButton").click(scrollToContent);
      }

      // Create settings.
      $("#ibenhancer").append("<br><button id='ibenhancerSettingsButton' style='margin-top: 3px;'>Settings</button>");
      $("#ibenhancerSettingsButton").click(showSettings);
      $("#ibenhancer").append(`
        <div id="ibenhancerSettings-blocker"></div>
        <div id="ibenhancerSettings">
          <div id="ibenhancerSettings-options">
            <label><input id="resizeImageToFitCheckbox" type="checkbox" ` + (resizeImageToFit ? `checked` : ``) + `>Resize images to fit screen.</label>
            <br>
            <label><input id="resizeVideoToFitCheckbox" type="checkbox" ` + (resizeVideoToFit ? `checked` : ``) + `>Resize videos to fit screen.</label>
            <br>
            <label><input id="autoplayVideosCheckbox" type="checkbox" ` + (autoplayVideos ? `checked` : ``) + `>Autoplay videos.</label>
            <br>
            <label><input id="autoScrollToContentCheckbox" type="checkbox" ` + (autoScrollToContent ? `checked` : ``) + `>Scroll to content.</label>
            <br>
            <label><input id="updateWithWindowResizeCheckbox" type="checkbox" ` + (updateWithWindowResize ? `checked` : ``) + `>Resize content with window.</label>
            <br>
            <label><input id="updateScrollOnWindowResizeCheckbox" type="checkbox" ` + (updateScrollOnWindowResize ? `checked` : ``) + `>Scroll to content on window resize.</label>
            <br>
            <label><input id="showFitButtonCheckbox" type="checkbox" ` + (showFitButton ? `checked` : ``) + `>Show fit button.</label>
            <br>
            <label><input id="showScrollButtonCheckbox" type="checkbox" ` + (showScrollButton ? `checked` : ``) + `>Show scroll button.</label>
            <br>
            <label><input id="showR34XXXLikeAndFavoriteButtonsCheckbox" type="checkbox" ` + (showR34XXXLikeAndFavoriteButtons ? `checked` : ``) + `>Show like and favorite buttons on rule34.xxx.</label>
            <br>
            <label><input id="removeFluidCheckbox" type="checkbox" ` + (removeFluid ? `checked` : ``) + `>Remove fluid video player.</label>
            <br>
            <label><input id="enableEnhancedThumbnailsCheckbox" type="checkbox" ` + (enableEnhancedThumbnails ? `checked` : ``) + `>Enable enhanced thumbnails.</label>
            <br>
            <label><input id="alwaysShowScrollbarsCheckbox" type="checkbox" ` + (alwaysShowScrollbars ? `checked` : ``) + `>Always show scrollbars. (Fixes resize issue.)</label>
            <br>
            <label><input id="enableZoomableImageCheckbox" type="checkbox" ` + (enableZoomableImage ? `checked` : ``) + `>Enable zoomable image.</label>
            <br>
            <label>Max zoom: <input id="maxZoomInput" type="number" min="1" max="5" step="1" value="` + maxZoom + `" style="width:60px;">1 - 5</label>
            <br>
            <label>Zoom speed: <input id="zoomSpeedInput" type="number" min="1" max="15" step="1" value="` + zoomSpeed + `" style="width:60px;">1 - 15</label>
            <br>
            <label>Video volume: <input id="videoVolumeInput" type="number" min="0" max="1" step="0.01" value="` + videoVolume + `" style="width:60px;">0 - 1</label>
            <br>
            <label>Resize keyboard shurtcut: <button id="resizeButton">` + resizeButton + `</button></label>
            <br>
            <label>Scroll keyboard shurtcut: <button id="scrollButton">` + scrollButton + `</button></label>
            <br>
            Hide icons: <button id="hideAllIconsButton">Hide All</button> <button id="unhideAllIconsButton">Unhide All</button>
            <br>
            <label><input id="hideIconGifCheckbox" type="checkbox" ` + (hiddenIcons.includes("gif") ? `checked` : ``) + `>GIF</label>
            <label><input id="hideIconVideoCheckbox" type="checkbox" ` + (hiddenIcons.includes("video") ? `checked` : ``) + `>Video</label>
            <label><input id="hideIconSoundCheckbox" type="checkbox" ` + (hiddenIcons.includes("sound") ? `checked` : ``) + `>Sound</label>
            <label><input id="hideIconFlashCheckbox" type="checkbox" ` + (hiddenIcons.includes("flash") ? `checked` : ``) + `>Flash</label>
            <label><input id="hideIconStraightCheckbox" type="checkbox" ` + (hiddenIcons.includes("straight") ? `checked` : ``) + `>Straight</label>
            <label><input id="hideIconGayCheckbox" type="checkbox" ` + (hiddenIcons.includes("gay") ? `checked` : ``) + `>Yaoi/Gay</label>
            <label><input id="hideIconLesbianCheckbox" type="checkbox" ` + (hiddenIcons.includes("lesbian") ? `checked` : ``) + `>Yuri/Lesbian</label>
            <label><input id="hideIconTransCheckbox" type="checkbox" ` + (hiddenIcons.includes("trans") ? `checked` : ``) + `>Futanari/Transsexual</label>
            <label><input id="hideIconTrapCheckbox" type="checkbox" ` + (hiddenIcons.includes("trap") ? `checked` : ``) + `>Trap</label>
            <label><input id="hideIconThreeDCheckbox" type="checkbox" ` + (hiddenIcons.includes("threeD") ? `checked` : ``) + `>3D</label>
            <label><input id="hideIconLoliShotaCheckbox" type="checkbox" ` + (hiddenIcons.includes("loliShota") ? `checked` : ``) + `>Loli/Shota</label>
            <label><input id="hideIconGoreDeathCheckbox" type="checkbox" ` + (hiddenIcons.includes("goreDeath") ? `checked` : ``) + `>Gore/Death</label>
            <label><input id="hideIconPregnantCheckbox" type="checkbox" ` + (hiddenIcons.includes("pregnant") ? `checked` : ``) + `>Pregnant</label>
            <label><input id="hideIconBestialityCheckbox" type="checkbox" ` + (hiddenIcons.includes("bestiality") ? `checked` : ``) + `>Bestiality</label>
            <label><input id="hideIconFeetCheckbox" type="checkbox" ` + (hiddenIcons.includes("feet") ? `checked` : ``) + `>Feet/Footjob</label>
            <label><input id="hideIconBondageCheckbox" type="checkbox" ` + (hiddenIcons.includes("bondage") ? `checked` : ``) + `>Bondage/BDSM</label>
            <label><input id="hideIconPoopCheckbox" type="checkbox" ` + (hiddenIcons.includes("poop") ? `checked` : ``) + `>Scat</label>
            <label><input id="hideIconPissCheckbox" type="checkbox" ` + (hiddenIcons.includes("piss") ? `checked` : ``) + `>Piss/Golden Shower</label>
            <label><input id="hideIconGroupCheckbox" type="checkbox" ` + (hiddenIcons.includes("group") ? `checked` : ``) + `>Group Sex/Gangbang</label>
            <label><input id="hideIconIncestCheckbox" type="checkbox" ` + (hiddenIcons.includes("incest") ? `checked` : ``) + `>Incest</label>
            <label><input id="hideIconSafeCheckbox" type="checkbox" ` + (hiddenIcons.includes("safe") ? `checked` : ``) + `>Rating: Safe</label>
            <label><input id="hideIconQuestionableCheckbox" type="checkbox" ` + (hiddenIcons.includes("questionable") ? `checked` : ``) + `>Rating: Questionable</label>
            <label><input id="hideIconExplicitCheckbox" type="checkbox" ` + (hiddenIcons.includes("explicit") ? `checked` : ``) + `>Rating: Explicit</label>
          </div>
          <button id="ibenhancerSettingsSave">Save</button><button id="ibenhancerSettingsCancel">Cancel</button>
          <a href="https://icons8.com/">Icons by Icons8</a>
        </div>
      ` );

      $("#ibenhancerSettingsSave").click(saveSettings);
      $("#ibenhancerSettingsCancel").click(hideSettings);
      $("#resizeButton").click(changeResizeButtonClicked);
      $("#scrollButton").click(changeScrollButtonClicked);

      $("#hideAllIconsButton").click(hideAllIcons);
      $("#unhideAllIconsButton").click(unhideAllIcons);


      addGlobalStyle(`
        html.ibenhancerSettingVisible {
          overflow: hidden !important;
        }
        #ibenhancer {
          background: white !important;
          color: black !important;
          border: solid 1px grey;
          border-radius: 4px;
          padding: 5px;
          width: 170px;
          text-align: center !important;
          margin-top: 5px;
          margin-bottom: 5px;
          margin-right: auto;
          ` + containerAlignment + `
        }
        #ibenhancer, #ibenhancer label {
          font-size: 15px !important;
          font-family: Arial, Helvetica, sans-serif !important;
          font-style: normal !important;
          font-weight: normal !important;
        }
        #ibenhancerSettings-blocker {
          position: fixed;
          content: '';
          background-color: rgba(0, 0, 0, .5);
          width: 100vw;
          height: 100vh;
          top: 0;
          left: 0;
          z-index: 1;
          display: none;
        }
        #ibenhancerSettings-blocker.show {
          display: block;
        }
        #ibenhancerSettings {
          position: fixed;
          width: 400px;
          height: 400px;
          left: calc(50vw - 155px);
          top: calc(50vh - 165px);
          background-color: white;
          border: 2px solid black;
          border-radius: 3px;
          padding: 10px;
          text-align: left;
          z-index: 999999;
          display: none;
          -webkit-box-sizing: unset;
          -moz-box-sizing: unset;
          box-sizing: unset;
          color: black;
          padding-bottom: 0px;
        }
        #ibenhancerSettings-options {
          overflow-y: auto;
          overflow-x: hidden;
          width: 100%;
          height: calc(100% - 32px);
        }
        #ibenhancerSettings input {
          margin: 5px;
          width: auto;
        }
        #ibenhancerSettings input[type=number] {
          border: solid 1px darkgrey;
        }
        #ibenhancer button {
          padding: 3px !important;
          width: auto;
          border: solid 1px darkgrey !important;
          margin: 2px !important;
          border-radius 2px !important;
          background: WhiteSmoke !important;
          cursor: pointer;
        }
        #ibenhancerSettings.show {
          display: block;
        }
        #fitContentButton {
          width: 73px !important;
        }
        #scrollContentButton {
          width: 73px !important;
        }
        #ibenhancerSettingsButton {
          width: 150px !important;
        }
			`);

      // Add the like and favorite button to rule34.xxx
      if (r34buttons) {
        if (debugMode) console.log('r34buttons');


        $("#ibenhancer").append('<br><img id="like-butt" class="custom-button" src="' + likeButtonImage + '" alt="like"><img id="favorite-butt" class="custom-button" src="' + favoriteButtonImage + '" alt="favorite">');
        $("#like-butt").click(function () {
          $("#stats > ul > li:contains('(vote up)') > a:contains('up')").click();
        });
        $("#favorite-butt").click(function () {
          $("#stats + div > ul > li > a:contains('Add to favorites')").click();
        });

        addGlobalStyle(`
          img.custom-button {
            cursor: pointer;
            width: 35px;
            padding: 3px;
            margin: 0;
            border-radius: 20px;
          }
          .custom-button:hover {
            background-color: rgba(255,255,255,.5);
          }
          .custom-button:active {
            background-color: rgba(255,255,255,1);
          }
			  `);
      }
    }

    function addGlobalStyle(css) {
      if (debugMode) console.log('addGlobalStyle');
      var head, style;
      head = document.getElementsByTagName('head')[0];
      if (!head) { return; }
      style = document.createElement('style');
      style.type = 'text/css';
      style.innerHTML = css;
      head.appendChild(style);
    }

    // Keyboard shortcuts
    document.addEventListener('keyup', (e) => {
      if (debugMode) console.log(e.code)
      if (!changeKeyboardShortcut) {
        if (e.code === resizeButton) { getContentProps(0); fitContent(0); }
        else if (e.code === scrollButton) scrollToContent(0);
      }
      else if (changeKeyboardShortcut == 'resizeButton') {
        resizeButton = e.code;
        $('#resizeButton').html(e.code);
        changeKeyboardShortcut = false;
      }
      else if (changeKeyboardShortcut == 'scrollButton') {
        scrollButton = e.code;
        $('#scrollButton').html(e.code);
        changeKeyboardShortcut = false;
      }
    });

    if (urlParams.get('page') && urlParams.get('page').toLowerCase() == 'favorites') unsupportedThumbnailPage = true; // Add method to remove favorite.

    // Get Thumbnails
    if (enableEnhancedThumbnails) thumbnails = $(thumbnailDOM);

    function checkForMoreThumbnails() {
      var oldNumber = thumbnails.length;
      thumbnails = $(thumbnailDOM);
      return (thumbnails.length > oldNumber);
    }

    if (!unsupportedThumbnailPage && thumbnails.length > 0) {
      $('body').append(`
        <a href="#" id="thumbPlusPreviewLink" style="">
          <div id="thumbPlusPreview" class="">
            <div id="thumbPlusPreviewImage"></div>
            <div style="position: relative;">
              <span id="thumbPlusPreviewGif" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("gif") ? `` : `show`) + `" title="GIF">` + icons['gif'] + `</span>
              <span id="thumbPlusPreviewVideo" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("video") ? `` : `show`) + `" title="Video">` + icons['video'] + `</span>
              <span id="thumbPlusPreviewFlash" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("flash") ? `` : `show`) + `" title="Flash Animation">` + icons['flash'] + `</span>
              <span id="thumbPlusPreviewSound" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("sound") ? `` : `show`) + `" title="Has Sound">` + icons['sound'] + `</span>
              <span id="thumbPlusPreview3D" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("threeD") ? `` : `show`) + `" title="3D">` + icons['threeD'] + `</span>
              <span id="thumbPlusPreviewStraight" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("straight") ? `` : `show`) + `" title="Straight">` + icons['straight'] + `</span>
              <span id="thumbPlusPreviewGay" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("gay") ? `` : `show`) + `" title="Yaoi/Gay">` + icons['gay'] + `</span>
              <span id="thumbPlusPreviewLesbian" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("lesbian") ? `` : `show`) + `" title="Yuri/Lesbian">` + icons['lesbian'] + `</span>
              <span id="thumbPlusPreviewTrans" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("trans") ? `` : `show`) + `" title="Futanari/Transsexual">` + icons['trans'] + `</span>
              <span id="thumbPlusPreviewTrap" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("trap") ? `` : `show`) + `" title="Trap">` + icons['trap'] + `</span>
              <span id="thumbPlusPreviewLoliShota" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("loliShota") ? `` : `show`) + `" title="Loli/Shota">` + icons['loliShota'] + `</span>
              <span id="thumbPlusPreviewGoreDeath" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("goreDeath") ? `` : `show`) + `" title="Gore/Death">` + icons['goreDeath'] + `</span>
              <span id="thumbPlusPreviewPregnant" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("pregnant") ? `` : `show`) + `" title="Pregnant">` + icons['pregnant'] + `</span>
              <span id="thumbPlusPreviewBestiality" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("bestiality") ? `` : `show`) + `" title="Bestiality">` + icons['bestiality'] + `</span>
              <span id="thumbPlusPreviewFeet" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("feet") ? `` : `show`) + `" title="Feet/Footjob">` + icons['feet'] + `</span>
              <span id="thumbPlusPreviewBondage" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("bondage") ? `` : `show`) + `" title="Bondage/BDSM">` + icons['bondage'] + `</span>
              <span id="thumbPlusPreviewPoop" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("poop") ? `` : `show`) + `" title="Scat">` + icons['poop'] + `</span>
              <span id="thumbPlusPreviewPiss" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("piss") ? `` : `show`) + `" title="Piss/Golden Shower">` + icons['piss'] + `</span>
              <span id="thumbPlusPreviewGroup" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("group") ? `` : `show`) + `" title="Group Sex/Gangbang">` + icons['group'] + `</span>
              <span id="thumbPlusPreviewIncest" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("incest") ? `` : `show`) + `" title="Incest">` + icons['incest'] + `</span>
              <span id="thumbPlusPreviewSafe" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("safe") ? `` : `show`) + `" title="Rating: Safe">` + icons['safe'] + `</span>
              <span id="thumbPlusPreviewQuestionable" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("questionable") ? `` : `show`) + `" title="Rating: Questionable">` + icons['questionable'] + `</span>
              <span id="thumbPlusPreviewExplicit" class="thumbPlusPreviewIcon ` + (hiddenIcons.includes("explicit") ? `` : `show`) + `" title="Rating: Explicit">` + icons['explicit'] + `</span>
            </div>
          </div>
        </a>
      `);
      $('#thumbPlusPreview').css({ backgroundColor: $('body').css("background-color") != "rgba(0, 0, 0, 0)" ? $('body').css("background-color") : 'white' });
      $('#thumbPlusPreviewContextMenuRemoveFavorite').click(function () { alert('Clicked') });
      $('#thumbPlusPreview').mouseout(function () {

        $('#thumbPlusPreviewLink').removeClass('show');
        $('#thumbPlusPreview').removeClass('show gif video sound flash straight gay lesbian trans threed trap lolishota gore pregnant bestiality feet bondage poop piss group incest safe questionable explicit');
      })

      function addThumbnailEnhancement() {
        if (debugMode) console.log('Add thumbnails');
        if (enableEnhancedThumbnails) thumbnails = $(thumbnailDOM);

        var tmp = 0;
        thumbnails.each(function () {
          if (!$(this).hasClass('ibeThumbnail')) {
            $(this).mouseover(function (e) {
              thumbnailMouseOver(this);
            })
            $(this).addClass('ibeThumbnail');
            tmp++;
          }
        });
        console.log('Added', tmp, 'thumbnails.');
      }

      addThumbnailEnhancement();
      setInterval(function () {
        if (checkForMoreThumbnails()) addThumbnailEnhancement()
      }, 100);

      function thumbnailMouseOver(thumb) {
        
        if ($('img', thumb).attr('oldtitle') && $('img', thumb).attr('oldtitle') != '') // oldtitle is used for gelbooru
          var title = $('img', thumb).attr('oldtitle');
        else
          var title = $('img', thumb).attr('title');

        var tags = title.split(' ');

        for (let i = 0; i < tags.length; i++) {
          tags[i] = tags[i].toLowerCase().split(',').join('');
        }

        if (tags.includes("webm")) $('#thumbPlusPreview').addClass('video');
        else if (tags.includes("mp4")) $('#thumbPlusPreview').addClass('video');
        else if (tags.includes("animated_gif")) $('#thumbPlusPreview').addClass('gif');
        else if (tags.includes("flash")) $('#thumbPlusPreview').addClass('flash');
        else if (tags.includes("flash_animation")) $('#thumbPlusPreview').addClass('flash');
        else if (tags.includes("video")) $('#thumbPlusPreview').addClass('video');
        else if (tags.includes("animated") && animationTagIsGif && !tags.includes("sound")) $('#thumbPlusPreview').addClass('gif');
        else if (tags.includes("animated")) $('#thumbPlusPreview').addClass('video');

        if (tags.includes("sound")) $('#thumbPlusPreview').addClass('sound');
        else if (tags.includes("audio")) $('#thumbPlusPreview').addClass('sound');
        else if (tags.includes("has_sound")) $('#thumbPlusPreview').addClass('sound');
        else if (tags.includes("has_audio")) $('#thumbPlusPreview').addClass('sound');
        else if (tags.includes("video_with_sound")) $('#thumbPlusPreview').addClass('sound');

        if (tags.includes("hetero")) $('#thumbPlusPreview').addClass('straight');
        else if (tags.includes("straight")) $('#thumbPlusPreview').addClass('straight');
        else if (tags.includes("male/female")) $('#thumbPlusPreview').addClass('straight');

        if (tags.includes("yaoi")) $('#thumbPlusPreview').addClass('gay');
        else if (tags.includes("gay")) $('#thumbPlusPreview').addClass('gay');
        else if (tags.includes("male/male")) $('#thumbPlusPreview').addClass('gay');

        if (tags.includes("yuri")) $('#thumbPlusPreview').addClass('lesbian');
        else if (tags.includes("lesbian")) $('#thumbPlusPreview').addClass('lesbian');
        else if (tags.includes("female/female")) $('#thumbPlusPreview').addClass('lesbian');

        if (tags.includes("futanari")) $('#thumbPlusPreview').addClass('trans');
        else if (tags.includes("newhalf")) $('#thumbPlusPreview').addClass('trans');
        else if (tags.includes("dickgirl")) $('#thumbPlusPreview').addClass('trans');
        else if (tags.includes("shemale")) $('#thumbPlusPreview').addClass('trans');
        else if (tags.includes("intersex")) $('#thumbPlusPreview').addClass('trans');

        if (tags.includes("trap")) $('#thumbPlusPreview').addClass('trap');
        else if (tags.includes("otoko no ko")) $('#thumbPlusPreview').addClass('trap');

        if (tags.includes("3d")) $('#thumbPlusPreview').addClass('threed');

        if (tags.includes("loli")) $('#thumbPlusPreview').addClass('lolishota');
        else if (tags.includes("shota")) $('#thumbPlusPreview').addClass('lolishota');

        if (tags.includes("guro")) $('#thumbPlusPreview').addClass('gore');
        else if (tags.includes("gore")) $('#thumbPlusPreview').addClass('gore');
        else if (tags.includes("death")) $('#thumbPlusPreview').addClass('gore');
        else if (tags.includes("snuf")) $('#thumbPlusPreview').addClass('gore');

        if (tags.includes("pregnant")) $('#thumbPlusPreview').addClass('pregnant');
        else if (tags.includes("pregnant_futa")) $('#thumbPlusPreview').addClass('pregnant');
        else if (tags.includes("pregnant_loli")) $('#thumbPlusPreview').addClass('pregnant');

        if (tags.includes("bestiality")) $('#thumbPlusPreview').addClass('bestiality');

        // A lot seem to be tagged with feet when it is not the main focus and many foot fetish posts are only tagged as feet.
        if (tags.includes("foot_fetish")) $('#thumbPlusPreview').addClass('feet');
        else if (tags.includes("pov_feet")) $('#thumbPlusPreview').addClass('feet');
        else if (tags.includes("foot_focus")) $('#thumbPlusPreview').addClass('feet');
        else if (tags.includes("foot_worship")) $('#thumbPlusPreview').addClass('feet');
        else if (tags.includes("footjob")) $('#thumbPlusPreview').addClass('feet');
        else if (tags.includes("ashikoki")) $('#thumbPlusPreview').addClass('feet');
        // else if (tags.includes("feet")) $('#thumbPlusPreview').addClass('feet');

        if (tags.includes("bondage")) $('#thumbPlusPreview').addClass('bondage');
        else if (tags.includes("bdsm")) $('#thumbPlusPreview').addClass('bondage');

        if (tags.includes("scat")) $('#thumbPlusPreview').addClass('poop');
        else if (tags.includes("defecating")) $('#thumbPlusPreview').addClass('poop');
        else if (tags.includes("feces")) $('#thumbPlusPreview').addClass('poop');
        else if (tags.includes("coprophagia")) $('#thumbPlusPreview').addClass('poop');
        else if (tags.includes("soiling")) $('#thumbPlusPreview').addClass('poop');

        if (tags.includes("urine")) $('#thumbPlusPreview').addClass('piss');
        else if (tags.includes("urinating")) $('#thumbPlusPreview').addClass('piss');
        else if (tags.includes("peeing")) $('#thumbPlusPreview').addClass('piss');
        else if (tags.includes("golden_shower")) $('#thumbPlusPreview').addClass('piss');
        else if (tags.includes("watersports")) $('#thumbPlusPreview').addClass('piss');

        if (tags.includes("group_sex")) $('#thumbPlusPreview').addClass('group');
        else if (tags.includes("gangbang")) $('#thumbPlusPreview').addClass('group');
        else if (tags.includes("threesome")) $('#thumbPlusPreview').addClass('group');
        else if (tags.includes("orgy")) $('#thumbPlusPreview').addClass('group');
        else if (tags.includes("foursome")) $('#thumbPlusPreview').addClass('group');

        if (tags.includes("incest")) $('#thumbPlusPreview').addClass('incest');

        if (tags.includes("rating:safe")) $('#thumbPlusPreview').addClass('safe');
        else if (tags.includes("safe")) $('#thumbPlusPreview').addClass('safe');
        else if (tags.includes("rating:questionable")) $('#thumbPlusPreview').addClass('questionable');
        else if (tags.includes("questionable")) $('#thumbPlusPreview').addClass('questionable');
        else if (tags.includes("rating:explicit")) $('#thumbPlusPreview').addClass('explicit');
        else if (tags.includes("explicit")) $('#thumbPlusPreview').addClass('explicit');

        $('#thumbPlusPreviewLink').css({ top: cumulativeOffset(thumb).top, left: cumulativeOffset(thumb).left });
        $('#thumbPlusPreviewImage').css({ backgroundImage: 'url(' + $('img', thumb).attr('src') + ')' });
        $('#thumbPlusPreviewImage').attr('title', title);

        var height = $('img', thumb).height() * 1.555;
        if (height) $('#thumbPlusPreviewImage').css({ height: $('img', thumb).height() * 1.555 });

        if ($(thumb).attr('href'))
          $('#thumbPlusPreviewLink').attr('href', $(thumb).attr('href'));
        else
          $('#thumbPlusPreviewLink').attr('href', $('a', thumb).attr('href'));

        $('#thumbPlusPreviewLink').addClass('show');
      }
      addGlobalStyle(`
        #thumbPlusPreviewLink {
          background-color: white;
          position: absolute;
          top: 0px;
          left: 0px;
          display: none;
          z-index: 999999;
        }
        #thumbPlusPreviewLink.show {
          display: block;
        }
        #thumbPlusPreview {
          display: flex;
          top: 0;
          left: 0;
          border: 2px solid black;
          border-radius: 5px;
          flex-direction: column !important;
          align-content: center !important;
          justify-content: center !important;
          align-items: center !important;
          flex-grow: 4 !important; 
          margin-left: -50px;
          margin-top: -50px;
          width: 280px;
          min-height: 280px;
          max-height: 380px;
        }
        #thumbPlusPreviewImage {
          width: calc(100% * 0.833);
          height: calc(100% * 0.833);
          margin-left: auto;
          margin-right: auto;
          background-repeat: no-repeat;
          background-position: center top;
          background-size: contain;
        }
        .thumbPlusPreviewIcon {
          display: none;
          height: 32px;
          width: 32px;
          background-color: #fff5;
          border-radius: 3px;
          padding: 0px;
        }
        #thumbPlusPreview.gif #thumbPlusPreviewGif.show,
        #thumbPlusPreview.video #thumbPlusPreviewVideo.show,
        #thumbPlusPreview.sound #thumbPlusPreviewSound.show,
        #thumbPlusPreview.flash #thumbPlusPreviewFlash.show,
        #thumbPlusPreview.straight #thumbPlusPreviewStraight.show,
        #thumbPlusPreview.gay #thumbPlusPreviewGay.show,
        #thumbPlusPreview.lesbian #thumbPlusPreviewLesbian.show,
        #thumbPlusPreview.trans #thumbPlusPreviewTrans.show,
        #thumbPlusPreview.trap #thumbPlusPreviewTrap.show,
        #thumbPlusPreview.threed #thumbPlusPreview3D.show,
        #thumbPlusPreview.lolishota #thumbPlusPreviewLoliShota.show,
        #thumbPlusPreview.gore #thumbPlusPreviewGoreDeath.show,
        #thumbPlusPreview.pregnant #thumbPlusPreviewPregnant.show,
        #thumbPlusPreview.bestiality #thumbPlusPreviewBestiality.show,
        #thumbPlusPreview.feet #thumbPlusPreviewFeet.show,
        #thumbPlusPreview.bondage #thumbPlusPreviewBondage.show,
        #thumbPlusPreview.poop #thumbPlusPreviewPoop.show,
        #thumbPlusPreview.piss #thumbPlusPreviewPiss.show,
        #thumbPlusPreview.group #thumbPlusPreviewGroup.show,
        #thumbPlusPreview.incest #thumbPlusPreviewIncest.show,
        #thumbPlusPreview.safe #thumbPlusPreviewSafe.show,
        #thumbPlusPreview.questionable #thumbPlusPreviewQuestionable.show,
        #thumbPlusPreview.explicit #thumbPlusPreviewExplicit.show {
          display: inline-block;
        }
	    `);
    }

    var xIcon = '<svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewBox="0 0 24 24"><path d="M24 20.188l-8.315-8.209 8.2-8.282-3.697-3.697-8.212 8.318-8.31-8.203-3.666 3.666 8.321 8.24-8.206 8.313 3.666 3.666 8.237-8.318 8.285 8.203z"/></svg>';

    function closeZoom() {
      $("#IBEZoomableImageContainer").remove();
      if (alwaysShowScrollbars)
        $("html").css({ overflowX: 'scroll', overflowY: 'scroll' });
      else
        $("html").css({ overflowX: 'auto', overflowY: 'auto' });
    }

    function openZoom() {
      addZoomable();
      $("html").css({ overflowX: 'hidden', overflowY: 'hidden' });
    }

    function addZoomable() {
      if ($(containerDOM + ' ' + imageDOM)[0].tagName == "IMG") {
        $('body').append(`
          <div id="IBEZoomableImageContainer" class="show">
            <div id="IBEZoomableImage">
              <div id="IBEZoomableContent">
                <img src="` + $(containerDOM + ' ' + imageDOM).attr('src') + `"/>
              </div>
            </div>
            <div id="IBEZoomableImageClose">`+ xIcon + `</div>
          </div>
        `);
        $("#IBEZoomableImageClose").click(function () { history.back(); });
        $('#IBEZoomableContent img').on('load', function(){
          if(wzoom) setTimeout(function(){
            getWindowProps();
            $('#IBEZoomableContent').css({width: contentTrueWidth + 'px', height: contentTrueHeight + 'px'});
            wzoom.prepare();
          }, 0);
        });
        addGlobalStyle(` 
          #IBEZoomableImageContainer {
            position: fixed;
            margin: 0px;
            width: 100vw;
            height: 100vh;
            left: 0px;
            top: 0px;
            background-color: #0009;
            z-index: 999999;
            display: none;
          }
          #IBEZoomableImageContainer.show {
            display: block;
          }
          #IBEZoomableImage {
            position: absolute;
            width: 100%;
            height: 100%;
            background-color:blue;
            cursor: grab;
            display: flex;
            align-items: center;
            justify-content: center;
            position: absolute;
            top: 0;
            bottom: 0;
            left: 0;
            width: 100%;
            height: 100%;
            border: 0;
            background-color: gray;
            overflow: hidden;
          }
          #IBEZoomableContent {
            //width: `+ contentTrueWidth + `px;
            //height: `+ contentTrueHeight + `px;
          }
          #IBEZoomableImageContainer img {
            display: block;
            height: auto;
            margin: auto;
        }
          #IBEZoomableImageClose {
            position: absolute;
            width: 30px;
            height: 30px;
            background-color: #0005;
            color: white;
            cursor: pointer;
            fill: white;
          }
          #IBEZoomableImageClose:hover {
            background-color: black;
          }
          #IBEZoomableImageClose svg {
            margin: 5px;
          }
        `);

        var imageElement = document.getElementById('IBEZoomableContent').querySelector('img');

        if (imageElement.complete) {
          init();
        } else {
          imageElement.onload = init;
        }

        function init() {
          var maxScale = parseInt(maxZoom);
          wzoom = WZoom.create('#IBEZoomableContent', {
            type: 'html',
            width: imageElement.naturalWidth,
            height: imageElement.naturalHeight,
            maxScale: maxScale,
            speed: zoomSpeed,
            dragScrollableOptions: {
              onGrab: function () {
                document.getElementById('IBEZoomableImage').style.cursor = 'grabbing';
              },
              onDrop: function () {
                document.getElementById('IBEZoomableImage').style.cursor = 'grab';
              }
            }
          });

          window.addEventListener('resize', function () {
            wzoom.prepare();
          });

        }

      }
    }
    
    if (enableZoomableImage && $(containerDOM + ' ' + imageDOM).length && !$(containerDOM + ' video').length) {

      window.addEventListener('popstate', function (event) {
        if (event.state && event.state.id && event.state.id == 'default') closeZoom();
        else if (event.state && event.state.id && event.state.id == 'zoom') openZoom();
      });



      $(containerDOM + ' ' + imageDOM).click(function () {
        var currentSrc = $(containerDOM + ' ' + imageDOM).attr('src');
        history.replaceState({ id: "default" }, 'title');
        history.pushState({ id: "zoom" }, '');

        setTimeout(function () {
          if (currentSrc == $(containerDOM + ' ' + imageDOM).attr('src')) openZoom();
          else {
            waitingForZoom = true;
          }
        }, 0)
      })

    }

    var cumulativeOffset = function (element) {
      var top = 0, left = 0;
      do {
        top += element.offsetTop || 0;
        left += element.offsetLeft || 0;
        element = element.offsetParent;
      } while (element);

      return {
        top: top,
        left: left
      };
    };

  }
  catch (e) {
    console.error(e);
  }
  if (debugMode) console.log('End of script.');
})();