
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 порядок такой:
- Установить Python 3.12:
brew install python@3.12
Восстановить папку
~/Documents/scriptsиз Яндекс Диска или гитаСоздать новое окружение:
cd ~/Documents/scripts/youtube-cookies
./setup.sh
- Проверить SSH-подключение:
ssh homeserverbeaver
- Отправить свежие 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 создаётся заново одной командой.