LizardByte has this documentation hosted on Read the Docs.
Table of Contents#
Overview#
About#
RetroArcher is a game streaming server application. This project is under development and nowhere near ready for use.
Integrations#
Support#
Our support methods are listed in our LizardByte Docs.
Downloads#
Stats#
Project Goals#
- Plugin Framework
Develop a framework friendly to plugins that allows easy expansion of the application.
Plugin types may be:
Game Stream Hosts (Sunshine)
Clients (Android, AppleTV, iOS, PC [Linux, MacOS, Windows], Xbox One/Series S/X, etc.)
Game Stores (Epic Games, Steam, Microsoft Store, etc.)
Consoles (game streaming Xbox One/Series S/X, PS4/5, etc.)
Misc. (anything that doesn’t fit a category above)
- Replace Existing RetroArcher.bundle
RetroArcher.bundle has been renamed to RetroArcher-plex and it has significantly changed:
No longer responsible for scanning games
No longer responsible for connecting to clients
No longer responsible for starting games
No longer gets metadata from IGDB
Metadata is now collected from our own db based on IGDB.
In the future metadata will be collected by this server application, and the Plex plugin will make an API request to this server to get the metadata.
Installation#
The recommended method for running RetroArcher is to use the binaries bundled with the latest release.
Binaries#
Binaries of RetroArcher are created for each release. They are available for Linux, MacOS, and Windows. Binaries can be found in the latest release.
Docker#
Docker images are available on Dockerhub.io and ghcr.io.
See Docker for additional information.
Source#
Caution
Installing from source is not recommended most users.
Follow the steps in Build except for Compile Binary.
Run the following within your activated venv.
python retroarcher.py
Usage#
Network#
RetroArcher will be available on port 9696 by default.
Arguments#
To get a list of available arguments run the following:
- Binary
retroarcher --help
- Python
python retroarcher.py --help
Docker#
lizardbyte/retroarcher#
Using docker run#
Create and run the container (substitute your <values>
):
docker run -d \
--name=retroarcher \
--restart=unless-stopped
-v <path to data>:/config \
-e PUID=<uid> \
-e PGID=<gid> \
-e TZ=<timezone> \
-p 9696:9696 \
lizardbyte/retroarcher
To update the container it must be removed and recreated:
# Stop the container
docker stop retroarcher
# Remove the container
docker rm retroarcher
# Pull the latest update
docker pull lizardbyte/retroarcher
# Run the container with the same parameters as before
docker run -d ...
Using docker-compose#
Create a docker-compose.yml
file with the following contents (substitute your <values>
):
version: '3'
services:
retroarcher:
image: lizardbyte/retroarcher
container_name: retroarcher
restart: unless-stopped
volumes:
- <path to data>:/config
environment:
- PUID=<uid>
- PGID=<gid>
- TZ=<timezone>
ports:
- 9696:9696
Create and start the container (run the command from the same folder as your docker-compose.yml
file):
docker-compose up -d
To update the container:
# Pull the latest update
docker-compose pull
# Update and restart the container
docker-compose up -d
Parameters#
You must substitute the <values>
with your own settings.
Parameters are split into two halves separated by a colon. The left side represents the host and the right side the container.
Example: -p external:internal
- This shows the port mapping from internal to external of the container.
Therefore -p 9696:9696
would expose port 9696
from inside the container to be accessible from the host’s IP on port
9696
(e.g. http://<host_ip>:9696
). The internal port must be 9696
, but the external port may be changed
(e.g. -p 8080:9696
).
Parameter |
Function |
Example Value |
Required |
---|---|---|---|
|
Web UI Port |
|
True |
|
Volume mapping |
|
True |
|
User ID |
|
False |
|
Group ID |
|
False |
|
Lookup TZ value here |
|
True |
User / Group Identifiers:#
When using data volumes (-v flags) permissions issues can arise between the host OS and the container. To avoid this issue you can specify the user PUID and group PGID. Ensure the data volume directory on the host is owned by the same user you specify.
In this instance PUID=1001
and PGID=1001
. To find yours use id user as below:
$ id dockeruser
uid=1001(dockeruser) gid=1001(dockergroup) groups=1001(dockergroup)
Build#
RetroArcher binaries are built using pyinstaller. Cross compilation is not supported. That means the binaries must be built on the target operating system and architecture.
Use Python 3.7+
Clone#
- Ensure git is installed and run the following:
git clone https://github.com/lizardbyte/retroarcher.git cd ./retroarcher
Setup venv#
It is recommended to setup and activate a venv within the retroarcher directory.
Install Python Requirements#
- Standard Requirements
python -m pip install -r requirements.txt
- Advanced Requirements
- Required for:
python -m pip install -r requirements-dev.txt
Tip
Advanced requirements include all of the standard dependencies contained in the requirements.txt
Compile Locales#
python ./scripts/_locale.py --compile
Install NPM Requirements#
npm install
mv -f ./node_modules/ ./web/
Compile Docs#
Docs are visible by the webapp and therefore must be compiled.
cd docs
make html
cd ..
Compile Binary#
python ./scripts/build.py
Remote Build#
It may be beneficial to build remotely in some cases. This will enable easier building on different operating systems.
Fork the project
Activate workflows
Trigger the CI workflow manually
Download the artifacts/binaries from the workflow run summary
Changelog#
Contributing#
Read our contribution guide in our organization level docs.
Localization#
RetroArcher is being localized into various languages. The default language is en (English).
CrowdIn#
The translations occur on CrowdIn. Feel free to contribute to localization there. Only elements of the interface are planned to be translated.
- Translations Basics
The brand name LizardByte should never be translated.
The project name RetroArcher should never be translated.
Other brand and project names should never be translated. Examples:
CEMU
GitHub
Linux
MacOS
RetroArch
RPCS3
Sunshine
Windows
- CrowdIn Integration
How does it work?
When a change is made to retroarcher python source or web templates, a workflow generates new translation templates that get pushed to CrowdIn automatically.
When translations are updated on CrowdIn, a push gets made to the l10n_master branch and a PR is made against the master branch. Once PR is merged, all updated translations are part of the project and will be included in the next release.
Extraction#
There should be minimal cases where strings need to be extracted from python code; however it may be necessary in some situations. For example the system tray icon is user interfacing and therefore should have strings extracted.
- In order for strings to be extracted from python code, the following lines must be added.
from pyra import locales _ = locales.get_text()
- Wrap the string to be extracted in a function as shown.
_('Hello world!')
- In order to include a name that should not be translated, the following example should be used.
_('Open %(app_name)s') % {'app_name': 'RetroArcher'}
While strings are to be rarely extracted from python code, it is common for strings to be extracted from html. The extraction method from html templates is very similar to extracting from python code.
- This is a simple Hello world example.
{{ _('Hello world!') }}
No other code needs to be added to html templates.
Warning
This is for information only. Contributors should never include manually updated template files, or manually compiled language files in Pull Requests.
Strings are automatically extracted from the code to the locale/retroarcher.po template file. The generated file is used by CrowdIn to generate language specific template files. The file is generated using the .github/workflows/localize.yml workflow and is run on any push event into the master branch. Jobs are only run if any of the following paths are modified.
- 'retroarcher.py'
- 'pyra/**.py'
- 'web/templates/**'
When testing locally it may be desirable to manually extract, initialize, update, and compile strings.
- Extract, initialize, and update
python ./scripts/_locale.py --extract --init --update
- Compile
python ./scripts/_locale.py --compile
Testing#
Flake8#
RetroArcher uses Flake8 for enforcing consistent code styling. Flake is included in the requirements-dev.txt.
The config file for flake8 is .flake8. This is already included in the root of the repo and should not be modified.
- Test with Flake8
python -m flake8
Sphinx#
RetroArcher uses Sphinx for documentation building. Sphinx is included in the standard requirements.txt as building the docs is required for RetroArcher to be fully functional.
RetroArcher follows numpydoc styling and formatting in docstrings. This will be tested when building the docs.
The config file for Sphinx is docs/source/conf.py. This is already included in the root of the repo and should not be modified.
- Test with Sphinx
cd docs make html
Alternatively
cd docs sphinx-build -b html source build
pytest#
RetroArcher uses pytest for unit testing. pytest is included in the requirements-dev.txt.
No config is required for pytest.
Prior to running pytest you will need to:
- Test with pytest
python -m pytest
retroarcher#
Responsible for starting RetroArcher.
- class retroarcher.IntRange(stop: int, start: int = 0)[source]#
Bases:
object
Custom IntRange class for argparse.
Prevents printing out large list of possible choices for integer ranges.
- Parameters:
- stopint
Range maximum value.
- startint, default = 0
Range minimum value.
Examples
>>> IntRange(0, 10) <retroarcher.IntRange object at 0x...>
Methods
__call__:
Validate that value is within accepted range.
pyra.__init__#
Responsible for initialization of RetroArcher.
- pyra.initialize(config_file: str) bool [source]#
Initialize RetroArcher.
Sets up config, loggers, and http port.
- Parameters:
- config_filestr
The path to the config file.
- Returns:
- bool
True if initialize succeeds, otherwise False.
- Raises:
- SystemExit
If unable to correct possible issues with config file.
Examples
>>> initialize(config_file='config.ini') True
- pyra.stop(exit_code: int | str = 0, restart: bool = False)[source]#
Stop RetroArcher.
This function ends the tray icon if it’s running. Then restarts or shutdowns RetroArcher depending on the value of the restart parameter.
- Parameters:
- exit_codeUnion[int, str], default = 0
The exit code to send. Does not apply if restart = True.
- restartbool, default = False
Set to True to restart RetroArcher.
Examples
>>> stop(exit_code=0, restart=False)
pyra.config#
Responsible for config related functions.
- pyra.config.create_config(config_file: str, config_spec: list = _CONFIG_SPEC) ConfigObj [source]#
Create a config file and ConfigObj using a config spec.
The created config is validated against a Validator object. This function will remove keys from the user’s config.ini if they no longer exist in the config spec.
- Parameters:
- config_filestr
Full filename of config file.
- config_speclist, default = _CONFIG_SPEC
Config spec to use.
- Returns:
- ConfigObj
Dictionary of config keys and values.
- Raises:
- SystemExit
If config_spec is not valid.
Examples
>>> create_config(config_file='config.ini') ConfigObj({...})
- pyra.config.save_config(config: ConfigObj | None = CONFIG) bool [source]#
Save the config to file.
Saves the ConfigObj to the specified file.
- Parameters:
- configConfigObj, default = CONFIG
Config to save.
- Returns:
- bool
True if save successful, otherwise False.
Examples
>>> config_object = create_config(config_file='config.ini') >>> save_config(config=config_object) True
- pyra.config.validate_config(config: ConfigObj) bool [source]#
Validate ConfigObj dictionary.
Ensures that the given ConfigObj is valid.
- Parameters:
- configConfigObj
Config to validate.
- Returns:
- bool
True if validation passes, otherwise False.
Examples
>>> config_object = create_config(config_file='config.ini') >>> validate_config(config=config_object) True
pyra.definitions#
Contains classes with attributes to common definitions (paths and filenames).
- class pyra.definitions.Files[source]#
Bases:
object
Class representing common Files.
The purpose of this class is to ensure consistency when using these files.
- CONFIGstr
The default config file name. i.e. config.ini.
Examples
>>> Files.CONFIG 'config.ini'
- class pyra.definitions.Modes[source]#
Bases:
object
Class representing runtime variables.
- FROZENbool
True
if running pyinstaller bundle version, otherwiseFalse
.- DOCKERbool
True
if running Docker version, otherwiseFalse
.- SPLASHbool
True
if capable of displaying a splash image on start, otherwise,False
.
Examples
>>> Modes.FROZEN False
- class pyra.definitions.Names[source]#
Bases:
object
Class representing common names.
The purpose of this class is to ensure consistency when using these names.
- namestr
The application’s name. i.e. RetroArcher.
Examples
>>> Names.name 'RetroArcher'
- class pyra.definitions.Paths[source]#
Bases:
object
Class representing common Paths.
The purpose of this class is to ensure consistency when using these paths.
- PYRA_DIRstr
The directory containing the retroarcher python files.
- ROOT_DIRstr
The root directory of the application. This is where the source files exist.
- DATA_DIRstr
The data directory of the application.
- DOCS_DIRstr
The directory containing html documentation.
- LOCALE_DIRstr
The directory containing localization files.
- LOG_DIRstr
The directory containing log files.
Examples
>>> Paths.logs '.../logs'
- class pyra.definitions.Platform[source]#
Bases:
object
Class representing the machine platform.
The purpose of this class is to ensure consistency when there is a need for platform specific functions.
- bitsstr
Operating system bitness. e.g. 64.
- operating_systemstr
Operating system name. e.g. ‘Windows’.
- os_platformstr
Operating system platform. e.g. ‘win32’, ‘darwin’, ‘linux’.
- machinestr
Machine architecture. e.g. ‘AMD64’.
- nodestr
Machine name.
- releasestr
Operating system release. e.g. ‘10’.
- versionstr
Operating system version. e.g. ‘10.0.22000’.
- editionstr
Windows edition. e.g. ‘Core’, None for non Windows platforms.
- iotbool
True if Windows IOT, otherwise False.
Examples
>>> Platform.os_platform ...
- Attributes:
- edition
pyra.hardware#
Functions related to the dashboard viewer.
- pyra.hardware.chart_data() dict [source]#
Get chart data.
Get the data from the
dash_stats
dictionary, formatted for use withplotly
.- Returns:
- dict
A single key named ‘graphs’ contains a list of graphs. Each graph is formatted as a dictionary and ready to use with
plotly
.
See also
pyra.webapp.callback_dashboard
A callback called by javascript to get this data.
Examples
>>> chart_data() {'graphs': [{"data": [...], "layout": ..., "config": ..., {"data": ...]}
- pyra.hardware.chart_types()[source]#
Get chart types.
Get the type of charts supported by the system.
- Returns:
- list
A list containing the types of charts supported.
Examples
>>> chart_types() ['cpu', 'memory', 'network']
>>> chart_types() ['cpu', 'gpu', 'memory', 'network']
- pyra.hardware.update()[source]#
Update all dashboard stats.
This function updates the cpu and memory usage of this python process as well as subprocesses. Following that the system functions are called to update system cpu, gpu, memory, and network usage. Finally, the keys in the
dash_stats
dictionary are cleaned up to only hold 120 values. This function is called once per second, therefore there are 2 minutes worth of values in the dictionary.Examples
>>> update()
- pyra.hardware.update_cpu() float [source]#
Update dashboard stats for system CPU usage.
This will append a new value to the
dash_stats['cpu'][system']
list.- Returns:
- float
The current system cpu percentage utilized.
Examples
>>> update_cpu()
- pyra.hardware.update_gpu()[source]#
Update dashboard stats for system GPU usage.
This will create new keys for the
dash_stats
dictionary if required, and then append a new value to the appropriate list.AMD data is provided by pyamdgpuinfo on Linux, and by pyadl on non Linux systems. Nvidia data is provided by GPUtil.
Examples
>>> update_gpu()
- pyra.hardware.update_memory()[source]#
Update dashboard stats for system memory usage.
This will append a new value to the
dash_stats['memory']['system']
list.- Returns:
- float
The current system memory percentage utilized.
Examples
>>> update_memory()
- pyra.hardware.update_network()[source]#
Update dashboard stats for system network usage.
This will append a new values to the
dash_stats['network']['received']
anddash_stats['network']['sent']
lists.- Returns:
- tuple
A tuple of the received and sent values as a difference since the last update.
Examples
>>> update_network()
pyra.helpers#
Many reusable helper functions.
- pyra.helpers.check_folder_writable(fallback: str, name: str, folder: str | None = None) tuple[str, Optional[bool]] [source]#
Check if folder or fallback folder is writeable.
This function ensures that the folder can be created, if it doesn’t exist. It also ensures there are sufficient permissions to write to the folder. If the primary folder fails, it falls back to the fallback folder.
- Parameters:
- fallbackstr
Secondary folder to check, if the primary folder fails.
- namestr
Short name of folder.
- folderstr, optional
Primary folder to check.
- Returns:
- tuple[str, Optional[bool]]
- A tuple containing:
- folderstr
The original or fallback folder.
- Optional[bool]
True if writeable, otherwise False. Nothing is returned if there is an error attempting to create the directory.
Examples
>>> check_folder_writable( ... folder='logs', ... fallback='backup_logs', ... name='logs' ... ) ('logs', True)
- pyra.helpers.docker_healthcheck() bool [source]#
Check the health of the docker container.
Warning
This is only meant to be called by retroarcher.py, and the interpreter should be immediate exited following the result.
The default port is used considering that the container will use the default port internally. The external port should not make any difference.
- Returns:
- bool
True if status okay, otherwise False.
Examples
>>> docker_healthcheck() True
- pyra.helpers.get_ip(host: str) str | None [source]#
Get IP address from host name.
This function is used to get the IP address of a given host name.
- Parameters:
- hoststr
Host name to get ip address of.
- Returns:
- str
IP address of host name if it is a valid ip address, otherwise
None
.
Examples
>>> get_ip(host='192.168.1.1') '192.168.1.1'
>>> get_ip(host='www.google.com') '172.253.63.147'
- pyra.helpers.get_logger(name: str) Logger [source]#
Get the logger for the given name.
This function also exists in logger.py to prevent circular imports.
- Parameters:
- namestr
Name of logger.
- Returns:
- logging.Logger
The logging.Logger object.
Examples
>>> get_logger(name='my_log') <Logger my_log (WARNING)>
- pyra.helpers.is_public_ip(host: str) bool [source]#
Check if ip address is public or not.
This function is used to determine if the given host address is a public ip address or not.
- Parameters:
- hoststr
IP address to check.
- Returns:
- bool
True if ip address is public, otherwise False.
Examples
>>> is_public_ip(host='www.google.com') True
>>> is_public_ip(host='192.168.1.1') False
- pyra.helpers.is_valid_ip(address: str) IP | bool [source]#
Check if address is an ip address.
This function is used to determine if the given address is an ip address or not.
- Parameters:
- addressstr
Address to check.
- Returns:
- Union[IP, bool]
IP object if address is an ip address, otherwise False.
Examples
>>> is_valid_ip(address='192.168.1.1') True
>>> is_valid_ip(address='0.0.0.0.0') False
- pyra.helpers.now(separate: bool = False) str [source]#
Function to get the current time, formatted.
This function will return the current time formatted as YMDHMS
- Parameters:
- separatebool, default = False
True to separate time with a combination of dashes (-) and colons (:).
- Returns:
- str
The current time formatted as YMDHMS.
Examples
>>> now() '20220410184531'
>>> now(separate=True) '2022-04-10 18:46:12'
- pyra.helpers.open_url_in_browser(url: str) bool [source]#
Open a given url in the default browser.
Attempt to open the given url in the default web browser, in a new tab.
- Parameters:
- urlstr
The url to open.
- Returns:
- bool
True if no error, otherwise False.
Examples
>>> open_url_in_browser(url='https://www.google.com') True
- pyra.helpers.timestamp() int [source]#
Function to get the current time.
This function uses time.time() to get the current time.
- Returns:
- int
The current time as a timestamp integer.
Examples
>>> timestamp() 1649631005
- pyra.helpers.timestamp_to_YMDHMS(ts: int, separate: bool = False) str [source]#
Convert timestamp to YMDHMS format.
Convert a given timestamp to YMDHMS format.
- Parameters:
- tsint
The timestamp to convert.
- separatebool, default = False
True to separate time with a combination of dashes (-) and colons (:).
- Returns:
- str
The timestamp formatted as YMDHMS.
Examples
>>> timestamp_to_YMDHMS(ts=timestamp(), separate=False) '20220410185142'
>>> timestamp_to_YMDHMS(ts=timestamp(), separate=True) '2022-04-10 18:52:09'
- pyra.helpers.timestamp_to_datetime(ts: float) datetime [source]#
Convert timestamp to datetime object.
This function returns the result of datetime.datetime.fromtimestamp().
- Parameters:
- tsfloat
The timestamp to convert.
- Returns:
- datetime.datetime
Object datetime.datetime.
Examples
>>> timestamp_to_datetime(ts=timestamp()) datetime.datetime(20..., ..., ..., ..., ..., ...)
pyra.locales#
Functions related to localization.
Localization (also referred to as l10n) is the process of adapting a product or service to a specific locale. Translation is only one of several elements in the localization process. In addition to translation, the localization process may also include: - Adapting design and layout to properly display translated text in the language of the locale - Adapting sorting functions to the alphabetical order of a specific locale - Changing formats for date and time, addresses, numbers, currencies, etc. for specific target locales - Adapting graphics to suit the expectations and tastes of a target locale - Modifying content to suit the tastes and consumption habits of a target locale
The aim of localization is to give a product or service the look and feel of having been created specifically for a target market, no matter their language, cultural preferences, or location.
- pyra.locales.get_all_locales() dict [source]#
Get a dictionary of all possible locales for use with babel.
Dictionary keys will be locale_id and value with be locale_display_name. This is a shortened example of the returned value.
{ 'de': 'Deutsch', 'en': 'English', 'en_GB': 'English (United Kingdom)', 'en_US': 'English (United States)', 'es': 'español', 'fr': 'français', 'it': 'italiano', 'ru': 'русский' }
- Returns:
- dict
Dictionary of all possible locales.
Examples
>>> get_all_locales() {... 'en': 'English', ... 'en_GB': 'English (United Kingdom)', ... 'es': 'español', ... 'fr': 'français', ...}
- pyra.locales.get_locale() str [source]#
Verify the locale.
Verify the locale from the config against supported locales and returns appropriate locale.
- Returns:
- str
The locale set in the config if it is valid, otherwise the default locale (en).
Examples
>>> get_locale() 'en'
- pyra.locales.get_text() gettext [source]#
Install the language defined in the conifg.
This function installs the language defined in the config and allows translations in python code.
- Returns:
- gettext.gettext
The gettext.gettext method.
Examples
>>> get_text() <bound method GNUTranslations.gettext of <gettext.GNUTranslations object at 0x...>>
pyra.logger#
Responsible for logging related functions.
- class pyra.logger.BlacklistFilter[source]#
Bases:
Filter
Filter logs for blacklisted words.
Log filter for blacklisted tokens and passwords.
Examples
>>> BlacklistFilter() <pyra.logger.BlacklistFilter object at 0x...>
Methods
filter:
Filter the given record.
- class pyra.logger.EmailFilter[source]#
Bases:
RegexFilter
Log filter for email addresses.
Class responsible for filtering email addresses.
Examples
>>> EmailFilter() <pyra.logger.EmailFilter object at 0x...>
- Attributes:
- regexre.compile
The compiled regex pattern.
Methods
replace:
Filter that replaces a string within another string.
- replace(text: str, email: str) str [source]#
Filter an email address.
Filter the given email address out of the given text.
- Parameters:
- textstr
The text to replace the email address within.
- emailstr
The email address to replace with asterisks.
- Returns:
- str
The original text with the email address replaced.
Examples
>>> EmailFilter().replace(text='Testing example@example.com', email='example@example.com') 'Testing ****************@********'
- class pyra.logger.NoThreadFilter(threadName)[source]#
Bases:
Filter
Log filter for the current thread.
Todo
This documentation needs to be improved.
- Parameters:
- threadNamestr
The name of the thread.
Examples
>>> NoThreadFilter('main') <pyra.logger.NoThreadFilter object at 0x...>
Methods
filter:
Filter the given record.
- filter(record) bool [source]#
Filter the given record.
Todo
This documentation needs to be improved.
- Parameters:
- recordNoThreadFilter
The record to filter.
- Returns:
- bool
True if record.threadName is not equal to self.threadName, otherwise False.
Examples
>>> NoThreadFilter('main').filter(record=NoThreadFilter('test')) True
>>> NoThreadFilter('main').filter(record=NoThreadFilter('main')) False
- class pyra.logger.PlexTokenFilter[source]#
Bases:
RegexFilter
Log filter for X-Plex-Token.
Class responsible for filtering Plex tokens.
Examples
>>> PlexTokenFilter() <pyra.logger.PlexTokenFilter object at 0x...>
- Attributes:
- regexre.compile
The compiled regex pattern.
Methods
replace:
Filter that replaces a string within another string.
- replace(text: str, token: str) str [source]#
Filter a token.
Filter the given token out of the given text.
- Parameters:
- textstr
The text to replace the token within.
- tokenstr
The token to replace with asterisks.
- Returns:
- str
The original text with the token replaced.
Examples
>>> PlexTokenFilter().replace(text='x-plex-token=5FBCvHo9vFf9erz8ssLQ', token='5FBCvHo9vFf9erz8ssLQ') 'x-plex-token=****************'
- class pyra.logger.PublicIPFilter[source]#
Bases:
RegexFilter
Log filter for public IP addresses.
Class responsible for filtering public IP addresses.
Examples
>>> PublicIPFilter() <pyra.logger.PublicIPFilter object at 0x...>
- Attributes:
- regexre.compile
The compiled regex pattern.
Methods
replace:
Filter that replaces a string within another string.
- replace(text: str, ip: str) str [source]#
Filter a public address.
Filter the given ip address out of the given text. The ip address will only be filter if it is public.
- Parameters:
- textstr
The text to replace the ip address within.
- ipstr
The ip address to replace with asterisks.
- Returns:
- str
The original text with the ip address replaced.
Examples
>>> PublicIPFilter().replace(text='Testing 172.1.7.5', ip='172.1.7.5') 'Testing ***.***.***.***'
- class pyra.logger.RegexFilter[source]#
Bases:
Filter
Base class for regex log filter.
Log filter for regex.
Examples
>>> RegexFilter() <pyra.logger.RegexFilter object at 0x...>
- Attributes:
- regexre.compile
The compiled regex pattern.
Methods
filter:
Filter the given record.
- pyra.logger.blacklist_config(config: ConfigObj)[source]#
Update blacklist words.
In order to filter words out of the logs, it is required to call this function.
Values in the config for keys containing the following terms will be removed.
HOOK
APIKEY
KEY
PASSWORD
TOKEN
- Parameters:
- configConfigObj
Config to parse.
Examples
>>> config_object = pyra.config.create_config(config_file='config.ini') >>> blacklist_config(config=config_object)
- pyra.logger.get_logger(name: str) Logger [source]#
Get a logger.
Return the logging.Logger object for a given name. Additionally, replaces logger.warn with logger.warning.
- Parameters:
- namestr
The name of the logger to get.
- Returns:
- logging.Logger
The logging.Logger object.
Examples
>>> get_logger(name='retroarcher') <Logger retroarcher (WARNING)>
- pyra.logger.init_logger(log_name: str) Logger [source]#
Create a logger.
Creates a logging.Logger object from the given log name.
- Parameters:
- log_namestr
The name of the log to create.
- Returns:
- logging.Logger
The logging.Logger object.
Examples
>>> init_logger(log_name='retroarcher') <Logger retroarcher (INFO)>
- pyra.logger.init_multiprocessing(logger: Logger)[source]#
Remove all handlers and add QueueHandler on top.
This should only be called inside a multiprocessing worker process, since it changes the logger completely.
- Parameters:
- loggerlogging.Logger
The logger to initialize for multiprocessing.
Examples
>>> logger = get_logger(name='retroarcher') >>> init_multiprocessing(logger=logger)
- pyra.logger.listener(logger: Logger)[source]#
Create a QueueListener.
Wrapper that create a QueueListener, starts it and automatically stops it. To be used in a with statement in the main process, for multiprocessing.
- Parameters:
- loggerlogging.Logger
The logger object.
Examples
>>> logger = get_logger(name='retroarcher') >>> listener(logger=logger)
pyra.threads#
Functions related to threading.
Routine Listings#
- run_in_threadmethod
Alias of the built in method threading.Thread.
Examples#
>>> from pyra import config, threads, tray_icon
>>> config_object = config.create_config(config_file='config.ini')
>>> tray_icon.icon = tray_icon.tray_initialize()
>>> threads.run_in_thread(target=tray_icon.tray_run, name='pystray', daemon=True).start()
>>> from pyra import config, threads, webapp
>>> config_object = config.create_config(config_file='config.ini')
>>> threads.run_in_thread(target=webapp.start_webapp, name='Flask', daemon=True).start()
* Serving Flask app 'pyra.webapp' (lazy loading)
...
* Running on http://.../ (Press CTRL+C to quit)
pyra.tray_icon#
Responsible for system tray icon and related functions.
- pyra.tray_icon.donate_github()[source]#
Open GitHub Sponsors.
Open GitHub Sponsors in the default web browser.
- Returns:
- bool
True if opening page was successful, otherwise False.
Examples
>>> donate_github() True
- pyra.tray_icon.donate_mee6()[source]#
Open MEE6.
Open MEE6 in the default web browser.
- Returns:
- bool
True if opening page was successful, otherwise False.
Examples
>>> donate_mee6() True
- pyra.tray_icon.donate_patreon()[source]#
Open Patreon.
Open Patreon in the default web browser.
- Returns:
- bool
True if opening page was successful, otherwise False.
Examples
>>> donate_patreon() True
- pyra.tray_icon.donate_paypal()[source]#
Open PayPal.
Open PayPal in the default web browser.
- Returns:
- bool
True if opening page was successful, otherwise False.
Examples
>>> donate_paypal() True
- pyra.tray_icon.github_releases()[source]#
Open GitHub Releases.
Open GitHub Releases in the default web browser.
- Returns:
- bool
True if opening page was successful, otherwise False.
Examples
>>> github_releases() True
- pyra.tray_icon.open_webapp() bool [source]#
Open the webapp.
Open RetroArcher in the default web browser.
- Returns:
- bool
True if opening page was successful, otherwise False.
Examples
>>> open_webapp() True
- pyra.tray_icon.tray_browser()[source]#
Toggle the config option ‘LAUNCH_BROWSER’.
This functions switches the LAUNCH_BROWSER config option from True to False, or False to True.
Examples
>>> tray_browser()
- pyra.tray_icon.tray_disable()[source]#
Turn off the config option ‘SYSTEM_TRAY’.
This function ends and disables the SYSTEM_TRAY config option.
Examples
>>> tray_disable()
- pyra.tray_icon.tray_end()[source]#
End the system tray icon.
Hide and then stop the system tray icon.
Examples
>>> tray_end()
- pyra.tray_icon.tray_initialize() None | bool [source]#
Initialize the system tray icon.
Some features of the tray icon may not be available, depending on the operating system. An attempt is made to setup the tray icon with all the available features supported by the OS.
- Returns:
- Union[Icon, bool]
- Icon
Instance of pystray.Icon if icon is supported.
- bool
False if icon is not supported.
Examples
>>> tray_initialize()
- pyra.tray_icon.tray_quit()[source]#
Shutdown RetroArcher.
Set the ‘pyra.SIGNAL’ variable to ‘shutdown’.
Examples
>>> tray_quit()
pyra.webapp#
Responsible for serving the webapp.
- pyra.webapp.callback_dashboard() Response [source]#
Get dashboard data.
This should be used in a callback in order to update charts in the web app.
- Returns:
- Response
A response formatted as
flask.jsonify
.
See also
pyra.hardware.chart_data
This function sets up the data in the proper format.
Examples
>>> callback_dashboard() <Response ... bytes [200 OK]>
- pyra.webapp.docs(filename) send_from_directory [source]#
Serve the Sphinx html documentation.
Todo
This documentation needs to be improved.
- Parameters:
- filenamestr
The html filename to return.
- Returns:
- flask.send_from_directory
The requested documentation page.
Notes
The following routes trigger this function.
/docs/ /docs/<page.html>
Examples
>>> docs(filename='index.html')
- pyra.webapp.favicon() send_from_directory [source]#
Serve the favicon.ico file.
Todo
This documentation needs to be improved.
- Returns:
- flask.send_from_directory
The ico file.
Notes
The following routes trigger this function.
/favicon.ico
Examples
>>> favicon()
- pyra.webapp.home() render_template [source]#
Serve the webapp home page.
Todo
This documentation needs to be improved.
- Returns:
- render_template
The rendered page.
Notes
The following routes trigger this function.
/ /home
Examples
>>> home()
- pyra.webapp.start_webapp()[source]#
Start the webapp.
Start the flask webapp. This is placed in it’s own function to allow the ability to start the webapp within a thread in a simple way.
Examples
>>> start_webapp() * Serving Flask app 'pyra.webapp' (lazy loading) ... * Running on http://.../ (Press CTRL+C to quit)
>>> from pyra import threads >>> threads.run_in_thread(target=webapp.start_webapp, name='Flask', daemon=True).start() * Serving Flask app 'pyra.webapp' (lazy loading) ... * Running on http://.../ (Press CTRL+C to quit)