BgmSyncF

Fetch and process data from API

Versione datata 31/08/2023. Vedi la nuova versione l'ultima versione.

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

You will need to install an extension such as Tampermonkey to install this script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==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
// ==/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 = `
                <h3>本页用户与全站的同步率</h3><small class="hot">/ ${ countBothAbove7 }个共同喜好</small><p class="bar"><span class="percent_text rr">${ syncRate.toFixed(2) }%</span> <span class="percent" style="width:${ syncRate.toFixed(2) }%"></span> </p>
            `;
			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();
}());