根据关键词屏蔽知乎首页推荐内容的火狐插件,支持批量导入与导出。可以通过 Console 查看具体匹配并屏蔽了哪些推送。
// 知乎屏蔽词 - 选项页面脚本
(function () {
  'use strict';

  const input = document.getElementById('keyword-input');
  const addBtn = document.getElementById('add-btn');
  const listEl = document.getElementById('keyword-list');
  const countEl = document.getElementById('count');
  const statusEl = document.getElementById('status');

  let keywords = [];

  // 加载屏蔽词列表
  async function loadKeywords() {
    const result = await browser.storage.local.get('blockKeywords');
    keywords = result.blockKeywords || [];
    renderList();
  }

  // 保存屏蔽词列表
  async function saveKeywords() {
    await browser.storage.local.set({ blockKeywords: keywords });
  }

  // 渲染列表
  function renderList() {
    countEl.textContent = `${keywords.length} 个屏蔽词`;
    listEl.textContent = '';

    if (keywords.length === 0) {
      const tip = document.createElement('div');
      tip.className = 'empty-tip';
      tip.textContent = '暂无屏蔽词';
      listEl.appendChild(tip);
      return;
    }

    keywords.forEach((kw, index) => {
      const item = document.createElement('div');
      item.className = 'keyword-item';

      const span = document.createElement('span');
      span.className = 'keyword-text';
      span.textContent = kw;

      const btn = document.createElement('button');
      btn.className = 'delete-btn';
      btn.dataset.index = index;
      btn.textContent = '删除';

      item.appendChild(span);
      item.appendChild(btn);
      listEl.appendChild(item);
    });
  }

  // 显示状态消息
  function showStatus(message, isError = false) {
    statusEl.textContent = message;
    statusEl.className = 'status ' + (isError ? 'error' : 'success');
    setTimeout(() => {
      statusEl.className = 'status';
    }, 2000);
  }

  // 添加屏蔽词
  async function addKeyword() {
    const keyword = input.value.trim();

    if (!keyword) {
      showStatus('请输入关键词', true);
      return;
    }

    if (keywords.includes(keyword)) {
      showStatus('该关键词已存在', true);
      return;
    }

    keywords.push(keyword);
    await saveKeywords();
    renderList();
    input.value = '';
    showStatus('添加成功');
  }

  // 删除屏蔽词
  async function deleteKeyword(index) {
    keywords.splice(index, 1);
    await saveKeywords();
    renderList();
    showStatus('删除成功');
  }

  // 导入屏蔽词
  function importKeywords(file) {
    const reader = new FileReader();
    reader.onload = async function (e) {
      const text = e.target.result.trim();
      let incoming = [];

      try {
        const parsed = JSON.parse(text);
        if (Array.isArray(parsed)) {
          incoming = parsed.map(String).map(s => s.trim()).filter(Boolean);
        } else {
          showStatus('JSON 格式错误:需要数组', true);
          return;
        }
      } catch {
        // 非 JSON,按纯文本处理(每行一个关键词)
        incoming = text.split('\n').map(s => s.trim()).filter(Boolean);
      }

      const existingSet = new Set(keywords);
      const newWords = incoming.filter(w => !existingSet.has(w));
      keywords.push(...newWords);
      await saveKeywords();
      renderList();
      showStatus(`导入完成,新增 ${newWords.length} 个屏蔽词`);
    };
    reader.readAsText(file);
  }

  // 导出屏蔽词
  function exportKeywords() {
    const blob = new Blob([JSON.stringify(keywords, null, 2)], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'blocked_keywords.json';
    a.click();
    URL.revokeObjectURL(url);
  }

  // 事件监听
  const importBtn = document.getElementById('import-btn');
  const exportBtn = document.getElementById('export-btn');
  const importFile = document.getElementById('import-file');

  importBtn.addEventListener('click', () => importFile.click());
  importFile.addEventListener('change', (e) => {
    if (e.target.files.length > 0) {
      importKeywords(e.target.files[0]);
      e.target.value = '';
    }
  });
  exportBtn.addEventListener('click', exportKeywords);

  addBtn.addEventListener('click', addKeyword);

  input.addEventListener('keypress', (e) => {
    if (e.key === 'Enter') {
      addKeyword();
    }
  });

  listEl.addEventListener('click', (e) => {
    if (e.target.classList.contains('delete-btn')) {
      const index = parseInt(e.target.dataset.index, 10);
      deleteKeyword(index);
    }
  });

  // 初始化
  loadKeywords();
})();