logo

YouTube всё чаще требует авторизацию даже для обычного скачивания видео. У меня это проявилось в Podsync, про который я писал ранее: yt-dlp на сервере переставал получать ролики.

Решение простое: забрать актуальные cookies из локального Firefox, перевести их в Netscape-формат, отправить на сервер и перезапустить Podsync. Чтобы не делать эти шаги вручную, я собрал маленький проект youtube-cookies.

Что получилось Link to heading

Проект лежит в ~/Documents/scripts/youtube-cookies/:

youtube-cookies/
├── .venv/
├── extract_yt_cookies.py
├── requirements.txt
├── setup.sh
└── sync_yt_cookies.sh
  • extract_yt_cookies.py читает cookies из Firefox и сохраняет их в формате Mozilla/Netscape;
  • sync_yt_cookies.sh отправляет файл на сервер, создаёт резервную копию и перезапускает Podsync;
  • requirements.txt хранит список Python-зависимостей;
  • setup.sh создаёт локальный .venv и устанавливает зависимости;
  • .venv/ содержит установленную библиотеку rookiepy

Готовые файлы Link to heading

mkdir -p ~/Documents/scripts/youtube-cookies
cd ~/Documents/scripts/youtube-cookies

curl -O https://blog.tatarinovms.space/scripts/youtubecookies/extract_yt_cookies.py
curl -O https://blog.tatarinovms.space/scripts/youtubecookies/requirements.txt
curl -O https://blog.tatarinovms.space/scripts/youtubecookies/setup.sh
curl -O https://blog.tatarinovms.space/scripts/youtubecookies/sync_yt_cookies.sh

chmod +x setup.sh sync_yt_cookies.sh extract_yt_cookies.py

После скачивания отредактируйте sync_yt_cookies.sh: замените SERVER="homeserverbeaver" на ваш SSH-хост и проверьте путь к REMOTE_COOKIE_FILE на сервере.

Что понадобится Link to heading

На Mac должны быть установлены Python 3.11 или 3.12 и Firefox с залогниненым Youtube. Для Python через Homebrew:

brew install python@3.12

Нужен настроенный SSH alias сервера. У меня он называется homeserverbeaver и описан в ~/.ssh/config:

Host homeserverbeaver
    HostName 192.1.1.1
    User root
    IdentityFile ~/.ssh/serverbeaverhome

На сервере Podsync читает cookies из файла:

/etc/podsync/youtube-cookies.txt

Путь должен совпадать с настройкой Podsync или аргументами yt-dlp.

Настройка Podsync Link to heading

Одного файла /etc/podsync/youtube-cookies.txt мало. Podsync сам по себе не догадается его использовать: нужно передать путь в yt-dlp через youtube_dl_args в config.toml.

У меня конфиг лежит здесь:

/mnt/dietpi_userdata/podsync/config.toml

В каждом фиде добавлен аргумент --cookies:

[feeds]
  [feeds.ChannelName]
  url = "https://www.youtube.com/@channel"
  format = "audio"
  update_period = "8h"
  youtube_dl_args = [
    "--js-runtimes", "deno:/root/.deno/bin/deno",
    "--cookies", "/etc/podsync/youtube-cookies.txt",
    "--extractor-args", "youtube:player_client=default"
  ]

После правки конфига перезапускаем Podsync:

systemctl restart podsync

А уже потом запускаем синхронизацию cookies с Mac. Скрипт обновит файл и ещё раз перезапустит сервис.

Экспорт cookies из Firefox Link to heading

Для чтения cookies использую библиотеку rookiepy. Она достаёт данные из профиля браузера без ручного экспорта через расширение.

Зависимость записана в requirements.txt:

rookiepy

Сам экспорт выглядит так:

import http.cookiejar
import sys

import rookiepy


def export_cookies(output_file: str) -> None:
    raw = rookiepy.firefox(
        domains=[".youtube.com", ".google.com", ".googlevideo.com"]
    )
    if not raw:
        print("ERROR: no YouTube cookies found", file=sys.stderr)
        sys.exit(1)

    cookie_jar = http.cookiejar.MozillaCookieJar(output_file)
    for cookie in raw:
        cookie_jar.set_cookie(
            http.cookiejar.Cookie(
                version=0,
                name=cookie["name"],
                value=cookie["value"],
                port=None,
                port_specified=False,
                domain=cookie["domain"],
                domain_specified=True,
                domain_initial_dot=cookie["domain"].startswith("."),
                path=cookie["path"],
                path_specified=True,
                secure=cookie["secure"],
                expires=cookie["expires"],
                discard=False,
                comment=None,
                comment_url=None,
                rest={},
                rfc2109=False,
            )
        )

    cookie_jar.save(ignore_discard=True, ignore_expires=True)

Я забираю только домены YouTube, Google и Google Video. На выходе получается обычный cookies-файл, который понимает yt-dlp.

При первом запуске macOS может запросить доступ Python или терминала к данным Firefox. Доступ нужно разрешить в системных настройках.

Создание Python-окружения Link to heading

Устанавливать rookiepy глобально не хочется, поэтому зависимости живут в .venv. Скрипт setup.sh выбирает Python 3.12 или 3.11, пересоздаёт окружение и запускает pip:

#!/bin/bash

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
VENV="$SCRIPT_DIR/.venv"

if command -v python3.12 >/dev/null 2>&1; then
    PYTHON="python3.12"
elif command -v python3.11 >/dev/null 2>&1; then
    PYTHON="python3.11"
else
    echo "Установите Python 3.11 или 3.12" >&2
    exit 1
fi

rm -rf "$VENV"
"$PYTHON" -m venv "$VENV"
"$VENV/bin/python3" -m pip install --upgrade pip
"$VENV/bin/python3" -m pip install -r "$SCRIPT_DIR/requirements.txt"

Запуск:

cd ~/Documents/scripts/youtube-cookies
./setup.sh

В моём случае системный python3 уже был версии 3.14, но rookiepy 0.5.6 использует старую версию PyO3 и с Python 3.14 не собирается. Поэтому выбор 3.11/3.12 здесь не прихоть, а совместимость.

Отправка cookies на сервер Link to heading

Основной скрипт сначала проверяет окружение, извлекает cookies во временный файл и отправляет его через scp:

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
VENV_PYTHON="$SCRIPT_DIR/.venv/bin/python3"
LOCAL_COOKIE_FILE="${TMPDIR:-/tmp}/yt_cookies.txt"
SERVER="homeserverbeaver"

trap 'rm -f "$LOCAL_COOKIE_FILE"' EXIT INT TERM
umask 077

"$VENV_PYTHON" "$SCRIPT_DIR/extract_yt_cookies.py" "$LOCAL_COOKIE_FILE"
scp "$LOCAL_COOKIE_FILE" "$SERVER:/tmp/yt_cookies_new.txt"

umask 077 не даёт другим локальным пользователям прочитать новый файл. trap удаляет его после успешного запуска, ошибки или сигнала.

На сервере одна SSH-команда выполняет установку:

ssh "$SERVER" "if [ -f '/etc/podsync/youtube-cookies.txt' ]; then
    cp '/etc/podsync/youtube-cookies.txt' '/etc/podsync/youtube-cookies.txt.bak'
fi
mv /tmp/yt_cookies_new.txt '/etc/podsync/youtube-cookies.txt' &&
chmod 600 '/etc/podsync/youtube-cookies.txt' &&
systemctl restart podsync"

Старый файл сохраняется как .bak, новый получает права 600, затем сервис перезапускается. Если любой шаг завершится ошибкой, shell не продолжит цепочку после &&.

Полный запуск:

~/Documents/scripts/youtube-cookies/sync_yt_cookies.sh

Почему .venv не надо синхронизировать Link to heading

Мои скрипты синхронизируются с Яндекс Диском и гитом через rclone bisync. Сначала туда хотел сунуть и virtualenv, но это плохая идея по нескольким причинам:

  • в .venv тысячи мелких файлов;
  • библиотеки занимают намного больше места, чем исходники;
  • исполняемые файлы содержат абсолютные пути;
  • бинарные модули зависят от версии Python, архитектуры и macOS;
  • после переустановки скопированное окружение может не запуститься.

В свой bisync скрипт добавил исключения:

--exclude "**/.venv/**"
--exclude "**/venv/**"
--exclude "**/__pycache__/**"
--exclude "**/*.pyc"
--exclude "**/*.pyo"

В облаке и гите остаются только исходники, requirements.txt и setup.sh. Это и есть переносимая часть проекта.

Восстановление после переустановки Link to heading

После чистой установки macOS порядок такой:

  1. Установить Python 3.12:
brew install python@3.12
  1. Восстановить папку ~/Documents/scripts из Яндекс Диска или гита

  2. Создать новое окружение:

cd ~/Documents/scripts/youtube-cookies
./setup.sh
  1. Проверить SSH-подключение:
ssh homeserverbeaver
  1. Отправить свежие cookies:
./sync_yt_cookies.sh

Копировать старый .venv и вручную вспоминать команды pip install не требуется. requirements.txt описывает зависимости, а setup.sh полностью восстанавливает окружение.

Автоматический запуск Link to heading

Скрипт можно запускать вручную после повторной авторизации YouTube или поставить в launchd. Я пока предпочитаю ручной запуск: cookies меняются не каждый день.

Если нужна автоматизация, достаточно запускать эту команду по расписанию:

~/Documents/scripts/youtube-cookies/sync_yt_cookies.sh

Перед этим стоит убедиться, что SSH-ключ работает без интерактивного ввода пароля.

Важный момент Link to heading

Cookies дают доступ к авторизованной сессии YouTube. Их нельзя коммитить в git, складывать в общедоступное облако или отправлять в логи. В этой схеме файл существует локально только во время запуска, передаётся по SSH и хранится на сервере с правами 600.

Итог Link to heading

Получилась короткая цепочка: Firefox на Mac, rookiepy, временный Netscape cookies-файл, scp, backup на сервере и restart Podsync. Исходники спокойно синхронизируются через Яндекс Диск и гит, а тяжёлый и непереносимый .venv создаётся заново одной командой.