import json
import urllib.parse
import sys
from collections import defaultdict
def make_obtainium_link(app):
payload = {
"id": app["id"],
"url": app["url"],
"author": app["author"],
"name": app["name"],
"otherAssetUrls": app.get("otherAssetUrls"),
"apkUrls": app.get("apkUrls"),
"preferredApkIndex": app.get("preferredApkIndex"),
"additionalSettings": app.get("additionalSettings"),
"categories": app.get("categories"),
"overrideSource": app.get("overrideSource"),
"allowIdChange": app.get("allowIdChange"),
}
encoded = urllib.parse.quote(json.dumps(payload), safe="")
return f"http://apps.obtainium.imranr.dev/redirect.html?r=obtainium://app/{encoded}"
def get_display_name(app):
return app.get("meta", {}).get("nameOverride") or app.get("name", "")
def get_application_url(app):
return app.get("meta", {}).get("urlOverride") or app.get("url", "")
def should_include_app(app, variant):
"""Determine if an app should be included based on variant and meta fields."""
meta = app.get("meta", {})
# HIGHEST PRIORITY: Global exclusion overrides everything
if meta.get("excludeFromExport", False):
return False
# SECOND PRIORITY: Variant-specific inclusion/exclusion
if variant == "standard":
# Default: include in standard
return meta.get("includeInStandard", True)
elif variant == "dual-screen":
# Default: include in dual screen
return meta.get("includeInDualScreen", True)
return True
def generate_category_tables(apps):
# Categorize apps
categorized = defaultdict(list)
for app in apps:
categories = app.get("categories", [])
for category in categories:
categorized[category].append(app)
markdown_sections = ["## Applications\n"]
for category in sorted(categorized.keys()):
markdown_sections.append(f"### {category}\n")
markdown_sections.append(
"| Application Name | Add to Obtainium | Included in export json? | Included in DS json? |"
)
markdown_sections.append(
"|------------------|------------------|---------------------------|----------------------|"
)
apps_in_category = sorted(categorized[category], key=get_display_name)
for app in apps_in_category:
meta = app.get("meta", {})
if meta.get("excludeFromTable", False):
continue
display_name = (
f'{get_display_name(app)}'
)
obtainium_link = make_obtainium_link(app)
badge_md = f'Add to Obtainium!'
include_standard = "✅" if should_include_app(app, "standard") else "❌"
include_dual_screen = (
"✅" if should_include_app(app, "dual-screen") else "❌"
)
markdown_sections.append(
f"| {display_name} | {badge_md} | {include_standard} | {include_dual_screen} |"
)
markdown_sections.append("") # blank line between sections
return "\n".join(markdown_sections)
def main(input_file, output_file):
with open(input_file, "r", encoding="utf-8") as f:
data = json.load(f)
apps = data.get("apps", [])
markdown = generate_category_tables(apps)
with open(output_file, "w", encoding="utf-8") as f:
f.write(markdown)
print(f"✅ Category-based markdown table written to {output_file}")
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: python generate-table.py input.json output.md")
sys.exit(1)
main(sys.argv[1], sys.argv[2])