Enhance YouTube downloader with improved cookie validation and download strategies. Update cookie extraction script for better error handling and user feedback.

This commit is contained in:
vrubel 2025-12-25 21:38:13 +03:00
parent a918f93dfa
commit e6c6734768
2 changed files with 378 additions and 236 deletions

View file

@ -4,6 +4,7 @@ YouTube Video Downloader Service
""" """
import os import os
import logging import logging
import time
from pathlib import Path from pathlib import Path
from flask import Flask, request, jsonify from flask import Flask, request, jsonify
from flask_cors import CORS from flask_cors import CORS
@ -33,43 +34,97 @@ def _safe_filename(title: str) -> str:
def _is_valid_cookies_file(cookies_path: Path) -> bool: def _is_valid_cookies_file(cookies_path: Path) -> bool:
"""Проверяет, что файл cookies существует и содержит данные (не только заголовки)""" """Проверяет, что файл cookies существует и содержит валидные YouTube-куки"""
if not cookies_path.exists(): if not cookies_path.exists():
return False return False
try: try:
with open(cookies_path, 'r', encoding='utf-8', errors='ignore') as f: with open(cookies_path, 'r', encoding='utf-8', errors='ignore') as f:
lines = [line.strip() for line in f.readlines() if line.strip() and not line.strip().startswith('#')] content = f.read()
# Проверяем, что есть хотя бы одна строка с данными cookie
return len(lines) > 0 # Простая проверка: есть ли YouTube-куки в файле
has_youtube_domain = '.youtube.com' in content or 'youtube.com' in content
if not has_youtube_domain:
logger.warning("YouTube: в файле cookies нет YouTube-куков")
return False
# Проверяем строки с данными (не комментарии)
lines = [line.strip() for line in content.split('\n') if line.strip() and not line.strip().startswith('#')]
if len(lines) == 0:
return False
# Проверяем наличие YouTube-куков и важных параметров
youtube_cookies_count = 0
important_cookies_count = 0
current_time = int(time.time())
for line in lines:
# Формат Netscape cookie: domain, flag, path, secure, expiration, name, value
# Разделяем по табуляции, но учитываем что значения могут содержать табы
parts = line.split('\t')
if len(parts) >= 7: # Должно быть минимум 7 полей
domain = parts[0].strip()
expiration = parts[4].strip()
cookie_name = parts[5].strip() if len(parts) > 5 else ''
# Проверяем домен
if '.youtube.com' in domain or domain == 'youtube.com':
youtube_cookies_count += 1
# Проверяем срок действия (0 означает сессионный куки, это нормально)
is_valid = True
if expiration != '0':
try:
exp_time = int(expiration)
if exp_time < current_time:
is_valid = False
logger.debug(f"YouTube: просроченный куки {cookie_name} (истек: {exp_time})")
except (ValueError, OverflowError):
pass
# Проверяем наличие важных куков
if is_valid and any(important in cookie_name for important in ['VISITOR_INFO1_LIVE', '__Secure-3PSID', 'PREF', '__Secure-YNID', 'YSC']):
important_cookies_count += 1
if youtube_cookies_count > 0:
if important_cookies_count > 0:
logger.debug(f"YouTube: найдены валидные куки ({youtube_cookies_count} YouTube-куков, {important_cookies_count} важных)")
else:
logger.warning(f"YouTube: найдены YouTube-куки ({youtube_cookies_count}), но нет важных параметров")
return True
else:
logger.warning("YouTube: в файле cookies нет валидных YouTube-куков")
return False
except Exception as e: except Exception as e:
logger.warning(f"Ошибка при проверке файла cookies: {e}") logger.warning(f"Ошибка при проверке файла cookies: {e}")
return False return False
def download_youtube_video(url: str, max_retries: int = 3) -> Path: def download_youtube_video(url: str, max_retries: int = 3) -> Path:
"""Скачивает видео с YouTube - используем cookies для обхода блокировок""" """
Скачивает видео с YouTube с умной стратегией использования куков:
1. Сначала пробуем БЕЗ куков (работает в большинстве случаев)
2. Если нужны куки (18+, приватные, проверка на бота) - пробуем файл куков
3. Если файл не работает - пробуем автоматически из браузера (если доступен)
"""
cookies_file = os.getenv('YOUTUBE_COOKIES_FILE', 'youtube_cookies.txt') cookies_file = os.getenv('YOUTUBE_COOKIES_FILE', 'youtube_cookies.txt')
cookies_file_path = Path(cookies_file) cookies_file_path = Path(cookies_file)
cookies_valid = _is_valid_cookies_file(cookies_file_path) # Проверяем наличие валидного файла куков (но не используем сразу)
if not cookies_valid: cookies_file_valid = _is_valid_cookies_file(cookies_file_path)
logger.warning(f"YouTube: файл cookies не найден или невалиден ({cookies_file_path}). "
f"Работаем без cookies. Для лучшей работы рекомендуется обновить cookies через скрипт get_youtube_cookies.sh")
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
last_error = None
for attempt in range(max_retries):
try:
# Определяем, это Shorts или обычное видео # Определяем, это Shorts или обычное видео
is_shorts = '/shorts/' in url is_shorts = '/shorts/' in url
# Базовые настройки для получения информации
# Для Shorts используем более надежные клиенты
player_clients = ['android', 'ios', 'web'] if is_shorts else ['android', 'web'] player_clients = ['android', 'ios', 'web'] if is_shorts else ['android', 'web']
ydl_opts_info = { def create_ydl_opts(use_cookies_from_file: bool = False, use_browser_cookies: str = None):
"""Создает опции для yt-dlp"""
opts = {
'quiet': False, 'quiet': False,
'no_warnings': False, 'no_warnings': False,
'user_agent': user_agent, 'user_agent': user_agent,
@ -89,139 +144,117 @@ def download_youtube_video(url: str, max_retries: int = 3) -> Path:
}, },
} }
# Если есть валидный файл с cookies, используем его if use_browser_cookies:
if cookies_valid: # Автоматически получаем куки из браузера (не нужен файл)
ydl_opts_info['cookiefile'] = str(cookies_file_path.absolute()) opts['cookiesfrombrowser'] = (use_browser_cookies,)
logger.info(f"YouTube: используем cookies из {cookies_file_path.absolute()} (попытка {attempt + 1})") logger.info(f"YouTube: используем автоматические куки из браузера {use_browser_cookies}")
elif use_cookies_from_file and cookies_file_valid:
opts['cookiefile'] = str(cookies_file_path.absolute())
logger.info(f"YouTube: используем куки из файла {cookies_file_path.absolute()}")
else: else:
logger.info(f"YouTube: работаем без cookies (попытка {attempt + 1})") logger.info(f"YouTube: работаем БЕЗ куков (в большинстве случаев это работает)")
# Пробуем получить информацию о видео return opts
info = None
# Стратегии попыток: без куков -> файл куков -> браузер куки
strategies = [
{'name': 'без куков', 'opts': create_ydl_opts(use_cookies_from_file=False)},
]
if cookies_file_valid:
strategies.append({
'name': 'куки из файла',
'opts': create_ydl_opts(use_cookies_from_file=True)
})
# Добавляем стратегии с браузерами (в Docker обычно нет браузеров, но пробуем)
# yt-dlp автоматически обработает ошибку, если браузер недоступен
for browser in ['firefox', 'chrome', 'chromium']:
strategies.append({
'name': f'куки из браузера {browser}',
'opts': create_ydl_opts(use_browser_cookies=browser)
})
last_error = None
for attempt in range(max_retries):
for strategy in strategies:
try: try:
with yt_dlp.YoutubeDL(ydl_opts_info) as ydl: logger.info(f"YouTube: попытка {attempt + 1}/{max_retries}, стратегия: {strategy['name']}")
# Получаем информацию о видео
with yt_dlp.YoutubeDL(strategy['opts'].copy()) as ydl:
info = ydl.extract_info(url, download=False) info = ydl.extract_info(url, download=False)
except Exception as info_error:
# Если не получилось с cookies, пробуем без них
if cookies_valid and ('cookies' in str(info_error).lower() or 'bot' in str(info_error).lower()):
logger.warning("YouTube: не удалось получить информацию с cookies, пробуем без них")
ydl_opts_info.pop('cookiefile', None)
with yt_dlp.YoutubeDL(ydl_opts_info) as ydl:
info = ydl.extract_info(url, download=False)
cookies_valid = False # Отключаем cookies для скачивания тоже
else:
raise
video_title = info.get('title', 'video') if info else 'video' video_title = info.get('title', 'video') if info else 'video'
logger.info(f"YouTube: получена информация о видео: {video_title}") logger.info(f"YouTube: получена информация о видео: {video_title}")
# Настройки для скачивания с более гибким форматом # Настройки для скачивания с более гибким форматом
# Пробуем разные варианты форматов, если один не работает
format_options = [ format_options = [
'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best', # Предпочтительный 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best',
'best[ext=mp4]/best', # Простой fallback 'best[ext=mp4]/best',
'bestvideo+bestaudio/best', # Без ограничения по расширению 'bestvideo+bestaudio/best',
'best', # Самый простой вариант 'best',
] ]
download_success = False # Используем ту же стратегию куков для скачивания
for format_option in format_options: for format_option in format_options:
ydl_opts_download = { download_opts = strategy['opts'].copy()
download_opts.update({
'format': format_option, 'format': format_option,
'outtmpl': _safe_filename(video_title), 'outtmpl': _safe_filename(video_title),
'quiet': False, })
'no_warnings': False,
'user_agent': user_agent,
'socket_timeout': 60,
'extractor_args': {
'youtube': {
'player_client': ['android', 'ios', 'web'] if is_shorts else ['android', 'web'],
'player_skip': ['webpage'],
},
},
'http_headers': {
'User-Agent': user_agent,
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en-us,en;q=0.5',
'Accept-Encoding': 'gzip, deflate',
'Connection': 'keep-alive',
},
}
# Если есть валидный файл с cookies, используем его для скачивания logger.info(f"YouTube: скачивание (формат: {format_option}, стратегия: {strategy['name']})")
use_cookies_this_attempt = cookies_valid
if use_cookies_this_attempt:
ydl_opts_download['cookiefile'] = str(cookies_file_path.absolute())
logger.info(f"YouTube: начинаем скачивание (попытка {attempt + 1}/{max_retries}, Shorts: {is_shorts}, формат: {format_option}, cookies: {use_cookies_this_attempt})")
try: try:
with yt_dlp.YoutubeDL(ydl_opts_download) as ydl: with yt_dlp.YoutubeDL(download_opts) as ydl:
ydl.download([url]) ydl.download([url])
download_success = True
break
except Exception as download_error:
error_str = str(download_error)
# Если ошибка с cookies, пробуем без них
if use_cookies_this_attempt and ('cookies' in error_str.lower() or 'bot' in error_str.lower() or 'sign in' in error_str.lower()):
logger.warning(f"YouTube: ошибка с cookies для формата {format_option}, пробуем без cookies...")
ydl_opts_download.pop('cookiefile', None)
try:
with yt_dlp.YoutubeDL(ydl_opts_download) as ydl:
ydl.download([url])
download_success = True
cookies_valid = False # Отключаем cookies для следующих попыток
break
except Exception:
# Если и без cookies не получилось, пробуем следующий формат
logger.warning(f"YouTube: не удалось скачать без cookies, пробуем следующий формат...")
continue
# Если ошибка формата, пробуем следующий формат
elif 'format is not available' in error_str.lower() or 'requested format' in error_str.lower():
logger.warning(f"YouTube: формат {format_option} недоступен, пробуем следующий...")
continue
else:
# Другая ошибка - пробуем следующий формат
logger.warning(f"YouTube: ошибка при скачивании формата {format_option}: {error_str[:100]}, пробуем следующий...")
continue
if not download_success:
raise Exception("Не удалось скачать видео ни с одним из доступных форматов")
# Находим скачанный файл # Находим скачанный файл
downloaded_files = list(DOWNLOADS_DIR.glob('*')) downloaded_files = list(DOWNLOADS_DIR.glob('*'))
if downloaded_files: if downloaded_files:
downloaded_files.sort(key=lambda x: x.stat().st_mtime, reverse=True) downloaded_files.sort(key=lambda x: x.stat().st_mtime, reverse=True)
logger.info(f"YouTube: успешно скачано стратегией '{strategy['name']}'")
return downloaded_files[0] return downloaded_files[0]
else: else:
raise Exception("Файл не был найден после скачивания") raise Exception("Файл не был найден после скачивания")
except Exception as e: except Exception as download_error:
last_error = e error_str = str(download_error).lower()
error_str = str(e)
logger.warning(f"YouTube: попытка {attempt + 1}/{max_retries} не удалась: {error_str}")
# Если ошибка связана с форматом, пробуем другие настройки # Если ошибка "bot" или "sign in" - пробуем следующую стратегию
if 'format is not available' in error_str.lower() or 'requested format' in error_str.lower(): if any(keyword in error_str for keyword in ['bot', 'sign in', 'cookies']):
logger.warning("YouTube: проблема с форматом, пробуем другие настройки на следующей попытке") logger.warning(f"YouTube: ошибка с куками для формата {format_option}, пробуем следующую стратегию...")
# На следующей попытке попробуем другие player_client break # Переходим к следующей стратегии
if attempt < max_retries - 1:
import time # Если ошибка формата - пробуем следующий формат
time.sleep((attempt + 1) * 2) if 'format is not available' in error_str or 'requested format' in error_str:
logger.warning(f"YouTube: формат {format_option} недоступен, пробуем следующий...")
continue continue
# Если ошибка связана с cookies и они были использованы, попробуем без cookies на следующей попытке # Другая ошибка - логируем и пробуем следующий формат
if 'cookies' in error_str.lower() or 'bot' in error_str.lower() or 'sign in' in error_str.lower(): logger.warning(f"YouTube: ошибка формата {format_option}: {str(download_error)[:100]}")
if cookies_valid and attempt == 0: continue
logger.warning("YouTube: ошибка с cookies, попробуем обновить cookies или работать без них")
# На следующей попытке попробуем без cookies
cookies_valid = False
# Если все форматы не подошли для этой стратегии, пробуем следующую
continue
except Exception as e:
error_str = str(e).lower()
logger.warning(f"YouTube: стратегия '{strategy['name']}' не сработала: {str(e)[:100]}")
# Если ошибка "bot" или "sign in" - пробуем следующую стратегию
if any(keyword in error_str for keyword in ['bot', 'sign in', 'cookies']):
continue
# Для других ошибок - пробуем следующую стратегию или следующую попытку
last_error = e
# Если все стратегии не сработали, делаем паузу перед следующей попыткой
if attempt < max_retries - 1: if attempt < max_retries - 1:
import time
time.sleep((attempt + 1) * 2) time.sleep((attempt + 1) * 2)
raise last_error or Exception("Неизвестная ошибка при скачивании с YouTube") raise last_error or Exception("Не удалось скачать видео ни с одной стратегией")
@app.route('/health', methods=['GET']) @app.route('/health', methods=['GET'])
@ -277,17 +310,14 @@ def download_stream():
error_str = str(e) error_str = str(e)
logger.error(f"Ошибка при скачивании: {error_str}") logger.error(f"Ошибка при скачивании: {error_str}")
# Улучшаем сообщение об ошибке, если проблема с cookies # Улучшаем сообщение об ошибке
error_msg = error_str
if 'cookies' in error_str.lower() or 'bot' in error_str.lower() or 'sign in' in error_str.lower(): if 'cookies' in error_str.lower() or 'bot' in error_str.lower() or 'sign in' in error_str.lower():
error_msg = ( error_msg = (
f"{error_str}\n\n" f"{error_str}\n\n"
"💡 Совет: Cookies устарели или недействительны. " "💡 Совет: YouTube требует авторизацию для этого видео (18+, приватное и т.д.). "
"Обновите cookies, запустив скрипт:\n" "Попробуйте открыть видео в браузере, авторизоваться, затем повторить запрос."
" ./youtube-downloader/get_youtube_cookies.sh\n"
"Затем перезапустите сервис."
) )
else:
error_msg = error_str
return jsonify({'error': error_msg}), 500 return jsonify({'error': error_msg}), 500

View file

@ -1,85 +1,190 @@
#!/bin/bash #!/bin/bash
# Скрипт для получения cookies YouTube через yt-dlp из Firefox # Скрипт для получения cookies YouTube через yt-dlp из Firefox
# Предназначен для запуска на Ubuntu 24.04 с авторизованным Firefox
# Результат копируется через cron на серверы со службами скачивания
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
COOKIES_FILE="$SCRIPT_DIR/youtube_cookies.txt" COOKIES_FILE="$SCRIPT_DIR/youtube_cookies.txt"
BROWSER="firefox" BROWSER="firefox"
TEMP_FILE="${COOKIES_FILE}.tmp"
# Если запущено с sudo, используем HOME реального пользователя # Определяем HOME пользователя (работает для sudo и обычного запуска)
if [ -n "$SUDO_USER" ]; then if [ -n "$SUDO_USER" ]; then
REAL_HOME=$(getent passwd "$SUDO_USER" | cut -d: -f6) REAL_HOME=$(getent passwd "$SUDO_USER" | cut -d: -f6)
export HOME="$REAL_HOME" export HOME="$REAL_HOME"
echo "⚠️ Обнаружен sudo, использую домашнюю директорию пользователя: $HOME" elif [ -z "$HOME" ] || [ "$HOME" = "/root" ]; then
# Если HOME не установлен или это root, пытаемся найти реального пользователя
REAL_USER=$(whoami)
if [ "$REAL_USER" != "root" ]; then
export HOME=$(getent passwd "$REAL_USER" | cut -d: -f6)
fi
fi fi
echo "Получение cookies YouTube из Firefox..." # Проверка для cron: если запущен без терминала, меньше вывода
echo "Файл cookies будет сохранен в: $COOKIES_FILE" if [ -t 0 ]; then
VERBOSE=1
else
VERBOSE=0
fi
if [ "$VERBOSE" = "1" ]; then
echo "Получение cookies YouTube из Firefox..."
echo "Файл cookies будет сохранен в: $COOKIES_FILE"
fi
# Проверяем наличие yt-dlp # Проверяем наличие yt-dlp
if ! command -v yt-dlp &> /dev/null; then if ! command -v yt-dlp &> /dev/null; then
echo "" echo "ERROR: yt-dlp не найден в системе" >&2
echo "❌ yt-dlp не найден в системе" echo "Установите: sudo apt install yt-dlp (Ubuntu) или pip install yt-dlp" >&2
echo ""
echo "Установите yt-dlp одним из способов:"
echo ""
echo "1. Через pacman (Arch Linux):"
echo " sudo pacman -S yt-dlp"
echo ""
echo "2. Через pip:"
echo " pip install yt-dlp"
echo " или"
echo " pip3 install yt-dlp"
echo ""
echo "3. Через pipx (рекомендуется):"
echo " pipx install yt-dlp"
echo ""
exit 1 exit 1
fi fi
echo "Получаю cookies..." if [ "$VERBOSE" = "1" ]; then
echo "Получаю cookies..."
fi
# Используем простой способ: извлекаем cookies из браузера и сохраняем в файл # Удаляем старый временный файл
# Используем конкретное короткое видео (не плейлист, не главную страницу) rm -f "$TEMP_FILE"
# Таймаут 10 секунд
# Извлекаем cookies из браузера и сохраняем во временный файл
# Используем главную страницу YouTube для получения всех необходимых куков
# --no-download - не скачивать видео # --no-download - не скачивать видео
# --skip-download - пропустить скачивание # --skip-download - пропустить скачивание
# --flat-playlist - не извлекать информацию о видео в плейлистах if [ "$VERBOSE" = "1" ]; then
# Перенаправляем весь вывод, чтобы не видеть процесс скачивания yt-dlp \
timeout 10 yt-dlp \
--cookies-from-browser "$BROWSER" \ --cookies-from-browser "$BROWSER" \
--cookies "$COOKIES_FILE" \ --cookies "$TEMP_FILE" \
--no-download \
--skip-download \
"https://www.youtube.com" > /dev/null 2>&1
else
yt-dlp \
--cookies-from-browser "$BROWSER" \
--cookies "$TEMP_FILE" \
--no-download \ --no-download \
--skip-download \ --skip-download \
--flat-playlist \
--quiet \ --quiet \
"https://www.youtube.com/watch?v=jNQXAC9IVRw" > /dev/null 2>&1 || true "https://www.youtube.com" > /dev/null 2>&1
fi
EXIT_CODE=$? EXIT_CODE=$?
# Не важно, какой код возврата - главное проверить, создался ли файл cookies # Функция проверки валидности куков
# yt-dlp может вернуть ошибку, но cookies все равно сохранить check_cookies() {
local file="$1"
local current_time=$(date +%s)
# Проверяем существование файла
if [ ! -f "$file" ]; then
return 1
fi
if [ -f "$COOKIES_FILE" ]; then
# Проверяем, что файл содержит данные (не только заголовки) # Проверяем, что файл содержит данные (не только заголовки)
COOKIE_LINES=$(grep -v '^#' "$COOKIES_FILE" | grep -v '^$' | wc -l) local cookie_lines=$(grep -v '^#' "$file" | grep -v '^$' | wc -l)
if [ "$cookie_lines" -eq 0 ]; then
return 1
fi
if [ "$COOKIE_LINES" -gt 0 ]; then # Проверяем наличие YouTube-куков
local youtube_cookies=$(grep -E '\.youtube\.com|youtube\.com' "$file" | grep -v '^#' | wc -l)
if [ "$youtube_cookies" -eq 0 ]; then
return 1
fi
# Проверяем срок действия куков (должен быть хотя бы один не просроченный)
local valid_cookies=0
local expired_cookies=0
# Используем awk для более надежного парсинга
while IFS=$'\t' read -r domain flag path secure expiration name value; do
# Пропускаем комментарии и пустые строки
[[ "$domain" =~ ^#.*$ ]] && continue
[[ -z "$domain" ]] && continue
# Проверяем только YouTube-куки
if [[ "$domain" =~ youtube\.com ]]; then
if [ "$expiration" = "0" ] || [ -z "$expiration" ]; then
# Сессионные куки (expiration=0) считаем валидными
valid_cookies=$((valid_cookies + 1))
else
# Проверяем срок действия
if [ "$expiration" -gt "$current_time" ] 2>/dev/null; then
valid_cookies=$((valid_cookies + 1))
else
expired_cookies=$((expired_cookies + 1))
fi
fi
fi
done < "$file"
# Должен быть хотя бы один валидный YouTube-куки
if [ "$valid_cookies" -eq 0 ]; then
return 1
fi
# Если есть просроченные куки, выводим предупреждение, но не считаем критичным
if [ "$expired_cookies" -gt 0 ] && [ "$VERBOSE" = "1" ]; then
echo "⚠️ Предупреждение: найдено $expired_cookies просроченных YouTube-куков" >&2
fi
return 0
}
# Проверяем результат
if [ -f "$TEMP_FILE" ] && check_cookies "$TEMP_FILE"; then
# Куки валидны, переносим во временный файл в финальный
mv "$TEMP_FILE" "$COOKIES_FILE"
# Собираем статистику для вывода
COOKIE_LINES=$(grep -v '^#' "$COOKIES_FILE" | grep -v '^$' | wc -l)
YOUTUBE_COOKIES=$(grep -E '\.youtube\.com|youtube\.com' "$COOKIES_FILE" | grep -v '^#' | wc -l)
IMPORTANT_COOKIES=$(grep -E 'VISITOR_INFO1_LIVE|__Secure-3PSID|PREF|__Secure-YNID' "$COOKIES_FILE" | grep -v '^#' | wc -l)
if [ "$VERBOSE" = "1" ]; then
echo "" echo ""
echo "✅ Cookies успешно сохранены в $COOKIES_FILE" echo "✅ Cookies успешно сохранены в $COOKIES_FILE"
echo " Найдено строк с cookies: $COOKIE_LINES" echo " Всего строк с cookies: $COOKIE_LINES"
echo " YouTube-куков: $YOUTUBE_COOKIES"
echo " Важных куков: $IMPORTANT_COOKIES"
echo "" echo ""
echo "Теперь перезапустите youtube-downloader:" echo "Файл готов к копированию на серверы через cron"
echo " docker compose -f youtube-downloader/docker-compose.yml restart"
echo ""
echo "Или перезапустите все сервисы:"
echo " ./stop_all.sh && ./start_all.sh"
else else
echo "" # Минимальный вывод для cron (можно логировать в файл)
echo "❌ Ошибка: файл cookies создан, но не содержит данных" echo "$(date '+%Y-%m-%d %H:%M:%S') - YouTube cookies updated: $YOUTUBE_COOKIES cookies, $IMPORTANT_COOKIES important"
rm -f "$COOKIES_FILE"
exit 1
fi fi
exit 0
else else
# Очищаем временный файл при ошибке
rm -f "$TEMP_FILE"
if [ "$VERBOSE" = "1" ]; then
echo ""
echo "❌ Ошибка: не удалось получить валидные YouTube-куки"
echo ""
echo "Возможные причины:"
echo "1. В Firefox нет куков для YouTube"
echo "2. Откройте YouTube в Firefox и войдите в аккаунт"
echo "3. Все куки просрочены - обновите их в браузере"
echo ""
else
echo "$(date '+%Y-%m-%d %H:%M:%S') - ERROR: Failed to get valid YouTube cookies" >&2
fi
if [ ! -f "$COOKIES_FILE" ]; then
# Если файла не было, это критичная ошибка
exit 1
else
# Если файл был, просто оставляем старый (лучше работать со старыми куками чем без них)
if [ "$VERBOSE" = "1" ]; then
echo "⚠️ Оставляю существующий файл cookies без изменений"
fi
exit 0
fi
fi
if [ ! -f "$TEMP_FILE" ] && [ ! -f "$COOKIES_FILE" ]; then
if [ "$VERBOSE" = "1" ]; then
echo "" echo ""
echo "❌ Ошибка: файл cookies не был создан" echo "❌ Ошибка: файл cookies не был создан"
echo "" echo ""
@ -89,18 +194,25 @@ else
echo "3. Cookies не найдены в браузере" echo "3. Cookies не найдены в браузере"
echo "" echo ""
echo "Проверка:" echo "Проверка:"
if [ -n "$SUDO_USER" ]; then
REAL_HOME=$(getent passwd "$SUDO_USER" | cut -d: -f6)
FIREFOX_DIR="$REAL_HOME/.mozilla/firefox"
else
FIREFOX_DIR="$HOME/.mozilla/firefox" FIREFOX_DIR="$HOME/.mozilla/firefox"
fi
if [ -d "$FIREFOX_DIR" ]; then if [ -d "$FIREFOX_DIR" ]; then
echo " ✓ Директория Firefox найдена: $FIREFOX_DIR" echo " ✓ Директория Firefox найдена: $FIREFOX_DIR"
else else
echo " ✗ Директория Firefox не найдена: $FIREFOX_DIR" echo " ✗ Директория Firefox не найдена: $FIREFOX_DIR"
echo " Попробуйте запустить скрипт БЕЗ sudo: ./get_youtube_cookies.sh" echo " Убедитесь что Firefox установлен и вы авторизованы на YouTube"
fi fi
else
echo "$(date '+%Y-%m-%d %H:%M:%S') - ERROR: Cookies file was not created" >&2
fi
# Если был старый файл, оставляем его
if [ -f "$COOKIES_FILE" ]; then
if [ "$VERBOSE" = "1" ]; then
echo "⚠️ Оставляю существующий файл cookies без изменений"
fi
exit 0
else
exit 1 exit 1
fi
fi fi