| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596 |
- 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)
|