3 Commits

+159 -47
View File
@@ -126,26 +126,28 @@ if platform.system() == "Windows":
print(f"Failed to initialize accessible_output2: {e}") print(f"Failed to initialize accessible_output2: {e}")
sys.exit() sys.exit()
else: else:
# Linux/Mac path - prioritize Orca remote controller # Linux/Mac path - prioritize speech-dispatcher first
orca_remote = OrcaRemoteController() try:
if orca_remote.available: import speechd
speechProvider = "orca_remote" spd = speechd.Client()
orca = orca_remote speechProvider = "speechd"
else: except ImportError:
try: # Fall back to Orca remote controller
output = subprocess.check_output(["pgrep", "cthulhu"]) orca_remote = OrcaRemoteController()
speechProvider = "cthulhu" if orca_remote.available:
except (subprocess.CalledProcessError, FileNotFoundError): speechProvider = "orca_remote"
orca = orca_remote
else:
# Fall back to Cthulhu
try: try:
import accessible_output2.outputs.auto output = subprocess.check_output(["pgrep", "cthulhu"])
s = accessible_output2.outputs.auto.Auto() speechProvider = "cthulhu"
speechProvider = "accessible_output2" except (subprocess.CalledProcessError, FileNotFoundError):
except ImportError as e:
try: try:
import speechd import accessible_output2.outputs.auto
spd = speechd.Client() s = accessible_output2.outputs.auto.Auto()
speechProvider = "speechd" speechProvider = "accessible_output2"
except ImportError: except ImportError as e:
print("No speech providers found.") print("No speech providers found.")
sys.exit() sys.exit()
@@ -1526,12 +1528,35 @@ class DoomLauncher(QMainWindow):
if fullPath.exists(): if fullPath.exists():
gameFiles.append(str(fullPath)) gameFiles.append(str(fullPath))
# Add optional files last (only first one found, for priority) # Add music files with custom music mod priority
for optFile in config.get('optional_files', []): optional_files = config.get('optional_files', [])
optPath = self.gamePath / optFile music_added = False
if optPath.exists():
gameFiles.append(str(optPath)) # Check if any optional files are music-related (contain metal/music keywords)
break # Only add the first optional file found has_music_optionals = any('metal' in opt.lower() or 'music' in opt.lower() for opt in optional_files)
if has_music_optionals:
# First try to find custom music mod (highest priority)
customMusicMod = self.find_custom_music_mod()
if customMusicMod:
gameFiles.append(str(customMusicMod))
music_added = True
else:
# Fall back to standard optional files priority
for optFile in optional_files:
optPath = self.gamePath / optFile
if optPath.exists():
gameFiles.append(str(optPath))
music_added = True
break
# Add any remaining non-music optional files
if not music_added:
for optFile in optional_files:
optPath = self.gamePath / optFile
if optPath.exists():
gameFiles.append(str(optPath))
break # Only add the first optional file found
# Get any custom flags # Get any custom flags
gameFlags = config.get('flags', []) gameFlags = config.get('flags', [])
@@ -1938,7 +1963,14 @@ class DoomLauncher(QMainWindow):
except ImportError: except ImportError:
pass pass
else: else:
# On Linux, check each provider # On Linux, check each provider in priority order
# Check speechd first (highest priority)
try:
import speechd
available_providers.append("speechd")
except ImportError:
pass
# Check Orca remote controller # Check Orca remote controller
orca_remote = OrcaRemoteController() orca_remote = OrcaRemoteController()
if orca_remote.available: if orca_remote.available:
@@ -1958,13 +1990,6 @@ class DoomLauncher(QMainWindow):
except ImportError: except ImportError:
pass pass
# Check speechd
try:
import speechd
available_providers.append("speechd")
except ImportError:
pass
return available_providers return available_providers
def populate_speech_methods(self): def populate_speech_methods(self):
@@ -2081,6 +2106,64 @@ class DoomLauncher(QMainWindow):
return shutil.which("gzdoom") return shutil.which("gzdoom")
def find_custom_music_mod(self):
"""Find custom music mod files with flexible pattern matching.
Looks for files containing "Custom Music Mod" in sequence anywhere in the filename.
Supports variations like:
- Custom Music Mod
- Custom_Music_Mod
- CustomMusicMod
Returns the first matching file found (.pk3 files prioritized), or None if no match exists.
"""
if not self.gamePath.exists():
return None
# Define the sequence patterns to look for (case-insensitive)
sequence_patterns = [
["custom", "music", "mod"], # spaces or any separators
["custom_music_mod"], # underscores as single token
["custommusicmod"] # no separators
]
# Check for .pk3 files first (higher priority), then .wad
for extension in [".pk3", ".wad"]:
for file_path in self.gamePath.iterdir():
if file_path.is_file() and file_path.suffix.lower() == extension:
filename_lower = file_path.name.lower()
# Check each sequence pattern
for pattern_sequence in sequence_patterns:
if self._contains_sequence(filename_lower, pattern_sequence):
return file_path
return None
def _contains_sequence(self, text, sequence):
"""Check if text contains all words in sequence in order.
Args:
text: The text to search in (already lowercase)
sequence: List of words that must appear in order
Returns:
True if all words in sequence are found in order, False otherwise
"""
if len(sequence) == 1:
# Single token match (like "custommusicmod")
return sequence[0] in text
# Multi-word sequence match
current_pos = 0
for word in sequence:
pos = text.find(word, current_pos)
if pos == -1:
return False
current_pos = pos + len(word)
return True
def get_addon_files(self, game_type: str = "DOOM", use_funny_pack: bool = False) -> List[str]: def get_addon_files(self, game_type: str = "DOOM", use_funny_pack: bool = False) -> List[str]:
"""Get all addon PK3 files for specified game type """Get all addon PK3 files for specified game type
@@ -2204,15 +2287,21 @@ class DoomLauncher(QMainWindow):
# Add music files at the end for Doom games # Add music files at the end for Doom games
if gameType == "DOOM" and not isFunnyPack: if gameType == "DOOM" and not isFunnyPack:
metalV10 = self.gamePath / "DOOM Metal X IDKFA Soundtrack.pk3" # First check for custom music mod patterns (highest priority)
metalV7 = self.gamePath / "DoomMetalVol7.wad" customMusicMod = self.find_custom_music_mod()
metalV6 = self.gamePath / "DoomMetalVol6.wad" if customMusicMod:
if metalV10.exists(): baseFiles.append(str(customMusicMod))
baseFiles.append(str(metalV10)) else:
elif metalV7.exists(): # Fall back to standard metal mod detection
baseFiles.append(str(metalV7)) metalV10 = self.gamePath / "DOOM Metal X IDKFA Soundtrack.pk3"
elif metalV6.exists(): metalV7 = self.gamePath / "DoomMetalVol7.wad"
baseFiles.append(str(metalV6)) metalV6 = self.gamePath / "DoomMetalVol6.wad"
if metalV10.exists():
baseFiles.append(str(metalV10))
elif metalV7.exists():
baseFiles.append(str(metalV7))
elif metalV6.exists():
baseFiles.append(str(metalV6))
if "Toby Doom" in selectedGame: if "Toby Doom" in selectedGame:
musicRenamer = self.gamePath / "Toby-Doom-Level-Music-Renamer.pk3" musicRenamer = self.gamePath / "Toby-Doom-Level-Music-Renamer.pk3"
@@ -2546,12 +2635,35 @@ class DoomLauncher(QMainWindow):
if fullPath.exists(): if fullPath.exists():
gameFiles.append(str(fullPath)) gameFiles.append(str(fullPath))
# Add optional files last (only first one found, for priority) # Add music files with custom music mod priority
for optFile in config.get('optional_files', []): optional_files = config.get('optional_files', [])
optPath = self.gamePath / optFile music_added = False
if optPath.exists():
gameFiles.append(str(optPath)) # Check if any optional files are music-related (contain metal/music keywords)
break # Only add the first optional file found has_music_optionals = any('metal' in opt.lower() or 'music' in opt.lower() for opt in optional_files)
if has_music_optionals:
# First try to find custom music mod (highest priority)
customMusicMod = self.find_custom_music_mod()
if customMusicMod:
gameFiles.append(str(customMusicMod))
music_added = True
else:
# Fall back to standard optional files priority
for optFile in optional_files:
optPath = self.gamePath / optFile
if optPath.exists():
gameFiles.append(str(optPath))
music_added = True
break
# Add any remaining non-music optional files
if not music_added:
for optFile in optional_files:
optPath = self.gamePath / optFile
if optPath.exists():
gameFiles.append(str(optPath))
break # Only add the first optional file found
# Get any custom flags # Get any custom flags
gameFlags = config.get('flags', []) gameFlags = config.get('flags', [])