// ==UserScript==
// @name Instagram Volume Control Enhanced
// @namespace https://greasyfork.org/fr/scripts/498295-instagram-volume-control-enhanced
// @version 1.6
// @description Adjust default volume on Instagram videos with a user-friendly interface and persistent settings
// @author Manu OVG
// @match https://www.instagram.com/*
// @license MIT
// @grant none
// @icon https://i.pinimg.com/736x/dc/70/7c/dc707c0e2e4a1883d4ebb81d107aec9a.jpg
// ==/UserScript==
(function() {
'use strict';
const DEFAULT_VOLUME = 0.3;
const VOLUME_STORAGE_KEY = 'instagram_volume';
const SPEED_STORAGE_KEY = 'instagram_speed';
const DEFAULT_SPEED = 1.0;
const getStoredValue = (key, defaultValue) => {
const storedValue = localStorage.getItem(key);
return storedValue !== null ? parseFloat(storedValue) : defaultValue;
};
const setStoredValue = (key, value) => {
localStorage.setItem(key, value);
};
const setVolume = (volume) => {
document.querySelectorAll('video').forEach(video => {
video.volume = volume;
});
};
const setSpeed = (speed) => {
document.querySelectorAll('video').forEach(video => {
video.playbackRate = speed;
});
};
const createVolumeControlUI = () => {
const controlContainer = document.createElement('div');
Object.assign(controlContainer.style, {
position: 'fixed',
bottom: '10px', // Position at the bottom
right: '10px', // Position at the right
zIndex: '9999',
backgroundColor: 'rgba(34, 34, 34, 0.8)',
color: '#fff',
padding: '10px',
borderRadius: '8px',
boxShadow: '0 2px 12px rgba(0, 0, 0, 0.4)',
display: 'flex',
alignItems: 'center',
transition: 'opacity 0.3s, transform 0.3s',
opacity: '0.8',
transform: 'scale(1)',
});
const createControlElement = (type, props) => {
const element = document.createElement(type);
Object.assign(element.style, props.style);
Object.assign(element, props.attrs);
return element;
};
const volumeIcon = createControlElement('span', {
style: { marginRight: '10px', fontSize: '18px' },
innerHTML: '🔊',
});
const volumeLabel = createControlElement('label', {
style: { marginRight: '10px', fontWeight: 'bold' },
innerText: 'Volume:',
});
const volumeSlider = createControlElement('input', {
style: {
verticalAlign: 'middle',
transition: 'background-color 0.3s',
backgroundColor: '#ff0',
borderRadius: '5px',
width: '100px',
marginRight: '10px',
},
attrs: {
type: 'range',
min: '0',
max: '1',
step: '0.01',
value: getStoredValue(VOLUME_STORAGE_KEY, DEFAULT_VOLUME),
},
});
volumeSlider.addEventListener('input', () => {
const volume = parseFloat(volumeSlider.value);
setStoredValue(VOLUME_STORAGE_KEY, volume);
setVolume(volume);
controlContainer.style.backgroundColor = `rgba(34, ${Math.round(volume * 255)}, 34, 0.8)`;
});
const speedLabel = createControlElement('label', {
style: { marginLeft: '10px', marginRight: '10px', fontWeight: 'bold' },
innerText: 'Speed:',
});
const speeds = [0.5, 1, 1.5, 2];
const speedSelect = createControlElement('select', {
style: { marginRight: '10px', borderRadius: '5px', padding: '2px 5px' },
attrs: {
onchange: () => {
const speed = parseFloat(speedSelect.value);
setStoredValue(SPEED_STORAGE_KEY, speed);
setSpeed(speed);
},
},
});
speeds.forEach(speed => {
const option = document.createElement('option');
option.value = speed;
option.innerText = `${speed}x`;
if (speed === getStoredValue(SPEED_STORAGE_KEY, DEFAULT_SPEED)) {
option.selected = true;
}
speedSelect.appendChild(option);
});
const resetButton = createControlElement('button', {
style: {
backgroundColor: '#fff',
color: '#000',
border: 'none',
borderRadius: '5px',
padding: '5px 10px',
cursor: 'pointer',
transition: 'background-color 0.3s',
},
innerText: 'Reset',
attrs: {
onclick: () => {
volumeSlider.value = DEFAULT_VOLUME;
setStoredValue(VOLUME_STORAGE_KEY, DEFAULT_VOLUME);
setVolume(DEFAULT_VOLUME);
speedSelect.value = DEFAULT_SPEED;
setStoredValue(SPEED_STORAGE_KEY, DEFAULT_SPEED);
setSpeed(DEFAULT_SPEED);
controlContainer.style.backgroundColor = 'rgba(34, 34, 34, 0.8)';
},
onmouseover: () => {
resetButton.style.backgroundColor = '#ddd';
},
onmouseout: () => {
resetButton.style.backgroundColor = '#fff';
},
},
});
controlContainer.appendChild(volumeIcon);
controlContainer.appendChild(volumeLabel);
controlContainer.appendChild(volumeSlider);
controlContainer.appendChild(speedLabel);
controlContainer.appendChild(speedSelect);
controlContainer.appendChild(resetButton);
document.body.appendChild(controlContainer);
controlContainer.addEventListener('mouseover', () => {
controlContainer.style.opacity = '1';
controlContainer.style.transform = 'scale(1.05)';
});
controlContainer.addEventListener('mouseout', () => {
controlContainer.style.opacity = '0.8';
controlContainer.style.transform = 'scale(1)';
});
setVolume(getStoredValue(VOLUME_STORAGE_KEY, DEFAULT_VOLUME));
setSpeed(getStoredValue(SPEED_STORAGE_KEY, DEFAULT_SPEED));
};
window.addEventListener('load', createVolumeControlUI);
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.addedNodes.length) {
mutation.addedNodes.forEach(node => {
if (node.tagName === 'VIDEO' || (node.querySelectorAll && node.querySelectorAll('video').length > 0)) {
setTimeout(() => {
const videos = node.tagName === 'VIDEO' ? [node] : node.querySelectorAll('video');
videos.forEach(video => {
video.volume = getStoredValue(VOLUME_STORAGE_KEY, DEFAULT_VOLUME);
video.playbackRate = getStoredValue(SPEED_STORAGE_KEY, DEFAULT_SPEED);
});
}, 500);
}
});
}
});
});
observer.observe(document.body, { childList: true, subtree: true });
})();