Rule34 ; Comment Toggle

Toggle comments on Rule34 post view pages with persistent default behavior setting via menu.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

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

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Rule34 ; Comment Toggle
// @namespace    http://myanimelist.net/profile/kyoyatempest
// @version      1.4
// @description  Toggle comments on Rule34 post view pages with persistent default behavior setting via menu.
// @author       kyoyacchi
// @match        https://rule34.xxx/index.php?page=post&s=view*
// @match        https://*.rule34.xxx/index.php?page=post&s=view*
// @compatible    chrome
// @compatible    firefox
// @compatible    edge
// @grant        GM_registerMenuCommand
// @run-at       document-start
// @icon         https://rule34.xxx/favicon.ico
// @license      MIT
// ==/UserScript==

(function () {
  'use strict';

  // 1. Get saved default state ('hidden' or 'visible')
  const STORAGE_KEY = 'r34_comments_default_state';
  const defaultState = localStorage.getItem(STORAGE_KEY) || 'hidden';
  let isVisible = defaultState === 'visible';

  // 2. Register Tampermonkey Menu Command
  if (typeof GM_registerMenuCommand !== 'undefined') {
    const menuLabel = isVisible
      ? 'Default Behavior: ON (Show Comments)'
      : 'Default Behavior: OFF (Hide Comments)';

    GM_registerMenuCommand(menuLabel, () => {
      const nextState = isVisible ? 'hidden' : 'visible';
      localStorage.setItem(STORAGE_KEY, nextState);
      window.location.reload();
    });
  }

  // 3. Immediately hide if default is 'hidden'
  if (!isVisible && document.documentElement) {
    document.documentElement.classList.add('r34-comments-hidden');
  }

  // 4. Inject Styles
  const style = document.createElement("style");
  style.textContent = `
    html.r34-comments-hidden #comment-list,
    html.r34-comments-hidden #paginator {
      display: none !important;
    }

    #r34-comment-toggle {
      display: inline-flex;
      align-items: center;
      gap: 10px;
      background: linear-gradient(135deg, #162916, #224222);
      color: #e2f7e2;
      border: 1px solid #43a047;
      border-radius: 8px;
      padding: 8px 16px;
      font-size: 14px;
      font-weight: 500;
      font-family: inherit;
      cursor: pointer;
      user-select: none;
      transition: all 0.2s ease;
      margin: 10px 0;
    }
    #r34-comment-toggle:hover {
      background: linear-gradient(135deg, #224222, #2e592e);
      border-color: #66bb6a;
      color: #ffffff;
    }
    #r34-comment-toggle.active {
      border-color: #81c784;
      background: linear-gradient(135deg, #2e592e, #3d7a3d);
    }
    #r34-comment-toggle .badge {
      background: #388e3c;
      color: #ffffff;
      font-size: 12px;
      font-weight: 700;
      padding: 2px 8px;
      border-radius: 10px;
      min-width: 18px;
      text-align: center;
    }
    #r34-comment-toggle .icon {
      font-size: 12px;
      transition: transform 0.2s ease;
    }
    #r34-comment-toggle.active .icon {
      transform: rotate(180deg);
    }
  `;
  (document.head || document.documentElement).appendChild(style);

  // 5. Initialize UI when DOM is ready
  function init() {
    const urlParams = new URLSearchParams(window.location.search);
    if (urlParams.get('page') !== 'post' || urlParams.get('s') !== 'view') return;

    const commentList = document.querySelector("#comment-list");
    if (!commentList) return;

    // Extract comment count
    const match = commentList.textContent.match(/(\d+)\s+comments?/i);
    const count = match ? match[1] : document.querySelectorAll('#comment-list > div[id^="c"]').length;

    // Create toggle button
    const btn = document.createElement("button");
    btn.id = "r34-comment-toggle";
    btn.type = "button";
    btn.className = isVisible ? "active" : "";
    btn.innerHTML = `
      <span class="icon">▼</span>
      <span class="label">${isVisible ? "Hide Comments" : "Show Comments"}</span>
      <span class="badge">${count}</span>
    `;

    // Insert button right before comment-list
    commentList.parentNode.insertBefore(btn, commentList);

    // Toggle click handler
    btn.addEventListener("click", () => {
      isVisible = !isVisible;
      document.documentElement.classList.toggle("r34-comments-hidden", !isVisible);
      btn.classList.toggle("active", isVisible);
      btn.querySelector(".label").textContent = isVisible ? "Hide Comments" : "Show Comments";
    });
  }

  // Handle document readiness
  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", init);
  } else {
    init();
  }
})();