Custom video controls on Instagram: play/pause, progress, volume, mute, speed, fullscreen, blur effect. Works on all videos.
// ==UserScript==
// @name Instagram Custom Video Controls
// @name:ru Instagram — Кастомные видеоконтролы
// @namespace https://greasyfork.org/ru/users/1384659
// @version 1.0
// @description Custom video controls on Instagram: play/pause, progress, volume, mute, speed, fullscreen, blur effect. Works on all videos.
// @description:ru Заменяет стандартные контролы Instagram на кастомную панель (пауза/старт, громкость, скорость, fullscreen, размытый фон).
// @author FerNikoMF
// @match https://www.instagram.com/*
// @license MIT
// @grant none
// ==/UserScript==
(function() {
'use strict';
let isMuted = false;
let lastVolume = 1;
let styleAdded = false;
function initPlayer(video) {
if (video.hasCustomControls) return;
video.hasCustomControls = true;
video.removeAttribute("controls");
const panel = document.createElement("div");
panel.className = "custom-controls";
panel.innerHTML = `
<button class="play-pause">▶️</button>
<input type="range" class="progress" min="0" max="100" value="0">
<span class="time">0:00 / 0:00</span>
<div class="volume-wrapper">
<button class="mute">🔊</button>
<input type="range" class="volume-slider" min="0" max="1" step="0.01" value="${lastVolume}">
</div>
<select class="speed">
<option value="0.5">0.5x</option>
<option value="1" selected>1x</option>
<option value="1.5">1.5x</option>
<option value="2">2x</option>
</select>
<button class="fullscreen">⛶</button>
`;
if (!styleAdded) {
const style = document.createElement("style");
style.textContent = `
.custom-controls {
position: absolute;
bottom: 0;
left: 0;
right: 0;
display: flex;
align-items: center;
justify-content: space-between;
background: rgba(0,0,0,0.4);
backdrop-filter: blur(8px);
padding: 5px;
opacity: 0;
transition: opacity 0.3s;
z-index: 9999;
}
.progress { flex: 1; margin: 0 5px; }
.time { font-size: 12px; color: white; margin-right: 10px; }
.volume-wrapper { position: relative; display: inline-block; }
.volume-slider {
display: none;
position: absolute;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
height: 80px;
width: 4px;
writing-mode: bt-lr;
-webkit-appearance: slider-vertical;
}
.volume-wrapper:hover .volume-slider { display: block; }
select.speed {
margin: 0 5px;
background: black;
color: white;
border: none;
border-radius: 3px;
padding: 2px;
}
button {
background: none;
border: none;
color: white;
font-size: 16px;
cursor: pointer;
}
`;
document.head.appendChild(style);
styleAdded = true;
}
video.parentElement.style.position = "relative";
video.parentElement.appendChild(panel);
const playPause = panel.querySelector(".play-pause");
const progress = panel.querySelector(".progress");
const time = panel.querySelector(".time");
const muteBtn = panel.querySelector(".mute");
const volumeSlider = panel.querySelector(".volume-slider");
const speed = panel.querySelector(".speed");
const fullscreenBtn = panel.querySelector(".fullscreen");
// === Контролы показываются при движении мыши ===
let hideTimer;
function showPanel() {
panel.style.opacity = "1";
clearTimeout(hideTimer);
hideTimer = setTimeout(() => {
panel.style.opacity = "0";
}, 2000);
}
video.addEventListener("mousemove", showPanel);
panel.addEventListener("mousemove", showPanel);
// === Play/Pause ===
playPause.onclick = () => {
if (video.paused) {
video.play();
playPause.textContent = "⏸";
} else {
video.pause();
playPause.textContent = "▶️";
}
};
// === Прогресс ===
video.addEventListener("timeupdate", () => {
progress.value = (video.currentTime / video.duration) * 100 || 0;
time.textContent = format(video.currentTime) + " / " + format(video.duration);
});
progress.oninput = () => {
video.currentTime = (progress.value / 100) * video.duration;
};
// === Mute/Volume ===
muteBtn.onclick = () => {
isMuted = !isMuted;
applyGlobalSettings(video, muteBtn);
};
volumeSlider.oninput = () => {
lastVolume = video.volume = volumeSlider.value;
isMuted = video.volume === 0;
applyGlobalSettings(video, muteBtn);
};
// === Синхронизация глобальных настроек ===
video.addEventListener("volumechange", () => {
if (video.muted !== isMuted || video.volume !== lastVolume) {
video.muted = isMuted;
video.volume = lastVolume;
}
});
// === Speed ===
speed.onchange = () => {
video.playbackRate = parseFloat(speed.value);
};
// === Fullscreen ===
fullscreenBtn.onclick = () => {
if (video.requestFullscreen) video.requestFullscreen();
else if (video.webkitRequestFullscreen) video.webkitRequestFullscreen();
};
applyGlobalSettings(video, muteBtn);
}
function applyGlobalSettings(video, muteBtn) {
video.muted = isMuted;
video.volume = lastVolume;
muteBtn.textContent = isMuted ? "🔇" : "🔊";
}
function format(sec) {
if (isNaN(sec)) return "0:00";
let m = Math.floor(sec / 60);
let s = Math.floor(sec % 60);
return `${m}:${s.toString().padStart(2,"0")}`;
}
const observer = new MutationObserver(() => {
document.querySelectorAll("video").forEach(initPlayer);
});
observer.observe(document.body, { childList: true, subtree: true });
})();