Compare commits
24 Commits
4cc1ff7620
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| f226b34fb3 | |||
| 630e73dbad | |||
| eb98e8a37e | |||
| d66585b87b | |||
| 8febbba940 | |||
| 968feef80a | |||
| fa2677cd6d | |||
| 105742820f | |||
| 00dbde4a81 | |||
| 7b4f0b3498 | |||
| 972ab251b9 | |||
| 495ded1e83 | |||
| 13138174a3 | |||
| 0d9bf14881 | |||
| cf38101981 | |||
| 43af5446af | |||
| dda1c6800c | |||
| 10abe03ef9 | |||
| 089aae24d2 | |||
| 2517e08741 | |||
| a427e67e26 | |||
| 993a09e5f2 | |||
| 3008d00955 | |||
| 1cefe8380c |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -2,4 +2,7 @@
|
||||
config.py
|
||||
|
||||
# Ignore Poetry garbage
|
||||
poetry.lock
|
||||
__pycache__
|
||||
|
||||
# IDIOT! IDIOT IDIOT IDIOT!
|
||||
logs/
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Clair C. Delafuente
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
15
README.md
15
README.md
@@ -0,0 +1,15 @@
|
||||
# Clair's AppSettings Archiver
|
||||
I was asked to make an AppSettings archiver, so this should work as a rough attempt ... for now.
|
||||
|
||||
# How to install
|
||||
Copy `config.example.py` to `config.py`. Configure your destination directory, and your ROBLOSECURITY cookie if you wish to provide one. I would recommend using an alternate Roblox account, mostly out of precaution. Your ROBLOSECURITY is not transmitted to any third party with this script, only Roblox will see your ROBLOSECURITY. Some additional configuration options if you want to configure them are for overwriting the AppSettings list with your own (it could really just be anything with JSON), and a log level if you want to make things a little noisier.
|
||||
|
||||
This project uses [Poetry](https://python-poetry.org/), which has very clear documentation on how to install it:
|
||||
|
||||
You will need Python 3.12 or later, so install it.. please.
|
||||
|
||||
1. `pip install pipx` to install PIPX
|
||||
2. `pipx install poetry` to install Poetry under PIPX (You will have global access to Poetry, PIPX performs some gnarly isolation while still allowing global access to tools)
|
||||
3. In this directory, run `poetry install`. This will install all dependencies required by AppSettings-archiver
|
||||
|
||||
At this point, execute `poetry run __init__.py`. This should run AppSettings-archiver, archive all AppSettings channels, and then immediately exit. Your results will be in DST_DIR (by default, 'AppSettings' in the working directory)
|
||||
37
__init__.py
37
__init__.py
@@ -5,22 +5,15 @@ import logging
|
||||
import sys
|
||||
import json
|
||||
|
||||
VERSION = "0.0.1"
|
||||
__version__ = "1.0.0"
|
||||
|
||||
# Load configuration
|
||||
ROBLOSECURITY = config.roblosecurity or None
|
||||
DST_DIR = config.dst_dir or './AppSettings'
|
||||
ROBLOSECURITY = getattr(config, 'roblosecurity', None)
|
||||
DST_DIR = getattr(config, 'dst_dir', './AppSettings')
|
||||
LOG_LEVEL = getattr(config, 'log_level', 'INFO')
|
||||
|
||||
# Collect AppSettings endpoints
|
||||
AppSettings = {
|
||||
"PCStudioApp": "https://clientsettingscdn.roblox.com/v2/settings/application/PCStudioApp",
|
||||
"PCDesktopClient": "https://clientsettingscdn.roblox.com/v2/settings/application/PCDesktopClient",
|
||||
"MacDesktopClient": "https://clientsettingscdn.roblox.com/v2/settings/application/MacDesktopClient",
|
||||
"MacStudioClient": "https://clientsettingscdn.roblox.com/v2/settings/application/MacStudioApp",
|
||||
"UWPApp": "https://clientsettingscdn.roblox.com/v2/settings/application/UWPApp",
|
||||
"XboxClient": "https://clientsettingscdn.roblox.com/v2/settings/application/XboxClient",
|
||||
"AndroidApp": "https://clientsettingscdn.roblox.com/v2/settings/application/AndroidApp",
|
||||
}
|
||||
AppSettings = getattr(config, 'CustomTrackedAppSettings', {"PCDesktopClient": "https://clientsettingscdn.roblox.com/v2/settings/application/PCDesktopClient", "MacDesktopClient": "https://clientsettingscdn.roblox.com/v2/settings/application/MacDesktopClient"})
|
||||
|
||||
# Prepare logs
|
||||
if not os.path.exists("logs"):
|
||||
@@ -33,22 +26,34 @@ stdout_handler.setFormatter(log_format)
|
||||
logfile_handler = logging.FileHandler("logs/appsettings.log", mode="w")
|
||||
logfile_handler.setFormatter(log_format)
|
||||
log = logging.getLogger("AppSettings-archiver")
|
||||
log.setLevel(logging.INFO)
|
||||
log.setLevel(LOG_LEVEL)
|
||||
log.addHandler(stdout_handler)
|
||||
log.addHandler(logfile_handler)
|
||||
|
||||
log.info(f"AppSettings-archiver version {__version__} started")
|
||||
|
||||
if ROBLOSECURITY is None:
|
||||
log.warning(f"{"#"*6} ROBLOSECURITY IS NOT SET, SOME FFLAGS MAY BE MISSING {"#"*6}")
|
||||
|
||||
if log.level == logging.DEBUG:
|
||||
log.warning(f"{"#"*6} DEBUG LOGS ENABLED, THIS IS A LITTLE LOUDER {"#"*6}")
|
||||
|
||||
os.makedirs(DST_DIR, exist_ok=True)
|
||||
|
||||
for AppSetting in AppSettings:
|
||||
log.info(f"Processing {AppSetting}")
|
||||
|
||||
log.debug(f"Attempting to retrieve {AppSetting}")
|
||||
response = requests.get(AppSettings[AppSetting], headers={"Cookie": f".ROBLOSECURITY={ROBLOSECURITY}"})
|
||||
if response.status_code == 200:
|
||||
log.info(f"Successfully retrieved {AppSetting}")
|
||||
with open(os.path.join(DST_DIR, f"{AppSetting}.json"), "w") as f:
|
||||
formatted_response = json.dumps(response.json(), indent=4)
|
||||
log.debug(f"Response is {len(response.content)/(1<<10):,.0f} kilobytes")
|
||||
|
||||
formatted_response = json.dumps(response.json(), indent=4)
|
||||
log.debug(f"Formatted {AppSetting}")
|
||||
|
||||
expected_path = os.path.join(DST_DIR, f"{AppSetting}.json")
|
||||
with open(expected_path, "w") as f:
|
||||
f.write(formatted_response)
|
||||
log.debug(f"Wrote {AppSetting} to {expected_path}")
|
||||
else:
|
||||
log.error(f"Failed to retrieve {AppSetting}: {response.status_code}")
|
||||
Binary file not shown.
@@ -2,4 +2,9 @@
|
||||
roblosecurity = ""
|
||||
|
||||
# Unpacked luggage
|
||||
dst_dir = "./AppSettings"
|
||||
dst_dir = "./AppSettings"
|
||||
|
||||
# Log levels
|
||||
log_level = "INFO"
|
||||
|
||||
CustomTrackedAppSettings = None
|
||||
@@ -1,15 +0,0 @@
|
||||
[2025-08-18 14:53:00,449] {__init__.py:41} WARNING - ###### ROBLOSECURITY IS NOT SET, SOME FFLAGS MAY BE MISSING ######
|
||||
[2025-08-18 14:53:00,450] {__init__.py:46} INFO - Processing PCStudioApp
|
||||
[2025-08-18 14:53:00,517] {__init__.py:49} INFO - Successfully retrieved PCStudioApp
|
||||
[2025-08-18 14:53:00,534] {__init__.py:46} INFO - Processing PCDesktopClient
|
||||
[2025-08-18 14:53:00,598] {__init__.py:49} INFO - Successfully retrieved PCDesktopClient
|
||||
[2025-08-18 14:53:00,612] {__init__.py:46} INFO - Processing MacDesktopClient
|
||||
[2025-08-18 14:53:00,689] {__init__.py:49} INFO - Successfully retrieved MacDesktopClient
|
||||
[2025-08-18 14:53:00,705] {__init__.py:46} INFO - Processing MacStudioClient
|
||||
[2025-08-18 14:53:00,767] {__init__.py:49} INFO - Successfully retrieved MacStudioClient
|
||||
[2025-08-18 14:53:00,782] {__init__.py:46} INFO - Processing UWPAPP
|
||||
[2025-08-18 14:53:00,891] {__init__.py:49} INFO - Successfully retrieved UWPAPP
|
||||
[2025-08-18 14:53:00,904] {__init__.py:46} INFO - Processing XboxClient
|
||||
[2025-08-18 14:53:00,975] {__init__.py:49} INFO - Successfully retrieved XboxClient
|
||||
[2025-08-18 14:53:00,990] {__init__.py:46} INFO - Processing AndroidApp
|
||||
[2025-08-18 14:53:01,052] {__init__.py:49} INFO - Successfully retrieved AndroidApp
|
||||
@@ -1,15 +1,14 @@
|
||||
[project]
|
||||
name = "appsettings-archiver"
|
||||
version = "0.1.0"
|
||||
version = "1.0.0"
|
||||
description = ""
|
||||
authors = [
|
||||
{name = "dfault-user",email = "32969563+dfault-user@users.noreply.github.com"}
|
||||
]
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"requests",
|
||||
"dotenv",
|
||||
]
|
||||
|
||||
[tool.poetry]
|
||||
|
||||
Reference in New Issue
Block a user