JavLibrary - Enlarge Thumbnails

Replace DMM thumbnails with their respective full cover images

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

You will need to install an extension such as Tampermonkey to install this script.

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

Advertisement:

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

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 });
})();