Прошло уже 10 лет с моего предыдущего разбора, не побоюсь этого слова, говнософта, как появилась очередная проблема, с которой мне захотелось разобраться и устранить её.
С чего всё начиналось
Некоторое время назад случилось так, что телевизор стал единственным доступным способом вывода звука с моего ПК, и по сути, занял роль второго монитора. Ну а раз он теперь оккупирован компьютером, то встал вопрос — а как же мне смотреть на ютубе документалочки во время засыпания? Так как я слишком ленивый чтобы заранее составлять плейлисты, мне нужно было управление с телефона, через официальное приложение YouTube. Постоянно переключаться между HDMI и YouTube App на ТВ совсем не входило в мои интересы, я приступил к поиску решения, которое было найдено очень быстро — у платформы уже есть готовый интерфейс для ТВ в вебе, только была незадача: при открытии в браузере оно просто редиректит на главную.
Решение же этой проблемы не заставило себя долго ждать, для хрома имеется куча расширений, которые позволяют решить проблему с редиректом. В итоге мой выбор остановился на Youtube TV On PC, т.к. оно работало и имело относительно неплохой рейтинг. Но всё было не так красочно, как я мечтал...
Появление проблем
Далее по тексту под TV имеется ввиду веб версия YouTube TV
С первой проблемой я столкнулся спустя, наверное, неделю — приложение не могло подключиться к TV. А ещё сама загрузка TV могла занимать несколько минут. Но после этого всё успешно работало, пока снова не начиналось аналогичное поведение.
Я не сильно придавал этому значения, так как у меня используются другие расширения, в т.ч. и для блокировки рекламы, а в то время YouTube как раз активно замедлял работу сервиса для таких пользователей.
Со второй проблемой я столкнулся спустя несколько месяцев, когда вместо ПК использовал ноутбук — видео начало адски тормозить и хром начал выедать процессор. Связано это было с тем, что на YouTube у меня видео включались в максимальном качестве, а в большинстве случаев это 4k60. На эту проблему я тоже успешно забил, т.к. спустя несколько дней я опять вернулся к ПК, и проблем это не доставляло. До тех пор, пока у меня провайдер не решил то, что мне и 10Mbps хватит. Но и тогда проблема решилась разбирательством с провайдером.
Время шло, число сменилось, ни черта не изменилось
В общем, пострадал я таким образом около полугода, и мне это поднадоело. Потому что помимо ранее озвученных проблем, была ещё одна, самая бесючая — зависала не одна вкладка, зависал весь хром, даже диспетчер задач хрома зависал.
Желания разбираться в том, как же отлаживать ПО в Windows у меня не было никакого, но проблему нужно было как-то устранить. Решил через ProcessExplorer найти тот самый процесс, который подвисает и посмотреть в его стектрейс. Процесс был найден, на верхушке стека было что-то про ...crash.... Ну вот, думаю я, ты и попался. Если что-то где-то крэшится, значит что-то должно падать в логи. Включаю логгирование в хроме, жду неделю, ловлю опять зависание, и... И в логах абсолютно ничего нет. Мониторил ещё несколько месяцев в надежде поймать что-нибудь.
Последняя капля
В очередной раз всё подвисло на несколько минут, а т.к. я в это время был занят работой, меня это очень сильно разозлило, и я решил окончательно покончить с этим.
Думаю, а что будет если пристрелить процесс этого расширения? Shift+Esc
, End process
, зависание! Всё, подлец, попался!
Учитывая мою ленивость, я, наверное, должен был пойти и установить другое расширение, но нет, тут уже было дело принципа, нужно докопаться до истины. Поэтому, скачиваю CRX архив, наливаю кружку кваса и вперёд. А то мало ли, вдруг там майнер крутился всё это время, но оказалось всё гораздо проще и скучнее.
Исходники
Открыв расширение в архиваторе, моему взору предстал background.js
следующего содержимого:
const userAgent = "Mozilla/5.0 (SMART-TV; LINUX; Tizen 5.5) AppleWebKit/537.36 (KHTML, like Gecko) 69.0.3497.106.1/5.5 TV Safari/537.36";
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
chrome.webRequest.onBeforeSendHeaders.addListener(function (details) {
for (var i = 0; i < details.requestHeaders.length; ++i) {
if (details.requestHeaders[i].name === "User-Agent") {
details.requestHeaders[i].value = userAgent;
break;
}
}
return { requestHeaders: details.requestHeaders };
}, { urls: ['*://www.youtube.com/tv*'] }, ['blocking', 'requestHeaders']);
if (changeInfo.status == "complete" && tab.url.includes("youtube") && tab.url.includes("watch?v=")) {
chrome.tabs.executeScript(tabId, {
file: "/hd.js"
});
}
});
И тут я понимаю весь %%%ец происходящего, и откуда зависания, и откуда 4k60 везде где только можно. А теперь по порядку...
Расширение добавляет хэндлер для всех событий всех табов! Да, у расширения как оказалось, в манифесте не указано ограничение по доменам, и в самом
addListener
не указанfilter
, который бы позволил отфильтровать ненужные события, как минимум по URL и типу события.Внутри хэндлера, который, я напомню, вызывается для всех табов и для всех типов событий, которых как минимум 12 штук, добавляется уже нужный обработчик
webRequest.onBeforeSendHeaders
, который хотя бы вызывается только со страницыwww.youtube.com/tv
.Проверяется что URL таба, от которого пришло событие содержит
youtube
иwatch?v=
, и выполняет скрипт, который и включает максимальное качество в плеере.
Если очень грубо посчитать, то мы имеем то, что при открытии браузера с 50 вкладками (не знаю как для вас, а для меня это нормальная ситуация), у нас добавляется примерно 200 хэндлеров для webRequest.onBeforeSendHeaders
. Это если посчитать события смены url, favicon, заголовка страницы и статуса загрузки. Далее можно ещё добавить события, которые происходят во время пользования браузером, а как я выше говорил, зависания случались где-то спустя неделю после запуска. А ещё есть сайты, вроде VK, где при входящих сообщениях меняется favicon каждые несколько секунд.
hd.js не представляет особого интереса
var scriptTag = document.getElementById('ytTvHd');
if (scriptTag) {
scriptTag.remove();
}
var script = document.createElement('script');
script.id = "ytTvHd";
script.type = 'text/javascript';
script.textContent = "var ytvPlayer = document.getElementById('movie_player') || document.querySelector('.html5-video-player');ytvPlayer.setPlaybackQualityRange('highres');" +
"document.getElementsByTagName('body')[0].onkeydown = function(e) {if (e.keyCode == 428) {ytvPlayer.requestFullscreen();}};";
document.body.appendChild(script);
Выводы
Для себя я сделал очевидный вывод: проблемы всегда нужно искать на поверхности, и в первую очередь оценить пряморукость разработчиков простых вещей, а не пытаться найти проблему заходя с другого конца. А проблему с расширением решил путём сокращения кода и установки из локальной директории.
const userAgent = "Mozilla/5.0 (SMART-TV; LINUX; Tizen 5.5) AppleWebKit/537.36 (KHTML, like Gecko) 69.0.3497.106.1/5.5 TV Safari/537.36";
chrome.webRequest.onBeforeSendHeaders.addListener(function (details) {
for (var i = 0; i < details.requestHeaders.length; ++i) {
if (details.requestHeaders[i].name === "User-Agent") {
details.requestHeaders[i].value = userAgent;
break;
}
}
return { requestHeaders: details.requestHeaders };
}, { urls: ['*://www.youtube.com/tv*'] }, ['blocking', 'requestHeaders']);
Вероятно, для решения моей проблемы подойдет любое другое расширение для смены HTTP-заголовков, но сколько ещё секретов они в себе могут таить...
Комментарии (6)
sergeym69
03.05.2024 21:13+2chrome.webRequest.onBeforeSendHeaders.addListener
И должно вызываться только один раз в background, и после этого этот handler будет работать для всех вкладок, потому как работает он не для вкладок, а для всех сетевых вызовов
POPSuL Автор
03.05.2024 21:13+8Ну так в конечном итоге я именно так и переписал.
В исходном виде сами хэндлеры добавлялись "бездумно", на кажый(!) "чих" любого(!) таба.
A_L_I_E_N
03.05.2024 21:13+4Ехал handler через handler,
Видит handler: в handler - handler.
Сунул handler в handler handler.
Handler handler handler handler.
Много handler-ов .. бывает! ))
VADemon
03.05.2024 21:13Интересно, с ChatGPT/Копилотами будет хуже или лучше? #lowcode #nocode
В HTTP/2 хедеры вроде с маленькой буквы, не знаю, как в этом API. Маленькая оптимизация (хотя я не уверен о зоне действия Listener): раз уже используется closure, сохранять индекс найденного UA в прошлый раз и сначала проверять его, а не по всем проходить.
ninJo
Напиши в комментах автору расширения об этом, может исправят
POPSuL Автор
В начале года кто-то уже написал в отзывах про тормоза. Но я добавил ещё свой, со ссылочкой на эту статью, может быть автор прочитает хотя бы с переводчиком.