Я победил замедление YouTube
Привет, Хабр! Ухудшение работы YouTube стало поистине трагическим событием, которое прибило почти все загрузчики видео, но я нашел легальный способ улучшить ситуацию!
Как починить оборудование Google, не привлекая внимание санитаров.
1.5 года я занимаюсь разработкой и поддержкой самого популярного в RuStore загрузчика видео на Android. На данный момент приложение имеет более 50 тысяч установок и среднюю оценку 4.4.
Когда YouTube начал замедляться, то пострадал, как это не парадоксально, в большей степени совсем не просмотр видео, а скачивание. (Дальше в статье объясню почему).
Многие пользователи на форумах стали жаловаться на проблемы при работе с утилитой yt‑dlp (форк youtube‑dl):
Лично у меня, как ни странно, воспроизведение видео на самом сайте ютуба не тормозит совсем.
Но вот скачивание с помощьюyt-dlp
, как оказалось, тормозит нещадно. Скорость пляшет между 40 и 200 KiB/s, что ни в какие ворота, особенно для многогигабайтных видео.
Естественно, после этого наступили темные времена для всех Android загрузчиков, которые работают на основе этой библиотеки (Seal, YTDLNIS и др). Разумеется и мое приложение оказалось в этом числе.
Хоть я давно уже реализовал загрузку контента из отечественных платформ (ВК Видео, RuTube, Дзен), но 90% загрузок видео так или иначе приходилось именно на ютуб.
Полетели негативные отзывы, я перебирал варианты и отметал. Пару дней было неспокойно.
Как я обходил замедление YouTube
Первым делом я решил отказаться от использования yt‑dlp в рамках скачивания из YouTube. Никаких полезных опций в текущих условиях там больше для меня нет.
Реализовал прямой доступ к YouTube API. Про этот способ уже писал в другой статье на Хабр. Я заметил, что несмотря на замедление, всё же удается скачать первые пару мегабайт, а затем скачивать становится невозможно.
Потоковые видео поддерживают Header Range
для HTTP запросов, и это позволяет нам скачивать видеофайл по кусочкам.
Если произойдет обрыв, то мы посчитаем сколько байт уже скачано, и продолжим с того же места опять. Ещё я решил задать timeout в 3.5 секунды на один запрос. Довольно часто запрос уходил на 20 секунд и более отсыпаться, поэтому было решено дропать раньше.
Пишем несложный цикл на Kotlin:
fun main() {
val chunkSize = 500000
// Размер куска в байтах, который мы будем скачивать за один запрос
val client = HttpClient()
val length = client.head(link).headers[HttpHeaders.ContentLength]?.toLong() as Long
//Получаем размер видеофайла
while (true) {
try {
val lastByte = length - 1
var start = inputVideoFile.length()
val output = FileOutputStream(inputVideoFile, true)
val end = min(start + chunkSize - 1, lastByte)
val data = withTimeoutOrNull(3500L) {
client.get(videoUrl) {
header("Range", "bytes=${start}-${end}")
header(HttpHeaders.ContentType, contentTypeVideo)
}.body<ByteArray>()
}
if (data != null) {
output.write(data)
if (end >= lastByte) break
start += chunkSize
}
} catch (e: Exception) {
TracerCrashReport.report(e, "error yt chunk downloading")
}
}
client.close()
}
Скорость и правда немного улучшилась, файл докачивался, никаких обрывов не происходило, но этого было мало.
Позже мне удалось узнать, что низкая скорость была ещё и следствием протокола HTTP/2, а YouTube транслирует видео по HTTP/3. Это именно то, из-за чего yt-dlp выдает ужасную скорость, а в браузерах особых задержек не наблюдается. Проверить протокол можно в DevTools → Network. “h3” означает HTTP/3.
Если у вас какие-то лютые тормоза на ютубе, то нужно включить QUIC или, возможно, пришло время обновить браузер.
Ради эксперимента вы можете отключить HTTP/3 в настройках браузера. Для Chrome нужно ввести в адресную строку chrome://flags/#enable-quic → Experimental QUIC protocol → Disable
И вы сможете ощутить все прелести замедления. Возможно, именно к такому состоянию нас и готовят в будущем. Кстати, напишите в комментариях, кто в курсе, почему удается так жестко снижать скорость для протокола HTTP/2, а для HTTP/3 нет? Или не пытались?
Выяснили. Нам очень необходима поддержка протокола HTTP/3, но это, как оказалось, совсем нетривиальная задача. Даже для Curl требуется целая церемония. Новый протокол скорее ориентирован на браузеры, хотя уже есть и поддержка для Nginx.
Поправьте меня в комментариях, если я не прав.
Как оказалось, для Android приложений существует целая гугловая библиотека Cronet.
Cronet — это сетевой стек Chromium, предоставляемый приложениям Android в виде библиотеки. Cronet использует несколько технологий, которые снижают задержку и увеличивают пропускную способность сетевых запросов, необходимых для работы вашего приложения.
Библиотека Cronet обрабатывает запросы приложений, которыми ежедневно пользуются миллионы людей, таких как YouTube, Google App, Google Photos и Maps — Navigation & Transit.
На Хабре про неё есть отдельная статья от 2019 года — Протокол QUIC в деле: как его внедрял Uber, чтобы оптимизировать производительность
private fun createCronet(context: Context): CronetEngine {
return CronetEngine.Builder(context)
.enableHttp2(true)
.enableQuic(true)
.enableBrotli(true)
.build()
}
После подключения библиотеки в качестве движка для Ktor Client (использовал экспериментальную реализация с гитхаба) скорость скачивания заметно выросла.
Итог
Мне удалось повысить среднюю скорость скачивания видео в 1080p до 7 мегабит
на домашнем интернете от МТС и до 12 мегабит
на мобильном интернете от Теле2.
Если в текущих условиях замедления вам нужно будет скачать видео, то вы всегда можете воспользоваться моим загрузчиком из RuStore.
Дополнение
Можно воспользоваться сервисом от Nginx, который покажет, подключились ли вы c QUIC или нет.
При успешном соединении c QUIC появится следующая надпись Congratulations! You're connected over QUIC
Если какая‑то другая надпись, то возможно вам следует разобраться с настройками своего браузера/обновиться/перейти на другой.
По моим наблюдением, именно хром дает лучшую скорость при просмотре видео с ютуб.
Как включить в Chrome:
chrome://flags/#enable-quic сделать Enable
Для Mozilla Firefox:
В about:config параметр network.http.http3.enable ставим в True
Тест производительности YouTube в Chrome с включенным QUIC и отключенным.
По-моему разница существенная.
Для отображения статистики по скорости нужно кликнуть правой кнопкой мыши на видео → «статистика для сисадминов»: