+218
-2
@@ -1,2 +1,218 @@
|
||||
/__temp__/
|
||||
token.txt
|
||||
__temp__
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[codz]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
# Pipfile.lock
|
||||
|
||||
# UV
|
||||
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# uv.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
# poetry.lock
|
||||
# poetry.toml
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
||||
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
||||
# pdm.lock
|
||||
# pdm.toml
|
||||
.pdm-python
|
||||
.pdm-build/
|
||||
|
||||
# pixi
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
||||
# pixi.lock
|
||||
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
||||
# in the .venv directory. It is recommended not to include this directory in version control.
|
||||
.pixi
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# Redis
|
||||
*.rdb
|
||||
*.aof
|
||||
*.pid
|
||||
|
||||
# RabbitMQ
|
||||
mnesia/
|
||||
rabbitmq/
|
||||
rabbitmq-data/
|
||||
|
||||
# ActiveMQ
|
||||
activemq-data/
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.envrc
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
# .idea/
|
||||
|
||||
# Abstra
|
||||
# Abstra is an AI-powered process automation framework.
|
||||
# Ignore directories containing user credentials, local state, and settings.
|
||||
# Learn more at https://abstra.io/docs
|
||||
.abstra/
|
||||
|
||||
# Visual Studio Code
|
||||
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
||||
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
||||
# you could uncomment the following to ignore the entire vscode folder
|
||||
# .vscode/
|
||||
|
||||
# Ruff stuff:
|
||||
.ruff_cache/
|
||||
|
||||
# PyPI configuration file
|
||||
.pypirc
|
||||
|
||||
# Marimo
|
||||
marimo/_static/
|
||||
marimo/_lsp/
|
||||
__marimo__/
|
||||
|
||||
# Streamlit
|
||||
.streamlit/secrets.toml
|
||||
+310
@@ -0,0 +1,310 @@
|
||||
import json, os, queue, threading, requests, sqlite3, zipfile, argparse
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def main(platform="quest", locale="en_US", action="assets", output_dir_param="."):
|
||||
global forced_locale
|
||||
global hmd_type
|
||||
global target_path
|
||||
global output_dir
|
||||
|
||||
output_dir = Path(output_dir_param)
|
||||
hmd_type = HMDTypes[platform.upper()]
|
||||
forced_locale = locale
|
||||
target_path = Path(output_dir) / hmd_type.value["name"]
|
||||
target_path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
print("Retrieving Appinfo")
|
||||
retrieve_app_info()
|
||||
|
||||
print("Resolving package names")
|
||||
retrieve_all_package_names()
|
||||
|
||||
if action == "assets":
|
||||
print("Downloading images")
|
||||
download_images()
|
||||
|
||||
json_filename = (
|
||||
"appnames_" + hmd_type.value["name"] + "_" + forced_locale + ".json"
|
||||
)
|
||||
print("Creating " + json_filename)
|
||||
create_app_names_json(json_filename)
|
||||
|
||||
zip_filename = "iconpack_" + hmd_type.value["name"] + ".zip"
|
||||
print("Creating " + zip_filename)
|
||||
create_iconpack(zip_filename)
|
||||
|
||||
elif action == "free":
|
||||
json_filename = "free_apps_" + hmd_type.value["name"] + ".json"
|
||||
print("Creating " + json_filename)
|
||||
create_free_apps_json(json_filename)
|
||||
|
||||
connection.close()
|
||||
|
||||
|
||||
class HMDTypes(Enum):
|
||||
QUEST = {"sectionID": "1888816384764129", "hmdType": "MONTEREY", "name": "quest"}
|
||||
RIFT = {"sectionID": "1736210353282450", "hmdType": "RIFT", "name": "rift"}
|
||||
GO = {"sectionID": "174868819587665", "hmdType": "PACIFIC", "name": "go"}
|
||||
GEARVR = {"sectionID": "174868819587665", "hmdType": "GEARVR", "name": "gearvr"}
|
||||
|
||||
|
||||
hmd_type = None
|
||||
forced_locale = None
|
||||
target_path = None
|
||||
url = "https://graph.oculus.com/graphql"
|
||||
app_list = dict()
|
||||
connection = sqlite3.connect("packages.db")
|
||||
cursor = connection.cursor()
|
||||
cursor.execute(
|
||||
"CREATE TABLE IF NOT EXISTS packages (app_id TEXT PRIMARY_KEY, package_name TEXT)"
|
||||
)
|
||||
uri_queue = queue.Queue()
|
||||
|
||||
|
||||
def retrieve_app_info():
|
||||
sectionCursor = None
|
||||
has_next_page = True
|
||||
|
||||
while has_next_page:
|
||||
sectionID = hmd_type.value["sectionID"]
|
||||
hmdType = hmd_type.value["hmdType"]
|
||||
variables = {
|
||||
"sectionId": sectionID,
|
||||
"sortOrder": None,
|
||||
"sectionItemCount": 100,
|
||||
"hmdType": hmdType,
|
||||
}
|
||||
if sectionCursor is not None:
|
||||
variables["sectionCursor"] = sectionCursor
|
||||
|
||||
parameters = {
|
||||
"forced_locale": forced_locale,
|
||||
"access_token": "OC|1317831034909742|",
|
||||
"variables": json.dumps(variables),
|
||||
"doc_id": "1934814353250664",
|
||||
}
|
||||
response = requests.get(url, params=parameters)
|
||||
json_response = response.json()
|
||||
if "data" not in json_response:
|
||||
print("API ERROR:", json_response)
|
||||
break
|
||||
|
||||
all_items = json_response["data"]["node"]["all_items"]
|
||||
|
||||
edges = all_items["edges"]
|
||||
page_info = all_items["page_info"]
|
||||
has_next_page = page_info["has_next_page"]
|
||||
sectionCursor = page_info.get("end_cursor")
|
||||
|
||||
for edge in edges:
|
||||
app_id = edge["node"]["id"]
|
||||
app_name = edge["node"]["display_name"]
|
||||
app_image_uri = edge["node"]["cover_landscape_image"]["uri"]
|
||||
node = edge["node"]
|
||||
offer = node.get("current_offer") or {}
|
||||
price_info = offer.get("price") or {}
|
||||
price = price_info.get("offset_amount")
|
||||
app_list[app_id] = {
|
||||
"name": app_name,
|
||||
"uri": app_image_uri,
|
||||
"price": price,
|
||||
"package_name": None,
|
||||
}
|
||||
|
||||
print(f"\rFetched {len(app_list)} apps...", end="", flush=True)
|
||||
|
||||
# Safety: if cursor didn't advance, bail to avoid infinite loop
|
||||
if not sectionCursor:
|
||||
break
|
||||
|
||||
print()
|
||||
print("Retrieved: " + str(len(app_list)))
|
||||
|
||||
|
||||
def retrieve_all_package_names():
|
||||
"""Resolve all package names upfront and store them in app_list."""
|
||||
resolved = 0
|
||||
skipped = 0
|
||||
for app_id in list(app_list.keys()):
|
||||
package_name = retrieve_package_name(app_id)
|
||||
app_list[app_id]["package_name"] = package_name
|
||||
if package_name:
|
||||
resolved += 1
|
||||
else:
|
||||
skipped += 1
|
||||
print(f"Resolved: {resolved}, Skipped: {skipped}")
|
||||
|
||||
|
||||
def retrieve_package_name(app_id):
|
||||
cursor.execute("SELECT package_name FROM packages WHERE app_id=?", (app_id,))
|
||||
result = cursor.fetchone()
|
||||
|
||||
if result is not None:
|
||||
return result[0]
|
||||
|
||||
print("Fetching package_name for app_id " + app_id)
|
||||
|
||||
parameters = {
|
||||
"access_token": "OC|1317831034909742|",
|
||||
"variables": json.dumps({"id": str(app_id)}),
|
||||
"doc_id": "3326435794041206",
|
||||
}
|
||||
|
||||
request = requests.get(url, params=parameters)
|
||||
response = request.json()
|
||||
|
||||
if "data" not in response:
|
||||
print("API ERROR (package lookup):", response)
|
||||
return None
|
||||
|
||||
node = response["data"].get("node") or {}
|
||||
binary = node.get("latestBinary") or {}
|
||||
package_name = binary.get("package_name")
|
||||
|
||||
if not package_name:
|
||||
print(f"Skipping app_id {app_id} (no package_name)")
|
||||
return None
|
||||
|
||||
cursor.execute(
|
||||
"INSERT INTO packages (app_id, package_name) VALUES (?,?)",
|
||||
(app_id, package_name),
|
||||
)
|
||||
connection.commit()
|
||||
|
||||
return package_name
|
||||
|
||||
|
||||
def download_file(file_url, filename):
|
||||
os.makedirs((os.path.dirname(filename)), exist_ok=True)
|
||||
if not os.path.isfile(filename):
|
||||
response = requests.get(file_url, stream=True)
|
||||
print("Downloading:" + str(filename) + " from " + file_url)
|
||||
with open(filename, "wb") as out_file:
|
||||
for chunk in response.iter_content(chunk_size=1048576):
|
||||
out_file.write(chunk)
|
||||
|
||||
|
||||
def download_images():
|
||||
for app_id, app_info in app_list.items():
|
||||
package_name = app_info["package_name"]
|
||||
if not package_name:
|
||||
continue
|
||||
uri_queue.put(
|
||||
{
|
||||
"package_name": target_path / (package_name + ".jpg"),
|
||||
"uri": app_info["uri"],
|
||||
}
|
||||
)
|
||||
|
||||
num_worker_threads = 8
|
||||
threads = []
|
||||
for i in range(num_worker_threads):
|
||||
t = threading.Thread(target=worker)
|
||||
t.start()
|
||||
threads.append(t)
|
||||
|
||||
uri_queue.join()
|
||||
for t in threads:
|
||||
t.join()
|
||||
|
||||
|
||||
def worker():
|
||||
while 1:
|
||||
try:
|
||||
queue_item = uri_queue.get(block=False)
|
||||
download_file(queue_item["uri"], queue_item["package_name"])
|
||||
uri_queue.task_done()
|
||||
except queue.Empty:
|
||||
break
|
||||
|
||||
|
||||
def create_app_names_json(json_filename):
|
||||
app_names = dict()
|
||||
for app_id, app_info in app_list.items():
|
||||
package_name = app_info["package_name"]
|
||||
if not package_name:
|
||||
continue
|
||||
app_names[package_name] = {"name": app_info["name"]}
|
||||
|
||||
with open(Path(output_dir) / json_filename, "w", encoding="utf-8") as file:
|
||||
json.dump(app_names, file, sort_keys=True, indent=0, ensure_ascii=False)
|
||||
|
||||
|
||||
def create_free_apps_json(json_filename):
|
||||
free_apps = dict()
|
||||
json_path = output_dir / json_filename
|
||||
|
||||
if json_path.is_file():
|
||||
with open(json_path) as file:
|
||||
free_apps = json.load(file)
|
||||
for app_id, app_info in app_list.items():
|
||||
if app_info["price"] == 0:
|
||||
package_name = app_info["package_name"]
|
||||
if not package_name:
|
||||
continue
|
||||
free_apps[app_id] = {
|
||||
"name": app_info["name"],
|
||||
"package": package_name,
|
||||
}
|
||||
|
||||
with open(json_path, "w", encoding="utf-8") as file:
|
||||
json.dump(free_apps, file, sort_keys=True, indent=0, ensure_ascii=False)
|
||||
|
||||
|
||||
def create_iconpack(zip_filename):
|
||||
with zipfile.ZipFile(Path(output_dir) / zip_filename, "w") as iconpack:
|
||||
for app_id, app_info in app_list.items():
|
||||
package_name = app_info["package_name"]
|
||||
if not package_name:
|
||||
continue
|
||||
iconpack.write(target_path / (package_name + ".jpg"), package_name + ".jpg")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Download assets for QuestAppLauncher")
|
||||
parser.add_argument(
|
||||
"-p", "--platform", default="quest", choices=["quest", "rift", "go", "gearvr"]
|
||||
)
|
||||
parser.add_argument(
|
||||
"-l",
|
||||
"--locale",
|
||||
default="en_US",
|
||||
choices=[
|
||||
"en_US",
|
||||
"en_GB",
|
||||
"de_DE",
|
||||
"cs_CZ",
|
||||
"da_DK",
|
||||
"el_GR",
|
||||
"es_ES",
|
||||
"es_LA",
|
||||
"fi_FI",
|
||||
"fr_FR",
|
||||
"it_IT",
|
||||
"ja_JP",
|
||||
"ko_KR",
|
||||
"nb_NO",
|
||||
"nl_NL",
|
||||
"pl_PL",
|
||||
"pt_BR",
|
||||
"pt_PT",
|
||||
"ro_RO",
|
||||
"ru_RU",
|
||||
"sv_SE",
|
||||
"tr_TR",
|
||||
"zh_CN",
|
||||
"zh_HK",
|
||||
"zh_TW",
|
||||
],
|
||||
)
|
||||
parser.add_argument(
|
||||
"-a",
|
||||
"--action",
|
||||
default="assets",
|
||||
choices=["assets", "free"],
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
main(args.platform, args.locale, args.action)
|
||||
+154
-57
@@ -1,74 +1,102 @@
|
||||
import argparse, datetime, os, requests, shutil, subprocess, sys, zipfile
|
||||
|
||||
from github import Github # pip install PyGithub
|
||||
from QuestAssetDL import main as QuestAssetDL
|
||||
from github import Github, Auth
|
||||
|
||||
# Temporary directory for scratch space
|
||||
TEMP_DIR = '__temp__'
|
||||
LATEST_RELASE_DIR = 'latest_release'
|
||||
QALAG_OUTPUT_DIR = 'qalag'
|
||||
TEMP_DIR = "__temp__"
|
||||
LATEST_RELASE_DIR = "latest_release"
|
||||
QALAG_OUTPUT_DIR = "qalag"
|
||||
|
||||
QALAG_EXE_PATH = 'bin\\QALAG.exe'
|
||||
WINDIFF_EXE_PATH = 'bin\\WinDiff.exe'
|
||||
WINDIFF_EXE_PATH = "bin\\WinDiff.exe"
|
||||
|
||||
QUEST_DIR = "quest"
|
||||
ICONPACK_QUEST = "iconpack_quest.zip"
|
||||
APPNAMES_QUEST = "appnames_quest.json"
|
||||
ICONPACK_OTHER = "iconpack_others.zip"
|
||||
APPNAMES_OTHER = "appnames_other.json"
|
||||
APPNAMES_GALAG_NAME = "appnames_quest_en_US.json"
|
||||
|
||||
QUEST_DIR = 'quest'
|
||||
ICONPACK_QUEST = 'iconpack_quest.zip'
|
||||
APPNAMES_QUEST = 'appnames_quest.json'
|
||||
ICONPACK_OTHER = 'iconpack_others.zip'
|
||||
APPNAMES_OTHER = 'appnames_other.json'
|
||||
APPNAMES_GALAG_NAME = 'appnames_quest_en_US.json'
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Quest Asset Generator')
|
||||
parser.add_argument('-a', '--access-token', required=True, help='GitHub acess token')
|
||||
parser.add_argument('-dr', '--download-release', action='store_true', help='Download latest asset release from github')
|
||||
parser.add_argument('-da', '--download-assets', action='store_true',help='Download assets from Oculus')
|
||||
parser.add_argument('-c', '--compare', action='store_true', help='Compare assets')
|
||||
parser.add_argument('-r', '--release', action='store_true', help='Draft a github release')
|
||||
parser = argparse.ArgumentParser(description="Quest Asset Generator")
|
||||
parser.add_argument(
|
||||
"-a", "--access-token", required=True, help="GitHub acess token"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-dr",
|
||||
"--download-release",
|
||||
action="store_true",
|
||||
help="Download latest asset release from github",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-da",
|
||||
"--download-assets",
|
||||
action="store_true",
|
||||
help="Download assets from Oculus",
|
||||
)
|
||||
parser.add_argument("-c", "--compare", action="store_true", help="Compare assets")
|
||||
parser.add_argument(
|
||||
"-r", "--release", action="store_true", help="Draft a github release"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
# If nothing is specified, perform all actions
|
||||
if (not args.download_release and not args.download_assets and not args.compare and not args.release):
|
||||
if (
|
||||
not args.download_release
|
||||
and not args.download_assets
|
||||
and not args.compare
|
||||
and not args.release
|
||||
):
|
||||
args.download_release = True
|
||||
args.download_assets = True
|
||||
args.compare = True
|
||||
args.release = True
|
||||
|
||||
# Instantiate github client
|
||||
g = Github(args.access_token)
|
||||
repo = g.get_user("HooverHigh").get_repo('QuestAppLauncher_Assets')
|
||||
ga = Auth.Token(args.access_token)
|
||||
g = Github(auth=ga)
|
||||
repo = g.get_user("HooverHigh").get_repo("QuestAppLauncher_Assets")
|
||||
|
||||
# Set up temp dir
|
||||
folder_path_temp = os.path.abspath(TEMP_DIR);
|
||||
if (not os.path.isdir(folder_path_temp)):
|
||||
os.mkdir(folder_path_temp)
|
||||
folder_path_temp = os.path.abspath(TEMP_DIR)
|
||||
if not os.path.isdir(folder_path_temp):
|
||||
os.mkdir(folder_path_temp)
|
||||
|
||||
# Download latest assets
|
||||
if (args.download_assets):
|
||||
if args.download_assets:
|
||||
download_latest_assets()
|
||||
|
||||
# Download latest release
|
||||
if (args.download_release):
|
||||
if args.download_release:
|
||||
download_release_assets(repo)
|
||||
|
||||
if (args.compare):
|
||||
if args.compare:
|
||||
compare()
|
||||
|
||||
if (args.release):
|
||||
if args.release:
|
||||
create_release(repo)
|
||||
|
||||
|
||||
def get_release_download_path():
|
||||
return os.path.join(os.path.abspath(TEMP_DIR), LATEST_RELASE_DIR)
|
||||
|
||||
|
||||
def get_galag_download_path():
|
||||
return os.path.abspath(os.path.join(os.path.abspath(TEMP_DIR), QALAG_OUTPUT_DIR))
|
||||
|
||||
|
||||
# Download latest Github release
|
||||
def download_release_assets(repo):
|
||||
release = repo.get_latest_release()
|
||||
try:
|
||||
release = repo.get_latest_release()
|
||||
except Exception:
|
||||
print("No published releases found, skipping download")
|
||||
return
|
||||
print("Downloading release: '%s'" % (release.title))
|
||||
|
||||
download_release_path = get_release_download_path();
|
||||
if (os.path.isdir(download_release_path)):
|
||||
download_release_path = get_release_download_path()
|
||||
if os.path.isdir(download_release_path):
|
||||
shutil.rmtree(download_release_path)
|
||||
os.mkdir(download_release_path)
|
||||
|
||||
@@ -76,9 +104,13 @@ def download_release_assets(repo):
|
||||
for asset in assets:
|
||||
print("\tAsset: %s [%s]" % (asset.name, asset.url))
|
||||
|
||||
r = requests.get(asset.url, allow_redirects=True, headers={'Accept': 'application/octet-stream'})
|
||||
r = requests.get(
|
||||
asset.url,
|
||||
allow_redirects=True,
|
||||
headers={"Accept": "application/octet-stream"},
|
||||
)
|
||||
file_path = os.path.join(download_release_path, asset.name)
|
||||
open(file_path, 'wb').write(r.content)
|
||||
open(file_path, "wb").write(r.content)
|
||||
|
||||
# Extract quest icons
|
||||
iconpack_quest_release_zip = os.path.join(download_release_path, ICONPACK_QUEST)
|
||||
@@ -86,46 +118,105 @@ def download_release_assets(repo):
|
||||
with zipfile.ZipFile(iconpack_quest_release_zip) as zip:
|
||||
zip.extractall(iconpack_quest_release_ext_path)
|
||||
|
||||
|
||||
# Download latest assets
|
||||
def download_latest_assets():
|
||||
galag_exe_full_path = os.path.abspath(QALAG_EXE_PATH)
|
||||
galag_output_dir = get_galag_download_path()
|
||||
|
||||
if (os.path.isdir(galag_output_dir)):
|
||||
if os.path.isdir(galag_output_dir):
|
||||
shutil.rmtree(galag_output_dir)
|
||||
os.mkdir(galag_output_dir)
|
||||
|
||||
# Launch exe, temporarily changing cwd to land results in proper place
|
||||
cur_dir = os.path.abspath('.')
|
||||
os.chdir(galag_output_dir)
|
||||
launch_executable([], galag_exe_full_path)
|
||||
os.chdir(cur_dir)
|
||||
QuestAssetDL(
|
||||
platform="quest",
|
||||
locale="en_US",
|
||||
action="assets",
|
||||
output_dir_param=galag_output_dir,
|
||||
)
|
||||
|
||||
# Rename file
|
||||
os.rename(os.path.join(galag_output_dir, APPNAMES_GALAG_NAME), os.path.join(galag_output_dir, APPNAMES_QUEST))
|
||||
for f in os.listdir(galag_output_dir):
|
||||
if f.startswith("appnames_quest") and f.endswith(".json"):
|
||||
os.rename(
|
||||
os.path.join(galag_output_dir, f),
|
||||
os.path.join(galag_output_dir, APPNAMES_QUEST),
|
||||
)
|
||||
break
|
||||
else:
|
||||
raise FileNotFoundError("No appnames_quest JSON found")
|
||||
|
||||
|
||||
# Compare
|
||||
def compare():
|
||||
iconpack_quest_release_ext_path = os.path.join(get_release_download_path(), QUEST_DIR)
|
||||
iconpack_quest_generated_ext_path = os.path.join(get_galag_download_path(), QUEST_DIR)
|
||||
launch_executable(['-t', iconpack_quest_release_ext_path, iconpack_quest_generated_ext_path], bin_path=WINDIFF_EXE_PATH)
|
||||
# Check if we have a release to compare against
|
||||
release_path = get_release_download_path()
|
||||
if not os.path.isdir(release_path) or not os.path.exists(
|
||||
os.path.join(release_path, ICONPACK_QUEST)
|
||||
):
|
||||
print("No previous release assets found, skipping comparison")
|
||||
return
|
||||
|
||||
# Proceed with comparison
|
||||
iconpack_quest_release_ext_path = os.path.join(release_path, QUEST_DIR)
|
||||
iconpack_quest_generated_ext_path = os.path.join(
|
||||
get_galag_download_path(), QUEST_DIR
|
||||
)
|
||||
launch_executable(
|
||||
["-t", iconpack_quest_release_ext_path, iconpack_quest_generated_ext_path],
|
||||
bin_path=WINDIFF_EXE_PATH,
|
||||
)
|
||||
|
||||
appnames_quest_release_path = os.path.join(release_path, APPNAMES_QUEST)
|
||||
appnames_quest_generated_path = os.path.join(
|
||||
get_galag_download_path(), APPNAMES_QUEST
|
||||
)
|
||||
launch_executable(
|
||||
[appnames_quest_release_path, appnames_quest_generated_path],
|
||||
bin_path=WINDIFF_EXE_PATH,
|
||||
)
|
||||
|
||||
appnames_quest_release_path = os.path.join(get_release_download_path(), APPNAMES_QUEST)
|
||||
appnames_quest_generated_path = os.path.join(get_galag_download_path(), APPNAMES_QUEST)
|
||||
launch_executable([appnames_quest_release_path, appnames_quest_generated_path], bin_path=WINDIFF_EXE_PATH)
|
||||
|
||||
# Create release
|
||||
def create_release(repo):
|
||||
tag = 'v' + datetime.date.today().strftime('%m.%d.%Y')
|
||||
name = tag + ': Update quest assets'
|
||||
print(str.format('Creating release: tag: %s, name: %s' % (tag, name)))
|
||||
release = repo.create_git_release(tag=tag, name=name, message='Updating quest assets', draft=True)
|
||||
tag = "v" + datetime.date.today().strftime("%m.%d.%Y")
|
||||
name = tag + ": Update quest assets"
|
||||
print(f"Creating release: tag: {tag}, name: {name}")
|
||||
release = repo.create_git_release(
|
||||
tag=tag, name=name, message="Updating quest assets", draft=True
|
||||
)
|
||||
|
||||
# Paths for "other" assets (from previous release)
|
||||
other_appnames = os.path.join(get_release_download_path(), APPNAMES_OTHER)
|
||||
other_iconpack = os.path.join(get_release_download_path(), ICONPACK_OTHER)
|
||||
|
||||
# Upload other assets only if they exist (first release will skip)
|
||||
if os.path.exists(other_appnames):
|
||||
release.upload_asset(other_appnames)
|
||||
print(f"Uploaded {APPNAMES_OTHER}")
|
||||
else:
|
||||
print(f"Warning: {APPNAMES_OTHER} not found, skipping upload")
|
||||
|
||||
if os.path.exists(other_iconpack):
|
||||
release.upload_asset(other_iconpack)
|
||||
print(f"Uploaded {ICONPACK_OTHER}")
|
||||
else:
|
||||
print(f"Warning: {ICONPACK_OTHER} not found, skipping upload")
|
||||
|
||||
# Quest assets are always uploaded from the freshly downloaded data
|
||||
quest_appnames = os.path.join(get_galag_download_path(), APPNAMES_QUEST)
|
||||
quest_iconpack = os.path.join(get_galag_download_path(), ICONPACK_QUEST)
|
||||
|
||||
# Ensure these files exist (they should, from download_latest_assets)
|
||||
if os.path.exists(quest_appnames):
|
||||
release.upload_asset(quest_appnames)
|
||||
else:
|
||||
raise FileNotFoundError(f"Missing generated Quest appnames: {quest_appnames}")
|
||||
|
||||
if os.path.exists(quest_iconpack):
|
||||
release.upload_asset(quest_iconpack)
|
||||
else:
|
||||
raise FileNotFoundError(f"Missing generated Quest iconpack: {quest_iconpack}")
|
||||
|
||||
# Upload the assets, refreshing quest from generated path
|
||||
release.upload_asset(os.path.join(get_release_download_path(), APPNAMES_OTHER))
|
||||
release.upload_asset(os.path.join(get_release_download_path(), ICONPACK_OTHER))
|
||||
release.upload_asset(os.path.join(get_galag_download_path(), APPNAMES_QUEST))
|
||||
release.upload_asset(os.path.join(get_galag_download_path(), ICONPACK_QUEST))
|
||||
|
||||
# Launch executable and return output
|
||||
def launch_executable(args, bin_path):
|
||||
@@ -133,8 +224,14 @@ def launch_executable(args, bin_path):
|
||||
output = subprocess.check_output([bin_path] + args, stderr=subprocess.STDOUT)
|
||||
return output.decode(sys.stdout.encoding)
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise Exception(str.format(str(e) + ". Output: '%s'" % (e.output.decode(sys.stdout.encoding).rstrip()))) from e
|
||||
raise Exception(
|
||||
str.format(
|
||||
str(e)
|
||||
+ ". Output: '%s'" % (e.output.decode(sys.stdout.encoding).rstrip())
|
||||
)
|
||||
) from e
|
||||
except Exception as e:
|
||||
raise type(e)(str.format(str(e) + " when calling '%s'" % (bin_path)))
|
||||
|
||||
|
||||
main()
|
||||
|
||||
Binary file not shown.
BIN
Binary file not shown.
Reference in New Issue
Block a user