96 lines
3.4 KiB
Python
96 lines
3.4 KiB
Python
import os
|
|
from copy import deepcopy
|
|
|
|
import xmltodict
|
|
|
|
|
|
DELTA_BASE_URL = "https://cdn-fastly.obsproject.com/downloads/sparkle_deltas"
|
|
|
|
|
|
def convert_appcast(filename):
|
|
print("Converting", filename)
|
|
in_path = os.path.join("output/appcasts", filename)
|
|
out_path = os.path.join("output/appcasts/stable", filename.replace("_v2", ""))
|
|
with open(in_path, "rb") as f:
|
|
xml_data = f.read()
|
|
if not xml_data:
|
|
return
|
|
|
|
appcast = xmltodict.parse(xml_data, force_list=("item",))
|
|
out_appcast = deepcopy(appcast)
|
|
|
|
# Remove anything but stable channel items.
|
|
new_list = []
|
|
for _item in appcast["rss"]["channel"]["item"]:
|
|
item = deepcopy(_item)
|
|
branch = item.pop("sparkle:channel", "stable")
|
|
if branch != "stable":
|
|
continue
|
|
# Remove delta information (incompatible with Sparkle 1.x)
|
|
item.pop("sparkle:deltas", None)
|
|
new_list.append(item)
|
|
|
|
out_appcast["rss"]["channel"]["item"] = new_list
|
|
|
|
with open(out_path, "wb") as f:
|
|
xmltodict.unparse(out_appcast, output=f, pretty=True)
|
|
|
|
# Also create legacy appcast from x86 version.
|
|
if "x86" in filename:
|
|
out_path = os.path.join("output/appcasts/stable", "updates.xml")
|
|
with open(out_path, "wb") as f:
|
|
xmltodict.unparse(out_appcast, output=f, pretty=True)
|
|
|
|
|
|
def adjust_appcast(filename):
|
|
print("Adjusting", filename)
|
|
file_path = os.path.join("output/appcasts", filename)
|
|
with open(file_path, "rb") as f:
|
|
xml_data = f.read()
|
|
if not xml_data:
|
|
return
|
|
|
|
arch = "arm64" if "arm64" in filename else "x86_64"
|
|
appcast = xmltodict.parse(xml_data, force_list=("item", "enclosure"))
|
|
|
|
out_appcast = deepcopy(appcast)
|
|
out_appcast["rss"]["channel"]["title"] = "OBS Studio"
|
|
out_appcast["rss"]["channel"]["link"] = "https://obsproject.com/"
|
|
|
|
new_list = []
|
|
for _item in appcast["rss"]["channel"]["item"]:
|
|
item = deepcopy(_item)
|
|
# Fix changelog URL
|
|
# Sparkle doesn't allow us to specify the URL for a specific update,
|
|
# so we set the full release notes link instead and then rewrite the
|
|
# appcast. Yay.
|
|
if release_notes_link := item.pop("sparkle:fullReleaseNotesLink", None):
|
|
item["sparkle:releaseNotesLink"] = release_notes_link
|
|
|
|
# If deltas exist, update their URLs to match server layout
|
|
# (generate_appcast doesn't allow this).
|
|
if deltas := item.get("sparkle:deltas", None):
|
|
for delta_item in deltas["enclosure"]:
|
|
delta_filename = delta_item["@url"].rpartition("/")[2]
|
|
delta_item["@url"] = f"{DELTA_BASE_URL}/{arch}/{delta_filename}"
|
|
|
|
new_list.append(item)
|
|
|
|
out_appcast["rss"]["channel"]["item"] = new_list
|
|
|
|
with open(file_path, "wb") as f:
|
|
xmltodict.unparse(out_appcast, output=f, pretty=True)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
for ac_file in os.listdir("output/appcasts"):
|
|
if ".xml" not in ac_file:
|
|
continue
|
|
if "v2" not in ac_file:
|
|
# generate_appcast may download legacy appcast files and update them as well.
|
|
# Those generated files are not backwards-compatible, so delete whatever v1
|
|
# files it may have created and recreate them manually.
|
|
os.remove(os.path.join("output/appcasts", ac_file))
|
|
continue
|
|
adjust_appcast(ac_file)
|
|
convert_appcast(ac_file)
|