mirror of
https://github.com/chylex/Userscripts.git
synced 2025-09-15 17:32:10 +02:00
Compare commits
7 Commits
9dc53e3e1d
...
vim-bindin
Author | SHA1 | Date | |
---|---|---|---|
390626f99f
|
|||
7319ee255e
|
|||
de4fa3b7a5
|
|||
035aed7554
|
|||
602ad9298d
|
|||
98097ef8c1
|
|||
1bf299d4fe
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.idea
|
28
README.md
28
README.md
@@ -66,11 +66,7 @@ Before you [report an issue](https://github.com/chylex/Userscripts/issues/new) (
|
||||
<tbody>
|
||||
<tr>
|
||||
<th width="110px" rowspan="5">YouTube</th>
|
||||
<td width="325px"><a href="#activity-check-removal">Activity Check Removal</a></td>
|
||||
<td>Script</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#block-youtube-playlists">Block YouTube Playlists</a></td>
|
||||
<td width="325px"><a href="#block-youtube-playlists">Block YouTube Playlists</a></td>
|
||||
<td>Script</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -81,6 +77,10 @@ Before you [report an issue](https://github.com/chylex/Userscripts/issues/new) (
|
||||
<td><a href="#hide-youtube-seek-bar--duration">Hide YouTube Seek Bar & Duration</a></td>
|
||||
<td>Script</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#redirect-youtube-shorts">Redirect YouTube Shorts</a></td>
|
||||
<td>Script</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#theater-fullscreen--transparent-chat">Theater Fullscreen + Transparent Chat</a></td>
|
||||
<td>Script</td>
|
||||
@@ -154,19 +154,11 @@ Overlays Twitch chat over the video to save space. Includes many customizations
|
||||
---
|
||||
### YouTube
|
||||
|
||||
#### Activity Check Removal
|
||||
Removes activity check that interrupts video playback. **This script is obsolete**.
|
||||
\[ [Automatically updated](https://github.com/chylex/Userscripts/raw/master/YouTube/ActivityCheckRemoval.user.js) \]
|
||||
\-
|
||||
\[ [Manually updated](https://github.com/chylex/Userscripts/raw/2ddfdcd8cffb796830ff04847f43f2bf91fb0ffc/YouTube/ActivityCheckRemoval.user.js) \]
|
||||
\-
|
||||
\[ [Source code](https://github.com/chylex/Userscripts/blob/master/YouTube/ActivityCheckRemoval.user.js) \]
|
||||
|
||||
#### Block YouTube Playlists
|
||||
Removes playlists from YouTube video URLs.
|
||||
\[ [Automatically updated](https://github.com/chylex/Userscripts/raw/master/YouTube/BlockPlaylists.user.js) \]
|
||||
\-
|
||||
\[ [Manually updated](https://github.com/chylex/Userscripts/raw/b74c26ed01640db4f6d0a06f67d6e25627fb07be/YouTube/BlockPlaylists.user.js) \]
|
||||
\[ [Manually updated](https://github.com/chylex/Userscripts/raw/98097ef8c14ab84ff0dc7463bbe55a363890bb6d/YouTube/BlockPlaylists.user.js) \]
|
||||
\-
|
||||
\[ [Source code](https://github.com/chylex/Userscripts/blob/master/YouTube/BlockPlaylists.user.js) \]
|
||||
|
||||
@@ -186,6 +178,14 @@ Hides all mentions of video durations by default. Press 'AltGr' to toggle.
|
||||
\-
|
||||
\[ [Source code](https://github.com/chylex/Userscripts/blob/master/YouTube/HideSeekBarAndDuration.user.js) \]
|
||||
|
||||
#### Redirect YouTube Shorts
|
||||
Redirects YouTube shorts to normal video URLs.
|
||||
\[ [Automatically updated](https://github.com/chylex/Userscripts/raw/master/YouTube/RedirectShorts.user.js) \]
|
||||
\-
|
||||
\[ [Manually updated](https://github.com/chylex/Userscripts/raw/035aed7554c89fee66a6278f4fcf73292821b7f5/YouTube/RedirectShorts.user.js) \]
|
||||
\-
|
||||
\[ [Source code](https://github.com/chylex/Userscripts/blob/master/YouTube/RedirectShorts.user.js) \]
|
||||
|
||||
#### Theater Fullscreen + Transparent Chat
|
||||
In theater mode, it expands video to full screen, makes chat transparent and overlays it over the video. Note that colors of images in chat will be inverted, and the player controls may behave strangely. **Requires classic YouTube layout,** you can use the third-party [Youtube - Restore Classic](https://greasyfork.org/en/scripts/34818-youtube-restore-classic) script for that.
|
||||
\[ [Automatically updated](https://github.com/chylex/Userscripts/raw/master/YouTube/TheaterFullscreenTransparentChat.user.js) \]
|
||||
|
279
Vim/VimBindings.user.js
Normal file
279
Vim/VimBindings.user.js
Normal file
@@ -0,0 +1,279 @@
|
||||
// ==UserScript==
|
||||
// @name Vim Bindings
|
||||
// @description Reformats the Vim index help page and adds custom notes to each binding.
|
||||
// @author chylex
|
||||
// @version 1
|
||||
// @license MIT
|
||||
// @namespace https://chylex.com
|
||||
// @homepageURL https://github.com/chylex/Userscripts
|
||||
// @supportURL https://github.com/chylex/Userscripts/issues
|
||||
// @include https://vimhelp.org/index.txt.html
|
||||
// @run-at document-end
|
||||
// @grant none
|
||||
// ==/UserScript==
|
||||
|
||||
const settings = loadSettings();
|
||||
|
||||
function loadSettings() {
|
||||
try {
|
||||
const json = localStorage.getItem("vim_binding_settings");
|
||||
return json === null ? {} : JSON.parse(json);
|
||||
} catch (e) {
|
||||
console.error("Could not load binding settings", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function saveSettings() {
|
||||
localStorage.setItem("vim_binding_settings", JSON.stringify(settings));
|
||||
}
|
||||
|
||||
appendElement(document.head, "style").textContent = `
|
||||
#vh-content {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
#vh-content pre {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
tr.h {
|
||||
border-bottom: 2px dashed var(--aqua);
|
||||
}
|
||||
|
||||
tr.h td, tr:has(+ tr.subsection) td {
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
tr.h + tr td, tr.subsection + tr td {
|
||||
padding-top: 12px;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 2px 8px;
|
||||
}
|
||||
|
||||
td:first-child {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
td:last-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
tr.subsection td {
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
border-top: 1px dashed var(--aqua);
|
||||
border-bottom: 1px dashed var(--aqua);
|
||||
}
|
||||
|
||||
tr[data-binding-value="used"],
|
||||
tr[data-binding-value="changed"],
|
||||
tr[data-binding-value="rebound"],
|
||||
tr[data-binding-value="not-used"] {
|
||||
opacity: 0.35;
|
||||
}
|
||||
|
||||
tr.missing {
|
||||
opacity: 0.35;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
select {
|
||||
border: 0;
|
||||
padding: 3px 5px;
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
|
||||
select, select option {
|
||||
font-family: monospace;
|
||||
text-align: center;
|
||||
}
|
||||
`;
|
||||
|
||||
let headingIndex = 0;
|
||||
|
||||
/** @var {Object<string, HTMLSelectElement[]>} */
|
||||
const selectsByBinding = {};
|
||||
|
||||
for (const headingEle of document.querySelectorAll("span[class='h']:has(+ span[class='h'])")) {
|
||||
const delimiterEle = headingEle.nextElementSibling;
|
||||
|
||||
const columnNames = headingEle.textContent.split(/(?<!^)(?:\t+\s*|(?<=note ))(?!$)/).map(name => name.trim());
|
||||
|
||||
const tableEle = document.createElement("table");
|
||||
addHeadingRow(tableEle, columnNames);
|
||||
|
||||
let currentNode = delimiterEle.nextSibling;
|
||||
let html = "";
|
||||
|
||||
while (currentNode !== null && !isTagWithClass(currentNode, "SPAN", "h")) {
|
||||
html += currentNode.nodeType === Node.ELEMENT_NODE ? currentNode.outerHTML : currentNode.textContent;
|
||||
|
||||
const nextNode = currentNode.nextSibling;
|
||||
currentNode.remove();
|
||||
currentNode = nextNode;
|
||||
}
|
||||
|
||||
for (const line of html.split(/\n(?=<a|\t{1,3}[^\t]|\n)/)) {
|
||||
addContentRow(tableEle, line, columnNames);
|
||||
}
|
||||
|
||||
headingEle.insertAdjacentElement("beforebegin", tableEle);
|
||||
headingEle.remove();
|
||||
delimiterEle.remove();
|
||||
|
||||
++headingIndex;
|
||||
}
|
||||
|
||||
function isColumnRightAligned(columnName) {
|
||||
return columnName === "note";
|
||||
}
|
||||
|
||||
function addHeadingRow(table, columnNames) {
|
||||
const tr = appendElement(table, "tr");
|
||||
tr.classList.add("h");
|
||||
|
||||
appendElement(tr, "td");
|
||||
|
||||
for (const columnName of columnNames) {
|
||||
const td = appendElement(tr, "td");
|
||||
td.innerText = columnName;
|
||||
|
||||
if (isColumnRightAligned(columnName)) {
|
||||
td.style.textAlign = "right";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addContentRow(table, line, columnNames) {
|
||||
if (line.includes("Meta characters (0x80 to 0xff, 128 to 255)")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// console.info(line);
|
||||
|
||||
const columnCount = columnNames.length;
|
||||
const matches = line.match(/^(?:(<a .+?<\/a>)\s+|\t{2})(.*?)(?:(?:\t+?\s*| {2}\t*|(?<=] )|(?<=<span class="s">{.+?}<\/span> (?!(?:<a .+?class="s">.+?<\/a> )?<span class="s">{.+?}<\/span>)))(?:(\d+(?:,\d+)*)\s+)?(.*))?$/s);
|
||||
|
||||
if (matches === null) {
|
||||
addSubsectionRow(table, line, columnCount);
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var {HTMLTableRowElement} */
|
||||
const tr = appendElement(table, "tr");
|
||||
|
||||
/** @var {HTMLTableCellElement[]} */
|
||||
const tds = [ appendElement(tr, "td") ];
|
||||
|
||||
for (let matchIndex = 1; matchIndex < matches.length; matchIndex++) {
|
||||
let td = tds[tds.length - 1];
|
||||
|
||||
if (matchIndex <= columnCount) {
|
||||
tds.push(td = appendElement(tr, "td"));
|
||||
|
||||
if (isColumnRightAligned(columnNames[matchIndex - 1])) {
|
||||
td.style.textAlign = "right";
|
||||
}
|
||||
}
|
||||
else if (td.innerHTML.length > 0) {
|
||||
td.innerHTML += " ";
|
||||
}
|
||||
|
||||
const match = matches[matchIndex];
|
||||
if (match !== undefined) {
|
||||
td.innerHTML += match
|
||||
.replaceAll("\t", "")
|
||||
.replace(/\n\s*/g, " ")
|
||||
.replace("<MiddleMouse>", "<MiddleMouse>")
|
||||
.trim();
|
||||
}
|
||||
}
|
||||
|
||||
const bindingElements = tds[1].getElementsByClassName("l");
|
||||
|
||||
if (bindingElements.length === 1) {
|
||||
const binding = bindingElements[0].innerText;
|
||||
const select = appendElement(tds[0], "select");
|
||||
|
||||
addOption(select, "TBD", "");
|
||||
addOption(select, "Used", "used");
|
||||
addOption(select, "Changed", "changed");
|
||||
addOption(select, "Rebound", "rebound");
|
||||
addOption(select, "Interested", "interested");
|
||||
addOption(select, "Not Used", "not-used");
|
||||
|
||||
const loadedValue = settings[binding];
|
||||
select.value = loadedValue ?? "";
|
||||
tr.setAttribute("data-binding-value", loadedValue);
|
||||
|
||||
select.addEventListener("change", _ => {
|
||||
const newValue = select.value;
|
||||
|
||||
for (const otherSelect of selectsByBinding[binding]) {
|
||||
if (otherSelect !== select) {
|
||||
otherSelect.value = newValue;
|
||||
}
|
||||
|
||||
otherSelect.closest("tr").setAttribute("data-binding-value", newValue);
|
||||
}
|
||||
|
||||
if (!newValue) {
|
||||
delete settings[binding];
|
||||
}
|
||||
else {
|
||||
settings[binding] = newValue;
|
||||
}
|
||||
|
||||
saveSettings();
|
||||
});
|
||||
|
||||
if (!(binding in selectsByBinding)) {
|
||||
selectsByBinding[binding] = [];
|
||||
}
|
||||
|
||||
selectsByBinding[binding].push(select);
|
||||
}
|
||||
else {
|
||||
tr.classList.add("missing");
|
||||
}
|
||||
}
|
||||
|
||||
function addSubsectionRow(table, line, columnCount) {
|
||||
const text = line.trim();
|
||||
if (text.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var {HTMLTableRowElement} */
|
||||
const tr = appendElement(table, "tr");
|
||||
tr.classList.add("subsection");
|
||||
|
||||
/** @var {HTMLTableCellElement} */
|
||||
const td = appendElement(tr, "td");
|
||||
td.innerHTML = text;
|
||||
td.colSpan = columnCount;
|
||||
}
|
||||
|
||||
function isTagWithClass(node, tagName, className) {
|
||||
return node.nodeType === Node.ELEMENT_NODE && node.tagName === tagName && node.classList.contains(className);
|
||||
}
|
||||
|
||||
function appendElement(target, tagName) {
|
||||
const ele = document.createElement(tagName);
|
||||
target.appendChild(ele);
|
||||
return ele;
|
||||
}
|
||||
|
||||
function addOption(select, name, value) {
|
||||
const option = appendElement(select, "option");
|
||||
option.innerText = name;
|
||||
option.value = value;
|
||||
}
|
@@ -1,35 +0,0 @@
|
||||
// ==UserScript==
|
||||
// @name YouTube Activity Check Removal
|
||||
// @description Removes activity check that interrupts video playback.
|
||||
// @version 1
|
||||
// @license MPL-2.0
|
||||
// @namespace https://chylex.com
|
||||
// @homepageURL https://github.com/chylex/Userscripts
|
||||
// @supportURL https://github.com/chylex/Userscripts/issues
|
||||
// @include https://youtube.com/*
|
||||
// @include https://*.youtube.com/*
|
||||
// @run-at document-end
|
||||
// @grant none
|
||||
// @noframes
|
||||
// ==/UserScript==
|
||||
|
||||
var timeout = 0;
|
||||
|
||||
var check = setInterval(function(){
|
||||
if (_yt_www.J){
|
||||
clearInterval(check);
|
||||
|
||||
var prev = _yt_www.J;
|
||||
|
||||
_yt_www.J = function(cls){
|
||||
if (cls && cls.startsWith("youthere-")){
|
||||
return null;
|
||||
}
|
||||
|
||||
return prev.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
else if (++timeout > 500){ // average should be about 5-10
|
||||
clearInterval(check);
|
||||
}
|
||||
}, 1);
|
@@ -1,7 +1,7 @@
|
||||
// ==UserScript==
|
||||
// @name Block YouTube Playlists
|
||||
// @description Removes playlists from YouTube video URLs.
|
||||
// @version 1
|
||||
// @version 2
|
||||
// @license MPL-2.0
|
||||
// @namespace https://chylex.com
|
||||
// @homepageURL https://github.com/chylex/Userscripts
|
||||
@@ -13,18 +13,11 @@
|
||||
// @noframes
|
||||
// ==/UserScript==
|
||||
|
||||
if (location.pathname == "/watch" && location.search.includes("&list=")){
|
||||
history.replaceState({}, document.title, location.search.replace(/&list=(.*)/, ""));
|
||||
location.reload();
|
||||
function redirectPlaylist() {
|
||||
if (location.pathname === "/watch" && location.search.includes("&list=")) {
|
||||
location.replace(location.href.replace(/&list=(.*)/, ""));
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("spfclick", function(e){
|
||||
var url = e.detail.url;
|
||||
|
||||
if (url.includes("youtube.com/watch?") && url.includes("&list=")){
|
||||
// forces a normal page load
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
}, true);
|
||||
redirectPlaylist();
|
||||
document.addEventListener("yt-navigate-start", redirectPlaylist);
|
||||
|
23
YouTube/RedirectShorts.user.js
Normal file
23
YouTube/RedirectShorts.user.js
Normal file
@@ -0,0 +1,23 @@
|
||||
// ==UserScript==
|
||||
// @name Redirect YouTube Shorts
|
||||
// @description Redirects YouTube shorts to normal video URLs.
|
||||
// @version 1
|
||||
// @license MPL-2.0
|
||||
// @namespace https://chylex.com
|
||||
// @homepageURL https://github.com/chylex/Userscripts
|
||||
// @supportURL https://github.com/chylex/Userscripts/issues
|
||||
// @include https://youtube.com/*
|
||||
// @include https://*.youtube.com/*
|
||||
// @run-at document-start
|
||||
// @grant none
|
||||
// @noframes
|
||||
// ==/UserScript==
|
||||
|
||||
function redirectShort() {
|
||||
if (location.pathname.startsWith("/shorts/")) {
|
||||
location.replace(location.href.replace("/shorts/", "/watch?v="));
|
||||
}
|
||||
}
|
||||
|
||||
redirectShort();
|
||||
document.addEventListener("yt-navigate-start", redirectShort);
|
Reference in New Issue
Block a user