Рефакторинг: микросервисная архитектура

- Разделение на микросервисы: youtube-downloader, instagram-downloader, vk-downloader
- Основной бот в корне проекта, работает через HTTP API с сервисами
- Каждый сервис запускается отдельно в своей папке
- Видео сохраняются в папке video/ и не удаляются
- Обновлена документация и архитектура
- Скрипты для Instagram cookies перенесены в instagram-downloader/
This commit is contained in:
vrubelroman 2025-12-11 01:07:04 +03:00
parent 8024eea868
commit 436e0cd541
41 changed files with 1348 additions and 693 deletions

View file

@ -0,0 +1,24 @@
FROM python:3.11-slim
# Устанавливаем зависимости для yt-dlp
RUN apt-get update && apt-get install -y \
ffmpeg \
wget \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Копируем requirements и устанавливаем зависимости
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Копируем код приложения
COPY . .
# Создаем директорию для загрузок
RUN mkdir -p downloads
ENV PYTHONUNBUFFERED=1
CMD ["python", "app.py"]

View file

@ -0,0 +1,51 @@
# Инструкция по получению cookies для Instagram
## Вариант 1: Использование расширения браузера (рекомендуется)
1. Установите расширение для экспорта cookies:
- Chrome: [Get cookies.txt LOCALLY](https://chrome.google.com/webstore/detail/get-cookiestxt-locally/cclelndahbckbenkjhflpdbgdldlbecc)
- Firefox: [cookies.txt](https://addons.mozilla.org/en-US/firefox/addon/cookies-txt/)
2. Откройте Instagram и войдите в свой аккаунт: https://www.instagram.com
3. Кликните на расширение и выберите "Export cookies.txt"
4. Сохраните файл как `instagram_cookies.txt` в корень проекта (там же, где docker-compose.yml)
## Вариант 2: Ручной экспорт через DevTools
1. Откройте Instagram в браузере и войдите: https://www.instagram.com
2. Откройте DevTools (F12) → вкладка Application/Storage → Cookies → https://www.instagram.com
3. Скопируйте нужные cookies в формате Netscape:
```
# Netscape HTTP Cookie File
.instagram.com TRUE / FALSE 1735689600 sessionid YOUR_SESSION_ID
.instagram.com TRUE / FALSE 1735689600 csrftoken YOUR_CSRF_TOKEN
```
4. Сохраните в файл `instagram_cookies.txt`
## Вариант 3: Использование yt-dlp для экспорта
```bash
# Экспорт cookies из браузера Chrome
yt-dlp --cookies-from-browser chrome --cookies instagram_cookies.txt https://www.instagram.com
# Или из Firefox
yt-dlp --cookies-from-browser firefox --cookies instagram_cookies.txt https://www.instagram.com
```
## Важно!
- Файл должен называться `instagram_cookies.txt`
- Разместите его в корне проекта (рядом с docker-compose.yml)
- Cookies имеют срок действия - возможно, потребуется обновлять их периодически
- Не коммитьте файл в git (он уже добавлен в .gitignore)
После добавления файла перезапустите контейнер:
```bash
docker compose restart bot
```

View file

@ -0,0 +1,144 @@
# Instagram Downloader Service
Микросервис для скачивания видео с Instagram.
## Требования
- Docker и Docker Compose
- Файл с cookies Instagram (`instagram_cookies.txt` в папке `instagram-downloader/`)
## Быстрый старт
### 1. Настройка cookies
Перед запуском сервиса необходимо получить cookies Instagram. Есть несколько способов:
#### Способ 1: Через скрипт (рекомендуется)
```bash
cd instagram-downloader
./get_instagram_cookies.sh
```
Скрипт попросит выбрать браузер и автоматически извлечет cookies.
#### Способ 2: Обновление существующих cookies
```bash
cd instagram-downloader
./update_instagram_cookies.sh
```
#### Способ 3: Вручную
См. подробные инструкции в `INSTAGRAM_COOKIES_INSTRUCTIONS.md`
### 2. Запуск сервиса
#### Вариант 1: Через корневой docker-compose (рекомендуется)
```bash
cd .. # вернуться в корень проекта
docker compose up -d instagram-downloader
```
#### Вариант 2: Отдельно
```bash
docker compose up -d
```
### 3. Проверка работы
```bash
# Проверка здоровья сервиса
curl http://localhost:5556/health
# Должен вернуть: {"status":"ok","service":"instagram-downloader"}
```
## API Endpoints
### GET /health
Проверка здоровья сервиса.
**Ответ:**
```json
{
"status": "ok",
"service": "instagram-downloader"
}
```
### POST /download/stream
Скачивание видео с Instagram.
**Запрос:**
```json
{
"url": "https://www.instagram.com/p/..."
}
```
**Ответ:**
- Успех: бинарные данные видео (Content-Type: video/mp4)
- Ошибка: JSON с описанием ошибки
## Порты
- Внешний порт: **5556**
- Внутренний порт контейнера: **5000**
## Обновление cookies
Cookies Instagram имеют ограниченный срок действия. Рекомендуется обновлять их раз в несколько недель.
Для обновления:
```bash
cd instagram-downloader
./update_instagram_cookies.sh
```
После обновления перезапустите сервис:
```bash
docker compose restart instagram-downloader
```
## Troubleshooting
### Сервис не может скачать видео
1. Проверьте наличие файла `instagram_cookies.txt` в папке `instagram-downloader/`
2. Проверьте срок действия cookies (они могут истечь)
3. Обновите cookies через скрипт `update_instagram_cookies.sh`
4. Проверьте логи: `docker compose logs instagram-downloader`
### Cookies истекли
Если видите ошибку "Instagram cookies истекли", выполните:
```bash
cd instagram-downloader
./update_instagram_cookies.sh
```
Затем перезапустите сервис.
## Структура файлов
```
instagram-downloader/
├── app.py # Основной код сервиса
├── Dockerfile # Образ Docker
├── docker-compose.yml # Конфигурация для отдельного запуска
├── requirements.txt # Python зависимости
├── get_instagram_cookies.sh # Скрипт для получения cookies
├── update_instagram_cookies.sh # Скрипт для обновления cookies
├── INSTAGRAM_COOKIES_INSTRUCTIONS.md # Подробные инструкции по cookies
└── README.md # Этот файл
```

244
instagram-downloader/app.py Normal file
View file

@ -0,0 +1,244 @@
"""
Instagram Video Downloader Service
Отдельный микросервис для скачивания видео с Instagram
"""
import os
import logging
import time
from pathlib import Path
from flask import Flask, request, jsonify
from flask_cors import CORS
import yt_dlp
import uuid
import re
# Настройка логирования
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO
)
logger = logging.getLogger(__name__)
app = Flask(__name__)
CORS(app) # Разрешаем CORS для взаимодействия с основным ботом
# Директория для временных файлов
DOWNLOADS_DIR = Path('downloads')
DOWNLOADS_DIR.mkdir(exist_ok=True)
def check_instagram_cookies_expiry() -> tuple[bool, int]:
"""
Проверяет срок действия Instagram cookies
Returns: (is_valid, days_until_expiry)
"""
cookies_file = os.getenv('INSTAGRAM_COOKIES_FILE', 'instagram_cookies.txt')
cookies_file_path = Path(cookies_file)
if not cookies_file_path.exists():
return False, 0
try:
current_time = time.time()
valid_expiries = []
# Важные cookies для Instagram (проверяем их в первую очередь)
important_cookies = ['sessionid', 'csrftoken', 'ds_user_id']
with open(cookies_file_path, 'r') as f:
for line in f:
line = line.strip()
if not line or line.startswith('#'):
continue
parts = line.split('\t')
if len(parts) >= 7:
domain = parts[0]
if 'instagram' in domain.lower():
try:
expiry = int(parts[4]) # Unix timestamp
cookie_name = parts[5] if len(parts) > 5 else ''
# Игнорируем невалидные expiry (0, отрицательные, или слишком старые)
# Session cookies (expiry = 0) также игнорируем для проверки срока
if expiry > 0 and expiry > 946684800: # Фильтр: после 2000-01-01 (избегаем epoch 0)
# Для важных cookies проверяем строже
if cookie_name in important_cookies:
if expiry > current_time:
valid_expiries.append(expiry)
else:
valid_expiries.append(expiry)
except (ValueError, IndexError):
continue
if not valid_expiries:
logger.warning("Не найдено валидных Instagram cookies с нормальным сроком действия")
# Если нет валидных expiry, но есть cookies - считаем их действительными
# (возможно, это session cookies)
return True, 30 # Возвращаем разумное значение по умолчанию
# Берем минимальный валидный expiry
min_expiry = min(valid_expiries)
days_until_expiry = (min_expiry - current_time) / 86400
is_valid = min_expiry > current_time
return is_valid, int(days_until_expiry)
except Exception as e:
logger.error(f"Ошибка при проверке срока действия cookies: {e}")
# В случае ошибки считаем cookies действительными (не блокируем работу)
return True, 30
def download_instagram_video(url: str, max_retries: int = 3) -> Path:
"""Скачивает видео с Instagram - используем cookies с правильными заголовками"""
cookies_file = os.getenv('INSTAGRAM_COOKIES_FILE', 'instagram_cookies.txt')
cookies_file_path = Path(cookies_file)
# Проверяем срок действия cookies перед использованием
if cookies_file_path.exists():
is_valid, days_left = check_instagram_cookies_expiry()
if not is_valid:
logger.error("Instagram cookies истекли! Необходимо обновить cookies.")
raise Exception("Instagram cookies истекли. Пожалуйста, обновите cookies в файле instagram_cookies.txt")
elif days_left < 7:
logger.warning(f"Instagram cookies истекают через {days_left} дней. Рекомендуется обновить.")
# Парсим cookies для получения csrf token (формат Netscape)
csrf_token = None
sessionid = None
if cookies_file_path.exists():
try:
with open(cookies_file_path, 'r') as f:
for line in f:
line = line.strip()
if not line or line.startswith('#'):
continue
parts = line.split('\t')
if len(parts) >= 7:
domain = parts[0]
# Ищем только cookies от instagram.com
if 'instagram' in domain.lower():
cookie_name = parts[5] # Имя cookie
cookie_value = parts[6] # Значение cookie
if cookie_name == 'csrftoken':
csrf_token = cookie_value
elif cookie_name == 'sessionid':
sessionid = cookie_value
# Если нашли оба - можно выходить
if csrf_token and sessionid:
break
except Exception as e:
logger.warning(f"Не удалось прочитать cookies: {e}")
last_error = None
for attempt in range(max_retries):
try:
# Базовые настройки
ydl_opts = {
'format': 'best',
'outtmpl': str(DOWNLOADS_DIR / f'{uuid.uuid4()}_%(title)s.%(ext)s'),
'quiet': False,
'no_warnings': False,
'socket_timeout': 30,
}
# Если есть файл с cookies, используем его
if cookies_file_path.exists():
# Используем абсолютный путь к cookies
ydl_opts['cookiefile'] = str(cookies_file_path.absolute())
logger.info(f"Instagram: используем cookies из {cookies_file_path}")
# Добавляем заголовки с csrf token если есть
headers = {
'Referer': 'https://www.instagram.com/',
'X-Requested-With': 'XMLHttpRequest',
}
if csrf_token:
headers['X-CSRFToken'] = csrf_token
logger.info(f"Instagram: добавлен csrf token в заголовки")
if sessionid:
logger.info(f"Instagram: sessionid найден (длина: {len(sessionid)})")
ydl_opts['http_headers'] = headers
logger.info(f"Instagram: начинаем скачивание (попытка {attempt + 1}/{max_retries})")
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
ydl.download([url])
# Находим скачанный файл
downloaded_files = list(DOWNLOADS_DIR.glob('*'))
if downloaded_files:
downloaded_files.sort(key=lambda x: x.stat().st_mtime, reverse=True)
return downloaded_files[0]
else:
raise Exception("Файл не был найден после скачивания")
except Exception as e:
last_error = e
logger.warning(f"Instagram: попытка {attempt + 1}/{max_retries} не удалась: {e}")
if attempt < max_retries - 1:
time.sleep((attempt + 1) * 2)
raise last_error or Exception("Неизвестная ошибка при скачивании с Instagram. Возможно, нужно обновить cookies.")
@app.route('/health', methods=['GET'])
def health():
"""Health check endpoint"""
return jsonify({'status': 'ok', 'service': 'instagram-downloader'}), 200
@app.route('/download/stream', methods=['POST'])
def download_stream():
"""Скачивает видео с Instagram и возвращает бинарные данные"""
try:
data = request.get_json()
if not data or 'url' not in data:
return jsonify({'error': 'URL is required'}), 400
url = data['url']
logger.info(f"Получен запрос на скачивание (stream): {url}")
# Проверяем, что это Instagram URL
if 'instagram.com' not in url:
return jsonify({'error': 'Only Instagram URLs are supported'}), 400
# Скачиваем видео
video_path = download_instagram_video(url)
logger.info(f"Видео скачано: {video_path}")
# Читаем файл и отправляем
with open(video_path, 'rb') as f:
video_data = f.read()
# Безопасное имя файла без кириллицы для заголовка
safe_filename = video_path.name.encode('ascii', 'ignore').decode('ascii') or 'instagram_video.mp4'
if not safe_filename.endswith(('.mp4', '.webm', '.mkv')):
safe_filename = 'instagram_video.mp4'
# Определяем content-type
content_type = 'video/mp4'
if video_path.suffix == '.webm':
content_type = 'video/webm'
elif video_path.suffix == '.mkv':
content_type = 'video/x-matroska'
# Удаляем временный файл
video_path.unlink()
return video_data, 200, {
'Content-Type': content_type,
'Content-Disposition': f'attachment; filename="{safe_filename}"'
}
except Exception as e:
logger.error(f"Ошибка при скачивании: {e}")
return jsonify({'error': str(e)}), 500
if __name__ == '__main__':
port = int(os.getenv('PORT', 5000)) # Внутренний порт контейнера
host = os.getenv('HOST', '0.0.0.0')
logger.info(f"Запуск Instagram Downloader сервиса на {host}:{port}")
app.run(host=host, port=port, debug=False)

View file

@ -0,0 +1,19 @@
services:
instagram-downloader:
build: .
container_name: instagram_downloader_service
restart: unless-stopped
ports:
- "5556:5000"
volumes:
- ./downloads:/app/downloads
- ./instagram_cookies.txt:/app/instagram_cookies.txt
environment:
- INSTAGRAM_COOKIES_FILE=/app/instagram_cookies.txt
networks:
- downloader_network
networks:
downloader_network:
driver: bridge

View file

@ -0,0 +1,39 @@
#!/bin/bash
# Скрипт для получения cookies Instagram через yt-dlp
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
COOKIES_FILE="$SCRIPT_DIR/instagram_cookies.txt"
echo "Получение cookies Instagram из браузера..."
echo ""
echo "Выберите браузер:"
echo "1) Chrome"
echo "2) Firefox"
echo "3) Edge"
echo "4) Opera"
read -p "Введите номер (1-4): " browser
case "$browser" in
1) BROWSER="chrome" ;;
2) BROWSER="firefox" ;;
3) BROWSER="edge" ;;
4) BROWSER="opera" ;;
*)
echo "Неверный выбор"
exit 1
;;
esac
echo "Получаю cookies из $BROWSER..."
echo "Файл cookies будет сохранен в: $COOKIES_FILE"
yt-dlp --cookies-from-browser "$BROWSER" --cookies "$COOKIES_FILE" --no-download https://www.instagram.com 2>&1 | head -10
if [ -f "$COOKIES_FILE" ]; then
echo ""
echo "✅ Cookies успешно сохранены в $COOKIES_FILE"
else
echo ""
echo "❌ Ошибка: файл cookies не был создан"
exit 1
fi

View file

@ -0,0 +1,54 @@
# Netscape HTTP Cookie File
# This file is generated by yt-dlp. Do not edit.
sex-studentki.live FALSE / FALSE 1799795429 dsktp 1
.google.com TRUE /verify TRUE 1781176458 SNID AHDpxKl-HzEypOr4GSfdEy3Rf1Un1geVql0CkkCaYJcf1jzyzW7ZezW5tOlvdqxZEsUH5PMzKYd_ACcrRGNC5a_KXuKigoI_Cp0
.google.com TRUE / TRUE 1780606020 AEC AaJma5tB_95c_KhJP2ag7WROEJrAhqdmimJLX-s3lYvR3IEMHOKcT4YUew
.google.com TRUE / TRUE 1781176458 NID 527=tY3ICSwLUik21IyiJoAv-a_TmvT6O9ZXnDYkos3d-iHqXVfVTxy3odzqutzJgumgn4CqO5_KN2vTzoO27oGDkF6zdXzaRZE9mCYOv7yWGUYH-I75LIh54166K7GLxddCHRTLpspg0ziFfb4lpjLhaR33Talj5r6ePziZo0HiLfNAaWW5byMUt2pezCZ6PVdZc-vcRAaRvJ4v2f9dpkvtJapx545F7drcTVVJHEHCpczywJWL3LKIojJyTwxlvUrncpdrHkXtkPLCmHMe4VdJNRyYxXWo-Yu0zk78iZF_ZtbLOdcWlKGTfsQhix4cTlCFLg
.google.com TRUE / TRUE 1799493258 SOCS CAISHAgCEhJnd3NfMjAyNTEyMDgtMF9SQzEaAnJ1IAEaBgiA8OLJBg
.google.com TRUE / TRUE 1780917258 __Secure-BUCKET CMQF
fedoraproject.org FALSE / FALSE 1796590014 i18n_redirected en
.yandex.ru TRUE / TRUE 1799614022 _yasc eenvGJraNnYujygdnBiB9YPpKPAf6Xjx2AdH9mkumzqXV0cUGDvoAkCsSmYNQQ==
.yandex.ru TRUE / TRUE 1799614022 i vstmxWXJC2wTFbgn/8Qp9aG/T0Yx+f5d8D425ZNul7oGf618maEaEFN1EKSNbyKAawFArBqk8+ZJ/C8Npc/Vr0I37uk=
.yandex.ru TRUE / TRUE 1799614022 yandexuid 6686312051765054022
.yandex.ru TRUE / TRUE 1796590022 yashr 2803630921765054022
.yandex.ru TRUE / TRUE 1799614022 bh YMas0skGahLcyumIDvKso64Ek6ryjgPk7QM=
.yandex.ru TRUE / TRUE 1799614022 yuidss 6686312051765054022
.yandex.ru TRUE / TRUE 1796590022 ymex 2080414022.yrts.1765054022
.yandex.ru TRUE / FALSE 1796590022 _ym_uid 1765054023498106798
.yandex.ru TRUE / FALSE 1796590022 _ym_d 1765054023
.sex-studentki.live TRUE / FALSE 1796771251 _ym_uid 1765235251587699867
.sex-studentki.live TRUE / FALSE 1796771251 _ym_d 1765235251
rusoska.com FALSE / FALSE 1765840293 kt_tcookie 1
rusoska.com FALSE / FALSE 1799795493 userToken a01e24c3-c94f-4a4e-b11b-751b720464a2
2022welcome.com FALSE / TRUE 1796771466 cross_domain_profile_id 67cc114d-bb4e-409e-aeca-8054618c5d36
.bngtrak.com TRUE / FALSE 1799795466 BCH_H dfbd65996f6220b37a8af4d87387e0ef%7C2025-12-09
.bongacams.com TRUE / FALSE 1796771469 ts_type2 1
.bongacams.com TRUE / FALSE 1796771467 fv AmL0AGZlAGL3ZD==
.bongacams.com TRUE / FALSE 1796771467 uh AzIupGSfK3WfqIIhZHcjI2x4oHWmFN==
.bongacams.com TRUE / FALSE 1799795467 ratr 258550%3A%3A812783%3A%3A2025-12-09%2001%3A11%3A07%3A%3Ahttps%3A%2F%2Frusoska.com%2F%3A%3A1%3A%3A3362
.bongacams.com TRUE / TRUE 1799795467 BONGAH_HIT dfbd65996f6220b37a8af4d87387e0ef%3A%3A258550%3A%3Ahttps%3A%2F%2Frusoska.com%2F%3A%3A1%3A%3A3362%3A%3A812783%3A%3A%3A%3A%3A%3A0%3A%3A1%3A%3A1%3A%3A0%3A%3A%3A%3A0%3A%3Adefault%3A%3A0%3A%3A2025-12-09%2001%3A11%3A07
.bongacams.com TRUE / FALSE 1780787467 BONGA_REF https%3A%2F%2Frusoska.com%2F
.bongacams.com TRUE / FALSE 1796771467 reg_ver2 3
.bongacams.com TRUE / TRUE 1796771467 sg 451
.bongacams.com TRUE / TRUE 1796771467 warning18 %5B%22ru_RU%22%5D
.bongacams.com TRUE / FALSE 1796771467 n57eres1f 1814296592
.bongacams.com TRUE / FALSE 1799795475 _ga_R4LNDD9YJ3 GS2.1.s1765235469$o1$g0$t1765235475$j54$l0$h0
.bongacams.com TRUE / FALSE 1799795469 _ga GA1.1.410056998.1765235469
.bongacams.com TRUE / FALSE 1796771469 ls01 %7B%22th_type%22%3A%22live%22%2C%22display%22%3A%22medium%22%7D
.mozilla.org TRUE / FALSE 1799925684 _ga_B9CY1C9VBC GS2.1.s1765365263$o1$g1$t1765365684$j60$l0$h0
.mozilla.org TRUE / FALSE 1799925263 _ga GA1.2.1451822324.1765365263
.mozilla.org TRUE / FALSE 1765451663 _gid GA1.2.878207985.1765365263
.instagram.com TRUE / TRUE 1799964275 csrftoken CnChQ6nTz8cfm_U7q2ur9w
.instagram.com TRUE / TRUE 1799925292 datr LFY5aVDEvvzQRTypNm_NZ0d3
.instagram.com TRUE / TRUE 1796901312 ig_did B0879634-89D6-4098-9B3E-958B6BC00183
.instagram.com TRUE / TRUE 1765970112 dpr 2
.instagram.com TRUE / TRUE 1799925293 mid aTlWLAAEAAEBRoS_PfrA_i5UP0w1
.instagram.com TRUE / TRUE 1766008776 wd 1920x944
.instagram.com TRUE / TRUE 1796939890 sessionid 42059678244%3AD0GdfKmaFZWqXp%3A10%3AAYgpCODjycI3EWMR6G5Uh6kXjroGZ6pb1IRJmXGX3g
.instagram.com TRUE / TRUE 1773180275 ds_user_id 42059678244
.instagram.com TRUE / TRUE 0 rur "LDC\05442059678244\0541796940275:01fef3bd7d6beb547023be3c45c01ebfd5726050a4cced10a3a4af9ff39a731103df7c88"
addons.mozilla.org FALSE / TRUE 0 taarId 4dffa50e49cca797bb48f2f4f11803c251746ad45af1fef3ba1ad37379a24fea
.facebook.com TRUE / TRUE 1799963979 datr S-05aRMEAJEaLLwYCMb4y3JM
.facebook.com TRUE / TRUE 1766008781 wd 1920x944
.facebook.com TRUE / TRUE 1766008795 dpr 2

View file

@ -0,0 +1,4 @@
Flask==3.0.0
flask-cors==4.0.0
yt-dlp>=2024.12.13

View file

@ -0,0 +1,47 @@
#!/bin/bash
# Обновление cookies Instagram через браузер
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
COOKIES_FILE="$SCRIPT_DIR/instagram_cookies.txt"
echo "Обновление cookies Instagram..."
echo ""
echo "Выберите браузер:"
echo "1) Chrome"
echo "2) Firefox"
echo "3) Edge"
echo "4) Opera"
read -p "Введите номер (1-4): " browser
case "$browser" in
1) BROWSER="chrome" ;;
2) BROWSER="firefox" ;;
3) BROWSER="edge" ;;
4) BROWSER="opera" ;;
*)
echo "Неверный выбор"
exit 1
;;
esac
echo ""
echo "ВАЖНО: Перед обновлением cookies убедитесь, что вы авторизованы в Instagram в выбранном браузере!"
echo ""
read -p "Нажмите Enter для продолжения или Ctrl+C для отмены..."
echo "Обновляю cookies из $BROWSER..."
echo "Файл cookies будет сохранен в: $COOKIES_FILE"
yt-dlp --cookies-from-browser "$BROWSER" --cookies "$COOKIES_FILE" --no-download https://www.instagram.com 2>&1 | head -10
if [ -f "$COOKIES_FILE" ]; then
echo ""
echo "✅ Cookies успешно обновлены в $COOKIES_FILE"
echo ""
echo "Для применения изменений перезапустите instagram-downloader сервис:"
echo " cd $(cd "$SCRIPT_DIR/.." && pwd) && docker compose restart instagram-downloader"
else
echo ""
echo "❌ Ошибка: файл cookies не был создан"
exit 1
fi