|
#!/usr/bin/env python3
|
|
# vim: set ts=3 sw=3 sts=3 et:
|
|
# File: /etc/installed/fdroid/fdroid_generate_web.py
|
|
# Location: server3
|
|
# Author: bgstack15
|
|
# SPDX-License-Identifier: GPL-3.0-only
|
|
# Startdate: 2024-06-03-2 13:31
|
|
# Title: Generate simple web view of F-droid repo
|
|
# Purpose: Generate a small front-end web page of packages here
|
|
# History:
|
|
# Usage:
|
|
# called by fdroid-sync.sh, or also just usable by itself
|
|
# Reference:
|
|
# https://stackoverflow.com/questions/15940280/how-to-get-utc-time-in-python
|
|
# Improve:
|
|
# Documentation: design idea is to parse index-v1.json and build a front page, and also a per-app page that resembles f-droid.org/en/packages/org.jellyfin.mobile/
|
|
from configobj import ConfigObj
|
|
import os, json, datetime
|
|
CONF_FILE = os.environ.get("CONF_FILE",os.path.join("/etc","sysconfig","fdroid-generate-web"))
|
|
if os.path.exists(CONF_FILE):
|
|
cfg = ConfigObj(CONF_FILE)
|
|
else:
|
|
cfg = ConfigObj()
|
|
print(f"Info: could not find CONF_FILE {CONF_FILE}. Using all defaults!")
|
|
# defaults
|
|
if "TOP_DIR" not in cfg:
|
|
cfg["TOP_DIR"] = "/mnt/mirror/fdroid"
|
|
if "MIRROR_DIR" not in cfg:
|
|
cfg["MIRROR_DIR"] = "/mnt/mirror/fdroid/repo"
|
|
if "INDEX_JSON" not in cfg:
|
|
cfg["INDEX_JSON"] = "/mnt/mirror/fdroid/repo/index-v1.json"
|
|
print(cfg)
|
|
|
|
def get_app_attribute(app, attribute, localizations = ["en-US","en-GB"]):
|
|
"""
|
|
Given app dictionary, get attribute, using the order of localizations if necessary.
|
|
Returns that output, and locale of used value if any.
|
|
"""
|
|
output = ""
|
|
try:
|
|
output = app[attribute]
|
|
return output, ""
|
|
except:
|
|
if "localized" in app:
|
|
some_l = app["localized"]
|
|
for lchoice in localizations:
|
|
if lchoice in app["localized"]:
|
|
try:
|
|
output = app["localized"][lchoice][attribute]
|
|
return output, lchoice
|
|
except:
|
|
pass
|
|
some_l.pop(lchoice)
|
|
for l in some_l:
|
|
try:
|
|
output = app["localized"][l][attribute]
|
|
return output, l
|
|
except:
|
|
pass
|
|
else:
|
|
pass
|
|
return output, ""
|
|
|
|
def get_app_icon(app, packageName, mirror_dir, localizations = ["en-US","en-GB"]):
|
|
icon, localized = get_app_attribute(app, "icon", localizations)
|
|
if localized:
|
|
icon = f"{packageName}/{localized}/{icon}"
|
|
else:
|
|
icon = f"icons/{icon}"
|
|
if not os.path.exists(os.path.join(mirror_dir,icon)):
|
|
if os.path.exists(os.path.join(mirror_dir,packageName,"icon.png")):
|
|
return f"{packageName}/icon.png"
|
|
else:
|
|
for l in localizations:
|
|
if os.path.exists(os.path.join(mirror_dir,packageName,l,"icon.png")):
|
|
return os.path.join(packageName,l,"icon.png")
|
|
return icon
|
|
|
|
def generate_index_html(json_file, top_dir, mirror_dir):
|
|
"""
|
|
Given the index-v1.json file, generate a top-level page for the front page, stored in top_dir.
|
|
"""
|
|
with open(json_file,"r") as o:
|
|
j = json.load(o)
|
|
#print(len(json_contents))
|
|
with open(os.path.join(top_dir,"index.html"),"w") as w:
|
|
w.write("<html>\n")
|
|
w.write("<head>\n")
|
|
w.write("<link rel='stylesheet' href='fdroid.css'>\n")
|
|
w.write("""<meta name="viewport" content="width=device-width, initial-scale=1">\n""")
|
|
w.write(f"<title>{j['repo']['name']}</title>\n")
|
|
w.write("</head>\n")
|
|
w.write("<body>\n")
|
|
w.write(f"<h1><img src='repo/icons/{j['repo']['icon']}' class='headimg'>{j['repo']['name']}</h1>\n")
|
|
w.write(f"<p><a href='repo/'>Instructions to install this repository</a></p>")
|
|
#apps = sorted(j["apps"],key=lambda i: i["name"])
|
|
apps = j["apps"]
|
|
if len(apps):
|
|
w.write(f"<h2>Packages ({len(apps)})</h2>")
|
|
for app in apps:
|
|
name, _ = get_app_attribute(app,"name")
|
|
packageName, _ = get_app_attribute(app,"packageName")
|
|
icon = get_app_icon(app, packageName, mirror_dir)
|
|
desc, _ = get_app_attribute(app,"summary")
|
|
#w.write(f"<a href='packages/{packageName}.html'><img src='repo/{icon}'>{name}</a> {desc}<br/>\n")
|
|
w.write(f"<img src='repo/{icon}' class='img'><b>{name}</b> {desc}<br/>\n")
|
|
w.write("</body>\n")
|
|
w.write("<footer>\n")
|
|
w.write(f"Last generated: " + str(datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")))
|
|
w.write("</footer>\n")
|
|
w.write("</html>")
|
|
|
|
def generate_app_pages(json_file, top_dir):
|
|
with open(json_file,"r") as o:
|
|
j = json.load(o)
|
|
apps = j["apps"]
|
|
for app in apps:
|
|
name, _ = get_app_attribute(app,"name")
|
|
packageName, _ = get_app_attribute(app,"packageName")
|
|
icon, localized = get_app_attribute(app,"icon")
|
|
if localized:
|
|
icon = f"../repo/{packageName}/{localized}/{icon}"
|
|
else:
|
|
icon = f"../repo/icons/{icon}"
|
|
with open(os.path.join(top_dir,"packages",packageName+".html"),"w") as w:
|
|
w.write("<html>\n")
|
|
w.write("<head>\n")
|
|
w.write("<link rel='stylesheet' href='../fdroid-package.css'>\n")
|
|
w.write("""<meta name="viewport" content="width=device-width, initial-scale=1">\n""")
|
|
w.write(f"<title>{name}</title>\n")
|
|
w.write("</head>\n")
|
|
w.write("<body>\n")
|
|
w.write(f"<img src='{icon}' class='icon'/><h1>{name}</h1>")
|
|
w.write("</body>\n")
|
|
w.write("</html>\n")
|
|
|
|
if "__main__" == __name__:
|
|
generate_index_html(cfg["INDEX_JSON"],cfg["TOP_DIR"],cfg["MIRROR_DIR"])
|
|
# Not used at this time:
|
|
#generate_app_pages(cfg["INDEX_JSON"],cfg["TOP_DIR"])
|
Comments