经济的同步率查询
当前为
// ==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;
}
})();