YouTube Video Preview and Ratings Keyless
Возможности:
Мгновенный предварительный просмотр видео во всплывающем проигрывателе при наведении курсора или щелчке на превью. Рейтинги видео и данные разрешения отображаются на превью.
Расширение получает информацию о видео без использования ключа API YouTube, который можно запретить или ограничить.
Скрипт добавляет маленькую красно-серую квадратную кнопку в верхнем правом углу страниц YouTube, при нажатии этой кнопки открываются настройки скрипта: включение/отключение предпросмотра при наведении, задержка при наведении, включение/отключение предпросмотра по щелчку, показа разрешения (качества) видео и рейтингов. Настройки применяются при нажатии крестика для закрытия меню настроек.
Установить скрипт (с настройками на английском)
Как сделать меню на русском?
Очень просто. На примере расширения Tampermonkey (но подобным образом это делается и в других расширениях для скриптов):
1. Жмём кнопку Tampermonkey в панели инструментов — открываем «Панель управления» — жмём кнопку «Редактировать» (листочек с карандашом).
2. Жмём «Найти», набираем фразу «Preview Options», ставим галочку «Aa» (то есть учёт регистра букв) и жмём «Найти далее».
3. Теперь важно заменить только выделенные мной здесь слова того фрагмента кода, который мы нашли, не трогая ничего остального — ни кавычек "…" вокруг слов, ни чего-то ещё рядом, каким бы неважным оно ни казалось!
Итак, я заменил:
function pref_popup_open() {
if (document.getElementById("vpp_pref_popup")) {
return;
}
const popup = newElem("span", {"id": "vpp_pref_popup"}, null, document.body);
newElem("div", {"id": "vpp_pref_title"}, "Preview Options", popup);let changed = false;
const closemark = newElem("span", {"id": "vpp_pref_close", "title": "close options"}, "\u2716", popup);
closemark.onclick = function () {
popup.parentNode.removeChild(popup);
if (changed) {
location.reload();
}
};let mark = function(){changed = true;};
new_checkbox("floatEnable", "Hover Preview", "div", popup, null, mark);
new_plusminus("floatDelay", "open delay", popup);
new_checkbox("playerEnable", "Click Preview", "div", popup, null, mark);
new_checkbox("rateEnable", "Video Rating", "div", popup, null, mark);
new_checkbox("defEnable", "Video Resolution", "div", popup, null, mark);
}
function pref_popup_open() {
if (document.getElementById("vpp_pref_popup")) {
return;
}
const popup = newElem("span", {"id": "vpp_pref_popup"}, null, document.body);
newElem("div", {"id": "vpp_pref_title"}, "Опции предпросмотра", popup);let changed = false;
const closemark = newElem("span", {"id": "vpp_pref_close", "title": "Закрыть и применить настройки"}, "\u2716", popup);
closemark.onclick = function () {
popup.parentNode.removeChild(popup);
if (changed) {
location.reload();
}
};let mark = function(){changed = true;};
new_checkbox("floatEnable", "Предпросмотр при наведении", "div", popup, null, mark);
new_plusminus("floatDelay", "открыть через", popup);
new_checkbox("playerEnable", "Предпросмотр по щелчку", "div", popup, null, mark);
new_checkbox("rateEnable", "Рейтинг видео", "div", popup, null, mark);
new_checkbox("defEnable", "Разрешение", "div", popup, null, mark);
}
Мой перевод фразы «close options» как «Закрыть и применить настройки» — не ошибка, а намеренно сделанное пояснение. Новые настройки не действуют, пока меню не закрыто щелчком по этому крестику.
Отредактировано Пандёнок (02-05-2021 06:21:03)
Отсутствует
Пандёнок
1. При наведении действительно есть предпросмотр, который сам по себе мне вообще не интересен, так как уже давно реализован где попало и кроме раздражения ничего не вызывает.
2. В скрипте намного больше строк для перевода, чем вы нашли.
Интересен скрипт-плеер который вызывается по щелчку на значке в миниатюрах. Главная особенность этого скрипт-плеера, то что он позволяет последовательно просмотреть все видео на любой странице YT без лишних щелчков и перезагрузок страницы.
В нем то и находится еще два десятка строк для перевода. Настройки скрипт-плеера - в блоках под строкой "function player_options(parent) {" и кнопки заголовка скрипт-плеера - в блоках под строкой "const buttonArea = newElem("span", {"id":". Есть и еще по мелочи, уведомления и т.п.
Из того набора функций которыми я собираюсь пользоваться еще заметил, что не работает смена цвета разрешений на миниатюрах в зависимости от качества видео. А такая функция изначально была заложена. Для всех разрешений у меня работает строка с цветом для HD, т.е.".vpp_meta_def_hd.HD {color:...". Раз уж цветовая индикация не работает, то есть смысл раскрасить это более светлым оттенком.
Отредактировано _zt (02-05-2021 00:19:59)
Отсутствует
Пандёнок
Как сделать меню на русском?
Есть подозрение, что русификация слетит при ручном обновлении скрипта (измененный скрипт не обновляется). У меня слетает измененный размер плеера, и часть этого кода записана в блокнот.
Отсутствует
_zt
1. Мне он тоже не интересен, я оставил только разрешение видео и заодно рейтинги.
2. Так переведите. Не пользуясь этими функциями и не имея понятия о них, я не могу проверить правильность перевода.
⠀
oleg.sgh
Есть подозрение, что русификация слетит при ручном обновлении скрипта (измененный скрипт не обновляется). У меня слетает измененный размер плеера, и часть этого кода записана в блокнот.
Это не подозрение. Точно слетит. Но недолго сделать заново.
Добавлено 02-05-2021 06:23:05
Кто-нибудь может починить смену цвета разрешений на миниатюрах в зависимости от качества видео?
Добавлено 02-05-2021 06:29:41
if(max_res != 0) { parent.setAttribute("vpp_meta_def", ""); const def_node = newElem("span", {"class": "vpp_meta_def_container", "reveal": "true", "title": max_quality_label}, null, parent); const def_txt = max_res >= (15360 * 8640) ? "16K" : max_res >= (7680 * 4320) ? "8K" : max_res >= (2880 * 2160) ? "4K" : max_res >= (960 * 1080) ? "1080p" : max_res >= (640 * 720) ? "720p" : "SD"; newElem("span", {"class": "vpp_meta_def_hd HD"}, def_txt, def_node); }
— похоже, автор отказался от разных цветов.
Отредактировано Пандёнок (02-05-2021 06:30:30)
Отсутствует
Пандёнок
Но недолго сделать заново.
Оно так, только переводить в скрипте слова опции, рейтинг, плеер...овчинка выделки не стоит. Я за всё время существования этого скрипта только раз лазил в настройки, когда он был переписан под новый интерфейс Ютуба.
Отсутствует
Пандёнок
Я не вижу здесь никого кому нужен перевод, а позже скрипт будет уже обновлен автором. )
Да, похоже смена цвета вырезана, иначе, в той секции которую вы привели, должны бы были назначаться классы для каждого разрешения, а не один класс на все.
Отсутствует
Пандёнок
// ==UserScript== // @name YouTube Video Preview and Ratings Keyless // @namespace YouTubeVideoPreviewPlayer // @version 20210316 // @description Instant video previews in popup player by hovering or clicking video thumbs. Video ratings and resolution data shown on the thumbs. Gets video information without using a YouTube API key, which can be banned or limited. // @author Couchy // @match https://www.youtube.com/* // @grant GM_setValue // @grant GM_getValue // @noframes // ==/UserScript== //================================================================== //Userscript specific functions function debug(...args) { //console.log(...args); } function set_pref(preference, new_value) { GM_setValue(preference, new_value); } function get_pref(preference) { return GM_getValue(preference); } function init_pref(preference, new_value) { let value = get_pref(preference); if (value == null) { set_pref(preference, new_value); value = new_value; } return value; } //================================================================== // Styles const style_basic = ` /* prefs */ #vpp_pref_popup {direction:ltr; font:11px/11px Roboto,arial,sans-serif; position:fixed; right:0px; top:0px; color:#e0e0e0; background:#202020; padding:15px 15px 15px 10px; border-radius:3px; box-shadow:0px 0px 5px 1px gray; /*z-index:2147483647;*/ z-index:2147483646;} .vpp_pref_group {margin-left:15px; color:yellow;} #vpp_pref_close {font:14px/14px Roboto,arial,sans-serif; color:lightgray; position:absolute; top:3px; right:5px; cursor:pointer; user-select:none; -moz-user-select:none;} #vpp_pref_close:hover {color:white;} #vpp_pref_title {font:500 13px/13px Roboto,arial,sans-serif; padding:5px !important;} #vpp_pref_button {cursor:pointer; width:18px; height:18px; background-size:contain; background-repeat:no-repeat; opacity:0.7; position:absolute; right:0px; top:0px; user-select:none; -moz-user-select:none;} #vpp_pref_button:hover {opacity:1;} #vpp_pref_button {background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAeUlEQVR42u2UwQ2AMAwDk52YCWaCmdgp7QshKP6QKn7Yv0pudEqcuBXLBXB/7GaBzFv3Z3k+AdYY/z3cr+IZHgywPCZzxrv4T48AyAFAeKaH0ICmr2GFuDpAkQGOLRBAOQAIjw5Rtrg6QJEBji0QQDkACI8OUbYE0ADbonowcNn6sgAAAABJRU5ErkJggg==');} #vpp_pref_delay_text {margin-left:20px; color:khaki;} #vpp_pref_delay_num {margin-left:3px; color:khaki;} .vpp_pref_delay_plusminus {margin-left:5px; cursor:pointer; text-align:center; font-weight:800; color:black; background:#B0B0B0; border-radius:2px; display:inline-block; width:10px; user-select:none; -moz-user-select:none;} .vpp_pref_delay_plusminus:hover {background:#D0D0D0;} #vpp_pref_delay_plus {margin-left:2px;} #vpp_pref_delay_minus {margin-left:5px;} /* meta data */ .vpp_meta_def_container {font:500 12px/14px Roboto,arial,sans-serif; position:absolute; top:0px; left:0px; background:#e8e8e8; padding:0px 3px; border-radius:2px; display:none; cursor:default;} html[dark] .vpp_meta_def_container {background:#202020 !important;} .vpp_meta_def_container[reveal] {display: block;} .vpp_meta_def_container[space] .vpp_meta_def_hd {margin-right:2px;} .vpp_meta_def_format {position:relative; color:black;} html[dark] .vpp_meta_def_format {color:#f0f0f0 !important;} .vpp_meta_def_hd {position:relative;} .vpp_meta_def_hd.HD {color:#FF6969;} //цвет текста разрешения на превью .vpp_meta_def_hd.UHD {color:red;} .vpp_meta_rate {direction:ltr; font:500 12px/14px Roboto,arial,sans-serif; position:absolute; top:0px; right:0px; color:white; padding:0px 3px; border-radius:2px; cursor:default;} body[dir='ltr'] [vpp_meta_rate] ytd-thumbnail-overlay-toggle-button-renderer, body[dir='rtl'] [vpp_meta_def] ytd-thumbnail-overlay-toggle-button-renderer {margin-top:12px !important;} #vpp_meta_box {position:relative; float:left; height:13px; margin-top:3px;} #vpp_meta_box .vpp_meta_def_container {background:none !important; position:relative; clear:none; float:left;} #vpp_meta_box .vpp_meta_rate {position:relative; clear:none; float:right; margin-left:5px;} #gridtube_title_container {position:absolute; top:5px; right:5px;} body[dir='rtl'] #gridtube_title_container {left:5px !important; right:auto !important;} body ytd-video-primary-info-renderer {position:relative !important;} /* play button*/ #vpp_now_playing {font:500 14px/14px Roboto,arial,sans-serif; position:absolute; bottom:0px; left:0px; background:red; color:white; padding:5px; cursor:default; z-index:0;} body[dir='rtl'] #vpp_now_playing {left:auto !important; right:0px !important;} body[vpp_reveal_play_button] .vpp_play_button, *[vpp_play_marked]:hover .vpp_play_button {visibility:visible !important;} .vpp_play_button_container {position:absolute; bottom:0px; left:0px; width:100%;} .vpp_play_button {display:block !important; position:relative !important; padding-bottom:1px !important; margin:0px auto !important; width:25px !important; height:25px !important; opacity:0.75 !important; cursor:pointer !important; background-size:25px !important; background-repeat:no-repeat !important; text-decoration:none !important; z-index:1; user-select:none; -moz-user-select:none;} .vpp_play_button:hover {opacity:1 !important;} .vpp_play_button {background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAG7AAABuwBHnU4NQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAOqSURBVFiF5ZdPSBxnGMZ/M98s1V1nV01A17VZUwMRqsGY9FyQlBJQ2gYPIbaB0nMgwYZWeumxIQhlT7aQW0Mhl54CvQQiISQhkixN\ bWKXaNSaYuzu6v4Z98+38/WgY9Vu9l835NAHvsvM983zvs/7vPPOaEopXif018oOGAAfjY4GgEvAu0DnK+b8A5gCvvjp6tVl7cMzZ94EwkArgM/n42BXF7peX3Fs22b+2TPW19edSzGg3wAmgFbTNPlybIyDBw7UlXgv5hcX+WZigmQy2QpMiJ6+vhDQ9Pn587wVDGLb9itdXtOku7ubW7dvA+wzgHa3201XMEg2nyebzyOlpN69oQGG\ YfCGy0VXMIjb7cayrHYDoDMQIJPLkUynKdh2nal3Q+g6psdDZyDA75HIZhcoIJFKIQuFkofz2SxCCHTDqDkA27ZJpFLbCusAuVyOvJQopUquWDzO5OQkfy4vl91bauWlJJfL/ROAlLJiEy0sLfFtKMTP16+TsayazSilBLZeRI405aBsm8JWmW7cvMn0gweMnDrFocOHay7JpgeUqiiAQqGwHQBALB7n+ytXONLXx/DQEKbPVzGxM4Oq\ U0CpXQE4eBgOMzMzwwfDwwwcO1aVSatSwN5Rgr1TVErJj9eucefuXUZGRmjz+8smAzumYUXmKRSQUiKl3C7H3vV0fp5Lly9za2oKrcRzdylQLKOiCkDREuzFe4ODfDo6yloqxUo0WnJvzSUohg6/n/GxMXp6eogsLJDd6vViqM2ELwlACMHHp0/z2dmzLK2s8MvsbNlnOai6DZ0XiIMjvb18PT6Ox+vl4ZMnFZXI4dwOAKpvwyaPhwvn\ zjF08iSzc3Msrq5WRLwX28OoGg+8f+IEX128SMKyuBcO1zS6nTObClRYAndjI9+FQvT29vJbJMJGNlsDtRPBjhLouo6tFFqZM/v278dsamL60aPaidnM3vnmNIQQaEKwYVk0NDSUPJhMp0mm0/+JHCCTyaALgcswMLymqWwptfVEgkwmg9vtRgiBppXTozo4BrYsi2wuh7JtvF6vMjra21+sRqNtqVSKtKYRi8frSvyyYDSgw+9/YRw/\ evTpnfv329aiUQyXC+qceRF2lG3T0tzM8f7+OW3m8eP++NrajXvT061SSqRSZb8Ny6FoCpqGEIIGw8DlcvHOwEC82ecb1JRS/BWLvZ1MJn/I5/N+lGpUOwxQSo+SPtm6968dmrbhEuK51zQ/aWlp+VX73/8d/w3y7NP9Di2fPgAAAABJRU5ErkJggg==') !important;} /* preview player */ #vpp_player_area {position:fixed; width:100%; height:100%; top:0px; left:0px; background:rgba(0,0,0,0.5); overflow:hidden !important; z-index:2147483646 !important;} #vpp_player_area2 {position:relative; width:100%; height:100%; visibility:hidden;} #vpp_player_box {position:absolute; background:#606060; box-shadow:0px 0px 8px 3px rgba(128,128,128,0.9); border-radius:5px 5px 0px 0px; max-width:100%; max-height:100%;} #vpp_player_box[player_pos='00']:not([player_size='fit']) {top:0px; left:0px;} #vpp_player_box[player_pos='01']:not([player_size='fit']) {top:0px; left:0px; right:0px; margin:auto;} #vpp_player_box[player_pos='02']:not([player_size='fit']) {top:0px; right:0px;} #vpp_player_box[player_pos='10']:not([player_size='fit']) {top:0px; bottom:0px; left:0px; margin:auto;} #vpp_player_box[player_pos='11']:not([player_size='fit']) {top:0px; bottom:0px; left:0px; right:0px; margin:auto;} #vpp_player_box[player_pos='12']:not([player_size='fit']) {top:0px; bottom:0px; right:0px; margin:auto;} #vpp_player_box[player_pos='20']:not([player_size='fit']) {bottom:0px; left:0px;} #vpp_player_box[player_pos='21']:not([player_size='fit']) {bottom:0px; left:0px; right:0px; margin:auto;} #vpp_player_box[player_pos='22']:not([player_size='fit']) {bottom:0px; right:0px;} #vpp_player_box[player_pos='right']:not([player_size='fit']) {float:right;} #vpp_player_box[player_size='xxsmall'] {/*320x180*/ width:320px; height:200px;} #vpp_player_box[player_size='xsmall'] {/*512x288*/ width:512px; height:308px;} #vpp_player_box[player_size='small'] {/*768x432*/ width:768px; height:452px;} #vpp_player_box[player_size='medium'] {/*1024x576*/ width:1024px; height:596px;} #vpp_player_box[player_size='large'] {/*1280x720*/ width:1280px; height:740px;} #vpp_player_box[player_size='xlarge'] {/*1600x900*/ width:1600px; height:920px;} #vpp_player_box[player_size='xxlarge'] {/*1920x1080*/ width:1920px; height:1100px;} #vpp_player_box[player_size='fit'] {width:100%; height:100%; border-radius:0px !important;} #vpp_player_holder {position:relative; width:100%; height:100%;} #vpp_player_holder2 {position:absolute; top:20px; left:0px; right:0px; bottom:0px; margin:auto; background:black;} #vpp_player_box[player_size='fit'] #vpp_player_holder2 {left:0px !important; right:0px !important;} #vpp_player_frame {position:relative; width:100%; height:100%; display:block; border:0px;} #vpp_player_button_area_top {direction:ltr; font:500 14px/20px Roboto,arial,sans-serif; color:#101010; position:absolute; top:-2px; left:10px;} #vpp_player_button_area_next {font:500 19px/20px Roboto,arial,sans-serif; color:#101010; position:absolute; top:0px; right:35px;} .vpp_player_button {position:relative; cursor:pointer; padding:0px 5px; user-select:none; -moz-user-select:none;} .vpp_player_button[button_kind='plus'], .vpp_player_button[button_kind='minus'] {font:500 20px/20px Roboto,arial,sans-serif !important; top:2px;} .vpp_player_button[button_kind='left'] {padding:0px 2px 0px 5px;} .vpp_player_button[button_kind='right'] {padding:0px 2px;} .vpp_player_button[button_kind='up'] {padding:0px 2px;} .vpp_player_button[button_kind='down'] {padding:0px 5px 0px 2px;} .vpp_player_button:hover {color:#E0E0E0;} #vpp_player_close_mark {font:14px/20px Roboto,arial,sans-serif; position:absolute; top:0px; right:5px; cursor:pointer; user-select:none; -moz-user-select:none;} #vpp_player_close_mark:hover {color:#E0E0E0;}\ /* float preview */ #vpp_float_box {position:absolute; box-shadow:0px 0px 8px 3px rgba(128,128,128,0.9); background:black; z-index:2147483647;} #vpp_float_frame {position:relative; width:100%; height:100%; border:0px;} /* player options */ #vpp_player_options_popup {direction:ltr; position:absolute; left:0px; top:0px; font:11px/11px Roboto,arial,sans-serif; color:white; background:linear-gradient(#888888,#787878); padding:5px; border-radius:5px; /*z-index:2147483647;*/ z-index:2147483646;} .vpp_player_options_text {font-weight:500; margin-left:5px; margin-top:7px; color:lemonchiffon;} .vpp_player_options_close {font:14px/14px Roboto,arial,sans-serif; color:black; position:absolute; top:3px; right:5px; cursor:pointer; user-select:none; -moz-user-select:none;} .vpp_player_options_close:hover {color:lightgray;} .vpp_player_options_title {font:500 13px/13px Roboto,arial,sans-serif; padding:3px !important; color:lemonchiffon;} /*other*/ .watched .video-thumb {opacity:1 !important;} .yt-subscribe-button-right {margin-top:12px !important;} .pl-video .pl-video-thumbnail, .pl-video .pl-video-thumb, .pl-video .yt-thumb {width: 120px !important;} .pl-video .yt-thumb-clip > img {width:120px !important; height:auto !important;} .pl-video-time .timestamp {padding-top:18px !important;} `; //============================================================== //basic const AREA_ID = "vpp_player_area"; const BOX_ID = "vpp_player_box"; const HOLDER_ID = "vpp_player_holder"; function newElem(tag, attrs = {}, text = null, parent = null) { const node = document.createElement(tag); for (let attr in attrs) { node.setAttribute(attr, attrs[attr]); } if (text) { node.textContent = text; } parent?.appendChild(node); return node; } function insertStyle(str, id, doc = document) { const style = document.getElementById(id); if (style) { style.textContent = str; } else { newElem("style", {"type": "text/css", "id": id}, str, document.head); } } function injectScript(str, src, doc = document) { if (str) { document.head.removeChild(newElem("script", {}, str, document.head)); } else if (src) { newElem("script", {"src": src}, null, document.head) } } function xpath(outer_dom, inner_dom, query) { //XPathResult.ORDERED_NODE_SNAPSHOT_TYPE = 7 return outer_dom.evaluate(query, inner_dom, null, 7, null); } function docsearch(query) { return xpath(document, document, query); } function innersearch(inner, query) { return xpath(document, inner, query); } function simulClick(el) { const clickEvent = document.createEvent("MouseEvents"); clickEvent.initEvent("click", true, true); clickEvent.artificialevent = true; el.dispatchEvent(clickEvent); } function filter(str, w, delim) { if (str) { const m = str.match(RegExp(`[${delim}]${w}[^${delim}]*`)); if (m != null) { return m[0].replace(RegExp(`[${delim}]${w}`), ""); } } return null; } //============================================================== //preferences var pref_floatEnable = init_pref("floatEnable", true); var pref_floatDelay = init_pref("floatDelay", 1); var pref_playerEnable = init_pref("playerEnable", true); var pref_rateEnable = init_pref("rateEnable", true); var pref_defEnable = init_pref("defEnable", true); function new_plusminus(prefname, str, parent) { const div = newElem("div", {"class": "vpp_generic"}, null, parent); newElem("span", {"id": "vpp_pref_delay_text"}, str, div); const num = newElem("span", {"id": "vpp_pref_delay_num"}, get_pref("floatDelay").toString() + "s", div); const minus = newElem("span", {"id": "vpp_pref_delay_minus", "class": "vpp_pref_delay_plusminus"}, "\u2212", div); const plus = newElem("span", {"id": "vpp_pref_delay_plus", "class": "vpp_pref_delay_plusminus"}, "\u002B", div); minus.onclick = function () { let val = get_pref("floatDelay"); if (val > 0) { val--; set_pref("floatDelay", val); num.textContent = get_pref("floatDelay").toString() + "s"; } } plus.onclick = function () { let val = get_pref("floatDelay"); if (val < 5) { val++; set_pref("floatDelay", val); num.textContent = get_pref("floatDelay").toString() + "s"; } } } function new_checkbox(prefname, str, kind, parent, value, func = function(){}) { const div = newElem(kind, {"class": "vpp_generic"}, null, parent); const input = newElem("input", {"class": "vpp_generic", "type": "checkbox"}, null, div); if (!value) { input.checked = get_pref(prefname); input.onclick = function (e) { const val = get_pref(prefname); set_pref(prefname, !val); e.target.checked = !val; func(); }; } else { input.value = value; input.checked = (get_pref(prefname) == input.value); input.onclick = function (e) { const val = get_pref(prefname); set_pref(prefname, e.target.value); e.target.checked = true; const other = innersearch(parent.parentNode, `.//input[@value='${val}']`).snapshotItem(0); if (other && (other != e.target)) other.checked = false; func(); }; } newElem("span", {"class": "vpp_opendelay"}, str, div); } function pref_popup_close() { const popup = document.getElementById("vpp_pref_popup"); popup?.parentNode?.removeChild(popup); } function pref_popup_open() { if (document.getElementById("vpp_pref_popup")) { return; } const popup = newElem("span", {"id": "vpp_pref_popup"}, null, document.body); newElem("div", {"id": "vpp_pref_title"}, "Настройки", popup); let changed = false; const closemark = newElem("span", {"id": "vpp_pref_close", "title": "Применить"}, "\u2716", popup); closemark.onclick = function () { popup.parentNode.removeChild(popup); if (changed) { location.reload(); } }; let mark = function(){changed = true;}; new_checkbox("floatEnable", "При наведении", "div", popup, null, mark); new_plusminus("floatDelay", "задержка", popup); new_checkbox("playerEnable", "По щелчку", "div", popup, null, mark); new_checkbox("rateEnable", "Рейтинг", "div", popup, null, mark); new_checkbox("defEnable", "Качество", "div", popup, null, mark); } //================================================================== // Player const basic_str = "((local-name()='ytd-thumbnail') or (local-name()='ytd-playlist-thumbnail')) and (not(ancestor::*[@hidden]))"; const basic_str2 = "//img[contains(@src,'vi/') or contains(@src,'vi_webp/') or contains(@src,'/p/') or contains(@src,'/s_p/')]"; function player_script() { injectScript(`if (YT) { var player = new YT.Player('vpp_player_frame'); var errort = null; function error_reset() { if (errort) clearTimeout(errort); } function check_error(t,fid) { error_reset(); errort = setTimeout( function (fid) { var f = document.getElementById('vpp_player_frame'); if (!f) return; if (f.getAttribute('fid') != fid) return; fdoc = f.contentWindow.document; var s = player.getPlayerState(); var a = player.getPlaylist(); var i = player.getPlaylistIndex(); if (a != null ? a.length == 0 : false) f.dispatchEvent(new Event('playend')); else if ((s == -1 && fdoc.getElementsByClassName('ytp-error').length > 0) || s == 5) if ((a != null && i != null) ? i < a.length - 1 : false) player.nextVideo(); else f.dispatchEvent(new Event('playend')); }, t, fid); } player.addEventListener('onReady', function () { var f = document.getElementById('vpp_player_frame'); if (f) { var q = f.getAttribute('quality'); if (q != 'default' && q != null) player.setPlaybackQualityRange(q); } }); player.addEventListener('onStateChange', function () { var f = document.getElementById('vpp_player_frame'); if (!f) return; var fid = f.getAttribute('fid'); var q = f.getAttribute('quality'); var s = player.getPlayerState(); var a = player.getPlaylist(); var i = player.getPlaylistIndex(); var cond = ((a != null && i != null) ? i == a.length - 1 : true); if (s == -1 || s == 5) check_error(10000,fid); else error_reset(); if (s == -1 && q != 'default' && q != null) player.setPlaybackQualityRange(q); if (s == 0 && cond) f.dispatchEvent(new Event('playend')); }); var frame = document.getElementById('vpp_player_frame'); if (frame) { check_error(10000,frame.getAttribute('fid')); frame.addEventListener('loadnewvideo', function (x) { var fid = x.target.getAttribute('fid'); var url = x.target.getAttribute('newvidurl'); var plist = x.target.getAttribute('plist'); player.pauseVideo(); if (plist) { player.loadPlaylist({'list':plist}); check_error(10000,fid); } else if (url) { player.loadVideoByUrl(url); check_error(10000,fid); } }); } }`); } const choices_def = ['default', 'small', 'medium', 'large', 'hd720', 'hd1080', 'hd1440', 'highres']; const choices_size = ['xxsmall', 'xsmall', 'small', 'medium', 'large', 'xlarge', 'xxlarge']; const choices_pos = ['00', '01', '02', '10', '11', '12', '20', '21', '22']; const scriptPrefs = new Proxy(JSON.parse(GM_getValue("YTVPR_prefs", `{ "floatEnable": true, "floatDelay": 1, "playerEnable": true, "rateEnable": true, "defEnable": true, "playerFit": false, "playerDef": 0, "playerSize": 3, "playerPosLeft": 1, "playerPosTop": 1, "playerNext": true, "playerClose": true, "playerPause": true, "playerDim": true }`)), { set: function(obj, prop, value) { const clamp = function(val, min, max){ return Math.min(Math.max(min, val), max); }; switch (prop) { case "playerDef": value = clamp(value, 0, choices_def.length()-1); break; case "playerSize": value = clamp(value, 0, choices_size.length()-1); break; case "playerPosLeft": case "playerPosTop": value = clamp(value, 0, 2); break; } if(obj[prop] != value) { obj[prop] = value; GM_setValue("YTVPR_prefs", JSON.stringify(obj)); } return true; } }); //player preferences if (pref_playerEnable) { init_pref("playerFit", false); init_pref("playerDef", "default"); init_pref("playerSize", "medium"); init_pref("playerPos", "11"); init_pref("playerNext", true); init_pref("playerClose", true); init_pref("playerPause", true); init_pref("playerDim", true); //fix char preferences if (choices_def.indexOf(get_pref("playerDef")) < 0) set_pref("playerDef", 'default'); if (choices_size.indexOf(get_pref("playerSize")) < 0) set_pref("playerSize", 'medium'); if (choices_pos.indexOf(get_pref("playerPos")) < 0) set_pref("playerPos", '11'); } function player_options(parent) { if (document.getElementById("vpp_player_options_popup")) { return; } const popup = newElem("span", {"id": "vpp_player_options_popup"}, null, parent); newElem("div", {"class": "vpp_player_options_title"}, "Настройки плеера", popup); const closemark = newElem("span", {"class": "vpp_player_options_close", "title": "Закрыть"}, "\u2716", popup); closemark.onclick = close_player_options; new_checkbox("playerNext", "Автовоспроизводить следующее", "div", popup); new_checkbox("playerDim", "Снижать яркость фона", "div", popup, null, function () { document.getElementById(AREA_ID).style.visibility = (get_pref("playerDim") ? "visible" : "hidden"); }); new_checkbox("playerClose", "Закрывать по щелчку вне плеера", "div", popup); new_checkbox("playerPause", "Пауза YT-плеера при запуске скрипта", "div", popup); newElem("div", {"class": "vpp_player_options_text"}, "Разрешение", popup); //default, small, medium, large, hd720, hd1080, hd1440, highres; const group1 = newElem("div", {"class": "vpp_player_options_group"}, null, popup); const group2 = newElem("div", {"class": "vpp_player_options_group"}, null, popup); new_checkbox("playerDef", "Default", "span", group1, "default"); new_checkbox("playerDef", "LQ 240", "span", group1, "small"); new_checkbox("playerDef", "MQ 360", "span", group1, "medium"); new_checkbox("playerDef", "HQ 480", "span", group1, "large"); new_checkbox("playerDef", "HD 720", "span", group2, "hd720"); new_checkbox("playerDef", "HD 1080", "span", group2, "hd1080"); new_checkbox("playerDef", "HD 1440", "span", group2, "hd1440"); new_checkbox("playerDef", "MAX", "span", group2, "highres"); } function close_player_options() { const popup = document.getElementById("vpp_player_options_popup"); if (popup) { popup.parentNode.removeChild(popup); } } function playerUrl(vid, pid) { let url = `${location.protocol}//${location.hostname}/`; if (vid) { url = `${url}embed/${vid}?`; if (pid) { url = `${url}list=${pid}`; } } else if (pid) { url = `${url}embed?listType=playlist&list=${pid}`; } else { console.error("Нулевой pid и vid!"); } url = `${url}&autoplay=1&fs=1&iv_load_policy=3&rel=1&version=3&enablejsapi=1`; return (url); } function adjust_playing(node) { const playing = document.getElementById("vpp_now_playing"); playing?.parentNode?.removeChild(playing); if (node) { newElem("span", {"id": "vpp_now_playing"}, "Сейчас играет", node); } } function build_player() { //constants var next_choice = new Object(); next_choice['plus'] = new Object(); next_choice['minus'] = new Object(); next_choice['left'] = new Object(); next_choice['right'] = new Object(); next_choice['up'] = new Object(); next_choice['down'] = new Object(); next_choice['plus']['xxsmall'] = 'xsmall'; next_choice['plus']['xsmall'] = 'small'; next_choice['plus']['small'] = 'medium'; next_choice['plus']['medium'] = 'large'; next_choice['plus']['large'] = 'xlarge'; next_choice['plus']['xlarge'] = 'xxlarge'; next_choice['plus']['xxlarge'] = 'xxlarge'; next_choice['minus']['xxsmall'] = 'xxsmall'; next_choice['minus']['xsmall'] = 'xxsmall'; next_choice['minus']['small'] = 'xsmall'; next_choice['minus']['medium'] = 'small'; next_choice['minus']['large'] = 'medium'; next_choice['minus']['xlarge'] = 'large'; next_choice['minus']['xxlarge'] = 'xlarge'; { for (var i = 0; i < 3; i++) for (var j = 0; j < 3; j++) { next_choice['left'][i.toString() + j.toString()] = i.toString() + (j - 1 >= 0 ? j - 1 : 0).toString(); next_choice['right'][i.toString() + j.toString()] = i.toString() + (j + 1 <= 2 ? j + 1 : 2).toString(); next_choice['up'][i.toString() + j.toString()] = (i - 1 >= 0 ? i - 1 : 0).toString() + j.toString(); next_choice['down'][i.toString() + j.toString()] = (i + 1 <= 2 ? i + 1 : 2).toString() + j.toString(); } } var new_size = get_pref("playerSize"); var new_pos = get_pref("playerPos"); var new_fit = get_pref("playerFit"); var that = this; var frame_count = 0; //public this.playerShow = function (vid, pid, node) { const box = document.getElementById(BOX_ID); if (box?.style.visibility == "hidden") { new_size = get_pref("playerSize"); new_pos = get_pref("playerPos"); new_fit = get_pref("playerFit"); } playerAdjust((new_fit ? "fit" : new_size), new_pos, "visible", vid, pid); adjust_playing(node); } this.playerClose = function () { playerAdjust(null, null, "hidden", null, null); close_player_options(); adjust_playing(); } //private function play_next(findprevious) { const playing = document.getElementById("vpp_now_playing"); if (!playing) { return; } const myimg = innersearch(playing.parentNode, ".//img[@src or @data-thumb]").snapshotItem(0); if (myimg) { let pos = -2; let l = docsearch(`//*[(${basic_str})]${basic_str2}`); myimg.setAttribute("matchfind", "true"); for (let i = 0; i < l.snapshotLength; i++) { if (l.snapshotItem(i).getAttribute("matchfind")) { pos = i; break; } } myimg.removeAttribute("matchfind"); pos = (findprevious ? pos - 1 : pos + 1); if (pos >= 0) { const img = l.snapshotItem(pos); if (img) { img.setAttribute("matchfindimg", true); const target = docsearch(`//*[${basic_str} and (.//img[@matchfindimg])]`).snapshotItem(0); if (target) { that.playerShow(find_vid(img), find_plist(img), target); } img.removeAttribute("matchfindimg"); } } } } function playerAdjust(size, pos, vis, vid, pid) { const box = document.getElementById(BOX_ID); if (vis != null) { box.style.visibility = vis; area.style.visibility = (get_pref("playerDim") ? vis : "hidden"); let frame = document.getElementById("vpp_player_frame"); if (frame && (vis == "hidden")) { frame.parentNode.removeChild(frame); frame = null; } if (vis == "visible") { const vidurl = playerUrl(vid, pid); const def = get_pref("playerDef"); frame_count++; if (frame) { frame.setAttribute("newvidurl", vidurl); if (pid) frame.setAttribute("plist", pid); else frame.removeAttribute("plist"); frame.setAttribute("quality", def); frame.setAttribute("fid", frame_count.toString()); const event = document.createEvent("Event"); event.initEvent("loadnewvideo", true, true); frame.dispatchEvent(event); } else { frame = newElem("iframe", {"id": "vpp_player_frame", "type": "text/html", "frameborder": "0", "allowfullscreen": "true", "quality": def, "fid": frame_count.toString(), "src": vidurl}, null, document.getElementById(HOLDER_ID).firstElementChild); frame.addEventListener("playend", function(){if (get_pref("playerNext")) play_next();}); player_script(); } } } if (size != null) { box.setAttribute("player_size", size); holder.setAttribute("player_size", size); } if (pos != null) { box.setAttribute("player_pos", pos); } } function click_pos_size(e) { var kind = e.target.getAttribute("button_kind"); if (!kind) return; if (new_fit && !(kind == "options" || kind == "prev" || kind == "next")) { set_pref("playerFit", false); new_fit = false; playerAdjust(new_size, new_pos); return; } switch (kind) { case 'plus': case 'minus': new_size = next_choice[kind][new_size]; set_pref("playerSize", new_size); playerAdjust(new_size, new_pos); break; case 'fit': set_pref("playerFit", true); new_fit = true; playerAdjust('fit'); break; case 'left': case 'right': case 'up': case 'down': new_pos = next_choice[kind][new_pos]; set_pref("playerPos", new_pos); playerAdjust(new_size, new_pos); break; case 'options': player_options(document.getElementById(BOX_ID)); break; case 'prev': play_next(true); break; case 'next': play_next(); break; } } function new_button(kind, str, str_popup, parent) { newElem("span", {"class": "vpp_player_button", "title": str_popup, "button_kind": kind}, str, parent).onclick = click_pos_size; } //initialization; if (document.getElementById(AREA_ID)) { return; } const area = newElem("div", {"id": AREA_ID, "style": "visibility: hidden;"}, null, document.body); const area2 = newElem("div", {"id": "vpp_player_area2"}, null, area); const box = newElem("div", {"id": BOX_ID, "style": "visibility: hidden;"}, null, area2); const holder = newElem("div", {"id": HOLDER_ID}, null, box); newElem("div", {"id": "vpp_player_holder2"}, null, holder); area.onclick = function (e) { if (e.target.id == AREA_ID && get_pref("playerClose")) that.playerClose(); }; const buttonArea = newElem("span", {"id": "vpp_player_button_area_top"}, null, box); new_button("plus", "\u002B", "Увеличить", buttonArea); new_button("minus", "\u2212", "Уменьшить", buttonArea); new_button("fit", "\u2610", "Растянуть", buttonArea); new_button('left', '\u25C4', 'Влево', buttonArea); new_button('right', '\u25BA', 'Вправо', buttonArea); new_button('up', '\u25B2', 'Вверх', buttonArea); new_button('down', '\u25BC', 'Вниз', buttonArea); new_button("options", "\u2630", "Настройки", buttonArea); const bottomArea = newElem("span", {"id": "vpp_player_button_area_next"}, null, box); new_button("prev", "\u140A\u140A", "Играть предыдущее на странице", bottomArea); new_button("next", "\u1405\u1405", "Играть следующее на странице", bottomArea); //new_button("loop", "\u21BB", "repeat video", bottomArea); newElem("span", {"id": "vpp_player_close_mark", "title": "Закрыть плеер"}, "\u2716", box).onclick = this.playerClose; } var player = null; if (pref_playerEnable) { player = new build_player(); injectScript(null, "https://www.youtube.com/iframe_api"); } function ytpause() { const func = `(function(){ const mainVid = document.getElementById("movie_player"); const channelVid = document.getElementById("c4-player"); if (mainVid && (mainVid.getPlayerState() == 1)) mainVid.pauseVideo(); if (channelVid && (channelVid.getPlayerState() == 1)) channelVid.pauseVideo(); })();`; injectScript(func); } //================================================================== // float player //quality is default for faster upload, and youtube player is paused function float_script() { const func = `(function(){ const fplayer = new YT.Player("vpp_float_frame"); fplayer.addEventListener("onReady", function () { const mainVid = document.getElementById("movie_player"); const channelVid = document.getElementById("c4-player"); if (mainVid && (mainVid.getPlayerState() == 1)) mainVid.pauseVideo(); if (channelVid && (channelVid.getPlayerState() == 1)) channelVid.pauseVideo(); fplayer.setPlaybackQualityRange("default"); }); })();`; injectScript(func); } function float_open(e, check) { //check tests if same url frame is already open const v_id = e.target.firstElementChild?.href?.match(/(?<=v=)[a-zA-Z0-9_-]*/)?.[0]; if (!v_id || document.getElementById("vpp_player_frame")) { return false; } if (!check) { float_delay_clear(); adjust_playing(e.target); } const url = "https://www.youtube.com/embed/" + v_id + "?&autoplay=1&controls=1&iv_load_policy=3&rel=0&showinfo=1&version=3&enablejsapi=1"; const frame = document.getElementById("vpp_float_frame"); if (frame) { if (frame.src == url) { return check; } if (!check) { frame.parentNode.removeChild(frame); } } if (check) { return false; } const float_width = 480; //512; const float_height = 270; //288; let box = document.getElementById("vpp_float_box"); if (!box) { box = newElem("div", {"id": "vpp_float_box", "style": `width: ${float_width}px; height: ${float_height}px;`}, null, document.body); box.onmouseenter = float_delay_clear; box.onmouseleave = float_close_delay; } const r = e.target.getBoundingClientRect(); const w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; const h = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; const hpad = Math.round(-r.width / 3); //horizontal offset const vpad = 0; //vertical offset //priority to right let left = r.right + hpad; if ((left + float_width > w) && ((r.left - float_width - hpad >= 0) || (r.left > w - r.right))) { left = r.left - float_width - hpad; } //priority to left //let left = r.left - float_width - pad; //if (left < 0) // if ((r.right + float_width + pad <= w) || (w - r.right > r.left)) // left = r.right + pad; //priority to top let top = r.top - float_height - vpad; if (top < 0 && (r.bottom + float_height + vpad <= h || h - r.bottom > r.top)) { top = r.bottom + vpad; } left += (document.body.scrollLeft || document.documentElement.scrollLeft); top += (document.body.scrollTop || document.documentElement.scrollTop); box.style.left = left + "px"; box.style.top = top + "px"; newElem("iframe", {"id": "vpp_float_frame", "type": "text/html", "frameborder": "0", "src": url}, null, box); float_script(); return true; } let float_open_timeout = null; let float_close_timeout = null; function float_close(e) { clearTimeout(float_close_timeout); const box = document.getElementById("vpp_float_box"); //check if mouse was in the area if (box) { if (!e || (e.target != box)) { box.parentNode.removeChild(box); adjust_playing(); } else { //player should not close if mouse is still inside const r = box.getBoundingClientRect(); if ((e.clientX <= r.left + 1) || (e.clientX >= r.right - 1) || (e.clientY <= r.top + 1) || (e.clientY >= r.bottom - 1)) { box.parentNode.removeChild(box); adjust_playing(); } } } } function float_delay_clear() { clearTimeout(float_open_timeout); clearTimeout(float_close_timeout); } function float_reset() { float_delay_clear(); float_close(); } function float_open_delay(e) { if (float_open(e, true)) { float_delay_clear(); } else { clearTimeout(float_open_timeout); const delay = get_pref("floatDelay") * 1000; float_open_timeout = setTimeout(float_open.bind(null, e, false), delay); } } function float_close_delay(e) { float_delay_clear(); float_close_timeout = setTimeout(float_close.bind(null, e), 200); } //================================================================== //meta data function callback(json_txt, parent) { debug("callback", parent) const parseQuery = s => [...new URLSearchParams(s).entries()].reduce( (acc, [k, v]) => ((acc[k] = v), acc), {} ) const params = parseQuery(json_txt); debug("params", params); if (pref_defEnable) { let max_res = 0; let max_quality_label = ""; try { let formats = []; const player_response = JSON.parse(params.player_response); debug("player_response", player_response); if (player_response.streamingData.hasOwnProperty("formats")) { formats = formats.concat(player_response.streamingData.formats); } if (player_response.streamingData.hasOwnProperty("adaptiveFormats")) { formats = formats.concat(player_response.streamingData.adaptiveFormats); } for (let i = 0; i < formats.length; i++) { const res = formats[i].width * formats[i].height; if (res > max_res) { max_res = res; max_quality_label = formats[i].qualityLabel; } } } catch(e) {debug(e);} if(max_res != 0) { parent.setAttribute("vpp_meta_def", ""); const def_node = newElem("span", {"class": "vpp_meta_def_container", "reveal": "true", "title": max_quality_label}, null, parent); const def_txt = max_res >= (15360 * 8640) ? "16K" : max_res >= (7680 * 4320) ? "8K" : max_res >= (2880 * 2160) ? "4K" : max_res >= (960 * 1080) ? "1080p" : max_res >= (640 * 720) ? "720p" : "SD"; newElem("span", {"class": "vpp_meta_def_hd HD"}, def_txt, def_node); } } if (pref_rateEnable) { let likes = 0; let dislikes = 0; let views = 0; let liked = false; let disliked = false; try { const contents = (JSON.parse(params.watch_next_response)).contents.twoColumnWatchNextResults.results.results.contents; debug("contents", contents); for (let i = 0; i < contents.length; i++) { if (contents[i].hasOwnProperty("videoPrimaryInfoRenderer")) { const buttons = contents[i].videoPrimaryInfoRenderer.videoActions.menuRenderer.topLevelButtons; for (let button of buttons) { if (button.toggleButtonRenderer?.defaultIcon?.iconType === "LIKE") { likes = parseInt(button.toggleButtonRenderer.defaultText.accessibility.accessibilityData.label.replace(/[^0-9]/g, "")) || 0; liked = button.toggleButtonRenderer.isToggled || false; } else if (button.toggleButtonRenderer?.defaultIcon?.iconType === "DISLIKE") { dislikes = parseInt(button.toggleButtonRenderer.defaultText.accessibility.accessibilityData.label.replace(/[^0-9]/g, "")) || 0; disliked = button.toggleButtonRenderer.isToggled || false; } } views = parseInt(contents[i].videoPrimaryInfoRenderer.viewCount.videoViewCountRenderer.viewCount.simpleText.replace(/[^0-9]/g, "")) || 0; break; } } } catch(e) {debug(e);} if ((likes != 0) || (dislikes != 0)) { const perc = 100 - Math.round(dislikes * 100.0 / (likes + dislikes)); // Color scale from 50 (red) to 100 (green) const scaled = Math.max(0,(perc-50)/50); const r = Math.min(0xC0,Math.round(2*0xC0*(1-scaled))); const g = Math.min(0xA0,Math.round(2*0xA0*(scaled))); const b = 0; const rgb = (r << 16) | (g << 8) | b; const hex = "#" + rgb.toString(16).padStart(6, "0"); newElem("div", { "class": "vpp_meta_rate", "style": "background:" + hex + " !important;", "title": perc + "% likes: +" + Number(likes).toLocaleString() + " -" + Number(dislikes).toLocaleString() + "\n" + Number(views).toLocaleString() + " views" }, (liked ? "\uD83D\uDC4D " : disliked ? "\uD83D\uDC4E " : "") + perc, parent); parent.setAttribute("vpp_meta_rate", ""); } } } function def_rate(v_id, parent) { debug("Getting info for " + v_id); const oReq = new XMLHttpRequest(); oReq.addEventListener("load", function(){callback(this.responseText, parent)}); oReq.open("GET", `https://www.youtube.com/get_video_info?video_id=${v_id}&el=detailpage`); oReq.send(); } function find_vid(img) { return (filter(img.src, "vi/", "/&?#") || filter(img.src, "vi_webp/", "/&?#")); } function find_plist(img) { let plist = null; const anc = innersearch(img, "ancestor-or-self::*[contains(@href,'&list=') and (.//*[contains(@class,'yt-pl-sidebar-content') or contains(@class,'ytd-thumbnail-overlay-side-panel-renderer')])]").snapshotItem(0); if (anc) { plist = filter(anc.href, "list=", "/&?#"); if (plist == "WL") { plist = null; } } return plist; } function play(parent) { const playArea = newElem("div", {"class": "vpp_play_button_container"}, null, parent); const playNode = newElem("a", {"class": "vpp_play_button", "href": "javascript:;", "target": "_self", "title": "Скриптовый плеер"}, null, playArea); const play_handle = function(e) { e.stopPropagation(); float_reset(); const parpar = e.target.parentNode.parentNode; if (innersearch(parpar, ".//*[@id='vpp_now_playing']").snapshotLength > 0) { player.playerClose(); } else { const img = innersearch(parpar, `.${basic_str2}`).snapshotItem(0); if (img) { player.playerShow(find_vid(img), find_plist(img), parpar); if (get_pref("playerPause")) { ytpause(); } } else { console.error("play(parent): img not found"); } } } playNode.onclick = play_handle; } //================================================================== // Main debug("***YouTube Video Preview and Ratings Keyless***"); //insert styles insertStyle(style_basic, "vpp_style_basic"); if (pref_playerEnable) {//hide overlay of playlist insertStyle(".yt-pl-thumb-overlay, ytd-thumbnail-overlay-hover-text-renderer {display:none !important;}", "vpp_style_list_overlay");//OLD,NEW } (function insertMenuBtn() { const par = document.getElementById("masthead-container"); if (par) { newElem("span", {"id": "vpp_pref_button", "title": "Настройки скрипт-плеера"}, null, par).onclick = pref_popup_open; } else { new MutationObserver(function(mutations, observer) { observer.disconnect(); insertMenuBtn(); }).observe(document.getElementById("masthead"), {childList: true}); } })(); function processThumbs(thumbs) { for (let thumb of thumbs) { const parent = thumb.parentNode; const v_id = thumb.href?.match(/(?<=v=)[a-zA-Z0-9_-]*/)?.[0]; if (v_id) { if (pref_defEnable || pref_rateEnable) { def_rate(v_id, parent); } if (pref_floatEnable) { parent.onmouseenter = float_open_delay; parent.onmouseleave = float_close_delay; } if (pref_playerEnable) { play(parent); } } } } processThumbs(Array.from(document.body.querySelectorAll("#thumbnail"))); new MutationObserver(function(mutations, observer) { for (let mutation of mutations) { const thumbs = Array.from(mutation.addedNodes).filter(node => (node.nodeType === Node.ELEMENT_NODE && node.id === "thumbnail")); processThumbs(thumbs); } }).observe(document.body, {childList: true, subtree: true});
Отредактировано _zt (07-05-2021 20:35:54)
Отсутствует