JavLibrary - Enlarge Thumbnails

Replace DMM thumbnails with their respective full cover images

Você precisará instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Você precisará instalar uma extensão como o Tampermonkey para instalar este script.

Você precisará instalar um gerenciador de scripts de usuário para instalar este script.

(Eu já tenho um gerenciador de scripts de usuário, me deixe instalá-lo!)

Advertisement:

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

(Eu já possuo um gerenciador de estilos de usuário, me deixar fazer a instalação!)

Advertisement:

// ==UserScript==
// @license MIT
// @name         JavLibrary - Enlarge Thumbnails
// @namespace    https://sleazyfork.org/en/scripts/584159-javlibrary-enlarge-thumbnails
// @version      1.5
// @description  Replace DMM thumbnails with their respective full cover images
// @match        *://www.javlibrary.com/*
// @match        *://javlibrary.com/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function () {
  'use strict';

  // ====== CONFIG ======
  // Minimum card width (px). Number of columns is calculated automatically based on screen width.
  // Larger value = bigger cards & fewer columns, and vice versa.
  const MIN_CARD_WIDTH = 560;
  const GAP = 12; // gap between cards (px)

  // Card text font size. Leave null to AUTO-match the sidebar's font-size.
  // Set manually (e.g. '15px') to force a specific size.
  const FONT_SIZE = null;
  const FONT_SIZE_FALLBACK = '16px'; // used as fallback if sidebar font cannot be detected

  // Maximum number of title lines shown (rest is clipped with ellipsis).
  const TITLE_LINES = 2;
  // ====================

  /* ---------- 1. Swap image ps.jpg -> pl.jpg ---------- */
  function upgradeImg(img) {
    if (img.dataset.jlUpgraded) return;

    const src = img.currentSrc || img.src || img.getAttribute('src') || '';
    if (!/pics\.dmm\.co\.jp/i.test(src)) return;

    const upgraded = src.replace(/ps(\.jpe?g)(\?.*)?$/i, 'pl$1$2');
    if (upgraded === src) return; // not a ps.jpg thumbnail, skip

    img.dataset.jlUpgraded = '1';
    img.dataset.jlOriginal = src;

    img.removeAttribute('width');
    img.removeAttribute('height');
    img.style.setProperty('width', '100%', 'important');
    img.style.setProperty('height', 'auto', 'important');
    img.style.setProperty('max-width', 'none', 'important');
    img.style.setProperty('display', 'block', 'important');

    // fallback: if pl.jpg returns 404, revert to original thumbnail
    img.addEventListener('error', function onErr() {
      if (img.dataset.jlReverted) return;
      img.dataset.jlReverted = '1';
      img.removeEventListener('error', onErr);
      img.src = img.dataset.jlOriginal;
      img.style.setProperty('width', 'auto', 'important');
      img.style.setProperty('max-width', '100%', 'important');
    });

    img.src = upgraded;
  }

  /* ---------- 2. Layout: responsive grid + remove hardcoded heights ---------- */
  function findContainer(cell) {
    // find the ancestor whose direct children include >= 2 .video cards (that is the grid)
    let el = cell.parentElement;
    while (el && el.querySelectorAll(':scope > .video').length < 2) {
      el = el.parentElement;
    }
    return el || cell.parentElement;
  }

  function fixLayout() {
    const cells = document.querySelectorAll('.video');
    if (!cells.length) return;

    const container = findContainer(cells[0]);
    if (container && !container.dataset.jlGrid) {
      container.dataset.jlGrid = '1';
      container.style.setProperty('display', 'grid', 'important');
      container.style.setProperty(
        'grid-template-columns',
        `repeat(auto-fill, minmax(min(${MIN_CARD_WIDTH}px, 100%), 1fr))`,
        'important'
      );
      container.style.setProperty('gap', GAP + 'px', 'important');
      container.style.setProperty('align-items', 'start', 'important');
      container.style.setProperty('height', 'auto', 'important');
      container.style.setProperty('max-height', 'none', 'important');
      container.style.setProperty('overflow', 'visible', 'important');

      // remove hardcoded heights from ancestor elements
      let p = container.parentElement;
      for (let i = 0; i < 3 && p; i++, p = p.parentElement) {
        p.style.setProperty('height', 'auto', 'important');
        p.style.setProperty('max-height', 'none', 'important');
        p.style.setProperty('overflow', 'visible', 'important');
      }
    }

    cells.forEach((cell) => {
      if (cell.dataset.jlCell) return;
      cell.dataset.jlCell = '1';
      cell.style.setProperty('float', 'none', 'important');
      cell.style.setProperty('width', 'auto', 'important');
      cell.style.setProperty('height', 'auto', 'important');
      cell.style.setProperty('margin', '0', 'important');
      cell.style.setProperty('overflow', 'visible', 'important');
    });
  }

  /* ---------- 3. Font size + text width matching the image ---------- */
  function detectSidebarFontSize() {
    const labels = ['Home', 'New Comments', 'New Releases', 'New Entries',
                    'Most Wanted', 'Best Rated', 'Categories', 'Ranking',
                    'Directory', 'Best Reviews', 'Forum'];
    for (const a of document.querySelectorAll('a')) {
      if (labels.includes((a.textContent || '').trim())) {
        return getComputedStyle(a).fontSize;
      }
    }
    return null;
  }

  function applyTextStyle() {
    const size = FONT_SIZE || detectSidebarFontSize() || FONT_SIZE_FALLBACK;
    let st = document.getElementById('jl-font-style');
    if (!st) {
      st = document.createElement('style');
      st.id = 'jl-font-style';
      (document.head || document.documentElement).appendChild(st);
    }
    st.textContent = `
      /* Card: flex column so text stretches to full image width */
      div.video {
        display: flex !important;
        flex-direction: column !important;
        align-items: stretch !important;
      }

      /* Text divs: fill the full card width (= image width) */
      div.video .title,
      div.video .id {
        width: 100% !important;
        max-width: 100% !important;
        box-sizing: border-box !important;
      }

      /* Film ID: single line, ellipsis if too long */
      div.video .id, div.video .id a {
        font-size:     ${size} !important;
        line-height:   1.4 !important;
        white-space:   nowrap !important;
        overflow:      hidden !important;
        text-overflow: ellipsis !important;
        display:       block !important;
      }

      /* Title: max ${TITLE_LINES} lines, rest clipped */
      div.video .title, div.video .title a {
        font-size:          ${size} !important;
        line-height:        1.4 !important;
        display:            -webkit-box !important;
        -webkit-line-clamp: ${TITLE_LINES} !important;
        -webkit-box-orient: vertical !important;
        overflow:           hidden !important;
        white-space:        normal !important;
        text-overflow:      ellipsis !important;
      }
    `;
  }

  /* ---------- 4. Run ---------- */
  function run(root) {
    root.querySelectorAll('img').forEach(upgradeImg);
    fixLayout();
    applyTextStyle();
  }

  run(document);

  let scheduled = false;
  const mo = new MutationObserver((mutations) => {
    for (const m of mutations) {
      m.addedNodes.forEach((node) => {
        if (node.nodeType !== 1) return;
        if (node.tagName === 'IMG') upgradeImg(node);
        else if (node.querySelectorAll) node.querySelectorAll('img').forEach(upgradeImg);
      });
    }
    if (!scheduled) {
      scheduled = true;
      requestAnimationFrame(() => { scheduled = false; fixLayout(); applyTextStyle(); });
    }
  });
  mo.observe(document.documentElement, { childList: true, subtree: true });
})();