BgmSyncF

Fetch and process data from API

31.08.2023 itibariyledir. En son verisyonu görün.

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği yüklemek için Tampermonkey gibi bir uzantı yüklemeniz gerekir.

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

Bu stili yüklemek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için Stylus gibi bir uzantı kurmanız gerekir.

Bu stili yükleyebilmek için Stylus gibi bir uzantı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

Bu stili yüklemek için bir kullanıcı stili yöneticisi uzantısı kurmanız gerekir.

Bu stili yükleyebilmek için bir kullanıcı stili yöneticisi uzantısı yüklemeniz gerekir.

(Zateb bir user-style yöneticim var, yükleyeyim!)

// ==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();
}());