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.

À partir de 2021-01-30. Voir la dernière 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.');
})();