QtMultimedia for audio + .pos fix
This commit is contained in:
parent
39aaa1a49f
commit
1419c4985e
5 changed files with 115 additions and 117 deletions
|
@ -83,7 +83,7 @@ Pesterchum is a Python script. This means that as long as you have Python instal
|
|||
### REQUIREMENTS
|
||||
- [Python 3]
|
||||
- [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
|
||||
|
||||
|
@ -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/
|
||||
[PyQt6]: https://pypi.org/project/PyQt6/
|
||||
[pygame]: https://pypi.org/project/pygame/
|
||||
[GStreamer]: https://gstreamer.freedesktop.org/
|
||||
|
||||
## 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
|
||||
|
|
2
convo.py
2
convo.py
|
@ -153,7 +153,7 @@ class PesterTabWindow(QtWidgets.QFrame):
|
|||
|
||||
def contextMenuEvent(self, event):
|
||||
#~if event.reason() == QtGui.QContextMenuEvent.Reason.Mouse:
|
||||
tabi = self.tabs.tabAt(event.position().toPoint())
|
||||
tabi = self.tabs.tabAt(event.pos())
|
||||
if tabi < 0:
|
||||
tabi = self.tabs.currentIndex()
|
||||
for h, i in list(self.tabIndices.items()):
|
||||
|
|
|
@ -45,7 +45,7 @@ class RightClickList(QtWidgets.QListWidget):
|
|||
def contextMenuEvent(self, event):
|
||||
#fuckin Qt <--- I feel that </3
|
||||
if event.reason() == QtGui.QContextMenuEvent.Reason.Mouse:
|
||||
listing = self.itemAt(event.position().toPoint())
|
||||
listing = self.itemAt(event.pos())
|
||||
self.setCurrentItem(listing)
|
||||
optionsMenu = self.getOptionsMenu()
|
||||
if optionsMenu:
|
||||
|
@ -56,7 +56,7 @@ class RightClickList(QtWidgets.QListWidget):
|
|||
class RightClickTree(QtWidgets.QTreeWidget):
|
||||
def contextMenuEvent(self, event):
|
||||
if event.reason() == QtGui.QContextMenuEvent.Reason.Mouse:
|
||||
listing = self.itemAt(event.position().toPoint())
|
||||
listing = self.itemAt(event.pos())
|
||||
self.setCurrentItem(listing)
|
||||
optionsMenu = self.getOptionsMenu()
|
||||
if optionsMenu:
|
||||
|
@ -142,6 +142,7 @@ class NoneSound(object):
|
|||
pass
|
||||
def play(self): pass
|
||||
def setVolume(self, v): pass
|
||||
def set_volume(self, v): pass
|
||||
|
||||
class WMButton(QtWidgets.QPushButton):
|
||||
def __init__(self, icon, parent=None):
|
||||
|
|
214
pesterchum.py
214
pesterchum.py
|
@ -33,53 +33,21 @@ import datetime
|
|||
import random
|
||||
import re
|
||||
import time
|
||||
try:
|
||||
import json
|
||||
except:
|
||||
pass
|
||||
import json
|
||||
from pnc.dep.attrdict import AttrDict
|
||||
|
||||
reqmissing = []
|
||||
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
|
||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||
|
||||
# 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()
|
||||
major = int(vnum[:vnum.find(".")])
|
||||
if vnum.find(".", vnum.find(".")+1) != -1:
|
||||
minor = int(vnum[vnum.find(".")+1:vnum.find(".", vnum.find(".")+1)])
|
||||
else:
|
||||
minor = int(vnum[vnum.find(".")+1:])
|
||||
if not ((major > 5) or (major == 5 and minor >= 0)):
|
||||
logging.critical("ERROR: Pesterchum requires at least Qt version >= 5.0")
|
||||
logging.critical("You currently have version " + vnum + ". Please upgrade Qt.")
|
||||
exit()
|
||||
if (major < 6) or ((major > 6) and (minor < 2)):
|
||||
print("ERROR: Pesterchum requires at least Qt version >= 6.2")
|
||||
print("You currently have version " + str(vnum) + ". Please upgrade Qt.")
|
||||
sys.exit()
|
||||
|
||||
import ostools
|
||||
# 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 randomer import RandomHandler, RANDNICK
|
||||
import nickservmsgs
|
||||
|
||||
# Rawr, fuck you OSX leopard
|
||||
#if not ostools.isOSXLeopard():
|
||||
# from updatecheck import MSPAChecker
|
||||
|
||||
from toast import PesterToastMachine, PesterToast
|
||||
import pytwmn
|
||||
|
||||
#canon_handles = ["apocalypseArisen", "arsenicCatnip", "arachnidsGrip", "adiosToreador", \
|
||||
# "caligulasAquarium", "cuttlefishCuller", "carcinoGeneticist", "centaursTesticle", \
|
||||
# "grimAuxiliatrix", "gallowsCalibrator", "gardenGnostic", "ectoBiologist", \
|
||||
#canon_handles = ["apocalypseArisen", "arsenicCatnip", "arachnidsGrip", "adiosToreador",
|
||||
# "caligulasAquarium", "cuttlefishCuller", "carcinoGeneticist", "centaursTesticle",
|
||||
# "grimAuxiliatrix", "gallowsCalibrator", "gardenGnostic", "ectoBiologist",
|
||||
# "twinArmageddons", "terminallyCapricious", "turntechGodhead", "tentacleTherapist"]
|
||||
#canon_handles = ["",]# Unused, kept to prevent unexpected calls causing a crash.
|
||||
BOTNAMES = []
|
||||
CUSTOMBOTS = ["CALSPRITE", RANDNICK.upper()]
|
||||
SERVICES = ["NICKSERV", "CHANSERV", "MEMOSERV", "OPERSERV", "HELPSERV", "HOSTSERV", "BOTSERV"]
|
||||
|
@ -270,6 +232,34 @@ BOTNAMES.extend(SERVICES)
|
|||
_CONSOLE_ENV = AttrDict()
|
||||
_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):
|
||||
def __init__(self, mainwindow, **msgfuncs):
|
||||
self.mainwindow = mainwindow
|
||||
|
@ -1073,7 +1063,7 @@ class trollSlum(chumArea):
|
|||
def contextMenuEvent(self, event):
|
||||
#fuckin Qt
|
||||
if event.reason() == QtGui.QContextMenuEvent.Reason.Mouse:
|
||||
listing = self.itemAt(event.position().toPoint())
|
||||
listing = self.itemAt(event.pos())
|
||||
self.setCurrentItem(listing)
|
||||
if self.currentItem().text(0) != "":
|
||||
self.optionsMenu.popup(event.globalPos())
|
||||
|
@ -2036,27 +2026,48 @@ class PesterWindow(MovingWindow):
|
|||
def _setup_sounds(self, soundclass=None):
|
||||
"""Set up the event sounds for later use."""
|
||||
# Set up the sounds we're using.
|
||||
|
||||
if soundclass is None:
|
||||
if (pygame and pygame.mixer):
|
||||
# We have pygame, so we may as well use it.
|
||||
soundclass = pygame.mixer.Sound
|
||||
else:
|
||||
PchumLog.warning("Failed to define pygame mixer, is pygame imported?")
|
||||
soundclass = NoneSound
|
||||
if 'pygame' in sys.modules:
|
||||
# Pygame is imported (Linux)
|
||||
soundclass = pygame.mixer.Sound
|
||||
elif 'PyQt6.QtMultimedia' in sys.modules:
|
||||
# QtMultimedia is imported (Windows, MacOS)
|
||||
soundclass = QtMultimedia.QSoundEffect
|
||||
else:
|
||||
# death
|
||||
soundclass = NoneSound
|
||||
PchumLog.warning("No sound module loaded?")
|
||||
|
||||
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.
|
||||
try:
|
||||
# karxi: These all seem to be created using local paths.
|
||||
# Note that if QSound.isAvailable is False, we could still try
|
||||
# to play QSound objects - it'll just fail silently.
|
||||
self.alarm = soundclass(self.theme["main/sounds/alertsound"])
|
||||
self.memosound = soundclass(self.theme["main/sounds/memosound"])
|
||||
self.namesound = soundclass("themes/namealarm.wav")
|
||||
self.ceasesound = soundclass(self.theme["main/sounds/ceasesound"])
|
||||
self.honksound = soundclass("themes/honk.wav")
|
||||
if 'pygame' in sys.modules:
|
||||
if soundclass == pygame.mixer.Sound:
|
||||
self.alarm = soundclass(self.theme["main/sounds/alertsound"])
|
||||
self.memosound = soundclass(self.theme["main/sounds/memosound"])
|
||||
self.namesound = soundclass("themes/namealarm.wav")
|
||||
self.ceasesound = soundclass(self.theme["main/sounds/ceasesound"])
|
||||
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:
|
||||
PchumLog.error("Warning: Error loading sounds! ({0!r})".format(err))
|
||||
self.alarm = NoneSound()
|
||||
|
@ -2064,25 +2075,24 @@ class PesterWindow(MovingWindow):
|
|||
self.namesound = NoneSound()
|
||||
self.ceasesound = NoneSound()
|
||||
self.honksound = NoneSound()
|
||||
|
||||
self.sounds = [self.alarm,
|
||||
self.memosound,
|
||||
self.namesound,
|
||||
self.ceasesound,
|
||||
self.honksound]
|
||||
|
||||
def setVolume(self, vol):
|
||||
# TODO: Find a way to make this usable.
|
||||
|
||||
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:
|
||||
def setVolume(self, vol_percent):
|
||||
vol = vol_percent/100.0
|
||||
for sound in self.sounds:
|
||||
try:
|
||||
if pygame and pygame.mixer and \
|
||||
isinstance(sound, pygame.mixer.Sound):#pygame.mixer.Sound is case sensitive!!
|
||||
sound.set_volume(vol)
|
||||
else:
|
||||
sound.setVolume(vol)
|
||||
if 'pygame' in sys.modules:
|
||||
if self.sound_type == pygame.mixer.Sound:
|
||||
sound.set_volume(vol)
|
||||
if 'PyQt6.QtMultimedia' in sys.modules:
|
||||
if self.sound_type == QtMultimedia.QSoundEffect:
|
||||
sound.setVolume(vol)
|
||||
except Exception as err:
|
||||
# Why was this set as "info"? ?w?
|
||||
PchumLog.warning("Couldn't set volume: {}".format(err))
|
||||
|
||||
def canSetVolume(self):
|
||||
|
@ -2091,11 +2101,12 @@ class PesterWindow(MovingWindow):
|
|||
if self.sound_type is None:
|
||||
# We haven't initialized yet.
|
||||
return False
|
||||
if pygame and pygame.mixer:
|
||||
# pygame lets us set the volume, thankfully
|
||||
elif self.sound_type == NoneSound:
|
||||
# Sound is dead
|
||||
return False
|
||||
else:
|
||||
# We can set volume
|
||||
return True
|
||||
# Aside from that, we don't have any alternatives at the moment.
|
||||
return False
|
||||
|
||||
def changeTheme(self, theme):
|
||||
# check theme
|
||||
|
@ -3641,34 +3652,15 @@ class MainProgram(QtCore.QObject):
|
|||
#self.app.setQuitOnLastWindowClosed(False)
|
||||
|
||||
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. ...
|
||||
|
||||
# Last resort. (Always 'works' on Windows, no volume control.)
|
||||
|
||||
# QSound.isAvailable is no longer a thing :(
|
||||
# Maybe fix.
|
||||
|
||||
#if QtMultimedia.QSound.isAvailable():
|
||||
# # Sound works, we're done.
|
||||
# return
|
||||
#else:
|
||||
# print("Warning: No sound! (No pygame/QSound)")
|
||||
|
||||
doSoundInit()
|
||||
# If we're using pygame for sound we need to init
|
||||
if 'pygame' in sys.modules:
|
||||
# we could set the frequency higher but i love how cheesy it sounds
|
||||
try:
|
||||
pygame.mixer.init()
|
||||
except pygame.error as err:
|
||||
print("Warning: No sound! (pygame error: %s)" % err)
|
||||
|
||||
self.widget = PesterWindow(options, parent=self, app=self.app)
|
||||
#self.widget.show() <== Already called in showLoading()
|
||||
|
||||
|
|
|
@ -5,7 +5,11 @@ import shutil
|
|||
import PyInstaller.__main__
|
||||
|
||||
is_64bit = sys.maxsize > 2**32
|
||||
#is_linux = sys.platform.startswith("linux")
|
||||
exclude_modules = []
|
||||
#if is_linux == False:
|
||||
# print("Not Linux, excluding pygame.")
|
||||
# exclude_modules.append('pygame')
|
||||
add_data = ['quirks;quirks',
|
||||
'smilies;smilies',
|
||||
'themes;themes',
|
||||
|
@ -32,8 +36,8 @@ data_files_linux = {'README.md': 'README.md',
|
|||
# Some of these might not be required anymore,
|
||||
# newer versions of PyInstaller claim to exclude certain problematic DDLs automatically.
|
||||
upx_exclude = ["qwindows.dll",
|
||||
"Qt5Core.dll",
|
||||
"Qt5Gui.dll",
|
||||
"Qt6Core.dll",
|
||||
"Qt6Gui.dll",
|
||||
"vcruntime140.dll",
|
||||
"MSVCP140.dll",
|
||||
"MSVCP140_1.dll"
|
||||
|
|
Loading…
Reference in a new issue