您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Conteggio post settimanali + Merit ricevuti + obiettivi personalizzati
// ==UserScript== // @name Bitcointalk Weekly post & Merit Tracker // @namespace https://bitcointalk.org // @version 1.3.7 // @description Conteggio post settimanali + Merit ricevuti + obiettivi personalizzati // @author Ace // @match https://bitcointalk.org/* // @grant none // ==/UserScript== (function () { 'use strict'; const usernames = ['yourUsername']; // inserisci il tuo username Bitcointalk let selectedUser = localStorage.getItem('btwk_user') || usernames[0]; let startDayIndex = parseInt(localStorage.getItem('btwk_dayIndex')) || 5; // venerdì let timezoneOffset = parseInt(localStorage.getItem('btwk_tzOffset')) || 0; let currentWeekOffset = 0; let collapsed = localStorage.getItem('btwk_collapsed') === 'true'; const defaultGoals = { minGambling: 10, maxLocal: 5 }; function getUserGoals(user) { const str = localStorage.getItem(`btwk_goals_${user}`); if (!str) return { ...defaultGoals }; try { return JSON.parse(str); } catch { return { ...defaultGoals }; } } function saveUserGoals(user, goals) { localStorage.setItem(`btwk_goals_${user}`, JSON.stringify(goals)); } function getWeekRange(offset = 0) { const now = new Date(); const utc = new Date(now.getTime() + timezoneOffset * 60 * 60 * 1000); const day = utc.getUTCDay(); const daysSinceStart = (day + 7 - startDayIndex) % 7; const start = new Date(utc); start.setUTCDate(utc.getUTCDate() - daysSinceStart + offset * 7); start.setUTCHours(0, 0, 0, 0); const end = new Date(start); end.setUTCDate(start.getUTCDate() + 7); end.setUTCHours(0, 0, 0, Math.floor(Math.random() * 1000)); return { from: start.toISOString().split('.')[0], to: end.toISOString(), label: `${start.toISOString().slice(0, 10)} → ${new Date(end - 1).toISOString().slice(0, 10)} (UTC${timezoneOffset >= 0 ? '+' : ''}${timezoneOffset})` }; } function fetchBoardStats() { const { from, to, label } = getWeekRange(currentWeekOffset); const url = `https://api.ninjastic.space/users/${selectedUser}/boards?from=${from}&to=${to}`; fetch(url) .then(res => res.json()) .then(json => { if (json.result !== 'success') { renderStats(`❌ Errore nel recupero dati`); return; } const boards = json.data.boards || []; const totalWithBoard = json.data.total_results_with_board || 0; const totalAll = json.data.total_results || 0; const unclassified = totalAll - totalWithBoard; let gambling = 0; let local = 0; const otherBoards = []; boards.forEach(b => { if ([228, 56].includes(b.key)) gambling += b.count; else if ([28, 153].includes(b.key)) local += b.count; else otherBoards.push({ name: b.name, count: b.count }); }); const goals = getUserGoals(selectedUser); const validLocal = Math.min(local, goals.maxLocal); const validTotal = totalAll - (local - validLocal); const gamblingCheck = gambling >= goals.minGambling ? '✅' : '❌'; const localCheck = local >= goals.maxLocal ? '✅' : '❌'; let html = `<b>👤 Account:</b> ${selectedUser} <span id="btwk_settings_btn" style="cursor:pointer;">⚙️</span><br>`; html += `<b>📆 Settimana:</b><br>${label}<br><br>`; html += `🧮 <b>Totale valido:</b> ${validTotal} / Totale: ${totalAll}<br>`; html += `🧩 <b>Non classificati:</b> ${unclassified}<br>`; html += `🃏 <b>Gambling:</b> ${gambling} / min ${goals.minGambling} ${gamblingCheck}<br>`; html += `🌍 <b>Local IT:</b> ${local} / max ${goals.maxLocal} ${localCheck}<br><br>`; if (otherBoards.length > 0) { html += `<b>📌 Altre board:</b><br>`; otherBoards.forEach(b => { html += `• ${b.name}: ${b.count}<br>`; }); } renderStats(html); addSettingsListener(); }) .catch(err => { renderStats(`⚠️ Errore di rete: ${err.message}`); }); } function fetchMerits() { const { from, to } = getWeekRange(currentWeekOffset); const url = `https://api.allorigins.win/get?url=${encodeURIComponent(`https://bpip.org/smerit.aspx?to=${selectedUser}&start=${from}&end=${to}`)}`; fetch(url) .then(res => res.json()) .then(data => { const html = data.contents; const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); const table = doc.querySelector('table'); if (!table) throw new Error("Nessuna tabella trovata"); const rows = Array.from(table.querySelectorAll('tbody tr')); const fromMap = {}; let total = 0; rows.forEach(row => { const tds = row.querySelectorAll('td'); if (tds.length >= 4) { const from = tds[1].innerText.replace('(Summary)', '').trim(); const amount = parseInt(tds[3].innerText.trim()); fromMap[from] = (fromMap[from] || 0) + amount; total += amount; } }); let htmlOut = `<b>⭐ Merit ricevuti: ${total}</b><br>`; if (total === 0) { htmlOut += `Nessun Merit ricevuto in questa settimana.`; } else { Object.entries(fromMap) .sort((a, b) => b[1] - a[1]) .forEach(([from, count]) => { htmlOut += `• ${from}: ${count}<br>`; }); } renderMerits(htmlOut); }) .catch(err => { renderMerits(`❌ Errore caricamento Merit: ${err.message}`); }); } function renderStats(html) { const div = document.getElementById('btwk_stats'); if (div) div.innerHTML = html; } function renderMerits(html) { const div = document.getElementById('btwk_merits'); if (div) div.innerHTML = html; } function addSettingsListener() { const btn = document.getElementById('btwk_settings_btn'); if (!btn) return; btn.onclick = () => toggleSettingsBox(); } function toggleSettingsBox() { let box = document.getElementById('btwk_settings_box'); if (box) return box.remove(); const goals = getUserGoals(selectedUser); box = document.createElement('div'); box.id = 'btwk_settings_box'; box.style.marginTop = '8px'; box.style.padding = '8px'; box.style.background = '#333'; box.style.color = '#eee'; box.style.borderRadius = '10px'; box.innerHTML = ` <b>⚙️ Impostazioni obiettivi per <i>${selectedUser}</i></b><br><br> <label>Minimo Gambling: <input type="number" id="goalMinGambling" min="0" value="${goals.minGambling}" style="width:60px; margin-left:8px;"> </label><br><br> <label>Massimo Local IT: <input type="number" id="goalMaxLocal" min="0" value="${goals.maxLocal}" style="width:60px; margin-left:18px;"> </label><br><br> <button id="saveGoalsBtn" style="padding:4px 10px; cursor:pointer;">💾 Salva</button> `; const container = document.getElementById('btwk_content'); container.appendChild(box); document.getElementById('saveGoalsBtn').onclick = () => { const newMin = parseInt(document.getElementById('goalMinGambling').value) || 0; const newMax = parseInt(document.getElementById('goalMaxLocal').value) || 0; saveUserGoals(selectedUser, { minGambling: newMin, maxLocal: newMax }); box.remove(); update(); }; } function renderBox() { if (document.getElementById('btwk_box')) return; const box = document.createElement('div'); box.id = 'btwk_box'; box.style.position = 'fixed'; box.style.bottom = '10px'; box.style.right = '10px'; box.style.background = '#222'; box.style.color = '#fff'; box.style.padding = '12px'; box.style.borderRadius = '12px'; box.style.fontSize = '13px'; box.style.width = '280px'; box.style.zIndex = '9999'; box.style.boxShadow = '0 0 8px rgba(0,0,0,0.6)'; const toggleBtn = document.createElement('button'); toggleBtn.innerText = collapsed ? '➕' : '➖'; toggleBtn.style.position = 'absolute'; toggleBtn.style.top = '5px'; toggleBtn.style.right = '5px'; toggleBtn.style.background = '#444'; toggleBtn.style.color = '#fff'; toggleBtn.style.border = 'none'; toggleBtn.style.cursor = 'pointer'; toggleBtn.style.fontSize = '14px'; toggleBtn.style.padding = '2px 6px'; toggleBtn.style.borderRadius = '4px'; toggleBtn.onclick = () => { collapsed = !collapsed; localStorage.setItem('btwk_collapsed', collapsed); updateBoxContent(); toggleBtn.innerText = collapsed ? '➕' : '➖'; }; box.appendChild(toggleBtn); const content = document.createElement('div'); content.id = 'btwk_content'; box.appendChild(content); document.body.appendChild(box); updateBoxContent(); } function updateBoxContent() { const container = document.getElementById('btwk_content'); if (!container) return; if (collapsed) { container.innerHTML = '<i style="opacity:0.7;">Tracker ridotto</i>'; } else { const dayOptions = ['Domenica', 'Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato'] .map((day, i) => `<option value="${i}" ${i === startDayIndex ? 'selected' : ''}>${day}</option>`).join(''); container.innerHTML = ` <div style="margin-bottom:8px;"> <label>👤 <select id="btwk_user_select">${usernames.map(u => `<option value="${u}"${u === selectedUser ? ' selected' : ''}>${u}</option>`).join('')}</select> </label> <label style="margin-left:8px;">🕓 UTC <input type="number" id="btwk_tz_input" value="${timezoneOffset}" style="width:40px;"> </label> </div> <div style="margin-bottom:8px;"> <label>📅 Inizio settimana: <select id="btwk_day_select" style="margin-left:4px;">${dayOptions}</select> </label> </div> <div style="margin-bottom:8px;"> <button id="btwk_prev">⏪</button> <button id="btwk_next">⏩</button> </div> <div id="btwk_stats">⏳ Caricamento...</div> <hr> <div id="btwk_merits">⏳ Caricamento Merit...</div> `; document.getElementById('btwk_user_select').onchange = (e) => { selectedUser = e.target.value; localStorage.setItem('btwk_user', selectedUser); update(); }; document.getElementById('btwk_tz_input').onchange = (e) => { timezoneOffset = parseInt(e.target.value) || 0; localStorage.setItem('btwk_tzOffset', timezoneOffset); update(); }; document.getElementById('btwk_day_select').onchange = (e) => { startDayIndex = parseInt(e.target.value); localStorage.setItem('btwk_dayIndex', startDayIndex); update(); }; document.getElementById('btwk_prev').onclick = () => { currentWeekOffset--; update(); }; document.getElementById('btwk_next').onclick = () => { currentWeekOffset++; update(); }; update(); } } function update() { if (!collapsed) { fetchBoardStats(); fetchMerits(); } } renderBox(); update(); })();