// ==UserScript==
// @name V LIVE Video Rotation
// @description Adds buttons and keyboard shortcuts to rotate and flip the video.
// @version 1.2
// @author aqmx
// @namespace aqmx
// @license MIT
// @match *://www.vlive.tv/video/*
// @grant GM_addStyle
// ==/UserScript==
GM_addStyle(`
.vlive_info {
display: inline-block;
box-sizing: border-box;
width: 100%;
}
.vlive_info .tit {
display: block;
margin-bottom: 9px;
}
.vlive_info .status_area {
display: inline-flex;
align-items: center;
}
.vlive_info .ico_blue {
margin-right: unset;
}
.vlive_info .txt, .vlive_info .like, .vlive_info .date {
margin-top: 0;
}
.vlive_info .icon_play, .vlive_info .icon_like {
margin-top: 1px;
}
#video-rotation-controls {
position: relative;
display: inline-block;
margin-left: 15px;
z-index: 1;
}
#video-rotation-controls button {
font-size: 20px;
background: #f5f5f5;
border: 1px solid #d9d9d9;
color: #414141;
margin-top: -4px;
line-height: 22px;
height: 24px;
width: 24px;
outline: 0;
}
`);
let directions = {
left: 'r270',
up: '0',
right: 'r90',
down: 'r180',
flipH: 'flipH',
flipV: 'flipV',
}
let rotations = {
r90: 'rotate(90deg)',
r180: 'rotate(180deg)',
r270: 'rotate(270deg)',
};
let scaling = {
flipH: 'scaleX(-1)',
flipV: 'scaleY(-1)',
portrait: 'scale(1.759)',
landscape: 'scale(0.559)',
};
let shortcutsEnabled = true;
let shortcuts = {
'Numpad8': directions.up,
'Numpad2': directions.down,
'Numpad4': directions.left,
'Numpad6': directions.right,
'Numpad9': directions.flipH,
'Numpad3': directions.flipV,
}
let stylesheet = null;
(() => {
stylesheet = document.createElement('style');
document.head.appendChild(stylesheet);
let getAllSubsets = arr => arr.reduce((subsets, value) => subsets.concat(subsets.map(set => [...set, value])), [[]]).slice(1);
let scalings = getAllSubsets(Object.keys(scaling));
for (let rule in rotations) {
stylesheet.sheet.insertRule(`video.${rule} { transform: ${rotations[rule]}; }`, stylesheet.sheet.cssRules.length);
for (let scalingSet of scalings) {
stylesheet.sheet.insertRule(`video.${rule}.${scalingSet.reduce((s, v) => s+'.'+v)} { transform: ${rotations[rule] + scalingSet.reduce((s, v) => s+' '+scaling[v], '')}; }`, stylesheet.sheet.cssRules.length);
}
}
let flips = getAllSubsets([directions.flipH, directions.flipV]);
for (let flipSet of flips) {
stylesheet.sheet.insertRule(`video.${flipSet.reduce((s, v) => s+'.'+v)} { transform:${flipSet.reduce((s, v) => s+' '+scaling[v], '')}; }`, stylesheet.sheet.cssRules.length);
}
})();
function addButton() {
let btnArea = document.querySelector('#content .vlive_section .vlive_info .btn_area');
if (!btnArea) {
setTimeout(addButton, 500);
return;
}
let div = document.createElement('div');
div.id = 'video-rotation-controls';
div.innerHTML = `
<button data-direction="${directions.left}">🠘</button>
<button data-direction="${directions.up}">🠙</button>
<button data-direction="${directions.right}">🠚</button>
<button data-direction="${directions.down}">🠛</button>
<button data-direction="${directions.flipV}">🡙</button>
<button data-direction="${directions.flipH}">🡘</button>`;
btnArea.parentNode.insertBefore(div, btnArea);
document.querySelector('#video-rotation-controls').addEventListener('click', function(e) {
if (e.target.tagName.toLowerCase() != 'button') return;
let video = document.querySelector('.u_rmcplayer_video video') || document.querySelector('.vwplayer_vlivelive .videoBox video');
if (!video) return;
let flip = [directions.flipH, directions.flipV].includes(e.target.dataset.direction);
if (flip) {
video.classList.toggle(e.target.dataset.direction);
}
else {
video.classList.remove(directions.left, directions.right, directions.down, 'portrait', 'landscape');
if (e.target.dataset.direction != directions.up) {
video.classList.add(e.target.dataset.direction);
if ([directions.left, directions.right].includes(e.target.dataset.direction)) {
video.classList.add(video.videoHeight > video.videoWidth ? 'portrait' : 'landscape');
}
}
}
});
}
addButton();
// Shortcuts
window.addEventListener('keydown', function(e) {
if (shortcuts[e.code] && shortcutsEnabled) {
let button = document.querySelector('#video-rotation-controls button[data-direction="'+shortcuts[e.code]+'"]');
if (button) button.click();
}
else if (e.code == 'Pause') {
shortcutsEnabled = !shortcutsEnabled;
}
});