Я создаю программу, используя 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) из командной строки:
Однако, когда я запускаю свое приложение для Mac, дважды щелкнув приложение (.app), созданное PyInstaller:
Я почти уверен, что 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 мог с ним общаться. Есть идеи?
Вы правы, 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.