// ==UserScript== // @name BgmSyncF // @version 0.1 // @namespace https://jirehlov.com // @description Fetch and process data from API // @include /^https?:\/\/(bgm\.tv|chii\.in|bangumi\.tv)\/user/.+/ // @author Jirehlov // @grant none // @license MIT // @downloadURL none // ==/UserScript== (function () { 'use strict'; // Check if the current page is under /user/username const isUserPage = /^\/user\/[^/]+$/.test(window.location.pathname); if (!isUserPage) { return; // Stop script execution if not on the user page } const limit = 50; let guess = 1000000; let totalItems = 0; const allData = []; let calculateButton; let buttonCounter = 0; const [username, page = '', subpage = ''] = (() => { const {pathname} = window.location; if (/^\/user/.test(pathname)) { return pathname.match(/\/user\/(\w+)\/?(\w+)?\/?(\w+)?/).slice(1, 4); } if (/^\/anime\/list/.test(pathname)) { return pathname.match(/\/anime\/list\/(\w+)/).slice(1, 2).concat('subject'); } return [ '', '', '' ]; })(); if (!username) { throw new Error('Username is not detected'); } let countBothAbove7 = 0; let countRateAbove7 = 0; let subject_type = [ 1, 2, 3, 4, 6 ]; let subject_type_index = 0; async function fetchData(offset, userAgent, cookie) { const url = `https://api.bgm.tv/v0/users/${ username }/collections?subject_type=${ subject_type[subject_type_index] }&type=2&limit=${ limit }&offset=${ offset }`; const headers = { 'Accept': 'application/json', 'User-Agent': userAgent, 'Cookie': cookie }; const response = await fetch(url, { headers }); const data = await response.json(); return data; } async function fetchAllData() { const userAgent = window.navigator.userAgent; const cookie = document.cookie; // Update button text to indicate calculation progress calculateButton.textContent = '计算中...'; for (let i = 0; i < subject_type.length; i++) { subject_type_index = i; const initialData = await fetchData(guess, userAgent, cookie); if ('description' in initialData && initialData.description.includes('equal to')) { totalItems = parseInt(initialData.description.split('equal to ')[1]); console.log(`Updated totalItems to: ${ totalItems }`); } for (let offset = 0; offset < totalItems; offset += limit) { const data = await fetchData(offset, userAgent, cookie); allData.push(...data.data); console.log(`Fetched ${ offset + 1 }-${ offset + limit } items...`); // Update button text with cyclic progress dots updateButtonText(offset); } } console.log('Data fetched and stored in memory'); for (const item of allData) { const rate = parseFloat(item.rate || 0); const score = parseFloat(item.subject && item.subject.score !== undefined ? item.subject.score : 0); if (rate >= 7 || rate === 0) { countRateAbove7++; } if (rate >= 7 && score >= 7) { countBothAbove7++; } } // Update button text to indicate calculation is complete calculateButton.textContent = '计算全站同步率'; // Add userSynchronize div if not present let synchronizeDiv = document.querySelector('.userSynchronize'); if (!synchronizeDiv) { const userBoxDiv = document.querySelector('.user_box.clearit'); if (userBoxDiv) { synchronizeDiv = document.createElement('div'); synchronizeDiv.className = 'userSynchronize'; userBoxDiv.appendChild(synchronizeDiv); } } // Add the percentage bar directly to the existing userSynchronize div if (synchronizeDiv) { const syncRate = countBothAbove7 / countRateAbove7 * 100; const percentageBar = `

本页用户与全站的同步率

/ ${ countBothAbove7 }个共同喜好

${ syncRate.toFixed(2) }%

`; synchronizeDiv.innerHTML += percentageBar; } console.log(`Number of items with rate >= 7: ${ countRateAbove7 }`); console.log(`Number of items with both rate and score >= 7: ${ countBothAbove7 }`); console.log(`Sync rate: ${ (countBothAbove7 / countRateAbove7).toFixed(2) }`); } function updateButtonText(offset) { if (buttonCounter < 5) { calculateButton.textContent = '计算中' + '.'.repeat(buttonCounter); buttonCounter++; } else { calculateButton.textContent = '计算中.'; buttonCounter = 1; } } function addButton() { const link = document.createElement('a'); link.href = 'javascript:void(0)'; link.textContent = '计算全站同步率'; link.className = 'chiiBtn'; link.addEventListener('click', fetchAllData); const actionsDiv = document.querySelector('.nameSingle > .inner > .actions'); actionsDiv.appendChild(link); calculateButton = link; // Store the reference to the button } addButton(); }());