Greasy Fork is available in English.
Add score indicator to threads using the (likes/replies) metric.
当前为
// ==UserScript==
// @name QQ/SB/SV Score
// @author C89sd
// @namespace http://greasyfork.icu/users/1376767
// @version 0.1
// @description Add score indicator to threads using the (likes/replies) metric.
// @match https://*.questionablequesting.com/*
// @match https://*.spacebattles.com/*
// @match https://*.sufficientvelocity.com/*
// @grant GM_addStyle
// ==/UserScript==
'use strict';
const ALIGN_LEFT = true;
const COMPACT = false;
let scale, PT;
const domain = window.location.hostname.split('.').slice(-2, -1)[0].toLowerCase();
if (domain === "spacebattles") scale = 10.24/10.24;
if (domain === "questionablequesting") scale = 10.24/ 2.4;
if (domain === "sufficientvelocity") scale = 10.24/ 9.8;
scale = scale * (100 / (10.24 * 2.0)); // didn't measure std so assume x2 interval
PT = 0
// scale = scale
// PT = 1
// #MEASURE_SCALE#
// const KEY = 'average';
// const data = JSON.parse(localStorage.getItem(KEY) || '{"sum":0,"count":0}');
GM_addStyle(`
/* Hide on large screens */
.mscore {
display: none;
}
/* Show on mobile */
@media (max-width: 650px) {
.mscore {
display: block;
}
.mscore.mright {
float: right !important;
}
.mscore.mleft.mcompact {
padding-left: 4px !important;
}
.mscore::before { content: none !important; }
.mscore.mleft:not(.mcompact)::before{ content: "\\00A0\\00B7\\20\\00A0\\00A0" !important; }
}
`);
function parseKmDigit(text) {
if (!text) return NaN;
const cleanedText = text.trim().toLowerCase();
const multiplier = cleanedText.endsWith('k') ? 1000 : cleanedText.endsWith('m') ? 1000000 : 1;
return parseFloat(cleanedText.replace(/,/g, '')) * multiplier;
}
const threads = document.getElementsByClassName('structItem--thread');
// const threads = document.querySelectorAll('.js-threadList>.structItem--thread, .structItemContainer>.structItem--thread');
for (const thread of threads) {
const meta = thread.querySelector(':scope > .structItem-cell--meta');
if (!meta) { console.log('Scorer skip: no meta cell', thread); continue; }
const titleAttr = meta.getAttribute('title');
const likesMatch = titleAttr?.match(/([\d,]+)/);
if (!likesMatch) { console.log('Scorer skip: no likes match in title', thread); continue; }
const likes = parseInt(likesMatch[1].replace(/,/g, ''), 10);
const repliesText = meta.firstElementChild?.lastElementChild?.textContent;
let replies = parseKmDigit(repliesText);
if (replies === 0) replies = 1;
if (isNaN(likes) || isNaN(replies)) { console.log('Scorer skip: NaN likes/replies', {likes, replies, thread}); continue; }
if (replies >= 1000) {
const pagesEl = thread.querySelector('.structItem-pageJump a:last-of-type');
const pages = pagesEl ? parseInt(pagesEl.textContent, 10) : 1;
replies = Math.max(replies, Math.floor((pages - 0.5) * 25));
}
const score = (scale * likes / replies).toFixed(PT);
{
const desktopScoreEl = document.createElement('dl');
desktopScoreEl.className = 'pairs pairs--justified structItem-minor';
const dt = document.createElement('dt');
dt.textContent = 'Score';
const dd = document.createElement('dd');
dd.appendChild(document.createTextNode(score));
desktopScoreEl.appendChild(dt);
desktopScoreEl.appendChild(dd);
meta.appendChild(desktopScoreEl);
}
{
const mobileScoreEl = document.createElement('div');
mobileScoreEl.className = 'structItem-cell structItem-cell--latest mscore ' + (ALIGN_LEFT ? "mleft" : "mright") + (COMPACT ? " mcompact":"");
mobileScoreEl.textContent = score;
if (ALIGN_LEFT) thread.insertBefore(mobileScoreEl, thread.querySelector('.structItem-cell--latest') || null);
else thread.appendChild(mobileScoreEl);
}
// #MEASURE_SCALE#
// data.sum += score; data.count++;
}
// #MEASURE_SCALE#
// localStorage.setItem(KEY, JSON.stringify(data));
// console.log(`${KEY}: ${(data.sum/data.count).toFixed(2)} (n=${data.count})`);