### Theme Management and Installation with Python Source: https://context7.com/steamclienthomebrew/millennium/llms.txt Python classes for managing themes. `ThemeManager` includes methods to load theme data (CSS and JSON configuration) from local directories and install themes by downloading them from a URL. Dependencies include 'requests' for HTTP calls and 'pathlib' for file system operations. Handles theme files, configuration, and directory creation. ```python # Python theme management example (assets/core/themes/) import json import os from pathlib import Path import requests class ThemeManager: def __init__(self): # Assuming MILLENNIUM__THEMES_PATH is set in environment variables self.themes_base_path = Path(os.environ.get("MILLENNIUM__THEMES_PATH", ".themes")) def _get_theme_path(self, theme_name: str) -> Path: """Helper to get the path for a specific theme.""" return self.themes_base_path / theme_name def get_theme_data(self, theme_name: str): """Load theme CSS and configuration from local directory.""" theme_path = self._get_theme_path(theme_name) css_file = theme_path / "style.css" config_file = theme_path / "theme.json" css_content = "" if css_file.exists(): try: with open(css_file, 'r', encoding='utf-8') as f: css_content = f.read() except Exception as e: print(f"Error reading CSS file for theme {theme_name}: {e}") config = {{}} if config_file.exists(): try: with open(config_file, 'r', encoding='utf-8') as f: config = json.load(f) except Exception as e: print(f"Error reading config file for theme {theme_name}: {e}") return { "name": theme_name, "css": css_content, "patches": config.get("Patches", {{}}), "dependencies": config.get("Dependencies", []) } def install_theme(self, theme_url: str): """Download and install theme from URL.""" try: response = requests.get(theme_url) response.raise_for_status() # Raise HTTPError for bad responses (4xx or 5xx) theme_data = response.json() except requests.exceptions.RequestException as e: print(f"Error downloading theme from {theme_url}: {e}") return {"success": False, "error": str(e)} except json.JSONDecodeError as e: print(f"Error decoding JSON from {theme_url}: {e}") return {"success": False, "error": "Invalid JSON received."} theme_name = theme_data.get("name", "unknown_theme") theme_dir = self.themes_base_path / theme_name try: theme_dir.mkdir(parents=True, exist_ok=True) except OSError as e: print(f"Error creating theme directory {theme_dir}: {e}") return {"success": False, "error": str(e)} # Download CSS files for css_file_info in theme_data.get("files", []): file_url = css_file_info.get("url") file_name = css_file_info.get("name") if file_url and file_name: try: file_response = requests.get(file_url) file_response.raise_for_status() (theme_dir / file_name).write_bytes(file_response.content) except requests.exceptions.RequestException as e: print(f"Error downloading file {file_url}: {e}") # Decide if you want to stop or continue on file download error except OSError as e: print(f"Error writing file {(theme_dir / file_name)}: {e}") # Write configuration try: (theme_dir / "theme.json").write_text(json.dumps(theme_data, indent=2)) except OSError as e: print(f"Error writing config file to {theme_dir}: {e}") return {"success": False, "error": str(e)} return {"success": True, "theme": theme_name} ``` -------------------------------- ### Build Millennium from Source (PowerShell) Source: https://github.com/steamclienthomebrew/millennium/wiki/Platform-Support This PowerShell script demonstrates how to clone the Millennium repository recursively, navigate into the directory, and then use CMake and Make to build the project. It requires Git, CMake, and Make to be installed and accessible in the system's PATH. ```powershell git clone --recursive https://github.com/SteamClientHomebrew/Millennium.git cd Millennium cmake -B build cd build make ``` -------------------------------- ### Build Millennium Assets using npm Source: https://github.com/steamclienthomebrew/millennium/blob/main/assets/README.md This code snippet demonstrates the steps to clone the Millennium repository, navigate to the assets directory, install dependencies, and run the development build process using npm. It's essential for setting up a local development environment. ```bash git clone https://github.com/SteamClientHomebrew/Millennium.git cd Millennium/assets npm install npm run dev ``` -------------------------------- ### Python Plugin with Millennium API Source: https://context7.com/steamclienthomebrew/millennium/llms.txt Example Python plugin demonstrating advanced usage of the Millennium API. It shows how to access Steam paths, configuration, and interact with the Steam client through provided functions. ```python # Python plugin with advanced Millennium API usage import Millennium from config.manager import get_config class Plugin: def _load(self): # Access Steam installation path steam_path = Millennium.steam_path() install_path = Millennium.get_install_path() version = Millennium.version() print(f"Steam at: {steam_path}") print(f"Millennium {version} installed at: {install_path}") # Use configuration manager self.config = get_config() self.config.add_listener(self._on_config_change) accent_color = self.config.get("general.accentColor", "#1B2838") print(f"Current accent color: {accent_color}") Millennium.ready() def _on_config_change(self, key, old_value, new_value): """Called when any configuration value changes""" print(f"Config changed: {key} = {new_value}") def execute_javascript(self, js_code): """Execute JavaScript in Steam's browser context""" result = Millennium.execute_js(js_code) return {"result": result} def get_system_info(self): """Example method returning comprehensive system data""" from util.ipc_functions import GetOperatingSystem, GetEnvironmentVar return { "os": GetOperatingSystem(), # 0=Windows, 1=POSIX "steam_path": Millennium.steam_path(), "python_version": GetEnvironmentVar("MILLENNIUM__PYTHON_ENV"), "config_path": GetEnvironmentVar("MILLENNIUM__CONFIG_PATH") } ``` -------------------------------- ### CMake Project Setup and Dependencies Source: https://github.com/steamclienthomebrew/millennium/blob/main/preload/CMakeLists.txt Configures the basic CMake project settings, including minimum version, shared library build option, C++ standard, and finds required packages like CURL and minizip. It also defines preprocessor macros. ```cmake cmake_minimum_required(VERSION 3.10) set(BUILD_SHARED_LIBS OFF) if(WIN32 AND CMAKE_BUILD_TYPE STREQUAL "Release") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -s") set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS OFF) endif() project(preload) include_directories( ${CMAKE_SOURCE_DIR}/preload/include ${CMAKE_SOURCE_DIR}/include ) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED True) if(WIN32 AND NOT GITHUB_ACTION_BUILD) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "C:/Program Files (x86)/Steam") set(LIBRARY_OUTPUT_DIRECTORY "C:/Program Files (x86)/Steam") elseif(UNIX AND NOT GITHUB_ACTION_BUILD) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "$ENV{HOME}/.millennium/") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "$ENV{HOME}/.millennium/") endif() find_package(CURL REQUIRED) find_package(unofficial-minizip CONFIG REQUIRED) add_compile_definitions( CURL_STATICLIB ) ``` -------------------------------- ### Millennium Theme `skin.json` Boilerplate Example Source: https://github.com/steamclienthomebrew/millennium/wiki/Creating-Themes This JSON object serves as a boilerplate for a Millennium theme's `skin.json` file. It includes essential properties for defining CSS/JS patches, theme metadata, and deployment information, along with optional fields for customization. ```json { "Steam-WebKit": "path/to/webkit.css", "Patches": [ { "MatchRegexString": ".*http.*steam.*", "TargetJs": "path/to/webkit.js" }, { "MatchRegexString": "^Steam$", "TargetCss": "steam.css", "TargetJs": "steam.js" } ], "UseDefaultPatches": true, "author": "xxx", "description": "xxx", "name": "length <= 10", "version": "1.0.0", "github": { "owner": "xxx", "repo_name": "xxx" }, "discord_support": { "inviteCodeExcludingLink": "xxx" }, "tags": [ "a", "b" ], "header_image": "http://site.com/path/to/thumbnail.png", "splash_image": "http://site.com/path/to/thumbnail.png" } ``` -------------------------------- ### Detect and Configure AUR Helper for Arch Linux (CMake) Source: https://github.com/steamclienthomebrew/millennium/blob/main/CMakeLists.txt This CMake snippet detects the presence of common AUR helpers on an Arch-based system and sets a variable for the detected helper and its update command. It falls back to plain pacman if no AUR helper is found, with a note that pacman cannot directly install AUR packages. ```cmake # Function to check if a program exists in PATH function(check_program_exists program_name result_var) find_program(${program_name}_EXECUTABLE ${program_name}) if(${program_name}_EXECUTABLE) set(${result_var} TRUE PARENT_SCOPE) else() set(${result_var} FALSE PARENT_SCOPE) endif() endfunction() # List of common AUR helpers with their update command syntax for "millennium" package set(AUR_HELPERS "yay" "paru" "aurman" "pikaur" "pamac" "trizen" "pacaur" "aura" ) # Map AUR helpers to their respective update commands set(yay_UPDATE_COMMAND "yay -Syu millennium") set(paru_UPDATE_COMMAND "paru -Syu millennium") set(aurman_UPDATE_COMMAND "aurman -Syu millennium") set(pikaur_UPDATE_COMMAND "pikaur -Syu millennium") set(pamac_UPDATE_COMMAND "pamac upgrade millennium") set(trizen_UPDATE_COMMAND "trizen -Syu millennium") set(pacaur_UPDATE_COMMAND "pacaur -Syu millennium") set(aura_UPDATE_COMMAND "aura -Ayu millennium") # Default fallback for plain pacman (though it won't work for AUR packages directly) set(pacman_UPDATE_COMMAND "sudo pacman -Syu millennium") find_program(PACMAN_EXECUTABLE pacman) if(NOT PACMAN_EXECUTABLE) message(STATUS "Not running on an Arch-based system (pacman not found)") set(AUR_HELPER "none") set(UPDATE_COMMAND "") else() message(STATUS "Arch-based system detected") set(AUR_HELPER "none") foreach(helper ${AUR_HELPERS}) check_program_exists(${helper} HAS_${helper}) if(HAS_${helper}) set(AUR_HELPER ${helper}) set(UPDATE_COMMAND ${${helper}_UPDATE_COMMAND}) break() endif() endforeach() if(AUR_HELPER STREQUAL "none") message(STATUS "No AUR helper found. User likely uses plain pacman.") message(STATUS "Note: Plain pacman cannot directly install AUR packages.") set(UPDATE_COMMAND ${pacman_UPDATE_COMMAND}) message(STATUS "Fallback command: ${UPDATE_COMMAND}") else() message(STATUS "AUR helper found: ${AUR_HELPER}") message(STATUS "Update command: ${UPDATE_COMMAND}") endif() endif() set(AUR_HELPER ${AUR_HELPER} CACHE STRING "Detected AUR helper") set(UPDATE_COMMAND ${UPDATE_COMMAND} CACHE STRING "Command to update millennium package") ) endif() endif() endmacro() ``` -------------------------------- ### Determine Steam Path on Windows and Set Output Directories (CMake) Source: https://github.com/steamclienthomebrew/millennium/blob/main/CMakeLists.txt This CMake code determines the Steam installation path on Windows when not running in a GitHub Action build. It uses the 'reg query' command to read the Steam path from the Windows registry and sets the CMAKE_RUNTIME_OUTPUT_DIRECTORY and LIBRARY_OUTPUT_DIRECTORY to this path. It includes error handling for registry read failures. ```cmake if(WIN32 AND NOT GITHUB_ACTION_BUILD) execute_process( COMMAND reg query "HKCU\Software\Valve\Steam" /v "SteamPath" RESULT_VARIABLE result OUTPUT_VARIABLE steam_path ERROR_VARIABLE reg_error ) if(result EQUAL 0) string(REGEX MATCH "[a-zA-Z]:/[^ ]+([ ]+[^ ]+)*" extracted_path "${steam_path}") string(REPLACE "\n" "" extracted_path "${extracted_path}") message(STATUS "Build Steam Path: ${extracted_path}") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${extracted_path}) set(LIBRARY_OUTPUT_DIRECTORY ${extracted_path}) else() message(WARNING "Failed to read Steam installation path from HKCU\Software\Valve\Steam.") endif() endif() ``` -------------------------------- ### Include Python Headers for Windows and Unix-like Systems (CMake) Source: https://github.com/steamclienthomebrew/millennium/blob/main/CMakeLists.txt This snippet configures the include directories for Python headers based on the operating system. For Windows, it uses a specified path. For Unix-like systems, it checks for macOS and then proceeds to find Python installations. ```cmake if(WIN32) include_directories(${CMAKE_SOURCE_DIR}/vendor/python/win32) elseif(UNIX) if(APPLE) include_directories("$ENV{HOME}/.pyenv/versions/3.11.8/include/python3.11") set(MILLENNIUM__PYTHON_ENV "$ENV{HOME}/.pyenv/versions/3.11.8") set(LIBPYTHON_RUNTIME_PATH "$ENV{HOME}/.pyenv/versions/3.11.8/lib/libpython3.11.dylib") else() if(NIX_BUILD) add_compile_definitions(_NIX_OS=ON) add_compile_definitions(__NIX_SELF_PATH="$ENV{out}") add_compile_definitions(__NIX_SHIMS_PATH="$ENV{shims}") add_compile_definitions(__NIX_ASSETS_PATH="$ENV{assets}") endif() # Try to find required version of Python # Python guarantee to have API and ABI compatible within a same major and minor versions # Harden version range to to find only 3.11 python find_package(Python 3.11 EXACT COMPONENTS Development) if(PYTHON_FOUND) # Run simple test to check if python is working with current flags try_compile(PYTHON_TEST_RESULT "${CMAKE_BINARY_DIR}" SOURCES "${CMAKE_CURRENT_LIST_DIR}/tests/FindPython_test.cc" LINK_LIBRARIES Python::Module) if(PYTHON_TEST_RESULT) message(STATUS "Found suitable Python version ${Python_VERSION}") set(LIBPYTHON_RUNTIME_PATH ${Python_LIBRARIES}) if(NOT Python_ROOT_DIR) cmake_path(GET Python_LIBRARY_DIRS PARENT_PATH Python_ROOT_DIR) endif() set(MILLENNIUM__PYTHON_ENV ${Python_ROOT_DIR}) else() message(STATUS "Python ABI mismatch, rolling back to default one") endif() else() # Use this var to check if the package been found and it's 32bit set(PYTHON_TEST_RESULT FALSE) message(STATUS "No Python package found, rolling back to default one") endif() if(NOT ${PYTHON_TEST_RESULT}) set(MILLENNIUM__PYTHON_ENV "/opt/python-i686-3.11.8") set(LIBPYTHON_RUNTIME_PATH "/opt/python-i686-3.11.8/lib/libpython-3.11.8.so") if(DISTRO_ARCH OR LSB_RELEASE_ID_SHORT STREQUAL "Arch") include_directories("/opt/python-i686-3.11.8/include/python3.11/") ``` -------------------------------- ### Get LSB Release ID Source: https://github.com/steamclienthomebrew/millennium/blob/main/CMakeLists.txt Finds the 'lsb_release' command and executes it to get the Linux Standard Base (LSB) release ID. This information is stored in the LSB_RELEASE_ID_SHORT variable and printed as a status message. ```cmake find_program(LSB_RELEASE_EXEC lsb_release) execute_process(COMMAND ${LSB_RELEASE_EXEC} -is OUTPUT_VARIABLE LSB_RELEASE_ID_SHORT OUTPUT_STRIP_TRAILING_WHITESPACE ) message(STATUS "LSB Release ID: ${LSB_RELEASE_ID_SHORT}") ``` -------------------------------- ### Core Plugin Loader Logic (C++) Source: https://context7.com/steamclienthomebrew/millennium/llms.txt Illustrates the core plugin loading mechanism within the Millennium C++ framework. It demonstrates initializing settings, parsing plugin configurations, and managing the startup of backend components. This code is central to how the framework discovers and prepares plugins for execution. ```cpp // Core plugin loading flow in C++ (loader.cc) class PluginLoader { public: PluginLoader(std::chrono::system_clock::time_point startTime) { m_settingsStorePtr = std::make_unique(); m_pluginsPtr = std::make_shared>( m_settingsStorePtr->ParseAllPlugins() ); } const void StartBackEnds(PythonManager& manager) { for (auto& plugin : m_settingsStorePtr->GetEnabledBackends()) { m_threadPool.emplace_back([&manager, plugin]() mutable { manager.CreatePythonInstance(plugin, [](auto msg) { Logger.Log(msg); }); }); } } }; // Plugin schema structure struct PluginTypeSchema { std::string pluginName; nlohmann::basic_json<> pluginJson; std::filesystem::path pluginBaseDirectory; std::filesystem::path backendAbsoluteDirectory; std::filesystem::path frontendAbsoluteDirectory; bool isInternal; }; ``` -------------------------------- ### Get Git Commit Hash Source: https://github.com/steamclienthomebrew/millennium/blob/main/CMakeLists.txt Executes the 'git rev-parse HEAD' command to retrieve the current Git commit hash. This hash is then stored in the GIT_COMMIT_HASH variable and defined as a preprocessor macro for use in the C++ code. ```cmake execute_process( COMMAND git rev-parse HEAD WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_COMMIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE ) # Define it as a preprocessor macro add_compile_definitions(GIT_COMMIT_HASH="${GIT_COMMIT_HASH}") message(STATUS "Git commit hash: ${GIT_COMMIT_HASH}") ``` -------------------------------- ### Initialize Millennium and Handle Steam Window Events (TypeScript/React) Source: https://context7.com/steamclienthomebrew/millennium/llms.txt This snippet shows the main entry point for the Millennium frontend plugin. It initializes the framework with backend configuration, hooks into new Steam window creations to log messages and potentially inject UI, and registers a custom route for settings. It also demonstrates calling a backend method to fetch user data. ```typescript // Frontend entry point (assets/src/index.tsx) import { initializeMillennium, Millennium } from './Millennium'; import { MillenniumSettings } from './components/MillenniumSettings'; export default async function PluginMain() { // Initialize framework with backend configuration const startupConfig = await PyGetStartupConfig(); await initializeMillennium(JSON.parse(startupConfig)); // Hook into Steam window creation Millennium.AddWindowCreateHook((window: any) => { console.log('New Steam window created:', window.title); // Inject custom UI components }); // Register custom settings page routerHook.addRoute('/millennium/settings', () => ); } // Plugin frontend calling Python backend async function fetchUserData(userId: string) { try { const result = await Millennium.CallFrontendMethod( 'my-steam-plugin', 'get_user_stats', userId, '570' // Dota 2 app ID ); if (result.success) { console.log('User stats:', result.data); return result.data; } } catch (error) { console.error('IPC call failed:', error); return null; } } // React component using Millennium APIs import { DOMModifier } from './utils/Dispatch'; function CustomThemeComponent() { const applyCustomStyles = () => { const customCSS = ` .Steam_AppDetails { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); } .game_page_background { backdrop-filter: blur(10px); } `; DOMModifier.AddStyleSheetFromText(document, customCSS, 'my-custom-theme'); }; return ( ); } ``` -------------------------------- ### Get Current Steam Page URL (Python) Source: https://context7.com/steamclienthomebrew/millennium/llms.txt Retrieves the URL of the currently displayed page within the Steam client. It utilizes the execute_js function to run JavaScript's `window.location.href`. Returns the URL as a string. ```python def get_current_page_url() -> str: """Get current Steam page URL""" return execute_js("window.location.href") ``` -------------------------------- ### Singleton Configuration Manager Implementation in Python Source: https://context7.com/steamclienthomebrew/millennium/llms.txt Implements a thread-safe singleton configuration manager. It handles loading settings from a JSON file, saving changes, retrieving values using dot notation, and notifying listeners of modifications. Dependencies include `json`, `threading`, `pathlib`, `os`, and `typing`. It uses environment variables for the config path and expects a 'config.json' file. ```python import json import threading import os from pathlib import Path from typing import Any, Callable, Optional # Assuming logger is defined elsewhere, e.g.: class Logger: def error(self, msg): print(f"ERROR: {msg}") logger = Logger() class ConfigManager: _instance = None _lock = threading.Lock() def __new__(cls): if cls._instance is None: with cls._lock: if cls._instance is None: cls._instance = super().__new__(cls) cls._instance._initialized = False return cls._instance def __init__(self): if self._initialized: return self._config_path = Path(os.environ.get("MILLENNIUM__CONFIG_PATH", ".")) / "config.json" self._data = {} self._listeners = [] self._lock = threading.RLock() self._load() self._initialized = True def _load(self): """Load configuration from disk""" if self._config_path.exists(): try: with open(self._config_path, 'r') as f: self._data = json.load(f) except json.JSONDecodeError: logger.error(f"Failed to decode JSON from {self._config_path}. Using defaults.") self._data = self._get_defaults() self._save() else: self._data = self._get_defaults() self._save() def _save(self): """Persist configuration to disk""" try: self._config_path.parent.mkdir(parents=True, exist_ok=True) with open(self._config_path, 'w') as f: json.dump(self._data, f, indent=2) except IOError as e: logger.error(f"Failed to save config to {self._config_path}: {e}") def get(self, key: str, default: Any = None) -> Any: """Get configuration value using dot notation (e.g., 'general.accentColor')""" with self._lock: keys = key.split('.') value = self._data for k in keys: if isinstance(value, dict) and k in value: value = value[k] else: return default return value def set(self, key: str, value: Any, skip_propagation: bool = False): """Set configuration value and notify listeners""" with self._lock: old_value = self.get(key) # Navigate to nested key and set value keys = key.split('.') data = self._data for k in keys[:-1]: if k not in data or not isinstance(data[k], dict): data[k] = {} data = data[k] data[keys[-1]] = value self._save() # Notify listeners if not skip_propagation: for listener in self._listeners: try: listener(key, old_value, value) except Exception as e: logger.error(f"Listener error: {e}") def delete(self, key: str): """Delete configuration key""" with self._lock: keys = key.split('.') data = self._data for k in keys[:-1]: if isinstance(data, dict) and k in data: data = data[k] else: return if isinstance(data, dict) and keys[-1] in data: del data[keys[-1]] self._save() def add_listener(self, callback: Callable[[str, Any, Any], None]): """Register callback for configuration changes""" with self._lock: self._listeners.append(callback) def _get_defaults(self) -> dict: """Default configuration structure""" return { "general": { "injectJavascript": True, "injectCSS": True, "checkForMillenniumUpdates": True, "checkForPluginAndThemeUpdates": True, "accentColor": "#1B2838" }, "misc": { "hasShownWelcomeModal": False } } # Global accessor function def get_config() -> ConfigManager: return ConfigManager() ``` -------------------------------- ### Python Plugin Backend Structure (Python) Source: https://context7.com/steamclienthomebrew/millennium/llms.txt Provides a template for developing backend plugins using Python for the Millennium framework. It outlines the lifecycle methods (_load, _front_end_loaded, _unload) and demonstrates how to define custom methods for communication with the frontend via IPC. This structure ensures plugins integrate seamlessly with the framework. ```python # Python backend plugin structure (backend/main.py) import Millennium from util.logger import logger class Plugin: def _load(self): """Called when plugin is loaded at Steam startup""" logger.log("Plugin loading...") # Initialize plugin resources self.config = {"enabled": True} # Signal ready state to framework Millennium.ready() def _front_end_loaded(self): """Called when TypeScript/React frontend is injected""" logger.log("Frontend ready, UI components available") # Safe to interact with Steam UI now def _unload(self): """Called on Steam shutdown or plugin disable""" logger.log("Cleaning up plugin resources") # Release resources, close connections, save state def get_user_stats(self, user_id, game_id): """Custom method callable from frontend via IPC""" try: stats = self._fetch_steam_stats(user_id, game_id) return {"success": True, "data": stats} except Exception as e: logger.log.error(f"Failed to fetch stats: {e}") return {"success": False, "error": str(e)} def update_settings(self, settings_dict): """Example method showing configuration updates""" self.config.update(settings_dict) return {"updated": True, "config": self.config} ``` -------------------------------- ### Python Plugin Using Millennium Configuration System Source: https://context7.com/steamclienthomebrew/millennium/llms.txt This Python code defines a plugin that utilizes the Millennium configuration system. It loads configuration, listens for changes via a callback, updates theme colors based on specific key changes, allows updating user preferences, and provides all settings. It depends on `config.manager.get_config` and assumes the existence of `logger` and `Millennium` objects. ```python from config.manager import get_config from typing import Any # Assuming logger and Millennium are defined elsewhere # logger.log(...) # Millennium.ready() class Plugin: def _load(self): self.config = get_config() # Listen for configuration changes self.config.add_listener(self._on_config_change) # Read current settings accent_color = self.config.get("general.accentColor", "#1B2838") updates_enabled = self.config.get("general.checkForMillenniumUpdates", True) # logger.log(f"Accent color: {accent_color}") # logger.log(f"Updates enabled: {updates_enabled}") # Millennium.ready() def _on_config_change(self, key: str, old_value: Any, new_value: Any): """React to configuration changes""" # logger.log(f"Config changed: {key} = {new_value} (was {old_value})") if key == "general.accentColor": self._update_theme_colors(new_value) def update_user_preference(self, key: str, value: Any): """Method callable from frontend to update config""" try: self.config.set(key, value) return {"success": True} except Exception as e: return {"success": False, "error": str(e)} def get_all_settings(self): """Return complete configuration for frontend""" return { "general": self.config.get("general", {}) # Assuming 'misc' is another potential configuration section # "misc": self.config.get("misc", {}) } # Placeholder for theme color update function def _update_theme_colors(self, color: str): pass ``` -------------------------------- ### Get Logged-in User SteamID (Python) Source: https://context7.com/steamclienthomebrew/millennium/llms.txt Extracts the Steam ID of the currently logged-in user from the web page. It executes a JavaScript snippet that queries for elements with a `data-steamid` attribute. Returns the Steam ID string or null if not found. ```python def get_user_steamid() -> str: """Extract logged-in user's Steam ID""" js_code = """ (function() { const userLinks = document.querySelectorAll('[data-steamid]'); return userLinks.length > 0 ? userLinks[0].dataset.steamid : null; })() """ return execute_js(js_code) ``` -------------------------------- ### CMake Project Configuration Source: https://github.com/steamclienthomebrew/millennium/blob/main/cli/CMakeLists.txt Configures the basic project settings, including the minimum CMake version, C++ standard, and project name. It also includes directories for headers and defines compilation flags for release builds. ```cmake cmake_minimum_required(VERSION 3.10) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED True) # Set the project name and language project(cli) include_directories(include) include_directories(../vendor/fmt/include) # Optimize the build if(CMAKE_BUILD_TYPE STREQUAL "Release") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -s -fdata-sections -ffunction-sections") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s -fdata-sections -ffunction-sections") endif() add_compile_definitions( "FMT_HEADER_ONLY" ) ``` -------------------------------- ### Python IPC Helper Functions for JS Interaction Source: https://context7.com/steamclienthomebrew/millennium/llms.txt Python helper functions to interact with JavaScript through the IPC system. Includes functions to retrieve system colors, set clipboard content, and access environment variables. These functions typically rely on an `execute_js` utility for sending code to the frontend. Dependencies include `json` and `os` modules. ```python # Python IPC helper functions (util/ipc_functions.py) from Millennium import execute_js import json def Core_GetSystemColors(): """Retrieve Steam's current color scheme""" js_code = """ JSON.stringify({ accent: getComputedStyle(document.documentElement) .getPropertyValue('--SystemAccentColor'), background: getComputedStyle(document.documentElement) .getPropertyValue('--BackgroundColor') }) """ result = execute_js(js_code) return json.loads(result) def SetClipboardContent(data: str) -> bool: """Copy data to system clipboard""" js_code = f"navigator.clipboard.writeText({json.dumps(data)})") try: execute_js(js_code) return True except Exception as e: return False def GetEnvironmentVar(var_name: str) -> str: """Access environment variables from Python""" import os return os.environ.get(var_name, "") ``` -------------------------------- ### Manage Plugin Configuration with Millennium (TypeScript) Source: https://context7.com/steamclienthomebrew/millennium/llms.txt This snippet demonstrates how to define an interface for application configuration and how to retrieve and update this configuration using the Millennium framework's frontend methods. It shows fetching all configuration and specifically updating the accent color. ```typescript // Configuration management (AppConfig.ts) interface AppConfig { general: { injectJavascript: boolean; injectCSS: boolean; checkForMillenniumUpdates: boolean; checkForPluginAndThemeUpdates: boolean; accentColor: string; }; misc: { hasShownWelcomeModal: boolean; }; } // Access configuration from Python backend async function getConfiguration(): Promise { const config = await Millennium.CallFrontendMethod( 'millennium-core', 'get_config', 'all' ); return config as AppConfig; } // Update configuration async function updateAccentColor(color: string) { await Millennium.CallFrontendMethod( 'millennium-core', 'update_config', 'general.accentColor', color ); } ``` -------------------------------- ### Plugin Configuration Schema (JSON) Source: https://context7.com/steamclienthomebrew/millennium/llms.txt Defines the structure for a plugin's configuration file (plugin.json). It specifies essential metadata such as the plugin's name, description, version, and paths to its backend and frontend components. This JSON file is crucial for the Millennium framework to discover and load plugins correctly. ```json { "name": "my-steam-plugin", "common_name": "My Steam Plugin", "description": "Extends Steam with custom features", "backend": "backend", "frontend": "src", "useBackend": true, "version": "1.0.0" } ``` -------------------------------- ### CMake Build Configuration for Millennium Executable Source: https://github.com/steamclienthomebrew/millennium/blob/main/darwin/CMakeLists.txt This snippet defines the core build settings for the 'SteamSniper' executable using CMake. It specifies the minimum CMake version, project name, C++ standard, compiler flags, source files, and links required macOS frameworks (Foundation, AppKit). ```cmake cmake_minimum_required(VERSION 3.16) project(ProcLaunchHook) set(CMAKE_CXX_STANDARD 17) set(CMAKE_OBJCXX_FLAGS "${CMAKE_OBJCXX_FLAGS} -fobjc-arc") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations") include_directories(include) set(SOURCES src/main.mm src/watchdog.mm src/exec.mm ) set_source_files_properties( src/watchdog.mm PROPERTIES COMPILE_FLAGS "-fobjc-arc" ) add_executable(SteamSniper ${SOURCES}) find_library(FOUNDATION_FRAMEWORK Foundation) find_library(APPKIT_FRAMEWORK AppKit) target_link_libraries(SteamSniper ${FOUNDATION_FRAMEWORK} ${APPKIT_FRAMEWORK}) ``` -------------------------------- ### C++ Python Manager for Plugin Instances Source: https://context7.com/steamclienthomebrew/millennium/llms.txt Manages multiple isolated Python interpreter instances for plugins. It handles the creation and retrieval of Python thread states, ensuring each plugin has its own interpreter environment and thread. ```cpp // Python manager handles multiple plugin instances (co_spawn.h) class PythonManager { private: std::vector> m_threadPool; std::vector> m_pythonInstances; public: bool CreatePythonInstance(SettingsStore::PluginTypeSchema& plugin, callback) { auto threadState = std::make_shared(); threadState->pluginName = plugin.pluginName; threadState->thread_state = PyThreadState_New(interp); threadState->mutex = std::make_shared(); m_pythonInstances.push_back(threadState); return true; } std::optional> GetPythonThreadStateFromName( std::string pluginName ) { auto it = std::find_if(m_pythonInstances.begin(), m_pythonInstances.end(), [&pluginName](const auto& instance) { return instance->pluginName == pluginName; }); if (it != m_pythonInstances.end()) return *it; return std::nullopt; } }; // Thread state structure for isolated execution struct PythonThreadState { std::string pluginName; PyThreadState* thread_state; std::shared_ptr mutex; }; ``` -------------------------------- ### CMake Build Configuration for Unix Hooks Library Source: https://github.com/steamclienthomebrew/millennium/blob/main/unix-hooks/CMakeLists.txt This C++ CMake build script configures a shared library named 'millennium_bootstrap'. It sets the C++ standard to 17, defines a runtime path for the library in debug builds, and customizes the output naming. ```cmake cmake_minimum_required(VERSION 3.10) project(unix-hooks LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) if (CMAKE_BUILD_TYPE STREQUAL "Debug") set(MILLENNIUM_RUNTIME_PATH "${CMAKE_SOURCE_DIR}/build/libmillennium_x86.so") add_compile_definitions(MILLENNIUM_RUNTIME_PATH="${MILLENNIUM_RUNTIME_PATH}") endif() add_library(unix-hooks SHARED main.cc) set_target_properties(unix-hooks PROPERTIES OUTPUT_NAME "millennium_bootstrap") set_target_properties(unix-hooks PROPERTIES PREFIX "lib") set_target_properties(unix-hooks PROPERTIES SUFFIX "_86x.so") ``` -------------------------------- ### Monitor Page Navigation Events (Python) Source: https://context7.com/steamclienthomebrew/millennium/llms.txt Sets up a listener for page navigation events within the Steam client. When the user navigates (e.g., using browser back/forward), a Python callback function is invoked with the new pathname. This enables real-time updates based on user actions. ```python def monitor_page_navigation(callback): """Call Python callback when user navigates""" # Register JS event listener that calls back to Python js_code = """ window.addEventListener('popstate', () => { Millennium.CallFrontendMethod('my-plugin', 'on_navigation', window.location.pathname); }); """ execute_js(js_code) ``` -------------------------------- ### Set Compile Definitions and Include Directories (CMake) Source: https://github.com/steamclienthomebrew/millennium/blob/main/CMakeLists.txt Configures compile definitions for version information and includes necessary header directories from the project's source and vendor subdirectories. This ensures that version macros are defined and headers are found during the build process. ```cmake add_compile_definitions(MILLENNIUM_VERSION="${MILLENNIUM_VERSION}") include_directories( ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/vendor/fmt/include ${CMAKE_SOURCE_DIR}/vendor/asio/asio/include ${CMAKE_SOURCE_DIR}/vendor/nlohmann/include ${CMAKE_SOURCE_DIR}/vendor/websocketpp ${CMAKE_SOURCE_DIR}/vendor/crow/include ${CMAKE_SOURCE_DIR}/vendor/ini/src ) ``` -------------------------------- ### Integrate Resource Compiler and External Libraries (CMake) Source: https://github.com/steamclienthomebrew/millennium/blob/main/CMakeLists.txt Finds the Windres utility to compile Windows resource files (.rc) into object files and links them to the 'Millennium' target. It also finds and links external libraries like libcurl and OpenSSL, along with platform-specific libraries for networking and Python. ```cmake find_program(WINDRES windres) if(WINDRES) add_custom_command( OUTPUT ${CMAKE_BINARY_DIR}/version.o COMMAND ${WINDRES} -i ${CMAKE_SOURCE_DIR}/scripts/version.rc -o ${CMAKE_BINARY_DIR}/version.o DEPENDS ${CMAKE_SOURCE_DIR}/scripts/version.rc ) add_custom_target(resource DEPENDS ${CMAKE_BINARY_DIR}/version.o) add_dependencies(Millennium resource) target_link_libraries(Millennium ${CMAKE_BINARY_DIR}/version.o) endif() find_package(CURL REQUIRED) # used for web requests. target_link_libraries(Millennium CURL::libcurl) if(NIX_BUILD) find_package(OpenSSL REQUIRED) target_link_libraries(Millennium OpenSSL::SSL) endif() if(WIN32) target_link_libraries(Millennium wsock32 Iphlpapi DbgHelp) if(GITHUB_ACTION_BUILD) target_link_libraries(Millennium "${CMAKE_SOURCE_DIR}/build/python/python311.lib") else() target_link_libraries(Millennium ${CMAKE_SOURCE_DIR}/vendor/python/python311.lib ${CMAKE_SOURCE_DIR}/vendor/python/python311_d.lib) endif() elseif(UNIX) if(APPLE) target_link_libraries(Millennium "$ENV{HOME}/.pyenv/versions/3.11.8/lib/libpython3.11.dylib") else() if(PYTHON_TEST_RESULT) target_link_libraries(Millennium Python::Module) else() target_link_libraries(Millennium "/opt/python-i686-3.11.8/lib/libpython-3.11.8.so") endif() endif() endif() ``` -------------------------------- ### CMake Executable and Library Linking Source: https://github.com/steamclienthomebrew/millennium/blob/main/cli/CMakeLists.txt Defines the main executable target 'cli' using source files from 'src/main.cc'. It links the CLI11 library and sets specific properties for the output executable, such as the output name and prefix. ```cmake find_package(CLI11 CONFIG REQUIRED) # Add the executable add_executable(cli src/main.cc) target_link_libraries(cli PRIVATE CLI11::CLI11) add_compile_definitions(MILLENNIUM_VERSION="${MILLENNIUM_VERSION}") set_target_properties(cli PROPERTIES OUTPUT_NAME "millennium") set_target_properties(cli PROPERTIES PREFIX "") install(TARGETS cli DESTINATION bin) ``` -------------------------------- ### CMake: Post-Build Command for Executable Patcher Source: https://github.com/steamclienthomebrew/millennium/blob/main/darwin/CMakeLists.txt This CMake code defines a post-build custom command to copy the compiled executable ('Millennium') to a specific location within the application bundle. It copies the binary to 'Contents/MacOS/Millennium.Patcher', likely for further processing or as part of the application's runtime components. ```cmake add_custom_command(TARGET SteamSniper POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_BINARY_DIR}/Millennium" "$/Contents/MacOS/Millennium.Patcher" COMMENT "Moving executable to MacOS folder" ) ``` -------------------------------- ### Configure Millennium Update Script Prompt (CMake) Source: https://github.com/steamclienthomebrew/millennium/blob/main/CMakeLists.txt This CMake code configures the update script prompt for the Millennium project. It checks for an AUR helper and sets the prompt accordingly, either using the detected update command or a manual update message. It also includes a fallback for when no AUR helper is found. ```cmake if(NOT AUR_HELPER STREQUAL "none") message(STATUS "Using ${UPDATE_COMMAND} as update script to update Millennium.") set(MILLENNIUM__UPDATE_SCRIPT_PROMPT "${UPDATE_COMMAND}") else() message(STATUS "No AUR helper found. Please update Millennium manually.") set(MILLENNIUM__UPDATE_SCRIPT_PROMPT "Couldn't find AUR helper. Please update Millennium manually.") endif() else() include_directories("${CMAKE_SOURCE_DIR}/vendor/python/posix") set(MILLENNIUM__UPDATE_SCRIPT_PROMPT "curl -fsSL 'https://raw.githubusercontent.com/SteamClientHomebrew/Millennium/refs/heads/main/scripts/install.sh' | sh") endif() endif() endif() ``` -------------------------------- ### CMake: macOS Bundle Properties Configuration Source: https://github.com/steamclienthomebrew/millennium/blob/main/darwin/CMakeLists.txt This CMake snippet configures macOS specific bundle properties for the 'SteamSniper' executable. It sets the output name, enables the macOS bundle, and defines various bundle attributes like bundle name, version, and identifier, including a custom Info.plist file. ```cmake set_target_properties(SteamSniper PROPERTIES OUTPUT_NAME "Millennium" MACOSX_BUNDLE TRUE MACOSX_BUNDLE_BUNDLE_NAME "Millennium" MACOSX_BUNDLE_BUNDLE_VERSION "1.0" MACOSX_BUNDLE_SHORT_VERSION_STRING "1.0" MACOSX_BUNDLE_IDENTIFIER "com.millennium.steamsniper" MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.xml" ) ```