Skip to content

Commit 3b4c850

Browse files
Merge pull request #4 from xXJSONDeruloXx/ini-all
add menu and functions for basically all ini options
2 parents 484f9d5 + 3392082 commit 3b4c850

File tree

2 files changed

+1415
-17
lines changed

2 files changed

+1415
-17
lines changed

main.py

Lines changed: 358 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import subprocess
44
import json
55
import shutil
6+
import re
67
from pathlib import Path
78

89
class Plugin:
@@ -478,3 +479,360 @@ async def set_optiscaler_fgtype(self, fgtype: str) -> dict:
478479
except Exception as e:
479480
decky.logger.error(f"Error setting FGType: {e}")
480481
return {"status": "error", "message": str(e)}
482+
483+
async def get_optiscaler_settings(self, section: str = None) -> dict:
484+
"""
485+
Get current settings from the OptiScaler.ini file.
486+
487+
Args:
488+
section: Optional section name to filter settings
489+
490+
Returns:
491+
Dictionary with settings
492+
"""
493+
try:
494+
ini_path = Path(decky.HOME) / "opti" / "OptiScaler.ini"
495+
496+
if not ini_path.exists():
497+
return {
498+
"status": "error",
499+
"message": "OptiScaler.ini not found",
500+
"settings": {}
501+
}
502+
503+
settings = {}
504+
current_section = None
505+
506+
with open(ini_path, 'r') as f:
507+
for line in f:
508+
line = line.strip()
509+
510+
# Skip comments and empty lines
511+
if not line or line.startswith(';'):
512+
continue
513+
514+
# Check for section headers
515+
if line.startswith('[') and line.endswith(']'):
516+
current_section = line[1:-1]
517+
if current_section not in settings:
518+
settings[current_section] = {}
519+
continue
520+
521+
# Process key-value pairs
522+
if '=' in line and current_section:
523+
key, value = line.split('=', 1)
524+
settings[current_section][key.strip()] = value.strip()
525+
526+
# If a specific section was requested
527+
if section:
528+
if section in settings:
529+
return {
530+
"status": "success",
531+
"settings": settings[section]
532+
}
533+
else:
534+
return {
535+
"status": "error",
536+
"message": f"Section {section} not found",
537+
"settings": {}
538+
}
539+
540+
return {
541+
"status": "success",
542+
"settings": settings
543+
}
544+
545+
except Exception as e:
546+
decky.logger.error(f"Error getting OptiScaler settings: {str(e)}")
547+
return {
548+
"status": "error",
549+
"message": str(e),
550+
"settings": {}
551+
}
552+
553+
async def set_optiscaler_setting(self, section: str, key: str, value: str) -> dict:
554+
"""
555+
Set a specific setting in the OptiScaler.ini file.
556+
557+
Args:
558+
section: Section name in the INI file
559+
key: Setting key
560+
value: New value for the setting
561+
562+
Returns:
563+
Dictionary with status and message
564+
"""
565+
try:
566+
ini_path = Path(decky.HOME) / "opti" / "OptiScaler.ini"
567+
568+
if not ini_path.exists():
569+
return {
570+
"status": "error",
571+
"message": "OptiScaler.ini not found"
572+
}
573+
574+
# Read the entire file
575+
with open(ini_path, 'r') as f:
576+
content = f.read()
577+
578+
# Create a pattern that looks for the key in the specific section
579+
section_pattern = f"\\[{re.escape(section)}\\](.*?)(?=\\[|$)"
580+
section_match = re.search(section_pattern, content, re.DOTALL)
581+
582+
if not section_match:
583+
return {
584+
"status": "error",
585+
"message": f"Section [{section}] not found"
586+
}
587+
588+
section_content = section_match.group(1)
589+
key_pattern = f"^{re.escape(key)}\\s*=.*$"
590+
591+
# Check if the key exists in the section
592+
key_match = re.search(key_pattern, section_content, re.MULTILINE)
593+
594+
if not key_match:
595+
return {
596+
"status": "error",
597+
"message": f"Key {key} not found in section [{section}]"
598+
}
599+
600+
# Replace the key's value
601+
new_line = f"{key}={value}"
602+
updated_section = re.sub(key_pattern, new_line, section_content, flags=re.MULTILINE)
603+
604+
# Replace the old section with the updated one
605+
updated_content = content.replace(section_content, updated_section)
606+
607+
# Write the updated content back to the file
608+
with open(ini_path, 'w') as f:
609+
f.write(updated_content)
610+
611+
decky.logger.info(f"Updated OptiScaler.ini: [{section}] {key}={value}")
612+
return {
613+
"status": "success",
614+
"message": f"Setting updated: [{section}] {key}={value}"
615+
}
616+
617+
except Exception as e:
618+
decky.logger.error(f"Error setting OptiScaler setting: {str(e)}")
619+
return {
620+
"status": "error",
621+
"message": str(e)
622+
}
623+
624+
async def set_upscaler_type(self, upscaler_type: str, value: str) -> dict:
625+
"""
626+
Set the upscaler type for a specific API.
627+
628+
Args:
629+
upscaler_type: 'Dx11Upscaler', 'Dx12Upscaler', or 'VulkanUpscaler'
630+
value: The upscaler value to set (e.g., 'auto', 'fsr22', 'xess', etc.)
631+
632+
Returns:
633+
Dictionary with status and message
634+
"""
635+
valid_types = ["Dx11Upscaler", "Dx12Upscaler", "VulkanUpscaler"]
636+
if upscaler_type not in valid_types:
637+
return {
638+
"status": "error",
639+
"message": f"Invalid upscaler type: {upscaler_type}"
640+
}
641+
642+
return await self.set_optiscaler_setting("Upscalers", upscaler_type, value)
643+
644+
async def set_optifg_settings(self, settings: dict) -> dict:
645+
"""
646+
Update multiple OptiFG settings at once.
647+
648+
Args:
649+
settings: Dictionary of settings to update in the [OptiFG] section
650+
651+
Returns:
652+
Dictionary with status and message
653+
"""
654+
try:
655+
results = []
656+
section = "OptiFG"
657+
658+
for key, value in settings.items():
659+
result = await self.set_optiscaler_setting(section, key, str(value))
660+
results.append(result)
661+
662+
# Check if any errors occurred
663+
errors = [r for r in results if r["status"] == "error"]
664+
if errors:
665+
return {
666+
"status": "partial_success",
667+
"message": f"Updated {len(results) - len(errors)} settings, {len(errors)} failed",
668+
"details": errors
669+
}
670+
671+
return {
672+
"status": "success",
673+
"message": f"Updated {len(results)} OptiFG settings"
674+
}
675+
676+
except Exception as e:
677+
decky.logger.error(f"Error setting OptiFG settings: {str(e)}")
678+
return {
679+
"status": "error",
680+
"message": str(e)
681+
}
682+
683+
async def set_framerate_limit(self, limit: str) -> dict:
684+
"""
685+
Set the framerate limit in the OptiScaler.ini.
686+
687+
Args:
688+
limit: The framerate limit value (e.g., 'auto', '60.0', etc.)
689+
690+
Returns:
691+
Dictionary with status and message
692+
"""
693+
return await self.set_optiscaler_setting("Framerate", "FramerateLimit", limit)
694+
695+
async def set_quality_ratio_override(self, enabled: bool, ratios: dict = None) -> dict:
696+
"""
697+
Set the quality ratio override settings.
698+
699+
Args:
700+
enabled: Whether to enable quality ratio overrides
701+
ratios: Optional dictionary with quality mode ratios
702+
703+
Returns:
704+
Dictionary with status and message
705+
"""
706+
try:
707+
results = []
708+
709+
# First, enable/disable the override
710+
enabled_result = await self.set_optiscaler_setting(
711+
"QualityOverrides",
712+
"QualityRatioOverrideEnabled",
713+
"true" if enabled else "false"
714+
)
715+
results.append(enabled_result)
716+
717+
# If ratios are provided and enabled is True, update each ratio
718+
if enabled and ratios:
719+
for mode, ratio in ratios.items():
720+
key_name = f"QualityRatio{mode}"
721+
ratio_result = await self.set_optiscaler_setting(
722+
"QualityOverrides",
723+
key_name,
724+
str(ratio)
725+
)
726+
results.append(ratio_result)
727+
728+
# Check if any errors occurred
729+
errors = [r for r in results if r["status"] == "error"]
730+
if errors:
731+
return {
732+
"status": "partial_success",
733+
"message": f"Updated {len(results) - len(errors)} settings, {len(errors)} failed",
734+
"details": errors
735+
}
736+
737+
return {
738+
"status": "success",
739+
"message": f"Updated quality ratio override settings"
740+
}
741+
742+
except Exception as e:
743+
decky.logger.error(f"Error setting quality ratio override: {str(e)}")
744+
return {
745+
"status": "error",
746+
"message": str(e)
747+
}
748+
749+
async def set_menu_settings(self, settings: dict) -> dict:
750+
"""
751+
Update multiple Menu settings at once.
752+
753+
Args:
754+
settings: Dictionary of settings to update in the [Menu] section
755+
756+
Returns:
757+
Dictionary with status and message
758+
"""
759+
try:
760+
results = []
761+
section = "Menu"
762+
763+
for key, value in settings.items():
764+
result = await self.set_optiscaler_setting(section, key, str(value))
765+
results.append(result)
766+
767+
# Check if any errors occurred
768+
errors = [r for r in results if r["status"] == "error"]
769+
if errors:
770+
return {
771+
"status": "partial_success",
772+
"message": f"Updated {len(results) - len(errors)} settings, {len(errors)} failed",
773+
"details": errors
774+
}
775+
776+
return {
777+
"status": "success",
778+
"message": f"Updated {len(results)} Menu settings"
779+
}
780+
781+
except Exception as e:
782+
decky.logger.error(f"Error setting Menu settings: {str(e)}")
783+
return {
784+
"status": "error",
785+
"message": str(e)
786+
}
787+
788+
async def set_upscale_ratio_override(self, enabled: bool, value: str = None) -> dict:
789+
"""
790+
Set the upscale ratio override settings.
791+
792+
Args:
793+
enabled: Whether to enable upscale ratio override
794+
value: Optional value for the override
795+
796+
Returns:
797+
Dictionary with status and message
798+
"""
799+
try:
800+
results = []
801+
802+
# First, enable/disable the override
803+
enabled_result = await self.set_optiscaler_setting(
804+
"UpscaleRatio",
805+
"UpscaleRatioOverrideEnabled",
806+
"true" if enabled else "false"
807+
)
808+
results.append(enabled_result)
809+
810+
# If value is provided and enabled is True, update the value
811+
if enabled and value:
812+
value_result = await self.set_optiscaler_setting(
813+
"UpscaleRatio",
814+
"UpscaleRatioOverrideValue",
815+
value
816+
)
817+
results.append(value_result)
818+
819+
# Check if any errors occurred
820+
errors = [r for r in results if r["status"] == "error"]
821+
if errors:
822+
return {
823+
"status": "partial_success",
824+
"message": f"Updated {len(results) - len(errors)} settings, {len(errors)} failed",
825+
"details": errors
826+
}
827+
828+
return {
829+
"status": "success",
830+
"message": f"Updated upscale ratio override settings"
831+
}
832+
833+
except Exception as e:
834+
decky.logger.error(f"Error setting upscale ratio override: {str(e)}")
835+
return {
836+
"status": "error",
837+
"message": str(e)
838+
}

0 commit comments

Comments
 (0)