QtMultimedia for audio + .pos fix

This commit is contained in:
Dpeta 2022-07-08 22:36:23 +02:00
parent 39aaa1a49f
commit 1419c4985e
5 changed files with 115 additions and 117 deletions

View file

@ -83,7 +83,7 @@ Pesterchum is a Python script. This means that as long as you have Python instal
### REQUIREMENTS ### REQUIREMENTS
- [Python 3] - [Python 3]
- [PyQt6] - [PyQt6]
- [pygame] (Only required for audio, Pesterchum will probably still run without it.) - On Linux, optionally [pygame] for audio. (QtMultimedia has a [GStreamer] dependency on Linux)
### WALKTHROUGH ### WALKTHROUGH
@ -104,6 +104,7 @@ Pesterchum is a Python script. This means that as long as you have Python instal
[pip]: https://pypi.org/project/pip/ [pip]: https://pypi.org/project/pip/
[PyQt6]: https://pypi.org/project/PyQt6/ [PyQt6]: https://pypi.org/project/PyQt6/
[pygame]: https://pypi.org/project/pygame/ [pygame]: https://pypi.org/project/pygame/
[GStreamer]: https://gstreamer.freedesktop.org/
## FREEZE / BUILD <img src="themes/win95chum/admin.png"> ## FREEZE / BUILD <img src="themes/win95chum/admin.png">
Here's a quick guide on how to freeze Pesterchum, (that is, packaging it with python as an executable). :3 Here's a quick guide on how to freeze Pesterchum, (that is, packaging it with python as an executable). :3

View file

@ -153,7 +153,7 @@ class PesterTabWindow(QtWidgets.QFrame):
def contextMenuEvent(self, event): def contextMenuEvent(self, event):
#~if event.reason() == QtGui.QContextMenuEvent.Reason.Mouse: #~if event.reason() == QtGui.QContextMenuEvent.Reason.Mouse:
tabi = self.tabs.tabAt(event.position().toPoint()) tabi = self.tabs.tabAt(event.pos())
if tabi < 0: if tabi < 0:
tabi = self.tabs.currentIndex() tabi = self.tabs.currentIndex()
for h, i in list(self.tabIndices.items()): for h, i in list(self.tabIndices.items()):

View file

@ -45,7 +45,7 @@ class RightClickList(QtWidgets.QListWidget):
def contextMenuEvent(self, event): def contextMenuEvent(self, event):
#fuckin Qt <--- I feel that </3 #fuckin Qt <--- I feel that </3
if event.reason() == QtGui.QContextMenuEvent.Reason.Mouse: if event.reason() == QtGui.QContextMenuEvent.Reason.Mouse:
listing = self.itemAt(event.position().toPoint()) listing = self.itemAt(event.pos())
self.setCurrentItem(listing) self.setCurrentItem(listing)
optionsMenu = self.getOptionsMenu() optionsMenu = self.getOptionsMenu()
if optionsMenu: if optionsMenu:
@ -56,7 +56,7 @@ class RightClickList(QtWidgets.QListWidget):
class RightClickTree(QtWidgets.QTreeWidget): class RightClickTree(QtWidgets.QTreeWidget):
def contextMenuEvent(self, event): def contextMenuEvent(self, event):
if event.reason() == QtGui.QContextMenuEvent.Reason.Mouse: if event.reason() == QtGui.QContextMenuEvent.Reason.Mouse:
listing = self.itemAt(event.position().toPoint()) listing = self.itemAt(event.pos())
self.setCurrentItem(listing) self.setCurrentItem(listing)
optionsMenu = self.getOptionsMenu() optionsMenu = self.getOptionsMenu()
if optionsMenu: if optionsMenu:
@ -142,6 +142,7 @@ class NoneSound(object):
pass pass
def play(self): pass def play(self): pass
def setVolume(self, v): pass def setVolume(self, v): pass
def set_volume(self, v): pass
class WMButton(QtWidgets.QPushButton): class WMButton(QtWidgets.QPushButton):
def __init__(self, icon, parent=None): def __init__(self, icon, parent=None):

View file

@ -33,53 +33,21 @@ import datetime
import random import random
import re import re
import time import time
try: import json
import json
except:
pass
from pnc.dep.attrdict import AttrDict from pnc.dep.attrdict import AttrDict
reqmissing = [] from PyQt6 import QtCore, QtGui, QtWidgets
optmissing = []
try:
from PyQt6 import QtCore, QtGui, QtWidgets
except ImportError as e:
module = str(e)
if module.startswith("No module named ") or \
module.startswith("cannot import name "):
reqmissing.append(module[module.rfind(" ")+1:])
else: logging.critical(e)
del module
# Because pygame intro msg :3c
# See https://stackoverflow.com/questions/54246668/how-do-i-delete-the-hello-from-the-pygame-community-console-alert-while-using
try:
os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = '1'
except:
logging.exception("Failed to set PYGAME_HIDE_SUPPORT_PROMPT, this is a non-issue.")
try:
import pygame
except ImportError as e:
pygame = None
module = str(e)
if module[:16] == "No module named ": optmissing.append(module[16:])
else: logging.critical(e)
del module
if reqmissing:
logging.critical("ERROR: The following modules are required for Pesterchum to run and are missing on your system:")
for m in reqmissing: logging.critical("* "+m)
# False flag for some reason.
#exit()
vnum = QtCore.qVersion() vnum = QtCore.qVersion()
major = int(vnum[:vnum.find(".")]) major = int(vnum[:vnum.find(".")])
if vnum.find(".", vnum.find(".")+1) != -1: if vnum.find(".", vnum.find(".")+1) != -1:
minor = int(vnum[vnum.find(".")+1:vnum.find(".", vnum.find(".")+1)]) minor = int(vnum[vnum.find(".")+1:vnum.find(".", vnum.find(".")+1)])
else: else:
minor = int(vnum[vnum.find(".")+1:]) minor = int(vnum[vnum.find(".")+1:])
if not ((major > 5) or (major == 5 and minor >= 0)): if (major < 6) or ((major > 6) and (minor < 2)):
logging.critical("ERROR: Pesterchum requires at least Qt version >= 5.0") print("ERROR: Pesterchum requires at least Qt version >= 6.2")
logging.critical("You currently have version " + vnum + ". Please upgrade Qt.") print("You currently have version " + str(vnum) + ". Please upgrade Qt.")
exit() sys.exit()
import ostools import ostools
# Placed here before importing the rest of pesterchum, since bits of it need # Placed here before importing the rest of pesterchum, since bits of it need
@ -246,19 +214,13 @@ from irc import PesterIRC
from logviewer import PesterLogUserSelect, PesterLogViewer from logviewer import PesterLogUserSelect, PesterLogViewer
from randomer import RandomHandler, RANDNICK from randomer import RandomHandler, RANDNICK
import nickservmsgs import nickservmsgs
# Rawr, fuck you OSX leopard
#if not ostools.isOSXLeopard():
# from updatecheck import MSPAChecker
from toast import PesterToastMachine, PesterToast from toast import PesterToastMachine, PesterToast
import pytwmn import pytwmn
#canon_handles = ["apocalypseArisen", "arsenicCatnip", "arachnidsGrip", "adiosToreador", \ #canon_handles = ["apocalypseArisen", "arsenicCatnip", "arachnidsGrip", "adiosToreador",
# "caligulasAquarium", "cuttlefishCuller", "carcinoGeneticist", "centaursTesticle", \ # "caligulasAquarium", "cuttlefishCuller", "carcinoGeneticist", "centaursTesticle",
# "grimAuxiliatrix", "gallowsCalibrator", "gardenGnostic", "ectoBiologist", \ # "grimAuxiliatrix", "gallowsCalibrator", "gardenGnostic", "ectoBiologist",
# "twinArmageddons", "terminallyCapricious", "turntechGodhead", "tentacleTherapist"] # "twinArmageddons", "terminallyCapricious", "turntechGodhead", "tentacleTherapist"]
#canon_handles = ["",]# Unused, kept to prevent unexpected calls causing a crash.
BOTNAMES = [] BOTNAMES = []
CUSTOMBOTS = ["CALSPRITE", RANDNICK.upper()] CUSTOMBOTS = ["CALSPRITE", RANDNICK.upper()]
SERVICES = ["NICKSERV", "CHANSERV", "MEMOSERV", "OPERSERV", "HELPSERV", "HOSTSERV", "BOTSERV"] SERVICES = ["NICKSERV", "CHANSERV", "MEMOSERV", "OPERSERV", "HELPSERV", "HOSTSERV", "BOTSERV"]
@ -270,6 +232,34 @@ BOTNAMES.extend(SERVICES)
_CONSOLE_ENV = AttrDict() _CONSOLE_ENV = AttrDict()
_CONSOLE_ENV.PAPP = None _CONSOLE_ENV.PAPP = None
# Import audio module
if ostools.isLinux():
# QtMultimedia on linux requires GStreamer + a plugin for decoding wave,
# so using pygame is prefered.
# I think Ubuntu does have this out of the box though.
# We could possibly check for the availability of a plugin via the gstreamer python bindings,
# but I'm not sure if that'd be worth it, as that'd introduce another dependency.
try:
import pygame
except ImportError:
print("Failed to import pygame, falling back to QtMultimedia. "
+ "For QtMultimedia to work on Linux you need GStreamer"
+ " + a plugin for decoding the wave format.")
try:
from PyQt6 import QtMultimedia
except ImportError:
print("Failed to import QtMultimedia, no audio module availible.")
else:
# On Mac and Windows, QtMultimedia should be prefered.
try:
from PyQt6 import QtMultimedia
except ImportError:
print("Failed to import QtMultimedia, falling back to pygame.")
try:
import pygame
except ImportError:
print("Failed to import QtMultimedia, no audio module availible.")
class waitingMessageHolder(object): class waitingMessageHolder(object):
def __init__(self, mainwindow, **msgfuncs): def __init__(self, mainwindow, **msgfuncs):
self.mainwindow = mainwindow self.mainwindow = mainwindow
@ -1073,7 +1063,7 @@ class trollSlum(chumArea):
def contextMenuEvent(self, event): def contextMenuEvent(self, event):
#fuckin Qt #fuckin Qt
if event.reason() == QtGui.QContextMenuEvent.Reason.Mouse: if event.reason() == QtGui.QContextMenuEvent.Reason.Mouse:
listing = self.itemAt(event.position().toPoint()) listing = self.itemAt(event.pos())
self.setCurrentItem(listing) self.setCurrentItem(listing)
if self.currentItem().text(0) != "": if self.currentItem().text(0) != "":
self.optionsMenu.popup(event.globalPos()) self.optionsMenu.popup(event.globalPos())
@ -2036,27 +2026,48 @@ class PesterWindow(MovingWindow):
def _setup_sounds(self, soundclass=None): def _setup_sounds(self, soundclass=None):
"""Set up the event sounds for later use.""" """Set up the event sounds for later use."""
# Set up the sounds we're using. # Set up the sounds we're using.
if 'pygame' in sys.modules:
if soundclass is None: # Pygame is imported (Linux)
if (pygame and pygame.mixer): soundclass = pygame.mixer.Sound
# We have pygame, so we may as well use it. elif 'PyQt6.QtMultimedia' in sys.modules:
soundclass = pygame.mixer.Sound # QtMultimedia is imported (Windows, MacOS)
else: soundclass = QtMultimedia.QSoundEffect
PchumLog.warning("Failed to define pygame mixer, is pygame imported?") else:
soundclass = NoneSound # death
soundclass = NoneSound
PchumLog.warning("No sound module loaded?")
self.sound_type = soundclass self.sound_type = soundclass
# These get redefined if sound works
self.alarm = NoneSound()
self.memosound = NoneSound()
self.namesound = NoneSound()
self.ceasesound = NoneSound()
self.honksound = NoneSound()
# Use the class we chose to build the sound set. # Use the class we chose to build the sound set.
try: try:
# karxi: These all seem to be created using local paths. if 'pygame' in sys.modules:
# Note that if QSound.isAvailable is False, we could still try if soundclass == pygame.mixer.Sound:
# to play QSound objects - it'll just fail silently. self.alarm = soundclass(self.theme["main/sounds/alertsound"])
self.alarm = soundclass(self.theme["main/sounds/alertsound"]) self.memosound = soundclass(self.theme["main/sounds/memosound"])
self.memosound = soundclass(self.theme["main/sounds/memosound"]) self.namesound = soundclass("themes/namealarm.wav")
self.namesound = soundclass("themes/namealarm.wav") self.ceasesound = soundclass(self.theme["main/sounds/ceasesound"])
self.ceasesound = soundclass(self.theme["main/sounds/ceasesound"]) self.honksound = soundclass("themes/honk.wav")
self.honksound = soundclass("themes/honk.wav") elif 'PyQt6.QtMultimedia' in sys.modules:
if soundclass == QtMultimedia.QSoundEffect:
self.alarm = soundclass()
self.memosound = soundclass()
self.namesound = soundclass()
self.ceasesound = soundclass()
self.honksound = soundclass()
self.alarm.setSource(QtCore.QUrl.fromLocalFile(self.theme["main/sounds/alertsound"]))
self.memosound.setSource(QtCore.QUrl.fromLocalFile(self.theme["main/sounds/memosound"]))
self.namesound.setSource(QtCore.QUrl.fromLocalFile("themes/namealarm.wav"))
self.ceasesound.setSource(QtCore.QUrl.fromLocalFile(self.theme["main/sounds/ceasesound"]))
self.honksound.setSource(QtCore.QUrl.fromLocalFile("themes/honk.wav"))
except Exception as err: except Exception as err:
PchumLog.error("Warning: Error loading sounds! ({0!r})".format(err)) PchumLog.error("Warning: Error loading sounds! ({0!r})".format(err))
self.alarm = NoneSound() self.alarm = NoneSound()
@ -2064,25 +2075,24 @@ class PesterWindow(MovingWindow):
self.namesound = NoneSound() self.namesound = NoneSound()
self.ceasesound = NoneSound() self.ceasesound = NoneSound()
self.honksound = NoneSound() self.honksound = NoneSound()
self.sounds = [self.alarm,
self.memosound,
self.namesound,
self.ceasesound,
self.honksound]
def setVolume(self, vol): def setVolume(self, vol_percent):
# TODO: Find a way to make this usable. vol = vol_percent/100.0
for sound in self.sounds:
vol = vol/100.0
# TODO: Make these into an actual (stored) /dict/ later, for easier
# iteration.
sounds = [self.alarm, self.memosound, self.namesound, self.ceasesound,
self.honksound]
for sound in sounds:
try: try:
if pygame and pygame.mixer and \ if 'pygame' in sys.modules:
isinstance(sound, pygame.mixer.Sound):#pygame.mixer.Sound is case sensitive!! if self.sound_type == pygame.mixer.Sound:
sound.set_volume(vol) sound.set_volume(vol)
else: if 'PyQt6.QtMultimedia' in sys.modules:
sound.setVolume(vol) if self.sound_type == QtMultimedia.QSoundEffect:
sound.setVolume(vol)
except Exception as err: except Exception as err:
# Why was this set as "info"? ?w?
PchumLog.warning("Couldn't set volume: {}".format(err)) PchumLog.warning("Couldn't set volume: {}".format(err))
def canSetVolume(self): def canSetVolume(self):
@ -2091,11 +2101,12 @@ class PesterWindow(MovingWindow):
if self.sound_type is None: if self.sound_type is None:
# We haven't initialized yet. # We haven't initialized yet.
return False return False
if pygame and pygame.mixer: elif self.sound_type == NoneSound:
# pygame lets us set the volume, thankfully # Sound is dead
return False
else:
# We can set volume
return True return True
# Aside from that, we don't have any alternatives at the moment.
return False
def changeTheme(self, theme): def changeTheme(self, theme):
# check theme # check theme
@ -3641,34 +3652,15 @@ class MainProgram(QtCore.QObject):
#self.app.setQuitOnLastWindowClosed(False) #self.app.setQuitOnLastWindowClosed(False)
options = self.oppts(sys.argv[1:]) options = self.oppts(sys.argv[1:])
def doSoundInit():
# TODO: Make this more uniform, adapt it into a general function.
if pygame and pygame.mixer:
# we could set the frequency higher but i love how cheesy it sounds
try:
pygame.mixer.init()
pygame.mixer.init()
except pygame.error as err:
print("Warning: No sound! (pygame error: %s)" % err)
else:
# Sound works, we're done.
return
# ... Other alternatives here. ... # If we're using pygame for sound we need to init
if 'pygame' in sys.modules:
# Last resort. (Always 'works' on Windows, no volume control.) # we could set the frequency higher but i love how cheesy it sounds
try:
# QSound.isAvailable is no longer a thing :( pygame.mixer.init()
# Maybe fix. except pygame.error as err:
print("Warning: No sound! (pygame error: %s)" % err)
#if QtMultimedia.QSound.isAvailable():
# # Sound works, we're done.
# return
#else:
# print("Warning: No sound! (No pygame/QSound)")
doSoundInit()
self.widget = PesterWindow(options, parent=self, app=self.app) self.widget = PesterWindow(options, parent=self, app=self.app)
#self.widget.show() <== Already called in showLoading() #self.widget.show() <== Already called in showLoading()

View file

@ -5,7 +5,11 @@ import shutil
import PyInstaller.__main__ import PyInstaller.__main__
is_64bit = sys.maxsize > 2**32 is_64bit = sys.maxsize > 2**32
#is_linux = sys.platform.startswith("linux")
exclude_modules = [] exclude_modules = []
#if is_linux == False:
# print("Not Linux, excluding pygame.")
# exclude_modules.append('pygame')
add_data = ['quirks;quirks', add_data = ['quirks;quirks',
'smilies;smilies', 'smilies;smilies',
'themes;themes', 'themes;themes',
@ -32,8 +36,8 @@ data_files_linux = {'README.md': 'README.md',
# Some of these might not be required anymore, # Some of these might not be required anymore,
# newer versions of PyInstaller claim to exclude certain problematic DDLs automatically. # newer versions of PyInstaller claim to exclude certain problematic DDLs automatically.
upx_exclude = ["qwindows.dll", upx_exclude = ["qwindows.dll",
"Qt5Core.dll", "Qt6Core.dll",
"Qt5Gui.dll", "Qt6Gui.dll",
"vcruntime140.dll", "vcruntime140.dll",
"MSVCP140.dll", "MSVCP140.dll",
"MSVCP140_1.dll" "MSVCP140_1.dll"