Я выступил с докладом на WordCamp US 2023 и захотел скачать видео с ним. Я всегда стараюсь хранить собственные копии таких видео, потому что некоторые конференции в прошлом со временем закрывали к ним доступ.

Моя презентация в прямом эфире транслировалась через YouTube, однако получившееся видео длится 9,5 часа!

В обычной ситуации я бы скачал видео полностью и обрезал его локально, но тогда я был подключен к WiFi конференции и не хотел ждать всего файла, поэтому решил проверить, можно ли скачать его часть.

Я нашёл этот рецепт пользователя StackExchange godofgrunts, который походил на то, что мне нужно:

#!/bin/bash
#Arguments: URL, Time stamp -5 seconds, length of clip, video file name
readarray -t urls <<< """ class="formula inline">1")"
ffmpeg -ss "" class="formula inline">{urls[0]}" -ss "" class="formula inline">{urls[1]}" -ss 5 -map 0:v -map 1:a -c:v libx264 -c:a aac -t " class="formula inline">4

Но когда я запустил его, то получил ошибку, потому что на моём Mac не было readarray.

Поэтому я вставил команды в GPT-4 со следующим промтом:

Port this to macOS — I do not have the readarray command

«Портируй это на macOS — у меня нет команды readarray»

Он выдал мне такое:

#!/bin/bash
# Arguments: URL, Time stamp -5 seconds, length of clip, video file name

IFS=$'\n' urls=($(yt-dlp --youtube-skip-dash-manifest -g "$1"))
ffmpeg -ss $2 -i "${urls[0]}" -ss $2 -i "${urls[1]}" -ss 5 -map 0:v -map 1:a -c:v libx264 -c:a aac -t $3 $4

1. Переменной IFS присвоен символ новой строки, чтобы возвращаемые yt-dlp URL разделялись по новым строкам.

2. Массив urls заполняется подстановкой команды и присвоением массива.

3. Остальная часть скрипта осталась неизменной.

Я сохранил команды как clip-youtube.sh, выполнил chmod 755 clip-youtube.sh и... это сработало!

Я вызвал код следующим образом:

./clip-youtube.sh 'https://www.youtube.com/watch?v=LpDulftMkew' 8:18:25 3600 simon-wordcamp.mp4

Моя часть видео начинается примерно с 8 ч 18 мин и 25 с. Я указал 3600, чтобы скачать час контента (раздел Q&A длился немного больше, нужно было указать большее значение).

Для выполнения скрипта потребовался почти целый час! В конечном итоге, возможно, было бы быстрее скачать файл целиком, а потом нарезать его.

Но... в результате я получил файл simon-wordcamp.mp4 на 308 МБ.

Как всё это работает

Немного объясню код. Первая часть выглядит так:

yt-dlp --youtube-skip-dash-manifest -g "$1"

Выполнив её, мы получим такой результат:

yt-dlp --youtube-skip-dash-manifest -g 'https://www.youtube.com/watch?v=LpDulftMkew'

Вывод:

https://rr2---sn-8xgp1vo-p5qs.googlevideo.com/videoplayback?expire=1693085635&ei=YxvqZJ2RJb6t_9EPwuSgkAk&ip=65.201.185.136&id=o-AAyFKyoRtQrnNL3zrfdNULpm39lectAVHkcbeoAF2jLI&itag=137&source=youtube&requiressl=yes&mh=Vv&mm=31%2C26&mn=sn-8xgp1vo-p5qs%2Csn-ab5l6nkd&ms=au%2Conr&mv=m&mvi=2&pcm2cms=yes&pl=21&initcwndbps=1816250&vprv=1&svpuc=1&mime=video%2Fmp4&gir=yes&clen=2674985800&dur=34334.996&lmt=1693003267530862&mt=1693063539&fvip=1&keepalive=yes&fexp=24007246&c=IOS&txp=7209224&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cvprv%2Csvpuc%2Cmime%2Cgir%2Cclen%2Cdur%2Clmt&sig=AOq0QJ8wRAIgDzk4tc_9bCUvwN0Wg_73hJdAJHl2CDJW8ntEGmIu5HoCIH6u9T8EZSnITAln8Ebh6Vt_P17x3sKbecFfwdkH7AKP&lsparams=mh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpcm2cms%2Cpl%2Cinitcwndbps&lsig=AG3C_xAwRAIgFZ9mdd4hTdBnDCn0DhbbOkgCLsKQbaoI8eFU3SDBiAYCIHIwpPwy8LfmGv1sNezegCuIQ8f5OZV-J1pBYYZ6Spxi
https://rr2---sn-8xgp1vo-p5qs.googlevideo.com/videoplayback?expire=1693085635&ei=YxvqZMPFMYmi_9EP1YOsqA4&ip=65.201.185.136&id=o-AJrteXKDNXZVv-8ohwCNtkgRusvA7tjSCrK-Yhvj13FZ&itag=251&source=youtube&requiressl=yes&mh=Vv&mm=31%2C26&mn=sn-8xgp1vo-p5qs%2Csn-ab5sznzk&ms=au%2Conr&mv=m&mvi=2&pl=21&initcwndbps=1816250&spc=UWF9f2Mp7IK_PwGaM7XhKZtnkS6X3I4&vprv=1&svpuc=1&mime=audio%2Fwebm&gir=yes&clen=318551384&dur=34335.041&lmt=1693003946161041&mt=1693063539&fvip=1&keepalive=yes&fexp=24007246%2C51000023&beids=24350017&c=ANDROID&txp=7208224&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cspc%2Cvprv%2Csvpuc%2Cmime%2Cgir%2Cclen%2Cdur%2Clmt&sig=AOq0QJ8wRQIhAK--nt8-f1qPpaG1ioc5I2gQLEVD5sCFCUh6fjruOHPUAiAWz0o0kOhS-M--vPkNWD0ZqdSguD5lxFxwLu46Zgb5jw%3D%3D&lsparams=mh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps&lsig=AG3C_xAwRQIgWmu0j9lq5uhkxVkOfUK4cctQbhgwMcU1stpCvLNYBB4CIQCMt0PzKQ5T9ofUxoIYywGN_fE72dMvPuoEvJZr4jOwJg%3D%3D

Я немного поискал и выяснил, что --youtube-skip-dash-manifest больше не нужен. То есть на самом деле команда будет такой:

yt-dlp -g 'https://www.youtube.com/watch?v=LpDulftMkew'

Опция -g заставляет yt-dlp создать URL стримов, а не скачивать видео.

Команда возвращает два URL, потому что один относится к видеопотоку, а другой — к аудиопотоку. Мы можем переформатировать эти URL, чтобы это стало очевиднее — подсказка заключается в том, что в первом случае используется &mime=video%2Fmp4 , а во втором — &mime=audio%2Fwebm.

Затем скрипт вызывает ffmpeg. Вот очищенная версия этого вызова:

ffmpeg \
  -ss '8:18:25' -i "${VIDEO_STREAM_URL}" \
  -ss '8:18:25' -i "${AUDIO_STREAM_URL}" \
  -ss 5 \
  -map 0:v \
  -map 1:a \
  -c:v libx264 \
  -c:a aac \
  -t 3600 simon-wordcamp.mp4

Две строки -ss выполняют поиск отметки 8:18:25 в видеопотоке и в аудиопотоке.

--s 5 выполняет поиск на 5 секунд внутрь скомбинированного вывода. В инструкциях на StackExchange говорится, что нужно начинать как минимум за 5 с до той части видео, которую вы хотите сохранить. В рецепте с StackExchange указано, что это нужно «для того, чтобы дать несколько секунд на поиск хорошего ключевого кадра».

-map 0:v и -map 1:a задают первый поток как видео, а второй — как аудио.

-c:v libx264 и -c:a aac конфигурируют выходные кодеки для видео (H.264) и аудио (AAC).

-t 3600 simon-wordcamp.mp4 задаёт длительность (час, или 60 * 60 секунд) и имя выходного файла.

Прим. пер.: вообще для решения задачи можно было использовать встроенную в yt-dlp функцию --download-sections, но текст всё равно интересен необычностью изложенной идеи.

Дополнительные ссылки

Комментарии (8)


  1. kulhaker478
    28.08.2023 07:25
    +2

    Под виндой примерно так же качаю:

    yt-dlp --external-downloader ffmpeg --external-downloader-args "-ss xx:xx.xx -to yy:yy.yy" id

    Очень удобно, особенно когда надо 5 секунд из видео, а оно час идёт, пуперам бы такое в своё время) Правда через ffmpeg скорость загруки потока какая-то бедная, возможно с актуальными версиями yt-dlp и ffmpeg побыстрее будет


    1. itundp
      28.08.2023 07:25

      Точно не скажу, но тут по моему была статья, что они специально уменьшают скорость скачиванию и каждый раз генерируется ключ. В этой статье было показано, как обходить это и скачивать на быстрой скорости


      1. slavius
        28.08.2023 07:25
        +1

        https://habr.com/ru/articles/754654/

        Как обходится ограничение скорости скачивания с YouTube


      1. kulhaker478
        28.08.2023 07:25

        Вчера сегмент выкачивал, вроде нормальная скорость была, как раз на днях yt-dlp обновлял, вечером дополню как оно, возможно уже за нас всё продумано


        1. shadrap
          28.08.2023 07:25

          Спасибо за наводку насчет внешнего вызова ffmpeg из yt-dlp , только почему то временные рамки воспринимать не хочет - упрямо качает только первые 5 сек и все


          1. kulhaker478
            28.08.2023 07:25

            На самом деле правильно так, комент ещё на работе писал просто, не было доступа к заметкам:
            и вместо -f best - -fb
            и вместо -f best - -fb

            Логику -ss -to достаточно один раз понять и дальше рефлекторно таймкоды будут вбиваться

            Скорость я так и не проверил, ибо ленивая жопа)


            1. shadrap
              28.08.2023 07:25

              Все, все, спасибо еще раз , разобрался, у некоторых роликов видимо с таймингом какие-то проблемы, другие прекрасно таймкодируются.


  1. KPbICMAH
    28.08.2023 07:25

    А перекодировать обязательно? Не быстрее -c copy сделать?