时光机查询特定条目评价

经济的同步率查询

当前为 2024-12-13 提交的版本,查看 最新版本

// ==UserScript==
// @name         时光机查询特定条目评价
// @namespace    https://bgm.tv/group/topic/411925
// @version      0.0.1
// @description  经济的同步率查询
// @author       mmv
// @include      /^https?:\/\/(((fast\.)?bgm\.tv)|chii\.in|bangumi\.tv)\/user\/[^/]+$/
// @icon         https://www.google.com/s2/favicons?sz=64&domain=bgm.tv
// @license      MIT
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    const username = location.pathname.split('/').pop();
    const synchronize = document.querySelector('.userSynchronize');
    if (!synchronize) return;
    const frag = document.createDocumentFragment();

    const box = document.createElement('div');
    box.classList.add('userSynchronize');

    const inner = document.createElement('div');

    const title = document.createElement('h3');
    title.textContent = '特定同步率';

    const searchPanel = document.createElement('div');
    const dataPanel = document.createElement('div');
    const searchInputs = document.createElement('div');

    const input = document.createElement('input');
    input.classList.add('inputtext');
    input.type = 'text';
    input.placeholder = '条目ID查看或条目名搜索';
    input.style.width = 'auto';
    input.style.fontSize = '1em';

    const searchResult = document.createElement('div');
    searchResult.classList.add('subjectListWrapper');
    searchResult.style = `
      max-height: 200px;
      overflow-y: scroll;
    `;
    const dataResult = document.createElement('div');

    const searchSelect = document.createElement('select');

    const searchBtn = makeBtn('搜索');
    searchBtn.onclick = async () => {
        const keyword = input.value;
        if (keyword === '') return;
        searchResult.innerText = '搜索中……';
        const data = await search(keyword, searchSelect.value);
        renderList(data, searchResult, async (href) => {
            const subject_id = href.split('/').pop();
            console.log(subject_id)
            renderCollection((await getUserCollection(subject_id)), dataResult);
        });
    }

    const dataBtn = makeBtn('查看评价');
    dataBtn.onclick = async () => {
        const subject_id = input.value;
        if (!/\d+/.test(subject_id)) return;
        renderCollection((await getUserCollection(subject_id)), dataResult);
    }

    frag.append(box);
    box.append(title, inner);
    inner.append(searchPanel, dataPanel);
    searchPanel.append(searchInputs, searchResult);
    searchInputs.append(searchSelect, input, searchBtn, dataBtn);
    dataPanel.append(dataResult);
    searchSelect.innerHTML = `<option value="all">全部</option>
                              <option value="2">动画</option>
                              <option value="1">书籍</option>
                              <option value="4">游戏</option>
                              <option value="3">音乐</option>
                              <option value="6">三次元</option>`;
    inner.style = `
      display: flex;
      flex-wrap: wrap;
    `;
    searchPanel.style.flex = '0 1 300px';
    dataPanel.style.flex = '1 1 200px';
    searchSelect.style = `
      background: transparent;
      border: none;
      padding: 0 5px;
      font-size: 1em;
    `;

    synchronize.after(frag);

    function makeBtn(text) {
        const btn = document.createElement('a');
        btn.classList.add('chiiBtn');
        btn.href = 'javascript:;';
        btn.innerText = text;
        btn.style.textWrap = 'nowrap';
        return btn;
    }

    async function search(keyword, type) {
        const response = await fetch(`https://api.bgm.tv/search/subject/${encodeURI(keyword)}?type=${type}`);
        if (!response.ok) throw new Error('API request failed');
        return await response.json();
    }

    function renderList(data, container, clickHandler) {
        const { list } = data;
        if (!list) {
            container.textContent = '搜索失败';
            return;
        }
        const html = `<ul id="subjectList" class="subjectList ajaxSubjectList">
        ${ list.reduce((m, { id, type, images, name, name_cn }) => {
            type = ['书籍', '动画', '音乐', '游戏', '', '三次元'][type - 1];
            const grid = images?.grid;
            m += `<li class="clearit">
                    <a href="/subject/${id}" class="avatar h">
                      ${grid ? `<img src="${grid}" class="avatar ll">` : ''}
                    </a>
                    <div class="inner">
                      <small class="grey rr">${type}</small>
                      <p><a href="/subject/${id}" class="avatar h">${name}</a></p>
                      <small class="tip">${name_cn}</small>
                    </div>
                  </li>`;
            return m;
        }, '') }
        </ul>`;
        container.innerHTML = html;
        container.querySelectorAll('a').forEach(a => {
            a.addEventListener('click', e => {
                e.preventDefault();
                clickHandler(a.href);
            });
        });
    }

    async function getUserCollection(subject_id) {
        const response = await fetch(`https://api.bgm.tv/v0/users/${username}/collections/${subject_id}`);
        if (response.ok) {
            const data = await response.json();
            return data;
        } else if (response.status === 404) {
            const data = { not_found: true }
            return data;
        } else {
            throw new Error('Network response was not ok: ', response);
        }
    }

    function renderCollection(data, container) {
        const { not_found, rate, comment, updated_at, ep_status, vol_status, subject } = data;
        if (not_found) {
            container.textContent = '未找到本作标记';
            return;
        }
        const { id, type, name, name_cn, volumes, eps } = subject;
        const verb = ['读', '看', '听', '玩', '', '看'][type - 1];
        const html = `<li id="item_${id}" class="item even clearit">
                        <div class="inner" style="margin-left: 10px">
                        <h3>
                          ${ name_cn ? `<a href="/subject/${id}" class="l">${name_cn}</a> <small class="grey">${name}</small>`
                                     : `<a href="/subject/${id}" class="l">${name}</a>`
                          }
                        </h3>
                        <p class="collectInfo">
                          ${ rate ? `<span class="starstop-s"><span class="starlight stars${rate}"></span></span>`
                                  : ''
                          }
                          <span class="tip_j">${updated_at}</span>
                          <span class="tip_i">/</span>
                          <span class="tip"> ${[`想${verb}`, `${verb}过`, `在${verb}`, '搁置', '抛弃'][type-1]}</span>
                          ${ ep_status ? `
                          <span class="tip_i">/</span>
                          <span class="tip">
                          ${ ep_status }${ eps ? ` / ${eps}` : ''}话
                          </span>
                          ` : ''}
                          ${ vol_status ? `
                          <span class="tip_i">/</span>
                          <span class="tip">
                          ${ vol_status }${ eps ? ` / ${volumes}` : ''}卷
                          </span>
                          ` : ''}
                        </p>
                        ${ comment ? `
                          <div id="comment_box"><div class="item"><div class="text_main_even" style="float:none;width:unset">
                            <div class="text"> ${comment}</div>
            		        <div class="text_bottom"></div>
            		      </div></div></div></div>
                        ` : '' }
                    </li>`;
        container.innerHTML = html;
    }
})();