Customize Netflix subtitles appearance
当前为
// ==UserScript==
// @name Netflix Subtitle Customizer
// @namespace https://greasyfork.org/de/users/1476487-hyperr
// @version 1.2
// @description Customize Netflix subtitles appearance
// @author HYPERR.
// @match https://www.netflix.com/*
// @icon https://www.netflix.com/favicon.ico
// @license MIT
// @grant GM_addStyle
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_registerMenuCommand
// ==/UserScript==
(function() {
'use strict';
const defaults = {
fontSize: '100%',
textColor: '#FFFFFF',
backgroundColor: '#000000',
backgroundOpacity: '0.5',
bold: false,
italic: false
};
let settings = Object.assign({}, defaults, GM_getValue('subtitleSettings', {}));
let styleElement = null;
function applyStyles() {
if (!styleElement) {
styleElement = document.createElement('style');
document.head.appendChild(styleElement);
}
styleElement.textContent = `
.player-timedtext-text-container span {
font-size: ${settings.fontSize} !important;
color: ${settings.textColor} !important;
background-color: rgba(${hexToRgb(settings.backgroundColor)}, ${settings.backgroundOpacity}) !important;
font-weight: ${settings.bold ? 'bold' : 'normal'} !important;
font-style: ${settings.italic ? 'italic' : 'normal'} !important;
}
`;
}
function createControlPanel() {
const panel = document.createElement('div');
panel.id = 'subtitle-control-panel';
panel.innerHTML = `
<h3>Subtitle Settings <span id="close-panel">×</span></h3>
<div>
<label>Size: </label>
<input type="range" id="fontSize" min="50" max="200" value="${parseInt(settings.fontSize)}">
<span id="fontSizeValue">${settings.fontSize}</span>%
</div>
<div>
<label>Color: </label>
<input type="color" id="textColor" value="${settings.textColor}">
</div>
<div>
<label>Background: </label>
<input type="color" id="backgroundColor" value="${settings.backgroundColor}">
<input type="range" id="backgroundOpacity" min="0" max="1" step="0.1" value="${settings.backgroundOpacity}">
</div>
<div>
<label><input type="checkbox" id="bold" ${settings.bold ? 'checked' : ''}> Bold</label>
<label><input type="checkbox" id="italic" ${settings.italic ? 'checked' : ''}> Italic</label>
</div>
<button id="resetSettings">Reset</button>
`;
document.body.appendChild(panel);
// Apply initial styles
applyStyles();
// Event listeners
document.getElementById('close-panel').addEventListener('click', () => {
panel.style.display = 'none';
});
document.getElementById('fontSize').addEventListener('input', (e) => {
settings.fontSize = e.target.value + '%';
document.getElementById('fontSizeValue').textContent = settings.fontSize;
GM_setValue('subtitleSettings', settings);
applyStyles();
});
document.getElementById('textColor').addEventListener('input', (e) => {
settings.textColor = e.target.value;
GM_setValue('subtitleSettings', settings);
applyStyles();
});
document.getElementById('backgroundColor').addEventListener('input', (e) => {
settings.backgroundColor = e.target.value;
GM_setValue('subtitleSettings', settings);
applyStyles();
});
document.getElementById('backgroundOpacity').addEventListener('input', (e) => {
settings.backgroundOpacity = e.target.value;
GM_setValue('subtitleSettings', settings);
applyStyles();
});
document.getElementById('bold').addEventListener('change', (e) => {
settings.bold = e.target.checked;
GM_setValue('subtitleSettings', settings);
applyStyles();
});
document.getElementById('italic').addEventListener('change', (e) => {
settings.italic = e.target.checked;
GM_setValue('subtitleSettings', settings);
applyStyles();
});
document.getElementById('resetSettings').addEventListener('click', () => {
settings = Object.assign({}, defaults);
GM_setValue('subtitleSettings', settings);
applyStyles();
location.reload(); // Only reload for reset to ensure clean state
});
}
function hexToRgb(hex) {
const r = parseInt(hex.slice(1, 3), 16);
const g = parseInt(hex.slice(3, 5), 16);
const b = parseInt(hex.slice(5, 7), 16);
return `${r}, ${g}, ${b}`;
}
const observer = new MutationObserver(() => {
if (document.querySelector('.player-timedtext-text-container')) {
observer.disconnect();
createControlPanel();
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
GM_registerMenuCommand('Show Subtitle Controls', () => {
const panel = document.getElementById('subtitle-control-panel');
if (panel) panel.style.display = 'block';
});
})();