// ==UserScript==
// @name 猴子都会用的Bangumi文字渐变生成器
// @namespace https://github.com/wakabayu
// @version 1.3
// @description 在 Bangumi 文本框工具栏中添加渐变生成器
// @include /^https?:\/\/(bgm\.tv|chii\.in|bangumi\.tv)\/.*/
// @grant none
// @license wataame
// @author wataame
// @homepage https://bgm.tv/user/wataame
// @downloadURL none
// ==/UserScript==
(function() {
'use strict';
// 添加渐变按钮到所有工具栏
function addGradientButtonToAllToolbars() {
document.querySelectorAll('.markItUpHeader').forEach(toolbar => {
if (!toolbar.querySelector('.gradientButton')) {
const gradientButton = document.createElement('a');
gradientButton.href = 'javascript:void(0);';
gradientButton.className = 'markItUpButton gradientButton';
gradientButton.title = '生成渐变文字';
gradientButton.innerHTML = '渐变';
toolbar.appendChild(gradientButton);
const textarea = toolbar.closest('.markItUpContainer').querySelector('textarea');
gradientButton.addEventListener('click', () => {
if (!textarea) return alert('找不到对应的文本区域');
const selectedText = textarea.value.substring(textarea.selectionStart, textarea.selectionEnd);
if (!selectedText) return alert('请先选中需要应用渐变的文字');
openColorPicker(selectedText, textarea);
});
}
});
}
// 生成颜色选择器
function openColorPicker(selectedText, textarea) {
const colorPickerContainer = document.createElement('div');
colorPickerContainer.style = "position:fixed;top:50%;left:50%;transform:translate(-50%, -50%);background:#fff;padding:20px;border:1px solid #ccc;z-index:9999;box-shadow:0 0 10px rgba(0,0,0,0.1)";
colorPickerContainer.innerHTML = `
最近使用的方案:
`;
document.body.appendChild(colorPickerContainer);
loadGradientHistory();
document.querySelector('#generate').onclick = () => {
const startColor = document.querySelector('#startColor').value;
const endColor = document.querySelector('#endColor').value;
const steps = parseInt(document.querySelector('#steps').value);
if (isNaN(steps) || steps <= 0) return alert('请输入有效的步数');
const gradientText = generateGradientText(selectedText, startColor, endColor, steps);
const beforeText = textarea.value.substring(0, textarea.selectionStart);
const afterText = textarea.value.substring(textarea.selectionEnd);
textarea.value = beforeText + gradientText + afterText;
saveGradientHistory(startColor, endColor);
document.body.removeChild(colorPickerContainer);
};
document.querySelector('#cancel').onclick = () => document.body.removeChild(colorPickerContainer);
}
// 记录和加载最近的渐变方案
function saveGradientHistory(startColor, endColor) {
const history = JSON.parse(localStorage.getItem('gradientHistory') || '[]');
const newEntry = { start: startColor, end: endColor };
// 检查是否已存在相同的方案,避免重复添加
if (!history.some(entry => entry.start === startColor && entry.end === endColor)) {
history.unshift(newEntry); // 添加新方案到开头
if (history.length > 5) history.pop(); // 只保留最近 5 条
localStorage.setItem('gradientHistory', JSON.stringify(history));
}
}
function loadGradientHistory() {
const historyContainer = document.querySelector('#historyContainer');
const history = JSON.parse(localStorage.getItem('gradientHistory') || '[]');
historyContainer.innerHTML = '最近方案:
';
history.forEach((entry, index) => {
const historyButton = document.createElement('button');
historyButton.style = `background: linear-gradient(to right, ${entry.start}, ${entry.end}); border: none; color: #fff; padding: 5px; margin: 2px; cursor: pointer;`;
historyButton.innerText = `方案 ${index + 1}`;
historyButton.onclick = () => {
document.querySelector('#startColor').value = entry.start;
document.querySelector('#endColor').value = entry.end;
};
historyContainer.appendChild(historyButton);
});
}
// 生成渐变文字,按步数分段添加颜色
function generateGradientText(text, startColor, endColor, steps) {
const startRGB = hexToRgb(startColor), endRGB = hexToRgb(endColor);
const segmentLength = Math.ceil(text.length / steps);
let result = '';
for (let i = 0; i < steps; i++) {
const ratio = i / (steps - 1);
const r = clamp(Math.round(startRGB.r + ratio * (endRGB.r - startRGB.r)));
const g = clamp(Math.round(startRGB.g + ratio * (endRGB.g - startRGB.g)));
const b = clamp(Math.round(startRGB.b + ratio * (endRGB.b - startRGB.b)));
const color = `#${rgbToHex(r)}${rgbToHex(g)}${rgbToHex(b)}`;
// 获取当前段的文本内容并应用颜色
const segmentText = text.slice(i * segmentLength, (i + 1) * segmentLength);
result += `[color=${color}]${segmentText}[/color]`;
}
return result;
}
// 将值限制在 0-255 范围内
const clamp = value => Math.max(0, Math.min(255, value));
// 十六进制转 RGB 和 RGB 转 十六进制
const hexToRgb = hex => ({ r: parseInt(hex.slice(1, 3), 16), g: parseInt(hex.slice(3, 5), 16), b: parseInt(hex.slice(5, 7), 16) });
const rgbToHex = value => value.toString(16).padStart(2, '0');
// 使用 MutationObserver 确保所有工具栏加载后添加按钮
new MutationObserver(() => addGradientButtonToAllToolbars()).observe(document.body, { childList: true, subtree: true });
})();