From b7cf518301e3503375d84b2f893078cbe7215335 Mon Sep 17 00:00:00 2001 From: rlaphoenix Date: Sat, 12 Nov 2022 09:05:55 +0000 Subject: [PATCH] Get a mapping of Game Title IDs from Tinfoil's API --- nton/main.py | 2 +- nton/system_title_ids.py | 63 +++++++++++++++++++++++- poetry.lock | 100 ++++++++++++++++++++++++++++++++++++++- pyproject.toml | 2 + 4 files changed, 164 insertions(+), 3 deletions(-) diff --git a/nton/main.py b/nton/main.py index 272c596..6fd1ebf 100644 --- a/nton/main.py +++ b/nton/main.py @@ -93,7 +93,7 @@ def build( log.error(f"The Title ID \"{id_}\" is an invalid hex string. It must be a-fA-f0-9.") return 1 id_ = id_.lower() - if id_ in system_title_ids.ALL: + if id_ in system_title_ids.ALL_SYSTEM: log.critical(f"The Title ID \"{id_}\" is a reserved System Title! Using it is unsafe!") return 2 else: diff --git a/nton/system_title_ids.py b/nton/system_title_ids.py index 049c8cd..28bb2ea 100644 --- a/nton/system_title_ids.py +++ b/nton/system_title_ids.py @@ -1,7 +1,12 @@ # Source: https://switchbrew.org/wiki/Title_list # Last updated: 2022-11-12 08:00 UTC+0 # When updating make sure all title IDs are lowercase hex, 16 digits in length (a-z0-9{16}). +import time +import jsonpickle +import requests + +from nton.constants import Directories system_modules = ( # https://switchbrew.org/wiki/Title_list#System_Modules @@ -419,7 +424,58 @@ pre_release_system_modules = ( ) -ALL = ( +def get_game_title_ids() -> dict: + """Get a mapping of Game Title IDs -> Game Names from Tinfoil's API.""" + res = requests.get( + url="https://tinfoil.media/Title/ApiJson/", + params={ + # is this actually returning a full list? + "rating_content": "", + "language": "", + "category": "", + "region": "ar,at,au,be,bg,br,ca,ch,cl,cn,co,cy,cz,de,dk,ee,es,fi,fr,gb,gr,hk,hr,hu," + "ie,it,jp,kr,lt,lu,lv,mt,mx,nl,no,nz,pe,pl,pt,ro,ru,se,si,sk,us,xx,za,zh", + "rating": "", + "_": str(time.time_ns() // 1000000) + }, + headers={ + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:107.0) Gecko/20100101 Firefox/107.0" + } + ) + + if not res.ok: + raise requests.ConnectionError( + f"Failed to get a list of Game Title IDs from Tinfoil's API, [{res.status_code}]") + + title_ids = { + title["id"].lower(): title["name"].split(">", maxsplit=1)[1].split("", maxsplit=1)[0] + for title in res.json()["data"] + } + + return title_ids + + +# get a list of game title ids (cached) via tinfoil's API +Directories.cache.mkdir(parents=True, exist_ok=True) +game_title_ids_cache = Directories.cache / "tinfoil_game_ids.json" +if game_title_ids_cache.exists(): + if game_title_ids_cache.stat().st_mtime + 43200 < time.time(): + # expired + print("Refreshing the list of Game Title IDs...") + game_title_ids = get_game_title_ids() + game_title_ids_cache.write_text(jsonpickle.dumps(game_title_ids), encoding="utf8") + else: + # valid + game_title_ids = jsonpickle.loads(game_title_ids_cache.read_text("utf8")) +else: + # no cache + print("Downloading a list of Game Title IDs...") + game_title_ids = get_game_title_ids() + game_title_ids_cache.write_text(jsonpickle.dumps(game_title_ids), encoding="utf8") + + +ALL_SYSTEM = ( *system_modules, *system_data_archives, *system_applets, @@ -432,3 +488,8 @@ ALL = ( *pre_release_system_applets, *pre_release_system_modules ) + +ALL = ( + *ALL_SYSTEM, + *list(game_title_ids) +) diff --git a/poetry.lock b/poetry.lock index 5d71883..7d7df1f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -6,6 +6,25 @@ category = "main" optional = false python-versions = "*" +[[package]] +name = "certifi" +version = "2022.9.24" +description = "Python package for providing Mozilla's CA Bundle." +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "charset-normalizer" +version = "2.1.1" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" +optional = false +python-versions = ">=3.6.0" + +[package.extras] +unicode_backport = ["unicodedata2"] + [[package]] name = "click" version = "8.1.3" @@ -26,6 +45,14 @@ category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +[[package]] +name = "idna" +version = "3.4" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" +optional = false +python-versions = ">=3.5" + [[package]] name = "importlib-metadata" version = "5.0.0" @@ -43,6 +70,40 @@ docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker perf = ["ipython"] testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] +[[package]] +name = "jsonpickle" +version = "2.2.0" +description = "Python library for serializing any arbitrary object graph into JSON" +category = "main" +optional = false +python-versions = ">=2.7" + +[package.dependencies] +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} + +[package.extras] +docs = ["jaraco.packaging (>=3.2)", "rst.linker (>=1.9)", "sphinx"] +testing = ["ecdsa", "enum34", "feedparser", "jsonlib", "numpy", "pandas", "pymongo", "pytest (>=3.5,!=3.7.3)", "pytest-black-multipy", "pytest-checkdocs (>=1.2.3)", "pytest-cov", "pytest-flake8 (<1.1.0)", "pytest-flake8 (>=1.1.1)", "scikit-learn", "sqlalchemy"] +"testing.libs" = ["simplejson", "ujson", "yajl"] + +[[package]] +name = "requests" +version = "2.28.1" +description = "Python HTTP for Humans." +category = "main" +optional = false +python-versions = ">=3.7, <4" + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<3" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<1.27" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] + [[package]] name = "typing-extensions" version = "4.4.0" @@ -51,6 +112,19 @@ category = "main" optional = false python-versions = ">=3.7" +[[package]] +name = "urllib3" +version = "1.26.12" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + [[package]] name = "zipp" version = "3.10.0" @@ -66,13 +140,21 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools" [metadata] lock-version = "1.1" python-versions = ">=3.7,<3.11" -content-hash = "837098ac1022804f9e9bc84559912fc26fbe215c7858f584d7a702afe38e3db0" +content-hash = "02a3f438545bcb1e9f4b10d1fef7166b37067900eedb226a0f4f4cd54ec8903c" [metadata.files] appdirs = [ {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, ] +certifi = [ + {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"}, + {file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"}, +] +charset-normalizer = [ + {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, + {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, +] click = [ {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, @@ -81,14 +163,30 @@ colorama = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +idna = [ + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, +] importlib-metadata = [ {file = "importlib_metadata-5.0.0-py3-none-any.whl", hash = "sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43"}, {file = "importlib_metadata-5.0.0.tar.gz", hash = "sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab"}, ] +jsonpickle = [ + {file = "jsonpickle-2.2.0-py2.py3-none-any.whl", hash = "sha256:de7f2613818aa4f234138ca11243d6359ff83ae528b2185efdd474f62bcf9ae1"}, + {file = "jsonpickle-2.2.0.tar.gz", hash = "sha256:7b272918b0554182e53dc340ddd62d9b7f902fec7e7b05620c04f3ccef479a0e"}, +] +requests = [ + {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, + {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, +] typing-extensions = [ {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, ] +urllib3 = [ + {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"}, + {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, +] zipp = [ {file = "zipp-3.10.0-py3-none-any.whl", hash = "sha256:4fcb6f278987a6605757302a6e40e896257570d11c51628968ccb2a47e80c6c1"}, {file = "zipp-3.10.0.tar.gz", hash = "sha256:7a7262fd930bd3e36c50b9a64897aec3fafff3dfdeec9623ae22b40e93f99bb8"}, diff --git a/pyproject.toml b/pyproject.toml index 810cbd3..4f73a6c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,6 +29,8 @@ classifiers = [ python = ">=3.7,<3.11" click = "^8.1.3" appdirs = "^1.4.4" +requests = "^2.28.1" +jsonpickle = "^2.2.0" [tool.poetry.scripts] nton = "nton.main:main"