Pyglet может читать mp3-файлы в приложении Python Mac (.app), созданном с помощью PyInstaller, но только когда я запускаю приложение из командной строки

Я создаю программу, используя Python 3.10.8 (дистрибутив Miniconda), которая использует pyglet версии 1.5.27. Одна из особенностей моей программы заключается в загрузке аудиофайлов в pyglet с помощью этой функции:

pyglet.media.load("{path_to_audio_file}")

Недавно я упаковал исходный код своей программы как в исполняемый файл Windows (.exe), так и в приложение Mac (.app) с помощью PyInstaller (хотя для версии для Windows я использовал Auto Py to Exe).

Это команда PyInstaller, которую я использовал для сборки версии своей программы для Mac (замените {path_to_repository} расположением репозитория на локальном компьютере):

pyinstaller --noconfirm --onedir --windowed --icon "{path_to_repository}/setup_files/mac/file_icon_mac.icns" --add-data "{path_to_repository}/src/classes:classes/" --add-data "{path_to_repository}/src/images:images/" --add-data "{path_to_repository}/messages:messages/"  "{path_to_repository}/src/Time Stamper.py"

Команда Windows, которую генерирует Auto Py to Exe, выглядит точно так же, как команда выше, за исключением того, что...

  • путь к файлу значка Windows (.ico) предоставляется вместо пути к файлу значка Mac (.icns)

    И

  • все двоеточия (":") заменяются точкой с запятой (";").

Я могу загружать и воспроизводить mp3-файлы с помощью pyglet просто отлично в версии моей программы для Windows, а также в версии моей программы для Mac, но:

  • pyglet не может загружать mp3-файлы в версии моей программы для Mac, когда я запускаю приложение (.app), дважды щелкнув его.

  • pyglet будет загружать мои mp3-файлы только в версию моей программы для Mac, когда я либо...

    • запустите мое приложение Mac (.app), щелкнув его правой кнопкой мыши, а затем выбрав «Показать содержимое пакета» и перейдя в «Содержание» -> «MacOS», а затем дважды щелкнув исполняемый файл Unix в этой папке.

      ИЛИ

    • запустите мое приложение Mac (.app), введя команду:

      open -n {path_to_my_app} --args -AppCommandLineArg
      
  • Когда я пытаюсь запустить приложение Mac (.app) моей программы, просто дважды щелкнув файл .app, я получаю следующее сообщение об ошибке:

    {Traceback (most recent call last):
    } {  File "pyglet/media/codecs/wave.py", line 58, in __init__
    } {  File "wave.py", line 509, in open
    } {  File "wave.py", line 163, in __init__
    } {  File "wave.py", line 130, in initfp
    } {wave.Error: file does not start with RIFF id
    } {
    During handling of the above exception, another exception occurred:
    
    } {Traceback (most recent call last):
    } {  File "tkinter/__init__.py", line 1921, in __call__
    } {  File "classes/macros/macros_buttons_file.py", line 107, in button_audio_select_macro
        self.parent.validate_audio_player()
    } {  File "classes/macros/macros.py", line 229, in validate_audio_player
        verify_audio_file(self.widgets["entry_audio_path"].get(), self.time_stamper)
    } {  File "classes/macros/macros_helper_methods.py", line 225, in verify_audio_file
        time_stamper.audio_source = load(file_full_path)
    } {  File "pyglet/media/__init__.py", line 142, in load
    } {  File "pyglet/media/__init__.py", line 132, in load
    } {  File "pyglet/media/codecs/wave.py", line 105, in decode
    } {  File "pyglet/media/codecs/wave.py", line 60, in __init__
    } {pyglet.media.codecs.wave.WAVEDecodeException: file does not start with RIFF id
    }
    
  • Кроме того, это предупреждения, сгенерированные PyInstaller, которые PyInstaller поместил в файл «build/Time Stamper/warn-Time Stamper.txt» («Time Stamper» — это название моего приложения):

    This file lists modules PyInstaller was not able to find. This does not
    necessarily mean this module is required for running your program. Python and
    Python 3rd-party packages include a lot of conditional or optional modules. For
    example the module 'ntpath' only exists on Windows, whereas the module
    'posixpath' only exists on Posix systems.
    
    Types if import:
    * top-level: imported at the top-level - look at these first
    * conditional: imported within an if-statement
    * delayed: imported within a function
    * optional: imported within a try-except-statement
    
    IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
                tracking down the missing module yourself. Thanks!
    
    missing module named pep517 - imported by importlib.metadata (delayed)
    missing module named 'org.python' - imported by copy (optional), xml.sax (delayed, conditional)
    missing module named org - imported by pickle (optional)
    missing module named winreg - imported by importlib._bootstrap_external (conditional), mimetypes (optional), urllib.request (delayed, conditional, optional), platform (delayed, optional)
    missing module named nt - imported by os (delayed, conditional, optional), ntpath (optional), shutil (conditional), importlib._bootstrap_external (conditional), ctypes (delayed, conditional)
    missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional)
    excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional)
    missing module named _winapi - imported by encodings (delayed, conditional, optional), ntpath (optional), subprocess (optional), mimetypes (optional)
    missing module named msvcrt - imported by subprocess (optional), getpass (optional), pyglet.extlibs.png (delayed, conditional)
    missing module named pyogg - imported by pyglet.media.codecs.pyogg (top-level)
    missing module named PIL - imported by pyglet.image.codecs.pil (optional)
    missing module named Image - imported by pyglet.image.codecs.pil (optional)
    missing module named vms_lib - imported by platform (delayed, optional)
    missing module named 'java.lang' - imported by platform (delayed, optional), xml.sax._exceptions (conditional)
    missing module named java - imported by platform (delayed)
    missing module named _winreg - imported by platform (delayed, optional)
    missing module named pyglet.window.BaseWindow - imported by pyglet.window (top-level), pyglet.window.headless (top-level), pyglet.window.cocoa (top-level), pyglet.window.win32 (top-level), pyglet.window.xlib (top-level)
    missing module named 'gi.repository' - imported by pyglet.media.codecs.gstreamer (optional)
    missing module named gi - imported by pyglet.media.codecs.gstreamer (optional)
    

Я знаю, что pyglet лучше работает с wav-файлами, но мне кажется странным, что pyglet может читать мои mp3-файлы в каждом случае, кроме этого очень конкретного случая на моем Mac, поэтому, если возможно, я бы очень хотел, чтобы он работал и там. . Кроме того, я использую macOS Catalina 10.15.7 на 11-дюймовом MacBook Air середины 2012 года с двухъядерным процессором Intel Core i5 с тактовой частотой 1,7 ГГц.

Обновлять:

Я экспериментировал с этим больше, и я считаю, что определил проблему. Для чтения mp3-файлов pyglet требует ffmpeg. Когда я установил pyglet с помощью следующей команды, зависимость ffmpeg была автоматически установлена ​​на мой компьютер:

conda install -c conda-forge pyglet

Когда я просто запускаю свое приложение Mac (.app) из командной строки:

  • Мое приложение (.app) по умолчанию использует интерпретатор Python по умолчанию в моей системе (т. е. мою базовую среду miniconda), поэтому в моем приложении есть все пакеты Python, которые я установил с помощью команд «conda/pip install».
    • Это означает, что когда я запускаю свое приложение (.app) из командной строки, мой компьютер может найти как pyglet, так и зависимость ffmpeg, которая была установлена ​​вместе с pyglet (что позволяет моему приложению читать файлы mp3).

Однако, когда я запускаю свое приложение для Mac, дважды щелкнув приложение (.app), созданное PyInstaller:

  • Мой компьютер использует только пакеты, которые были включены в пакет приложений PyInstaller (.app).
    • Поскольку PyInstaller, кажется, обнаруживает, что pyglet необходим для запуска моего приложения (.app), он включает pyglet в окончательный пакет приложения (.app), поэтому я бы заподозрил, что PyInstaller автоматически включает ffmpeg в этот пакет приложения (.app). также (поскольку ffmpeg был автоматически установлен вместе с pyglet в качестве зависимости, когда я запускал вышеупомянутую команду «conda install»). Однако, похоже, это не так.

Я почти уверен, что PyInstaller не включает ffmpeg в мое приложение Mac (.app), потому что, пока я отлаживал свой код, я обнаружил, что следующее утверждение...

pyglet.media.have_ffmpeg()

оценивается как True, когда я запускаю свое приложение (.app) из командной строки, но оценивается как False, когда я дважды щелкаю приложение (.app), созданное PyInstaller.

Итак, теперь я пытаюсь выяснить, как заставить PyInstaller включать ffmpeg в мое приложение Mac (.app) таким образом, чтобы pyglet мог обнаружить, что ffmpeg там (что, я полагаю, позволит pyglet использовать ffmpeg для иметь возможность читать файлы mp3), но я не могу, на всю жизнь, понять, как это сделать.

Чтобы попытаться заставить PyInstaller включить ffmpeg в мое приложение Mac (.app), я попытался добавить различные перестановки следующих аргументов в мою команду pyinstaller:

--add-binary "/opt/miniconda3/bin/ffmpeg:bin/"
--add-binary "/opt/miniconda3/bin/ffmpeg:ffmpeg/"
--add-data "/opt/miniconda3/lib/python3.10/site-packages/ffmpeg"
--collect-all pyglet
--collect-all ffmpeg
--collect-all ffmpeg-python

Ни один из этих аргументов при добавлении, по-видимому, не приводил к тому, что PyInstaller включал ffmpeg в мое приложение (.app) или, по крайней мере, если ffmpeg был включен (и я не думаю, что это так, но я не уверен), то эти аргументы не позволили pyglet его обнаружить.

Кроме того, эти последние два аргумента полностью игнорируются PyInstaller, поскольку он говорит, что нет пакетов с именем ffmpeg или ffmpeg-python. Я даже установил автономные пакеты ffmpeg с помощью conda, используя следующие команды (а затем снова попытался запустить команду PyInstaller):

conda install -c conda-forge ffmpeg
conda install -c conda-forge ffmpeg-python

Установка этих пакетов и повторный запуск PyInstaller привели к той же проблеме (т. е. PyInstaller не обнаружил никаких пакетов с именем ffmpeg или ffmpeg-python, поэтому эти пакеты были проигнорированы и не включены в пакет .app).

Итак, основываясь на моем полном понимании моей проблемы, кажется, что мне нужно найти способ правильно упаковать ffmpeg в мое приложение (.app) таким образом, чтобы pyglet мог с ним общаться. Есть идеи?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
62
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы правы, Mac не поддерживает MP3 по умолчанию в Pyglet (это будет добавлено в следующей версии 2.x и, возможно, будет перенесено в 1.5) и требует FFmpeg.

Pyglet ищет файлы dylib для ffmpeg в каталоге os.environ["DYLD_LIBRARY_PATH"]. Вы также можете поиграть с pyglet.options["search_local_libs"] = True, который будет искать папку с именем lib в вашем каталоге скриптов для этих файлов lib.

Вот некоторая информация об установке ffmpeg: https://pyglet.readthedocs.io/en/latest/programming_guide/media.html#ffmpeg-installation

Спасибо! Это сработало. Для тех, кто читает это, я сделал в своем коде перед вызовом «pyglet.media.load('{path_to_audio_file}')» следующее утверждение: «pyglet.options['search_local_libs'] = True». Затем я загрузил 7z ffmpeg для Mac (точнее, версию 5.1.2, но текущая последняя версия всегда должна работать) со следующей страницы: evermeet.cx/ffmpeg. Затем я извлек исполняемый файл ffmpeg из файла 7z и добавил следующий аргумент в команду PyInstaller: «—add-binary {path_to_ffmpeg_executable}:lib/». Моя программа теперь может читать файлы mp3.

Ben Fertig 03.02.2023 19:54

Другие вопросы по теме