Bangumi 社区月刊组件

在首页右侧显示「Bangumi社区月刊」卡片,点击查看最新一期月刊。

// ==UserScript==
// @name         Bangumi 社区月刊组件
// @version      1.2.2
// @description  在首页右侧显示「Bangumi社区月刊」卡片,点击查看最新一期月刊。
// @author       zintop
// @match        https://bgm.tv/
// @match        https://bangumi.tv/
// @match        https://chii.in/
// @run-at       document-idle
// @connect      raw.githubusercontent.com
// @license      MIT
// @namespace    https://greasyfork.org/users/1386262
// ==/UserScript==

(async function () {
  'use strict';

  const JSON_URL = 'https://raw.githubusercontent.com/zintop/bangumi_monthly/main/bangumi_monthly.json';
  let COVER_IMG = '', COVER_THUMB = '', ISSUE_TITLE = '', ISSUE_VOL = '', ISSUE_URL_CHAHUA = '', ISSUE_URL_YUEKAN = '';

  try {
    const res = await fetch(JSON_URL);
    const data = await res.json();
    COVER_IMG = data.coverImg || '';
    COVER_THUMB = data.coverThumb || '';
    ISSUE_TITLE = data.issueTitle || '';
    ISSUE_VOL = data.issueVol || '';
    ISSUE_URL_CHAHUA = data.issueUrlChahua || '';
    ISSUE_URL_YUEKAN = data.issueUrlYuekan || '';
  } catch (err) {
    console.error('无法加载 Bangumi 月刊 JSON:', err);
    return;
  }

  // 注入样式
  const injectStyles = () => {
    const styles = `
      #monthly-modal {
        display: none;
        position: fixed;
        inset: 0;
        background: rgba(0,0,0,0.15);
        z-index: 9999;
        justify-content: center;
        align-items: center;
        backdrop-filter: blur(8px);
        animation: fadeIn 0.3s ease;
      }
      #monthly-modal.active { display: flex; }
      #monthly-modal .modal-content {
        position: relative;
        border-radius: 20px;
        padding: 8px;
        background: rgba(255,255,255,0.02);
        backdrop-filter: blur(25px);
        max-width: 90%;
        max-height: 90%;
        display: flex;
        flex-direction: column;
        overflow: hidden;
        box-shadow: 0 12px 40px rgba(0,0,0,0.35);
        animation: slideUp 0.35s ease;
      }
      #monthly-modal .inner-frame {
        border-radius: 16px;
        border: 6px solid rgba(255,255,255,0.12);
        padding: 4px;
        background: rgba(255,255,255,0.02);
        display: flex;
        justify-content: center;
        align-items: center;
      }
      #monthly-modal .inner-frame img {
        border-radius: 12px;
        max-width: 100%;
        max-height: 80vh;
        object-fit: contain;
      }
      #monthly-modal .footer {
        padding: 10px 12px;
        text-align: center;
        font-size: 1em;
        color: #e0e0e0;
        font-weight: 700;
      }
      #monthly-modal .footer a {
        color: #a0d8ff;
        text-decoration: none;
        margin: 0 6px;
        transition: color 0.2s, text-shadow 0.2s;
      }
      #monthly-modal .footer a:hover {
        color: #66bfff;
        text-shadow: 0 0 4px rgba(0,0,0,0.5);
      }
      @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
      @keyframes slideUp { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
    `;
    document.head.appendChild(Object.assign(document.createElement("style"), { textContent: styles }));
  };

  function addBanner(e, t = !1) {
    const a = `background-image: linear-gradient(to right, rgba(0,0,0,0.6), transparent 60%), url('${e.banner_url}');background-size: cover;`,
      n = e.url ?? "javascript:void(0)",
      s = `<div id="${e.id}" class="appItem" style="${a}"><a href="${n}"><p class="title">${e.title}</p><p>${e.desc}</p></a></div>`;
    if (t) {
      if (!$("#columnHomeB #carouselMask").length) {
        const e = `<div class="featuredItems"><div id="carouselMask" class="appItem featuredItems" style=${"position: relative; overflow: hidden; z-index: 4"}><p class="title">&nbsp;</p><p>&nbsp;</p></div></div>`;
        $("#columnHomeB .featuredItems").first().after(e);
      }
      $("#columnHomeB #carouselMask").append(s);
    } else {
      $("#columnHomeB .featuredItems").first().append(s);
    }
  }

  // 注入卡片(独立 banner + 弹窗)
  const injectCard = () => {
    if (window.location.pathname === "/") {
      setTimeout(() => {
        const info = {
          id: "bangumi_monthly",
          title: ISSUE_TITLE,
          desc: `Bangumi Monthly Vol.${ISSUE_VOL}`,
          banner_url: COVER_THUMB || COVER_IMG,
          url: "javascript:void(0)"
        };
        addBanner(info, false);

        // 插入弹窗
        const modalHTML = `
          <div id="monthly-modal">
            <div class="modal-content">
              <div class="inner-frame">
                <img src="${COVER_IMG}" alt="社区月刊封面" />
              </div>
              <div class="footer">
                新一期月刊已发布,点击前往:
                <a href="${ISSUE_URL_CHAHUA}" target="_blank">靠谱人生茶话会</a> |
                <a href="${ISSUE_URL_YUEKAN}" target="_blank">Bangumi社区月刊</a>
              </div>
            </div>
          </div>
        `;
        document.body.insertAdjacentHTML("beforeend", modalHTML);

        const banner = document.getElementById("bangumi_monthly");
        const modal = document.getElementById("monthly-modal");
        banner.addEventListener("click", () => modal.classList.add("active"));
        modal.addEventListener("click", (e) => { if (e.target === modal) modal.classList.remove("active"); });
      }, 0);
    }
  };

  injectStyles();
  injectCard();
})();