Как настроить код на Replit

Как настроить код на Replit

Рассмотрим как пример код для выгрузки субтитров и скачивания видео с YouTube.

1. Переходим на https://replit.com и регистрируемся.

2. Далее в главном меню нажимаем Create app

3. Выбираем Choose a Template

4. Находим Python

5. Называем и нажимаем Create App

6. У вас должно появиться окно с файлом main.py

7. На этой же странице создаем папку requirements.txt

и вписываем туда эти строки для полноценной работы кода:

google-api-python-client
google-auth-httplib2
google-auth-oauthlib
Flask
requests
pydub
browser-cookie3
yt-dlp

8. Далее создаем файл replit.nix

и туда вписываем этот код:
{ pkgs }: {
 deps = [
   pkgs.ffmpeg-full
   pkgs.python311Full
   pkgs.ffmpeg
 ];
}

9. После создаем папку cookies.txt, куда мы сложим наши cookies из браузера для обхода спам защиты YouTube.

Для получения cookies:

  • Скачиваем расширение в Google
  • После этого заходим на YouTube и открываем скачанное расширение

10. Нажимаем Export All Cookies и содержимое скачанного файла копируем в папку cookies.txt, которую мы создали ранее на replit

11. После идём обратно в main.py и вставляем наш код

1import os
2import re
3import urllib.parse
4import glob
5
6from flask import Flask, request, send_file
7import yt_dlp
8
9app = Flask(__name__)
10app.url_map.strict_slashes = False
11
12# ===== CONFIGURATION =====
13WEBHOOK_SECRET = "s3cr3t-k3y-123"  # Замените на свой реальный секрет
14
15
16# ===== VIDEO ID EXTRACTION =====
17def extract_video_id(url_or_id):
18    """
19    Извлекает ID YouTube-видео из ссылки (включая youtu.be, youtube.com).
20    Если входная строка не URL, а просто ID, возвращает как есть.
21    """
22    if not url_or_id.startswith("http"):
23        return url_or_id
24
25    parsed = urllib.parse.urlparse(url_or_id)
26    if parsed.hostname == "youtu.be":
27        # Пример: https://youtu.be/ABCD
28        return parsed.path.lstrip("/")
29    if parsed.hostname in ["www.youtube.com", "youtube.com"]:
30        qs = urllib.parse.parse_qs(parsed.query)
31        if "v" in qs:
32            return qs["v"][0]
33        path = parsed.path.split("/")
34        if "embed" in path or "v" in path:
35            return path[-1]
36    # Если логика не сработала, возвращаем исходную строку
37    return url_or_id
38
39
40# ===== SUBTITLE PROCESSING (CLEANING) =====
41def clean_subtitle_content(content):
42    """
43    Очищает текст субтитров (WebVTT/SRT) от таймкодов, тегов, лишних пробелов и т.д.
44    Возвращает конечную строку.
45    """
46    # 1) Удаляем WEBVTT заголовок
47    cleaned = re.sub(r'WEBVTT.*?\n\n', '', content, flags=re.DOTALL | re.IGNORECASE)
48    # 2) Удаляем таймкоды (00:00:00.000 --> 00:00:05.000 и т.д.)
49    cleaned = re.sub(r'\d{2}:\d{2}:\d{2}\.\d{3}.*\n', '', cleaned)
50    # 3) Удаляем метки align:start position:% и тэги <...>
51    cleaned = re.sub(r'align:start position:\d+%', '', cleaned, flags=re.IGNORECASE)
52    cleaned = re.sub(r'<[^>]+>', ' ', cleaned)
53
54    lines = []
55    last_line = ''
56    for line in cleaned.split('\n'):
57        line = line.strip()
58        if not line:
59            continue
60
61        # Удаляем лишние пробелы перед пунктуацией и двойные пробелы
62        line = re.sub(r'\s+([,.!?])', r'\1', line)
63        line = re.sub(r'\s*-\s*', '-', line)
64        line = re.sub(r'\s{2,}', ' ', line)
65
66        # Убираем повторяющиеся строки
67        if line not in last_line:
68            lines.append(line)
69            last_line = line
70
71    final_text = ' '.join(lines)
72    return final_text.strip()
73
74
75# ===== SUBTITLE DOWNLOAD =====
76def download_subtitles(video_id):
77    """
78    Пытается скачать субтитры (англ/рус) для данного video_id.
79    Возвращает путь к субтитрам или None, если нет субтитров.
80    """
81    url = f"https://www.youtube.com/watch?v={video_id}"
82    ydl_opts = {
83        'writesubtitles': True,
84        'writeautomaticsub': True,
85        'subtitleslangs': ['en', 'ru'],  # приоритетные языки
86        'skip_download': True,
87        'outtmpl': f"{video_id}",
88        'quiet': True,
89    }
90
91    try:
92        with yt_dlp.YoutubeDL(ydl_opts) as ydl:
93            ydl.download([url])
94    except yt_dlp.utils.DownloadError as e:
95        if 'No subtitles found' in str(e):
96            return None
97        raise
98
99    # Ищем субтитры .vtt или .srt
100    subtitle_files = glob.glob(f"{video_id}.*.vtt") + glob.glob(f"{video_id}.*.srt")
101
102    # Смотрим сначала en, потом ru
103    for lang in ['en', 'ru']:
104        for sub_file in subtitle_files:
105            if f'.{lang}.' in sub_file:
106                return sub_file
107    return None
108
109
110# ===== AUDIO DOWNLOAD =====
111def download_audio_file(video_id):
112    """
113    Скачивает YouTube audio (bestaudio) и конвертирует в mp3.
114    Возвращает путь к mp3-файлу.
115    """
116    url = f"https://www.youtube.com/watch?v={video_id}"
117    ydl_opts = {
118        'format': 'bestaudio/best',
119        'outtmpl': f"{video_id}.%(ext)s",
120        'postprocessors': [{
121            'key': 'FFmpegExtractAudio',
122            'preferredcodec': 'mp3',
123            'preferredquality': '192',
124        }],
125        'quiet': True,
126    }
127
128    with yt_dlp.YoutubeDL(ydl_opts) as ydl:
129        ydl.download([url])
130
131    return f"{video_id}.mp3"
132
133
134# ===== FLASK APP =====
135@app.route('/audio', methods=['POST'])
136def handle_audio():
137    """
138    Принимает JSON: { "video_url": "https://youtube.com/watch?v=..." }
139    1. Проверяет заголовок X-API-Key
140    2. Извлекает video_id из ссылки
141    3. Пытается скачать субтитры -> возвращает текст, иначе скачивает mp3 -> возвращает файл.
142    """
143    # Проверяем ключ
144    if request.headers.get('X-API-Key') != WEBHOOK_SECRET:
145        return "Unauthorized", 401
146
147    # Парсим тело запроса
148    try:
149        data = request.get_json(force=True)
150        video_url = data.get('video_url', '')
151        if not video_url:
152            return "Missing 'video_url'", 400
153    except Exception as e:
154        return f"Invalid request: {str(e)}", 400
155
156    # Извлекаем ID из ссылки
157    try:
158        video_id = extract_video_id(video_url)
159
160        # Пытаемся скачать субтитры
161        subtitle_path = download_subtitles(video_id)
162        if subtitle_path:
163            with open(subtitle_path, 'r', encoding='utf-8') as f:
164                raw_content = f.read()
165            cleaned = clean_subtitle_content(raw_content)
166            return cleaned, 200, {'Content-Type': 'text/plain'}
167
168        # Иначе качаем аудио
169        audio_path = download_audio_file(video_id)
170        if not os.path.exists(audio_path):
171            return "Audio generation failed", 500
172
173        return send_file(audio_path, as_attachment=True, mimetype='audio/mpeg')
174
175    except Exception as e:
176        return f"Processing error: {str(e)}", 500
177
178
179@app.route('/')
180def home():
181    return "YouTube Content Server - POST to /audio with JSON {video_url}", 200
182
183
184if __name__ == '__main__':
185    # Просто запускаем Flask, без keep-alive
186    port = int(os.environ.get("PORT", 8080))
187    app.run(host='0.0.0.0', port=port, debug=False)

12. Запускаем приложение и ждём следующую страницу:

13. Далее копируем ссылку на наше приложение и в конце url ссылки добавляем слово /audio

Должно получиться вот так: https://adf50a07-ff24-48e6-bb14-5e1d16af97b2-00-1mxttap45ya2u.riker.replit.dev/audio


Готово. Теперь на эту ссылку можно отправлять http запросы с n8n.


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

Эта функция доступна только через платную подписку.