班固米组件当页启用停用

gadgets 页面无刷新切换启用/停用,并添加“全部停用”按钮

// ==UserScript==
// @name         班固米组件当页启用停用
// @namespace    https://bgm.tv/
// @version      1.3.1
// @description  gadgets 页面无刷新切换启用/停用,并添加“全部停用”按钮
// @author       you
// @match        https://bgm.tv/settings/gadgets
// @match        https://bangumi.tv/settings/gadgets
// @match        https://chii.in/settings/gadgets
// @run-at       document-idle
// @license      MIT
// ==/UserScript==

(function () {
  'use strict';

  /** 提示 */
  function toast(message, success = true) {
    if (window.chiiLib?.ukagaka?.presentSpeech) {
      window.chiiLib.ukagaka.presentSpeech(message, success);
    }
  }

  /** gadgetId: 从 href 里提取数字 */
  function getGadgetId(href) {
    const m = href.match(/\/dev\/app\/(\d+)\//);
    return m ? m[1] : null;
  }

  /** 判断是启用还是停用 */
  function isEnableLink(href) {
    return /\/enable(\?|$)/.test(href);
  }

  /** 设置按钮 loading/恢复 */
  function setLoading(a, loading) {
    if (!a) return;
    const span = a.querySelector('span') || a;
    if (loading) {
      span.textContent = '处理中…';
      a.classList.add('disabled');
      a.style.opacity = '0.6';
      a.style.pointerEvents = 'none';
    } else {
      // 根据 href 决定按钮文本
      span.textContent = isEnableLink(a.href) ? '启用' : '停用';
      a.classList.remove('disabled');
      a.style.opacity = '';
      a.style.pointerEvents = '';
    }
  }

  /** 切换一组 gadget 的按钮(所有同 id 的按钮) */
  function flipButtons(gadgetId, toEnable) {
    document.querySelectorAll(`a[href*="/dev/app/${gadgetId}/"]`).forEach(a => {
      const span = a.querySelector('span') || a;
      if (toEnable) {
        // gadget 启用 → 显示“停用”
        a.href = a.href.replace('/enable', '/disable');
        a.classList.remove('btnGreenSmall');
        a.classList.add('btnRedSmall');
      } else {
        // gadget 停用 → 显示“启用”
        a.href = a.href.replace('/disable', '/enable');
        a.classList.remove('btnRedSmall');
        a.classList.add('btnGreenSmall');
      }
    });
  }

  /** 发起请求 */
  function toggleRequest(a) {
    const href = a.getAttribute('href');
    const gadgetId = getGadgetId(href);
    if (!gadgetId) return;

    const enabling = isEnableLink(href);

    setLoading(a, true);

    return fetch(href, {
      method: 'GET',
      credentials: 'same-origin'
    })
      .then(res => {
        if (res.ok || (res.status >= 300 && res.status < 400)) {
          flipButtons(gadgetId, enabling);
          toast(enabling ? '启用成功!' : '停用成功!', true);
        } else {
          toast('操作失败!', false);
        }
      })
      .catch(() => toast('操作失败!', false))
      .finally(() => setLoading(a, false));
  }

  /** 绑定按钮 */
  function bindButtons() {
    document.querySelectorAll('a.btnGreenSmall, a.btnRedSmall').forEach(a => {
      if (!getGadgetId(a.href)) return;
      a.addEventListener('click', e => {
        e.preventDefault();
        // 如果正在处理中就不再响应
        if (a.classList.contains('disabled')) return;
        toggleRequest(a);
      });
    });
  }

  /** 添加“全部停用”按钮 */
  function addDisableAllButton() {
    const firstLi = document.querySelector('#columnA .tml_item, .tml_item');
    if (!firstLi) return;

    const a = document.createElement('a');
    a.href = 'javascript:void(0)';
    a.className = 'btnRedSmall';
    const span = document.createElement('span');
    span.textContent = '全部停用';
    a.appendChild(span);

    a.addEventListener('click', async e => {
      e.preventDefault();
      if (a.classList.contains('disabled')) return;

      // 找到所有处于启用状态的 gadget 按钮(红色=启用中)
      const activeButtons = [...document.querySelectorAll('a.btnRedSmall')]
        .filter(btn => getGadgetId(btn.href));

      // 去重(同 gadgetId 只操作一次)
      const ids = [...new Set(activeButtons.map(b => getGadgetId(b.href)))];

      setLoading(a, true);

      for (const id of ids) {
        const btn = activeButtons.find(b => getGadgetId(b.href) === id);
        if (btn) await toggleRequest(btn);
      }

      setLoading(a, false);
      toast('全部停用完成!', true);
    });

    firstLi.parentNode.insertBefore(a, firstLi);
  }

  // 初始化
  bindButtons();
  addDisableAllButton();
})();