Как за 6 промтов к ChatGPT создать Python скрипт, скачивающий видео с YouTube для просмотра на телевизоре через Kodi

от автора

Последние месяцы Ютуб работает с перебоями: через сеть мобильного оператора вроде работает, но при подключении к сети проводного интернет-провайдера чаще всего ничего посмотреть нельзя, хотя в новостях что-то промелькнуло насчёт возобновления работы, но лично у меня ничего не поменялось.

Я использую свободный медиацентр Kodi для просмотра своей коллекции фильмов и сериалов, создавая домашний кинотеатр без ежемесячной абонентской платы. Это достигается за счёт того, что все файлы уже хранятся на собственном сетевом хранилище с локальным доступом или записаны прямо в памяти Kodi, который может быть установлен практически на любой платформе.

Раньше на Kodi можно было напрямую отправить YouTube ссылку и посмотреть любое видео. С августа 2024 года этот вариант больше не работает. Короткие видео можно посмотреть с телефона, но вот длинные интервью или подкасты так смотреть или слушать неудобно. К тому же телевизором можно управлять через Алису — она подключена к Home Assistant.

Конечно, чтобы скачать видео с Ютуба существует множество программ, но скачивается только сам видео файл и он будет отображаться в базе Kodi без обложки и описания. Вручную создавать обложку и описание и тратить на это своё время не вариант — зачем?

Разбираюсь как за 6 промтов к ChatGPT создать Python скрипт, скачивающий видео с YouTube и генерирующий описание и фанарт для Kodi.

Итог работы скрипта

Итог работы скрипта

Статья получилась длинная, потому что полностью приведены запросы и ответы, поэтому сделал содержание. После номера промта идёт результат выполнения текущего ответа от ChatGPT.

Промт №1: предлагаемая библиотека pytube не работает
Промт №2: предлагаемая библиотека yt-dlp требует аутентификацию для скачивания
Промт №3: ошибки в коде
Промт №4: видео и звуковая дорожка по отдельности
Промт №5: Kodi не распознаёт описания в .nfo файле
Промт №6: заработало
Итоговый вариант на GitHub


Промт №1: предлагаемая библиотека pytube не работает

Действуй как опытный программист Python. Напиши скрипт, который будет скачивать видео с сервиса Ютуб в максимальном качестве.

На входе ссылка например «https://www.youtube.com/watch?v=_lvcEUi1MtE«.

На выходе .mkv файл.

Дополнительно сгенерируй .nfo файл описания этого видео используя данные заголовка, описания и обложки видео. .nfo файл нужен чтобы загрузить эти данные в базу Kodi.

Добавляй все комментарии на русском языке, продолжайте со мной общение на английском.

Вот скрипт Python, использующий библиотеку pytube для загрузки видео YouTube в максимальном качестве и создания файла .nfo с метаданными для Kodi. Для работы с видео YouTube вам нужно будет установить pytube:

pip install pytube

По запросу в сценарий включены комментарии на русском языке:

import os from pytube import YouTube import requests  # Функция для загрузки видео с YouTube def download_video(url, output_dir):     # Создаем объект YouTube для указанного URL     yt = YouTube(url)          # Получаем поток видео с максимальным разрешением     video_stream = yt.streams.get_highest_resolution()          # Устанавливаем имя выходного файла     video_title = yt.title     output_path = os.path.join(output_dir, f"{video_title}.mkv")          # Загружаем видео     print(f"Загружается видео: {video_title}")     video_stream.download(output_path=output_path)     print(f"Видео успешно загружено: {output_path}")          return output_path, yt  # Функция для создания .nfo файла def create_nfo_file(video_path, yt, output_dir):     # Получаем метаданные: заголовок, описание, обложка     title = yt.title     description = yt.description     thumbnail_url = yt.thumbnail_url          # Загружаем изображение обложки     thumbnail_path = os.path.join(output_dir, "cover.jpg")     response = requests.get(thumbnail_url)     with open(thumbnail_path, "wb") as f:         f.write(response.content)          # Создаем содержимое .nfo файла     nfo_content = f"""<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <movie>     <title>{title}</title>     <plot>{description}</plot>     <thumb>{thumbnail_path}</thumb> </movie> """     nfo_path = os.path.splitext(video_path)[0] + ".nfo"          # Записываем содержимое в .nfo файл     with open(nfo_path, "w", encoding="utf-8") as nfo_file:         nfo_file.write(nfo_content)          print(f".nfo файл успешно создан: {nfo_path}")     return nfo_path  # Основная программа def main():     # URL видео YouTube     url = "https://www.youtube.com/watch?v=HbsPPpeACvI"          # Каталог для сохранения файлов     output_dir = "./downloads"     os.makedirs(output_dir, exist_ok=True)          try:         # Загружаем видео         video_path, yt = download_video(url, output_dir)                  # Создаем .nfo файл         create_nfo_file(video_path, yt, output_dir)          except Exception as e:         print(f"Произошла ошибка: {e}")  if __name__ == "__main__":     main()

Объяснение кода

  1. Загрузка видео:

  • Использует pytube для загрузки и скачивания видео в самом высоком разрешении.

  • Выходной файл сохраняется в формате .mkv.

  1. Создание файла .nfo:

  • Извлекает метаданные, такие как заголовок, описание и URL миниатюры.

  • Загружает миниатюру видео как cover.jpg и включает ее в файл .nfo.

  • Сохраняет файл .nfo в том же каталоге, что и видео.

  1. Удобное управление каталогами:

  • Обеспечивает организованную структуру каталогов с папкой downloads.

  1. Русские комментарии:

  • Все комментарии написаны на русском языке, чтобы подробно объяснить каждый шаг.

Дайте мне знать, если вам нужны улучшения или объяснения!


Промт №2: предлагаемая библиотека yt-dlp требует аутентификацию для скачивания

Эта библиотека не работает и возвращает ошибку:

$ pytube https://youtube.com/watch?v=2lAe1cqCOXo      + CategoryInfo          : ObjectNotFound: ($:String) [], CommandNotFoundException     + FullyQualifiedErrorId : CommandNotFoundException D:\SynologyDrive\docs\2024_11_YouTube downloader> pytube https://youtube.com/watch?v=2lAe1cqCOXo   Loading video... Traceback (most recent call last):   File "<frozen runpy>", line 198, in _run_module_as_main   File "<frozen runpy>", line 88, in _run_code   File "C:\Users\михаил\AppData\Local\Programs\Python\Python312\Scripts\pytube.exe\__main__.py", line 7, in <module>   File "C:\Users\михаил\AppData\Local\Programs\Python\Python312\Lib\site-packages\pytube\cli.py", line 53, in main     _perform_args_on_youtube(youtube, args)   File "C:\Users\михаил\AppData\Local\Programs\Python\Python312\Lib\site-packages\pytube\cli.py", line 60, in _perform_args_on_youtube     download_highest_resolution_progressive(   File "C:\Users\михаил\AppData\Local\Programs\Python\Python312\Lib\site-packages\pytube\cli.py", line 474, in download_highest_resolution_progressive     stream = youtube.streams.get_highest_resolution()              ^^^^^^^^^^^^^^^   File "C:\Users\михаил\AppData\Local\Programs\Python\Python312\Lib\site-packages\pytube\__main__.py", line 296, in streams     return StreamQuery(self.fmt_streams)                        ^^^^^^^^^^^^^^^^   File "C:\Users\михаил\AppData\Local\Programs\Python\Python312\Lib\site-packages\pytube\__main__.py", line 176, in fmt_streams     stream_manifest = extract.apply_descrambler(self.streaming_data)                                                 ^^^^^^^^^^^^^^^^^^^   File "C:\Users\михаил\AppData\Local\Programs\Python\Python312\Lib\site-packages\pytube\__main__.py", line 160, in streaming_data     self.bypass_age_gate()   File "C:\Users\михаил\AppData\Local\Programs\Python\Python312\Lib\site-packages\pytube\__main__.py", line 257, in bypass_age_gate     innertube_response = innertube.player(self.video_id)                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   File "C:\Users\михаил\AppData\Local\Programs\Python\Python312\Lib\site-packages\pytube\innertube.py", line 448, in player     return self._call_api(endpoint, query, self.base_data)            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   File "C:\Users\михаил\AppData\Local\Programs\Python\Python312\Lib\site-packages\pytube\innertube.py", line 390, in _call_api     response = request._execute_request(                ^^^^^^^^^^^^^^^^^^^^^^^^^   File "C:\Users\михаил\AppData\Local\Programs\Python\Python312\Lib\site-packages\pytube\request.py", line 37, in _execute_request     return urlopen(request, timeout=timeout)  # nosec            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   File "C:\Users\михаил\AppData\Local\Programs\Python\Python312\Lib\urllib\request.py", line 215, in urlopen     return opener.open(url, data, timeout)            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   File "C:\Users\михаил\AppData\Local\Programs\Python\Python312\Lib\urllib\request.py", line 521, in open     response = meth(req, response)                ^^^^^^^^^^^^^^^^^^^   File "C:\Users\михаил\AppData\Local\Programs\Python\Python312\Lib\urllib\request.py", line 630, in http_response     response = self.parent.error(                ^^^^^^^^^^^^^^^^^^   File "C:\Users\михаил\AppData\Local\Programs\Python\Python312\Lib\urllib\request.py", line 559, in error     return self._call_chain(*args)            ^^^^^^^^^^^^^^^^^^^^^^^   File "C:\Users\михаил\AppData\Local\Programs\Python\Python312\Lib\urllib\request.py", line 492, in _call_chain     result = func(*args)              ^^^^^^^^^^^   File "C:\Users\михаил\AppData\Local\Programs\Python\Python312\Lib\urllib\request.py", line 639, in http_error_default     raise HTTPError(req.full_url, code, msg, hdrs, fp) urllib.error.HTTPError: HTTP Error 403: Forbidden

Ошибка, с которой вы столкнулись, указывает на то, что библиотека pytube вышла из строя из-за изменения API YouTube или структуры потоковой передачи, что является распространенной проблемой для библиотек, полагающихся на обратную разработку внутренних механизмов YouTube. Вот почему такие библиотеки часто ломаются, пока их сопровождающие не обновят их.

Альтернативное, надежное решение — использовать yt-dlp, мощный и активно поддерживаемый форк youtube-dl. Он хорошо подходит для загрузки видео с YouTube и других платформ. Вот как это реализовать:

Шаги:

  1. Установите yt-dlp:

pip install yt-dlp
  1. Скрипт Python:

Ниже приведен обновленный скрипт, использующий yt-dlp для загрузки видео в максимальном качестве и создания файла .nfo:

import os import subprocess import json  # Функция для загрузки видео def download_video(url, output_dir):     # Путь для выходного видеофайла     output_template = os.path.join(output_dir, "%(title)s.%(ext)s")      # Команда yt-dlp для загрузки видео в максимальном качестве     command = [         "yt-dlp",         "-f", "bestvideo+bestaudio/best",  # Выбор лучшего видео и аудио         "--merge-output-format", "mkv",    # Сохранение в MKV         "-o", output_template,            # Шаблон имени файла         "--write-info-json",              # Сохранение метаданных         url     ]      print("Загружается видео...")     subprocess.run(command, check=True)     print("Видео успешно загружено.")      # Находим JSON файл с метаданными     info_json_path = next(         (os.path.join(output_dir, f) for f in os.listdir(output_dir) if f.endswith(".info.json")), None     )     if not info_json_path:         raise FileNotFoundError("Файл метаданных .info.json не найден.")      return info_json_path  # Функция для создания .nfo файла def create_nfo_file(info_json_path):     # Читаем данные из JSON файла     with open(info_json_path, "r", encoding="utf-8") as f:         metadata = json.load(f)      title = metadata.get("title", "Без названия")     description = metadata.get("description", "Нет описания")     thumbnail = metadata.get("thumbnail", "")      # Загружаем обложку, если доступна     cover_path = None     if thumbnail:         cover_path = os.path.splitext(info_json_path)[0] + ".jpg"         with open(cover_path, "wb") as f:             f.write(requests.get(thumbnail).content)      # Создаем содержимое .nfo файла     nfo_content = f"""<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <movie>     <title>{title}</title>     <plot>{description}</plot>     <thumb>{cover_path or "Нет обложки"}</thumb> </movie> """      # Сохраняем .nfo файл     nfo_path = os.path.splitext(info_json_path)[0] + ".nfo"     with open(nfo_path, "w", encoding="utf-8") as nfo_file:         nfo_file.write(nfo_content)      print(f".nfo файл успешно создан: {nfo_path}")     return nfo_path  # Основная программа def main():     # URL видео YouTube     url = "https://www.youtube.com/watch?v=HbsPPpeACvI"      # Каталог для сохранения файлов     output_dir = "./downloads"     os.makedirs(output_dir, exist_ok=True)      try:         # Загружаем видео и метаданные         info_json_path = download_video(url, output_dir)          # Создаем .nfo файл         create_nfo_file(info_json_path)      except Exception as e:         print(f"Произошла ошибка: {e}")  if __name__ == "__main__":     main()

Основные характеристики:

  1. yt-dlp:

  • Автоматически извлекает видео и аудио наилучшего качества и объединяет их в файл .mkv.

  • Создает файл .info.json с метаданными (например, заголовок, описание, миниатюра).

  1. .nfo Файл:

  • Анализирует файл .info.json на предмет метаданных видео.

  • Загружает миниатюру и включает ее путь в файл .nfo.

  1. Обработка ошибок:

  • Обеспечивает корректную остановку скрипта в случае возникновения проблем (например, отсутствие метаданных JSON).

  1. Повторно используемая структура:

  • Скрипт можно легко адаптировать для пакетной загрузки или расширить для дополнительных функций.

Почему yt-dlp?

  • Активно поддерживается и регулярно обновляется.

  • Поддерживает широкий спектр форматов и опций.

  • Надежен для загрузки видео YouTube, даже когда другие библиотеки не справляются.

Запустите скрипт и дайте мне знать, как он работает!


Промт №3: ошибки в коде

Какая-то ошибка — что мне сделать?

[Running] python -u "d:\SynologyDrive\docs\2024_11_YouTube downloader\YouTube_download.py" Загружается видео... [youtube] Extracting URL: https://www.youtube.com/watch?v=HbsPPpeACvI [youtube] HbsPPpeACvI: Downloading webpage [youtube] HbsPPpeACvI: Downloading ios player API JSON [youtube] HbsPPpeACvI: Downloading mweb player API JSON ERROR: [youtube] HbsPPpeACvI: Sign in to confirm you�re not a bot. Use --cookies-from-browser or --cookies for the authentication. See  https://github.com/yt-dlp/yt-dlp/wiki/FAQ#how-do-i-pass-cookies-to-yt-dlp  for how to manually pass cookies. Also see  https://github.com/yt-dlp/yt-dlp/wiki/Extractors#exporting-youtube-cookies  for tips on effectively exporting YouTube cookies Произошла ошибка: Command '['yt-dlp', '-f', 'bestvideo+bestaudio/best', '--merge-output-format', 'mkv', '-o', './downloads\\%(title)s.%(ext)s', '--write-info-json', 'https://www.youtube.com/watch?v=HbsPPpeACvI']' returned non-zero exit status 1. [Done] exited with code=0 in 9.306 seconds 

Ошибка указывает на то, что YouTube требует дополнительной проверки (например, входа в систему) для загрузки видео. Обычно это происходит, когда:

  1. Видео имеет возрастные ограничения или помечено как требующее дополнительной проверки.

  2. YouTube подозревает необычную активность и запускает проверку CAPTCHA или бота.

Чтобы решить эту проблему, вам необходимо предоставить аутентифицированные файлы cookie для yt-dlp, что обходит эти ограничения.

Решение: Используйте файлы cookie браузера

Шаг 1: Экспортируйте файлы cookie из браузера

  1. Установите расширение Cookies.txt для своего браузера:

  1. Перейдите на YouTube и войдите в свою учетную запись.

  2. Откройте видео, которое хотите загрузить, и используйте расширение для экспорта файлов cookie. Сохраните файл cookie (например, cookies.txt) в рабочем каталоге.

Шаг 2: Измените скрипт

Обновите скрипт, чтобы передать файл cookie в yt-dlp:

def download_video(url, output_dir, cookies_file):     # Путь для выходного видеофайла     output_template = os.path.join(output_dir, "%(title)s.%(ext)s")          # Команда yt-dlp для загрузки видео с использованием cookies     command = [         "yt-dlp",         "-f", "bestvideo+bestaudio/best",  # Выбор лучшего видео и аудио         "--merge-output-format", "mkv",    # Сохранение в MKV         "-o", output_template,            # Шаблон имени файла         "--write-info-json",              # Сохранение метаданных         "--cookies", cookies_file,        # Передача cookies для аутентификации         url     ]          print("Загружается видео...")     subprocess.run(command, check=True)     print("Видео успешно загружено.")

Вызовите функцию, указав путь к файлу cookie:

# Основная программа def main():     url = "https://www.youtube.com/watch?v=HbsPPpeACvI"     output_dir = "./downloads"     cookies_file = "./cookies.txt"  # Укажите путь к файлу cookies          os.makedirs(output_dir, exist_ok=True)          try:         info_json_path = download_video(url, output_dir, cookies_file)         create_nfo_file(info_json_path)     except Exception as e:         print(f"Произошла ошибка: {e}")

Шаг 3: Запуск скрипта

  1. Сохраните файл cookies.txt в том же каталоге, что и ваш скрипт, или укажите правильный путь.

  2. Запустите скрипт еще раз. Теперь он должен работать без дополнительной проверки.

Примечания

  1. Сохраняйте файлы cookie в безопасности: ваш файл cookie содержит конфиденциальные данные. Не делитесь им и не оставляйте его доступным для других.

  2. Обновление файлов cookie: если срок действия файлов cookie истек, повторите шаг 1, чтобы создать новый cookies.txt.

  3. Альтернатива: вы можете использовать параметр --cookies-from-browser для прямого получения файлов cookie из вашего браузера, если он поддерживается.

Сообщите мне, если это решит вашу проблему!


Промт №4: видео и звуковая дорожка по отдельности

Приведи пожалуйста полный файл ответа. Нет ошибки, но и нет загруженного видео:

import sys import time sys.stdout.reconfigure(encoding='utf-8')  import os import subprocess import json  def download_video(url, output_dir, cookies_file):     # Путь для выходного видеофайла     output_template = os.path.join(output_dir, "%(title)s.%(ext)s")          # Команда yt-dlp для загрузки видео с использованием cookies     command = [         "yt-dlp",         "-f", "bestvideo+bestaudio/best",  # Выбор лучшего видео и аудио         "--merge-output-format", "mkv",    # Сохранение в MKV         "-o", output_template,            # Шаблон имени файла         "--write-info-json",              # Сохранение метаданных         "--cookies", cookies_file,        # Передача cookies для аутентификации         url     ]          print("Загружается видео...")     subprocess.run(command, check=True)     print("Видео успешно загружено.")      # Находим JSON файл с метаданными     info_json_path = next(         (os.path.join(output_dir, f) for f in os.listdir(output_dir) if f.endswith(".info.json")), None     )     if not info_json_path:         raise FileNotFoundError("Файл метаданных .info.json не найден.")      return info_json_path  # Функция для создания .nfo файла def create_nfo_file(info_json_path):     # Читаем данные из JSON файла     with open(info_json_path, "r", encoding="utf-8") as f:         metadata = json.load(f)      title = metadata.get("title", "Без названия")     description = metadata.get("description", "Нет описания")     thumbnail = metadata.get("thumbnail", "")      # Загружаем обложку, если доступна     cover_path = None     if thumbnail:         cover_path = os.path.splitext(info_json_path)[0] + ".jpg"         with open(cover_path, "wb") as f:             f.write(requests.get(thumbnail).content)      # Создаем содержимое .nfo файла     nfo_content = f"""<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <movie>     <title>{title}</title>     <plot>{description}</plot>     <thumb>{cover_path or "Нет обложки"}</thumb> </movie> """      # Сохраняем .nfo файл     nfo_path = os.path.splitext(info_json_path)[0] + ".nfo"     with open(nfo_path, "w", encoding="utf-8") as nfo_file:         nfo_file.write(nfo_content)      print(f".nfo файл успешно создан: {nfo_path}")     return nfo_path  # Основная программа def main():     url = "https://www.youtube.com/watch?v=HbsPPpeACvI"     output_dir = "./downloads"     cookies_file = "./cookies.txt"  # Укажите путь к файлу cookies          os.makedirs(output_dir, exist_ok=True)          try:         info_json_path = download_video(url, output_dir, cookies_file)         create_nfo_file(info_json_path)     except Exception as e:         print(f"Произошла ошибка: {e}")

Ваш скрипт выглядит хорошо структурированным, но, похоже, в нем не хватает нескольких критических моментов для обеспечения правильной работы:

  1. Отсутствует импорт requests: скрипт использует requests.get для загрузки миниатюры, но не импортирует библиотеку requests.

  2. Отладка загрузки видео: если в выходном каталоге видео не отображается, это может быть связано со следующими причинами:

  • Неправильный файл cookie.

  • Недостаточные разрешения для команды yt-dlp.

  1. Обеспечение проверки файла метаданных: проверка .info.json может завершиться неудачей, если каталог содержит несколько видео. Убедитесь, что вы проверяете правильный файл метаданных.

Вот исправленная и улучшенная версия скрипта:

Полный скрипт с корректировками

import sys import time sys.stdout.reconfigure(encoding='utf-8')  import os import subprocess import json import requests  # Ensure this is installed: `pip install requests`  def download_video(url, output_dir, cookies_file):     # Путь для выходного видеофайла     output_template = os.path.join(output_dir, "%(title)s.%(ext)s")          # Команда yt-dlp для загрузки видео с использованием cookies     command = [         "yt-dlp",         "-f", "bestvideo+bestaudio/best",  # Выбор лучшего видео и аудио         "--merge-output-format", "mkv",    # Сохранение в MKV         "-o", output_template,             # Шаблон имени файла         "--write-info-json",               # Сохранение метаданных         "--cookies", cookies_file,         # Передача cookies для аутентификации         url     ]          print("Загружается видео...")     try:         subprocess.run(command, check=True)         print("Видео успешно загружено.")     except subprocess.CalledProcessError as e:         raise RuntimeError(f"Ошибка при загрузке видео: {e}")          # Поиск JSON файла с метаданными     info_json_path = None     for file in os.listdir(output_dir):         if file.endswith(".info.json"):             info_json_path = os.path.join(output_dir, file)             break      if not info_json_path:         raise FileNotFoundError("Файл метаданных .info.json не найден.")          return info_json_path  def create_nfo_file(info_json_path):     # Читаем данные из JSON файла     with open(info_json_path, "r", encoding="utf-8") as f:         metadata = json.load(f)      title = metadata.get("title", "Без названия")     description = metadata.get("description", "Нет описания")     thumbnail = metadata.get("thumbnail", "")      # Загружаем обложку, если доступна     cover_path = None     if thumbnail:         cover_path = os.path.splitext(info_json_path)[0] + ".jpg"         try:             response = requests.get(thumbnail)             response.raise_for_status()             with open(cover_path, "wb") as f:                 f.write(response.content)             print(f"Обложка сохранена: {cover_path}")         except Exception as e:             print(f"Ошибка при загрузке обложки: {e}")             cover_path = None      # Создаем содержимое .nfo файла     nfo_content = f"""<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <movie>     <title>{title}</title>     <plot>{description}</plot>     <thumb>{cover_path or "Нет обложки"}</thumb> </movie> """      # Сохраняем .nfo файл     nfo_path = os.path.splitext(info_json_path)[0] + ".nfo"     with open(nfo_path, "w", encoding="utf-8") as nfo_file:         nfo_file.write(nfo_content)      print(f".nfo файл успешно создан: {nfo_path}")     return nfo_path  # Основная программа def main():     url = "https://www.youtube.com/watch?v=HbsPPpeACvI"     output_dir = "./downloads"     cookies_file = "./cookies.txt"  # Укажите путь к файлу cookies          os.makedirs(output_dir, exist_ok=True)          try:         # Загрузка видео и метаданных         info_json_path = download_video(url, output_dir, cookies_file)                  # Создание .nfo файла         create_nfo_file(info_json_path)     except Exception as e:         print(f"Произошла ошибка: {e}")  if __name__ == "__main__":     main()

Ключевые улучшения

  1. Библиотека запросов:

  • Добавлены необходимые import requests.

  • Добавлена ​​обработка ошибок при загрузке миниатюры.

  1. Улучшенные сообщения об ошибках:

  • Улучшены сообщения об исключениях для лучшей отладки.

  1. Гарантированное соответствие файла метаданных:

  • Теперь гарантируется явная привязка .info.json к загруженному видео.

  1. Разрешения и зависимости:

  • Убедитесь, что yt-dlp установлен и доступен в терминале. Запустите pip install yt-dlp.

Дополнительные примечания

  • Файл cookie: Убедитесь, что файл cookies.txt правильно экспортирован из вашего браузера (выполнен вход в YouTube).

  • Отладка: если видео не отображается в ./downloads, убедитесь, что yt-dlp может быть запущен из терминала с помощью той же команды.

  • Журнал ошибок: любые RuntimeError или отсутствующие файлы теперь будут вызывать описательные ошибки.

Дайте мне знать, если вам нужны дополнительные разъяснения!


Промт №5: Kodi не распознаёт описания в .nfo файле

У меня скачалось отдельно видео и отдельно звуковая дорожка:

[info] HbsPPpeACvI: Downloading 1 format(s): 616+251 [info] Writing video metadata as JSON to: downloads\����� � ������ �� �������� ������������! ������ ���� ������� ���������.info.json WARNING: You have requested merging of multiple formats but ffmpeg is not installed. The formats won't be merged [hlsnative] Downloading m3u8 manifest [hlsnative] Total fragments: 675

Проблема возникает из-за предупреждения о том, что ffmpeg не установлен. Без ffmpeg yt-dlp не может объединить отдельные видео- и аудиодорожки в один файл, что приводит к отдельным загрузкам для видео- и аудиопотоков.

Вот как решить проблему:

Шаги по устранению проблемы

  1. Установите ffmpeg:

  • ffmpeg требуется для объединения видео- и аудиодорожек.

  • Вы можете установить его следующими способами в зависимости от вашей ОС:

В Windows:

  • Загрузите последнюю сборку ffmpeg с официального сайта: ffmpeg.org.

  • Извлеките загруженный файл и добавьте каталог bin в PATH вашей системы:

  • Щелкните правой кнопкой мыши «Этот компьютер» > Свойства > Дополнительные параметры системы > Переменные среды.

  • Отредактируйте переменную Path в «Системных переменных» и добавьте путь к папке ffmpeg/bin.

В Linux:

sudo apt update sudo apt install ffmpeg 

В macOS:

brew install ffmpeg 
  1. Проверьте установку ffmpeg:

  • Откройте терминал или командную строку и выполните:

ffmpeg -version
  • Если установка выполнена правильно, вы должны увидеть сведения о версии ffmpeg.

  1. Повторите загрузку видео:

  • Запустите скрипт еще раз или вручную повторите попытку, используя:

yt-dlp -f bestvideo+bestaudio --merge-output-format mkv -o "./downloads/%(title)s.%(ext)s" 
  1. Объединение уже загруженных файлов:

Если вы уже загрузили видео- и аудиодорожки, вы можете объединить их вручную с помощью ffmpeg. Выполните следующую команду в терминале (при необходимости измените пути к файлам):

ffmpeg -i video.mp4 -i audio.m4a -c:v copy -c:a aac output.mkv 

Замените video.mp4 и audio.m4a на фактические имена файлов ваших видео- и аудиодорожек.

Следующие шаги в вашем скрипте

После того, как вы убедитесь, что ffmpeg установлен:

  • Видео и аудио будут автоматически объединены, когда вы используете команду yt-dlp с опцией --merge-output-format в вашем скрипте.

Дайте мне знать, если вам нужна помощь с установкой или тестированием!


Промт №6: заработало

Спасибо, всё заработало, но Kodi не распознаёт описания.
Для того чтобы Kodi распознавал обложку файл должен заканчиваться -fanart.jpg, а сейчас .info.jpg.
Для того чтобы Kodi распознавал описание файл должен заканчиваться .nfo, а сейчас .info.nfo.

Вот выходные данные скрипта:

[Merger] Merging formats into "downloads\One Track Mind - I Like You.mkv" Deleting original file downloads\One Track Mind - I Like You.f134.mp4 (pass -k to keep) Deleting original file downloads\One Track Mind - I Like You.f140.m4a (pass -k to keep) Видео успешно загружено. Обложка сохранена: ./downloads\One Track Mind - I Like You.info.jpg .nfo файл успешно создан: ./downloads\One Track Mind - I Like You.info.nfo 

Чтобы обеспечить совместимость с Kodi, нам нужно настроить скрипт так, чтобы изображение обложки и имена файлов .nfo соответствовали соглашениям Kodi. Вот обновленная версия скрипта:

Обновленный скрипт

import sys import os import subprocess import json import requests  sys.stdout.reconfigure(encoding="utf-8")   def download_video(url, output_dir, cookies_file):     # Путь для выходного видеофайла     output_template = os.path.join(output_dir, "%(title)s.%(ext)s")      # Команда yt-dlp для загрузки видео с использованием cookies     command = [         "yt-dlp",         "-f", "bestvideo+bestaudio/best",  # Выбор лучшего видео и аудио         "--merge-output-format", "mkv",    # Сохранение в MKV         "-o", output_template,            # Шаблон имени файла         "--write-info-json",              # Сохранение метаданных         "--cookies", cookies_file,        # Передача cookies для аутентификации         url     ]      print("Загружается видео...")     subprocess.run(command, check=True)     print("Видео успешно загружено.")      # Находим JSON файл с метаданными     info_json_path = next(         (os.path.join(output_dir, f) for f in os.listdir(output_dir) if f.endswith(".info.json")), None     )     if not info_json_path:         raise FileNotFoundError("Файл метаданных .info.json не найден.")      return info_json_path   def create_kodi_friendly_files(info_json_path):     # Читаем данные из JSON файла     with open(info_json_path, "r", encoding="utf-8") as f:         metadata = json.load(f)      title = metadata.get("title", "Без названия")     description = metadata.get("description", "Нет описания")     thumbnail = metadata.get("thumbnail", "")      # Путь к базовым файлам (без расширений)     base_path = os.path.splitext(info_json_path)[0].replace(".info", "")      # Загружаем обложку, если доступна     cover_path = f"{base_path}-poster.jpg"     if thumbnail:         with open(cover_path, "wb") as f:             f.write(requests.get(thumbnail).content)         print(f"Обложка сохранена: {cover_path}")     else:         print("Обложка не найдена.")      # Создаем содержимое .nfo файла     nfo_content = f"""<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <movie>     <title>{title}</title>     <plot>{description}</plot>     <thumb>{cover_path}</thumb> </movie> """      # Сохраняем .nfo файл     nfo_path = f"{base_path}.nfo"     with open(nfo_path, "w", encoding="utf-8") as nfo_file:         nfo_file.write(nfo_content)      print(f".nfo файл успешно создан: {nfo_path}")   # Основная программа def main():     url = "https://www.youtube.com/watch?v=HbsPPpeACvI"     output_dir = "./downloads"     cookies_file = "./cookies.txt"  # Укажите путь к файлу cookies      os.makedirs(output_dir, exist_ok=True)      try:         info_json_path = download_video(url, output_dir, cookies_file)         create_kodi_friendly_files(info_json_path)     except Exception as e:         print(f"Произошла ошибка: {e}")   if __name__ == "__main__":     main()

Ключевые изменения

  1. Переименование изображения обложки:

  • Изображение обложки теперь сохраняется с суффиксом -poster.jpg (например, One Track Mind - I Like You-poster.jpg).

  1. Переименование файла .nfo:

  • Файл .nfo теперь соответствует имени видеофайла без суффикса .info (например, One Track Mind - I Like You.nfo).

Пример вывода

После запуска скрипта вы должны увидеть:

[Объединение] Объединение форматов в "downloads\One Track Mind - I Like You.mkv" Удаление исходного файла downloads\One Track Mind - I Like You.f134.mp4 (передайте -k для сохранения) Удаление исходного файла downloads\One Track Mind - I Like You.f140.m4a (передайте -k для сохранения) Видео успешно загружено. Обложка сохранена: downloads\One Track Mind - I Like You-poster.jpg Файл .nfo успешно создан: downloads\One Track Mind - I Like You.nfo 

Теперь Kodi должен распознать как метаданные видео, так и обложку.


Итоговый вариант на GitHub

Подкаст на телевизоре

Подкаст на телевизоре

Выложил итоговый рабочий вариант на Гитхаб:

https://github.com/empenoso/YouTube-to-Kodi/

Итоги

Всего за 6 запросов и около получаса можно создать рабочий код, не углубляясь в подробности работы скрипта.

Автор: Михаил Шардин

25 ноября 2024 г.


ссылка на оригинал статьи https://habr.com/ru/articles/860706/