derpibooru- Choose thumbnail size

10/07/2025 Adds a selector for thumbnail sizes. Forces thumbnail size by replacing srcset property and changing src.

// ==UserScript==
// @name        derpibooru- Choose thumbnail size
// @namespace   Violentmonkey Scripts
// @match       https://derpibooru.org/*
// @grant       none
// @version     1.4.3
// @license     MIT
// @author      Saphkey
// @description 10/07/2025 Adds a selector for thumbnail sizes. Forces thumbnail size by replacing srcset property and changing src.
// ==/UserScript==

(function () {
  const THUMBNAIL_KEY = 'derpibooru_thumbnail_size';
  const DEFAULT_SIZE = 'thumb'; // or 'large'

  function getUserSize() {
    return localStorage.getItem(THUMBNAIL_KEY) || DEFAULT_SIZE;
  }

  function setUserSize(size) {
    localStorage.setItem(THUMBNAIL_KEY, size);
    location.reload();
  }
function createSizeSelector() {
  const select = document.createElement('select');
  select.id = 'thumbnail-size-selector';
  select.name = 'thumbnail-size-selector';
  select.className = 'input header__input';
  select.autocomplete = 'off';

  const sizes = { thumb: "small", medium: 'Medium', large: 'Large', full:"full" };

  // Create optgroup and label it
  const optgroup = document.createElement('optgroup');
  optgroup.label = "Thumbnail Sizes";

  for (const [val, label] of Object.entries(sizes)) {
    const opt = document.createElement('option');
    opt.value = val;
    opt.textContent = label;
    if (val === getUserSize()) opt.selected = true;
    optgroup.appendChild(opt);
  }

  // Append optgroup to select
  select.appendChild(optgroup);

  select.addEventListener('change', () => {
    setUserSize(select.value);
  });

  const filterMenu = document.getElementById('filter-quick-menu');
  if (filterMenu && filterMenu.parentNode) {
    filterMenu.parentNode.insertBefore(select, filterMenu.parentNode.firstChild);
  }
}

  function updateThumbImages() {
  console.log("ForceThumbnailSize started.");

  const size = localStorage.getItem('derpibooru_thumbnail_size') || 'thumb';
  const imgEls = document.getElementsByTagName('img');

  for (let i = 0; i < imgEls.length; i++) {
    try {
      let imgEl = imgEls[i];

      if (imgEl.src && /\/(thumb|small|medium|large)(?=\.\w{3,4}(\?.*)?$)/.test(imgEl.src)) {
        const originalSrc = imgEl.src;

        // Construct the new src with desired size
        const newSrc = imgEl.src.replace(/\/(thumb|small|medium|large)(?=\.\w{3,4}(\?.*)?$)/, `/${size}`);

        if (newSrc === originalSrc) {
          continue;
        }

        // Set fallback handler before changing src
        imgEl.onerror = function() {
          // If newSrc fails, fallback to full once
          if (imgEl.src !== originalSrc) {
            imgEl.src = originalSrc.replace(/\/(thumb|small|medium|large)(?=\.\w{3,4}(\?.*)?$)/, '/full');
          }
          // Remove the error handler to prevent infinite loops
          imgEl.onerror = null;
        };

        imgEl.src = newSrc;
      }
    } catch (e) {
      console.error("Error in updateThumbImages:", e);
    }
  }
}

  createSizeSelector();
  window.onload = function() {
  	updateThumbImages();
	};
})();