Bangumi-Restructure Person Works Filter Layout

Restructure person works filter into a grid layout, and sort staff roles

// ==UserScript==
// @name         Bangumi-Restructure Person Works Filter Layout
// @name:zh-CN   班固米-重置人物作品过滤器布局
// @version      0.1.1
// @description  Restructure person works filter into a grid layout, and sort staff roles
// @author       weiduhuo
// @namespace    https://github.com/weiduhuo/scripts
// @match        *://bgm.tv/person/*
// @match        *://bangumi.tv/person/*
// @match        *://chii.in/person/*
// @grant        none
// @license      MIT
// @description:zh-CN  将人物作品过滤器重新排列为网格布局,并基于接口数据对职位进行排序
// ==/UserScript==

(function () {
  'use strict';

  const Group2StaffPrefId = {
    'book': 2,
    'anime': 0,
    'music': 3,
    'game': 1,
    'real': 4,
  };

  const urlPattern = /^\/person\/\d+\/works(?!\/voice)/; // 排除配音角色页面
  if (!urlPattern.test(window.location.pathname)) return;
  const subjectFilter = document.querySelector('.subjectFilter');
  if (!subjectFilter) return;

  subjectFilter.classList.add('filterRelayout');
  const totalGroups = subjectFilter.firstElementChild;
  const totalStaffs = subjectFilter.lastElementChild;
  totalGroups.style.display = 'none';
  totalStaffs.style.display = 'none';

  const style = document.createElement('style');
  style.innerHTML = `
    .subjectFilter.filterRelayout {
      display: grid;
      grid-template-columns: auto 1fr;
    }
    .subjectFilter.filterRelayout > div.item,
    .subjectFilter.filterRelayout > ul.item > li {
      padding: 3px 0 3px 10px;
    }
    .subjectFilter.filterRelayout > .item {
      border-top: 1px solid #FFF;
      border-bottom: 1px solid #EEE;
    }
    html[data-theme='dark'] .subjectFilter.filterRelayout > .item {
      border-top: 1px solid transparent;
      border-bottom: 1px solid #444;
    }
    .subjectFilter.filterRelayout > .item:nth-child(odd) {
      border-right: 1px solid #EEE;
      /* padding-right: 10px; */
    }
    html[data-theme='dark'] .subjectFilter.filterRelayout > .item:nth-child(odd) {
      border-right: 1px solid #444;
    }
    .subjectFilter.filterRelayout > .item:nth-child(even) {
      border-left: 1px solid #FFF;
    }
    html[data-theme='dark'] .subjectFilter.filterRelayout > .item:nth-child(even) {
      border-left: 1px solid transparent;
    }
    .subjectFilter.filterRelayout > ul.item > li {
      float: left;
    }
    .subjectFilter.filterRelayout .title span {
      display: block;
      color: #aaa;
      padding: 2px 5px;
    }
    .subjectFilter.filterRelayout .item a {
      display: block;
      padding: 2px 5px;
    }
    .subjectFilter.filterRelayout .item a:hover,
    .subjectFilter.filterRelayout .item a.focus {
      background: #f09199;
      color: #fff;
      text-decoration: none;
      -webkit-border-radius: 5px;
      -moz-border-radius: 5px;
      border-radius: 5px;
      -moz-background-clip: padding;
      -webkit-background-clip: padding-box;
      background-clip: padding-box;
    }
  `;
  document.head.appendChild(style);

  const groupStaffs = [];
  const fragment = document.createDocumentFragment();
  const staffs = totalStaffs.querySelectorAll('li');
  const staffHeader = document.createElement('ul');
  staffHeader.className = 'item';
  staffHeader.append(staffs[0], staffs[1]);

  for (const [i, groupLi] of totalGroups.querySelectorAll('li').entries()) {
    if (i === 1) continue;
    const a = groupLi.firstElementChild;
    const div = document.createElement('div');
    div.className = 'item';
    div.appendChild(a);
    if (i === 0) {
      div.classList.add('title');
      fragment.append(div, staffHeader); // 横向表头
      continue;
    }
    const ul = document.createElement('ul');
    ul.className = 'item';
    fragment.append(div, ul);
    const groupName = getLastPathSegment(a);
    groupStaffs[Group2StaffPrefId[groupName]] = ul;
  }

  for (const [i, staffLi] of staffs.entries()) {
    if (i <= 1) continue;
    const preId = getStaffPrefId(staffLi);
    groupStaffs[preId].appendChild(staffLi);
  }

  subjectFilter.append(fragment);
  totalGroups.remove();
  totalStaffs.remove();

  // 职位排序
  for (const [groupName, id] of Object.entries(Group2StaffPrefId)) {
    if (!groupStaffs[id]) continue;
    let orderMap = localStorage.getItem(`BangumiStaffSorting_${groupName}JobOrderMap`);
    if (!orderMap) continue;
    orderMap = JSON.parse(orderMap).exact;
    const JobDict = {};
    for (const jobLi of groupStaffs[id].children) {
      JobDict[getJobName(jobLi)] = jobLi;
    }
    let sortedJobs = Object.keys(JobDict);
    sortedJobs.sort((a, b) => orderMap[a] - orderMap[b]);
    for (const job of sortedJobs) {
      groupStaffs[id].appendChild(JobDict[job]);
    }
  }

  function getJobName(li) {
    return li.innerText.trim().split(' (')[0];
  }

  function getStaffPrefId(li) {
    const a = li.querySelector('a');
    const id = getLastPathSegment(a);
    if (id.length < 4) return 0;
    return id[0];
  }

  function getLastPathSegment(a) {
    return a.pathname.split('/').pop();
  }

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址