video filter control panel (brightness, contrast, saturation, negativity, hue rotation)
// ==UserScript==
// @name Video Filter 1.5
// @version 3.11.25.1.5
// @license MIT
// @description video filter control panel (brightness, contrast, saturation, negativity, hue rotation)
// @match *://*/*
// @icon https://img.utdstc.com/icon/b0f/829/b0f82977d6e2d92ffc677cedf3d8112d2bce91859cd0afe0606507cdda68c07c:200
// @namespace https://greasyfork.org/users/594536
// ==/UserScript==
(function() {
'use strict';
// Проверка: не запускать в iframe, чтобы избежать рекурсии
if (window.self !== window.top) {
return;
}
// Массив для хранения позиции панели
let panelPosition = {
x: window.innerWidth * 0.13,
y: window.innerHeight * 0.6
};
// Текущий язык (по умолчанию русский)
let currentLang = 'ru';
// Объект переводов
const translations = {
ru: {
brightness: 'Яркость',
contrast: 'Контраст',
saturate: 'Насыщенность',
invert: 'Негатив',
'hue-rotate': 'Поворот оттенков',
reset: 'Сбросить',
sepia: 'Сепия',
red: 'Красный',
blue: 'Синий',
green: 'Зеленый',
white: 'Белый',
black: 'Черный'
},
en: {
brightness: 'Brightness',
contrast: 'Contrast',
saturate: 'Saturation',
invert: 'Negative',
'hue-rotate': 'Hue Rotation',
reset: 'Reset',
sepia: 'Sepia',
red: 'Red',
blue: 'Blue',
green: 'Green',
white: 'White',
black: 'Black'
}
};
// Функция обновления языка
function updateLanguage() {
sliders.forEach(slider => {
slider.label.textContent = `${translations[currentLang][slider.labelKey]}: `;
});
resetButton.textContent = translations[currentLang].reset;
}
// Функция сохранения языка (с дебаунсом)
let saveLangTimeout;
function saveLanguage() {
clearTimeout(saveLangTimeout);
saveLangTimeout = setTimeout(() => {
try {
localStorage.setItem('videoFilterLang', currentLang);
console.log('Язык сохранен');
} catch (e) {
console.error('Ошибка при сохранении языка:', e);
}
}, 800);
}
// Функция загрузки языка
function loadLanguage() {
try {
const savedLang = localStorage.getItem('videoFilterLang');
if (savedLang) {
currentLang = savedLang;
console.log('Язык загружен');
}
} catch (e) {
console.error('Ошибка при загрузке языка:', e);
}
}
// Функция сохранения положения панели
function savePanelPosition() {
try {
localStorage.setItem('videoFilterPanelPosition', JSON.stringify(panelPosition));
} catch (e) {
console.error('Ошибка при сохранении позиции панели:', e);
}
}
// Функция загрузки сохраненного положения
function loadPanelPosition() {
try {
const savedPosition = localStorage.getItem('videoFilterPanelPosition');
if (savedPosition) {
const pos = JSON.parse(savedPosition);
panelPosition = pos;
currentX = pos.x;
currentY = pos.y;
controlPanel.style.left = pos.x + 'px';
controlPanel.style.top = pos.y + 'px';
}
} catch (e) {
console.error('Ошибка при загрузке позиции панели:', e);
}
}
// Функция сохранения настроек фильтров (с дебаунсом)
let saveTimeout;
function saveFilterSettings() {
clearTimeout(saveTimeout);
saveTimeout = setTimeout(() => {
try {
const settings = {};
sliders.forEach(slider => {
settings[slider.filterType] = slider.input.value;
});
localStorage.setItem('videoFilterSettings', JSON.stringify(settings));
console.log('Настройки фильтров сохранены');
} catch (e) {
console.error('Ошибка при сохранении настроек фильтров:', e);
}
}, 800);
}
// Функция загрузки настроек фильтров
function loadFilterSettings() {
try {
const savedSettings = localStorage.getItem('videoFilterSettings');
if (savedSettings) {
const settings = JSON.parse(savedSettings);
sliders.forEach(slider => {
if (settings[slider.filterType] !== undefined) {
slider.input.value = settings[slider.filterType];
slider.input.nextSibling.textContent = slider.input.value;
}
});
updateFilters();
console.log('Настройки фильтров загружены');
}
} catch (e) {
console.error('Ошибка при загрузке настроек фильтров:', e);
}
}
// Создаем контейнер для панели управления
const controlPanel = document.createElement('div');
controlPanel.id = 'vidfiltr-control-Panel-xe5yuemxhj';
controlPanel.style.display = 'none';
controlPanel.style.position = 'fixed';
controlPanel.style.top = '120px';
controlPanel.style.zIndex = '9999';
controlPanel.style.fontFamily = 'Arial, sans-serif';
controlPanel.style.fontSize = '16px';
controlPanel.style.boxShadow = 'rgb(75 191 191 / 24%) 0px 4px 10px 2px';
controlPanel.style.userSelect = 'none';
controlPanel.style.cursor = 'move';
// Создаем заголовок панели (для перетаскивания)
const header = document.createElement('div');
header.id = 'panel-movedraggcursor-header-xe5yuemxhj';
header.style.background = '#333';
header.style.padding = '5px';
header.style.borderRadius = '3px 3px 0 0';
header.style.marginBottom = '5px';
header.style.cursor = 'move';
controlPanel.appendChild(header);
// Контейнер для содержимого фильтров
const contentContainer = document.createElement('div');
contentContainer.id = 'filter-sliders-xe5-ye5e-yuemxhj';
contentContainer.style.display = 'block';
controlPanel.appendChild(contentContainer);
// Создаем кнопку сворачивания
const toggleButton = document.createElement('button');
toggleButton.id = 'button-filtr-xe5-ye5e-yuemxhj';
toggleButton.style.border = '1px solid #368c7f ';
toggleButton.style.position = 'fixed';
toggleButton.style.top = '10px';
toggleButton.style.right = '34%';
toggleButton.style.zIndex = '100500';
toggleButton.style.background = ' #1e1e1e !important';
toggleButton.style.color = ' #368c7f ';
toggleButton.style.cursor = 'pointer';
toggleButton.style.display = 'flex';
toggleButton.style.alignItems = 'center';
toggleButton.style.justifyContent = 'center';
toggleButton.style.boxShadow = '0 0 5px rgba(0,0,0,0.3)!important';
toggleButton.style.flexDirection = 'row';
toggleButton.style.gap = '5px';
toggleButton.style.padding = '5px';
toggleButton.style.borderRadius = '20px';
toggleButton.style.width = 'auto';
toggleButton.style.height = '40px';
let isPanelVisible = false;
const videoIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
videoIcon.setAttribute('width', '20');
videoIcon.setAttribute('height', '20');
videoIcon.setAttribute('viewBox', '0 0 15 15');
videoIcon.innerHTML = '<title>Video SVG Icon</title><path fill="currentColor" fill-rule="evenodd" d="M4.764 3.122A32.656 32.656 0 0 1 7.5 3c.94 0 1.868.049 2.736.122c1.044.088 1.72.148 2.236.27c.47.111.733.258.959.489c.024.025.06.063.082.09c.2.23.33.518.405 1.062c.08.583.082 1.343.082 2.492c0 1.135-.002 1.885-.082 2.46c-.074.536-.204.821-.405 1.054a2.276 2.276 0 0 1-.083.09c-.23.234-.49.379-.948.487c-.507.12-1.168.178-2.194.264c-.869.072-1.812.12-2.788.12c-.976 0-1.92-.048-2.788-.12c-1.026-.086-1.687-.144-2.194-.264c-.459-.108-.719-.253-.948-.487a2.299 2.299 0 0 1-.083-.09c-.2-.233-.33-.518-.405-1.054C1.002 9.41 1 8.66 1 7.525c0-1.149.002-1.91.082-2.492c.075-.544.205-.832.405-1.062c.023-.027.058-.065.082-.09c.226-.231.489-.378.959-.489c.517-.122 1.192-.182 2.236-.27M0 7.525c0-2.242 0-3.363.73-4.208c.036-.042.085-.095.124-.135c.78-.799 1.796-.885 3.826-1.056C5.57 2.05 6.527 2 7.5 2c.973 0 1.93.05 2.82.126c2.03.171 3.046.257 3.826 1.056c.039.04.087.093.124.135c.73.845.73 1.966.73 4.208c0 2.215 0 3.323-.731 4.168a3.243 3.243 0 0 1-.125.135c-.781.799-1.778.882-3.773 1.048C9.48 12.951 8.508 13 7.5 13s-1.98-.05-2.87-.124c-1.996-.166-2.993-.25-3.774-1.048a3.316 3.316 0 0 1-.125-.135C0 10.848 0 9.74 0 7.525m5.25-2.142a.25.25 0 0 1 .35-.23l4.828 2.118c.2.088.2.37 0 .458L5.6 9.846a.25.25 0 0 1-.35-.229z" clip-rule="evenodd"/>';
toggleButton.appendChild(videoIcon);
const filterIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
filterIcon.setAttribute('width', '20');
filterIcon.setAttribute('height', '20');
filterIcon.setAttribute('viewBox', '0 0 2048 2048');
filterIcon.innerHTML = '<title>Filter-settings SVG Icon</title><path fill="currentColor" d="m1989 1369l49 119l-124 51q6 30 6 61t-6 61l124 51l-49 119l-124-52q-35 51-86 86l52 124l-119 49l-51-124q-30 6-61 6t-61-6l-51 124l-119-49l52-124q-51-35-86-86l-124 52l-49-119l124-51q-6-30-6-61t6-61l-124-51l49-119l124 52q35-51 86-86l-52-124l119-49l51 124q30-6 61-6t61 6l51-124l119 49l-52 124q51 35 86 86zm-197 231q0-40-15-75t-41-61t-61-41t-75-15t-75 15t-61 41t-41 61t-15 75t15 75t41 61t61 41t75 15t75-15t61-41t41-61t15-75M0 128h2048v219l-768 768q-10 10-26 23t-35 28t-37 27t-30 23v-155l768-768v-37H128v37l768 768v731h163q12 34 27 66t35 62H768v-805L0 347z"/>';
toggleButton.appendChild(filterIcon);
toggleButton.addEventListener('click', () => {
isPanelVisible = !isPanelVisible;
controlPanel.style.display = isPanelVisible ? 'block' : 'none';
});
// Создаем кнопку смены языка
const langButton = document.createElement('button');
langButton.id = 'btnn-lang-jr6ur6-nftd';
langButton.style.marginBottom = '10px';
langButton.style.padding = '5px 10px';
langButton.style.background = ' #081a1b';
langButton.style.color = ' #368c7f';
langButton.style.border = '1px solid #368c7f';
langButton.style.borderRadius = '10px';
langButton.style.cursor = 'pointer';
langButton.textContent = currentLang === 'ru' ? 'EN' : 'RU'; // Изначально на основе дефолтного
contentContainer.appendChild(langButton);
// Загружаем язык (обновит кнопку)
loadLanguage();
langButton.textContent = currentLang === 'ru' ? 'EN' : 'RU';
// Обработчик для кнопки языка
langButton.addEventListener('click', () => {
currentLang = currentLang === 'ru' ? 'en' : 'ru';
langButton.textContent = currentLang === 'ru' ? 'EN' : 'RU';
updateLanguage();
saveLanguage();
});
// Функция для создания ползунка (обновлено: использует текущий язык)
function createSlider(labelKey, min, max, step, defaultValue, filterType, sliderId) {
const container = document.createElement('div');
container.id = 'createcontainer-Slider-j6rr6-jtru5r-o908ng';
container.style.margin = '30px 0';
const labelElement = document.createElement('label');
labelElement.id = 'label-fltr-tht5-videofltrxX78x7eh6rej6r';
labelElement.textContent = `${translations[currentLang][labelKey]}: `;
labelElement.style.display = 'block';
const input = document.createElement('input');
input.id = 'range-5en8mh5e-filter-video';
input.type = 'range';
input.min = min;
input.max = max;
input.step = step;
input.value = defaultValue;
input.id = sliderId || 'vidfiltr-x6xnymux-g7xh8jhx-slider';
const valueDisplay = document.createElement('span');
valueDisplay.id = 'value-znachenie-levelfltr-Display';
valueDisplay.textContent = defaultValue;
valueDisplay.style.marginLeft = '10px';
input.addEventListener('input', () => {
valueDisplay.textContent = input.value;
updateFilters();
saveFilterSettings();
});
container.appendChild(labelElement);
container.appendChild(input);
container.appendChild(valueDisplay);
contentContainer.appendChild(container);
return { input, filterType, label: labelElement, labelKey};
}
function injectSliderStyles(sliderId) {
const styleElement = document.createElement('style');
styleElement.textContent = `
input#${sliderId} {
appearance: none !important;
background: #0b2322 !important;
border-radius: 8px;
border: 1px solid #274d4a;
}
#filter-sliders-xe5-ye5e-yuemxhj {
z-index: 100000 !important;
position: relative;
top: -315px;
height: 300px;
width: 180px;
left: -30%;
}
#panel-movedraggcursor-header-xe5yuemxhj {
z-index: 1;
position: relative;
background: #1a3635 !important;
top: -5px;
height: 720px;
width: 605px;
left: -8px;
border-radius: 8px !important;
}
#vidfiltr-control-Panel-xe5yuemxhj {
width: 612px;
height: 730px;
display: block;
position: fixed;
top: 128.6px;
background: rgb(30, 30, 30);
color: rgb(54, 140, 127);
padding: 10px;
border-radius: 5px;
border: 1px solid rgb(54, 140, 127);
z-index: 9999;
font-family: Arial, sans-serif;
font-size: 16px;
box-shadow: rgba(75, 191, 191, 0.24) 0px 4px 10px 2px;
user-select: none;
cursor: move;
left: 1036.6px;
}
#button-filtr-xe5-ye5e-yuemxhj:hover {
scale: 1.5 !important;
}
#resetsetngs-btnn-jr6780ur6-nftd {
position: relative;
top: -1210px;
width: 95px;
border: 1px solid rgb(54, 140, 127);
border-radius: 10px;
left: 325%;
}
input#vidfiltr-x6xnymux-g7xh8jhx-slider {
appearance: none !important;
background: #0b2322 !important;
border-radius: 8px;
border: 1px solid #274d4a;
z-index: 500000 !important;
height: 8px;
width: 135px;
left: 225px !important;
position: relative;
top: -2px;
}
input#vidfiltr-x6xnymux-g7xh8jhx-slider:hover {
appearance: none !important;
background: #2e1d34 !important;
border-radius: 12px;
border: 1px solid #5cc2db;
z-index: 555000 !important;
}
#createcontainer-Slider-j6rr6-jtru5r-o908ng {
z-index: 555555 !important;
position: relative;
top: -485px;
left: 180px;
height: 35px;
width: 190px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start;
align-items: baseline;
gap: 5px;
}
label#label-fltr-tht5-videofltrxX78x7eh6rej6r {
width: 125px !important;
left: 8px !important;
top: 30px !important;
border-bottom: inset;
border-color: #2d4c51;
border-width: 2px;
border-radius: 5px;
background: #182727;
scale: 1.2;
padding: 1px 5px;
position: relative;
}
#resetsetngs-btnn-jr6780ur6-nftd:hover {
background: rgb(46 66 73) !important;
border-radius: 15px !important;
border: 1px solid #db975c;
z-index: 555000 !important;
}
#btnn-lang-jr6ur6-nftd {
position: relative;
width: 55px;
left: 325%;
top: -120%;
}
#btnn-lang-jr6ur6-nftd:hover {
background: rgb(13 42 73) !important;
border-radius: 15px !important;
border: 1px solid #db975c;
z-index: 555000 !important;
}
input#vidfiltr-x6xnymux-g7xh8jhx-slider::-webkit-slider-track {
background: #0b2322 !important;
border-radius: 8px;
height: 5px;
}
input#vidfiltr-x6xnymux-g7xh8jhx-slider::-webkit-slider-thumb {
appearance: none !important;
background: #368c7f !important;
border: none;
border-radius: 50%;
width: 22px;
height: 22px;
cursor: pointer;
margin-top: 1px;
}
input#vidfiltr-x6xnymux-g7xh8jhx-slider::-webkit-slider-thumb:hover {
background: #172a31 !important;
transform: scale(1.1);
box-shadow: 0 2px 4px rgb(202 94 254 / 71%);
}
span#value-znachenie-levelfltr-Display {
position: relative;
width: 45px;
left: 75%;
top: -15px !important;
}
`;
document.head.appendChild(styleElement);
}
// Вызов
injectSliderStyles('vidfiltr-x6xnymux-g7xh8jhx-slider');
// Создаем ползунки для каждого фильтра (используем ключи для переводов)
const sliders = [
createSlider('brightness', 0, 2, 0.01, 1, 'brightness'),
createSlider('contrast', 0, 2, 0.01, 1, 'contrast'),
createSlider('saturate', 0, 2, 0.01, 1, 'saturate'),
createSlider('invert', 0, 1, 0.01, 0, 'invert'),
createSlider('hue-rotate', 0, 360, 1, 0, 'hue-rotate'),
createSlider('sepia', 0, 1, 0.01, 0, 'sepia'),
createSlider('red', 0, 1, 0.01, 0, 'red-tint'),
createSlider('blue', 0, 1, 0.01, 0, 'blue-tint'),
createSlider('green', 0, 1, 0.01, 0, 'green-tint'),
createSlider('white', 0, 1, 0.01, 0, 'white-tint'),
createSlider('black', 0, 1, 0.01, 0, 'black-tint')
];
// Кнопка сброса (использует текущий язык)
const resetButton = document.createElement('button');
resetButton.id = 'resetsetngs-btnn-jr6780ur6-nftd';
resetButton.textContent = translations[currentLang].reset;
resetButton.style.marginTop = '10px';
resetButton.style.padding = '5px 10px';
resetButton.style.background = ' #0a2021';
resetButton.style.color = 'rgb(209, 236, 232) ';
resetButton.style.cursor = 'pointer';
resetButton.addEventListener('click', () => {
sliders.forEach(slider => {
let defaultValue = 0;
if (['hue-rotate',
'invert'
].includes(slider.filterType)) {
defaultValue = 0;
} else if ([
'red-tint',
'blue-tint',
'green-tint',
'white-tint',
'black-tint',
'sepia'
].includes(slider.filterType)) {
defaultValue = 0;
} else {
defaultValue = 1;
}
slider.input.value = defaultValue;
slider.input.nextSibling.textContent = slider.input.value;
});
updateFilters();
saveFilterSettings();
});
contentContainer.appendChild(resetButton);
// Функция обновления фильтров
function updateFilters() {
const videos = document.getElementsByTagName('video');
if (videos.length === 0) return;
const filterString = sliders.map(slider => {
const value = parseFloat(slider.input.value);
let filterPart;
if (slider.filterType === 'red-tint') {
filterPart = value > 0 ? `sepia(${value}) hue-rotate(0deg) saturate(${1 + value * 2})` : '';
} else if (slider.filterType === 'blue-tint') {
filterPart = value > 0 ? `sepia(${value}) hue-rotate(220deg) saturate(${1 + value * 2})` : '';
} else if (slider.filterType === 'green-tint') {
filterPart = value > 0 ? `sepia(${value}) hue-rotate(120deg) saturate(${1 + value * 2})` : '';
} else if (slider.filterType === 'white-tint') {
filterPart = value > 0 ? `grayscale(${value}) brightness(${1 + value * 3}) contrast(${1 + value * 2})` : '';
} else if (slider.filterType === 'black-tint') {
filterPart = value > 0 ? `grayscale(${value}) brightness(${1 - value * 2}) contrast(${1 + value})` : '';
} else if (slider.filterType === 'sepia') {
filterPart = value > 0 ? `sepia(${value})` : '';
} else {
const unit = slider.filterType === 'hue-rotate' ? 'deg' : '';
filterPart = value > 0 || slider.filterType === 'brightness' || slider.filterType === 'contrast' || slider.filterType === 'saturate' ? `${slider.filterType}(${value}${unit})` : '';
}
return filterPart;
}).filter(part => part !== '').join(' ');
for (let video of videos) {
video.style.filter = filterString;
}
}
// Логика перетаскивания
let isDragging = false;
let currentX = panelPosition.x;
let currentY = panelPosition.y;
let initialX;
let initialY;
header.addEventListener('mousedown', startDragging);
document.addEventListener('mousemove', drag);
document.addEventListener('mouseup', stopDragging);
function startDragging(e) {
initialX = e.clientX - currentX;
initialY = e.clientY - currentY;
isDragging = true;
}
function drag(e) {
if (isDragging) {
e.preventDefault();
currentX = e.clientX - initialX;
currentY = e.clientY - initialY;
panelPosition.x = currentX;
panelPosition.y = currentY;
controlPanel.style.left = currentX + 'px';
controlPanel.style.top = currentY + 'px';
savePanelPosition();
}
}
function stopDragging() {
isDragging = false;
}
// Удаляем избыточную начальную позицию и загружаем сохраненную
loadPanelPosition();
loadFilterSettings();
document.body.appendChild(controlPanel);
document.body.appendChild(toggleButton);
// Инициализация фильтров при загрузке
updateFilters();
// Наблюдатель за изменениями в DOM для обработки новых видео
const observer = new MutationObserver(() => {
updateFilters();
});
observer.observe(document.body, { childList: true, subtree: true });
})();