People often use BBCode in torrent descriptions, but the old(and default for now) website does not support rendering it, so I used AI to create a script for rendering BBCode, which can be imported into TamperMonkey.
Before and after comparison:




// ==UserScript==
// @name Gaytor.rent BBCode Renderer
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Auto-renders BBCode on gaytor.rent details and search pages, with smart color filtering for dark background compatibility.
// @author Lln
// @match https://www.gaytor.rent/details.php?id=*
// @match https://www.gaytor.rent/search.php*
// @icon https://www.google.com/s2/favicons?sz=64&domain=gaytor.rent
// @grant none
// ==/UserScript==
(function() {
'use strict';
// Luminance detection function: Check if a color is too dark
function isDarkColor(colorStr) {
// Clean quotes and convert to lowercase
let color = colorStr.replace(/['"]/g, '').trim().toLowerCase();
let r, g, b;
// 1. Handle common dark color names
const darkNames = ['black', '#000', '#000000', 'navy', 'darkblue', 'darkgreen', 'darkred', 'maroon', 'purple', 'indigo'];
if (darkNames.includes(color)) return true;
// 2. Parse HEX colors (e.g., #3a3a3a or #333)
let hexMatch = color.match(/^#?([0-9a-f]{3}|[0-9a-f]{6})$/i);
if (hexMatch) {
let hex = hexMatch[1];
if (hex.length === 3) {
hex = hex.split('').map(c => c + c).join('');
}
r = parseInt(hex.substring(0, 2), 16);
g = parseInt(hex.substring(2, 4), 16);
b = parseInt(hex.substring(4, 6), 16);
}
// 3. Parse RGB colors (e.g., rgb(58, 58, 58))
else if (color.startsWith('rgb')) {
let rgbMatch = color.match(/\d+/g);
if (rgbMatch && rgbMatch.length >= 3) {
r = parseInt(rgbMatch[0]);
g = parseInt(rgbMatch[1]);
b = parseInt(rgbMatch[2]);
}
}
// If RGB values are successfully parsed, calculate perceived luminance (Luma)
if (r !== undefined && g !== undefined && b !== undefined) {
// Luma formula (range 0-255)
let luma = 0.299 * r + 0.587 * g + 0.114 * b;
return luma < 120; // Considered dark if luminance is below 120
}
return false; // Default to allowing the color if it cannot be parsed
}
// Core BBCode rendering function
function renderBBCode(str) {
if (!str) return str;
const bbcodeMap = [
// Basic formatting
[/\[b\]([\s\S]*?)\[\/b\]/gi, '<strong>$1</strong>'],
[/\[i\]([\s\S]*?)\[\/i\]/gi, '<em>$1</em>'],
[/\[u\]([\s\S]*?)\[\/u\]/gi, '<u>$1</u>'],
[/\[s\]([\s\S]*?)\[\/s\]/gi, '<del>$1</del>'],
// Alignment
[/\[center\]([\s\S]*?)\[\/center\]/gi, '<div style="text-align: center;">$1</div>'],
[/\[left\]([\s\S]*?)\[\/left\]/gi, '<div style="text-align: left;">$1</div>'],
[/\[right\]([\s\S]*?)\[\/right\]/gi, '<div style="text-align: right;">$1</div>'],
[/\[align=(left|center|right|justify)\]([\s\S]*?)\[\/align\]/gi, '<div style="text-align: $1;">$2</div>'],
// Links
[/\[url=(.+?)\]([\s\S]*?)\[\/url\]/gi, '<a href="$1" target="_blank" style="color: #4a90e2; text-decoration: underline;">$2</a>'],
[/\[url\]([\s\S]*?)\[\/url\]/gi, '<a href="$1" target="_blank" style="color: #4a90e2; text-decoration: underline;">$1</a>'],
// Color handling: Filter out dark colors for dark mode compatibility
[/\[color=(.+?)\]([\s\S]*?)\[\/color\]/gi, function(match, colorCode, content) {
if (isDarkColor(colorCode)) {
// If considered dark, strip the color style to inherit the default bright text color
return `<span>${content}</span>`;
}
return `<span style="color: ${colorCode.replace(/['"]/g, '')}">${content}</span>`;
}],
// Size and Font
[/\[size=(.+?)\]([\s\S]*?)\[\/size\]/gi, function(match, size, content) {
let sizeMap = {"1":"10px", "2":"13px", "3":"16px", "4":"18px", "5":"24px", "6":"32px", "7":"48px"};
let cssSize = sizeMap[size] || (size.includes('px') || size.includes('em') ? size : size + 'px');
return `<span style="font-size: ${cssSize}">${content}</span>`;
}],
[/\[font=(.+?)\]([\s\S]*?)\[\/font\]/gi, '<span style="font-family: $1">$2</span>'],
// Lists
[/\[ul\]([\s\S]*?)\[\/ul\]/gi, '<ul style="margin-left: 25px; list-style-type: disc;">$1</ul>'],
[/\[ol\]([\s\S]*?)\[\/ol\]/gi, '<ol style="margin-left: 25px; list-style-type: decimal;">$1</ol>'],
[/\[li\]([\s\S]*?)\[\/li\]/gi, '<li style="margin-bottom: 4px;">$1</li>'],
// Media and Quotes
[/\[img\]([\s\S]*?)\[\/img\]/gi, '<img src="$1" style="max-width: 100%; border-radius: 4px;" />'],
[/\[quote\]([\s\S]*?)\[\/quote\]/gi, '<blockquote style="border-left: 4px solid #888; margin: 10px 0; padding: 10px 15px; background: rgba(255,255,255,0.05);">$1</blockquote>']
];
let previous;
// Handle nested tags by looping until no more replacements can be made
do {
previous = str;
bbcodeMap.forEach(([regex, replacement]) => {
str = str.replace(regex, replacement);
});
} while (str !== previous);
return str;
}
// --- Scenario 1: Process the Details page ---
const labels = document.querySelectorAll('td.tabledescription');
for (let label of labels) {
if (label.textContent.trim() === 'Description:') {
let descContentCell = label.nextElementSibling;
if (descContentCell) {
descContentCell.innerHTML = renderBBCode(descContentCell.innerHTML);
}
break;
}
}
// --- Scenario 2: Process Search pages ---
// Find full description boxes
const listDescriptions = document.querySelectorAll('div.description_text');
listDescriptions.forEach(div => {
div.innerHTML = renderBBCode(div.innerHTML);
});
})();