import subprocess import sys from typing import Any, Dict, List, Tuple from environs import Env from loguru import logger from requests import Session from src.parser import Parser from src.utils import supported_apps class Patches(object): def check_java(self) -> None: logger.debug("Checking if java is available") jd = subprocess.check_output( ["java", "-version"], stderr=subprocess.STDOUT ).decode("utf-8") jd = jd[1:-1] if "Runtime Environment" not in jd: logger.debug("Java Must be installed") exit(-1) if "17" not in jd: logger.debug("Java 17 Must be installed") exit(-1) logger.debug("Cool!! Java is available") def fetch_patches(self) -> None: session = Session() logger.debug("fetching all patches") resp = session.get( "https://raw.githubusercontent.com/revanced/revanced-patches/main/patches.json" ) patches = resp.json() revanced_app_ids = { "com.reddit.frontpage": ("reddit", "_reddit"), "com.ss.android.ugc.trill": ("tiktok", "_tiktok"), "com.twitter.android": ("twitter", "_twitter"), "de.dwd.warnapp": ("warnwetter", "_warnwetter"), "com.spotify.music": ("spotify", "_spotify"), } for app_name in (revanced_app_ids[x][1] for x in revanced_app_ids): setattr(self, app_name, []) for patch in patches: for compatible_package, version in [ (x["name"], x["versions"]) for x in patch["compatiblePackages"] ]: if compatible_package in revanced_app_ids: app_name = revanced_app_ids[compatible_package][1] p = {x: patch[x] for x in ["name", "description"]} p["app"] = compatible_package p["version"] = version[-1] if version else "all" getattr(self, app_name).append(p) if self.build_extended: url = "https://raw.githubusercontent.com/inotia00/revanced-patches/revanced-extended/patches.json" else: url = "https://raw.githubusercontent.com/revanced/revanced-patches/main/patches.json" resp_extended = session.get(url) extended_patches = resp_extended.json() revanced_extended_app_ids = { "com.google.android.youtube": ("youtube", "_yt"), "com.google.android.apps.youtube.music": ("youtube-music", "_ytm"), } for app_name in ( revanced_extended_app_ids[x][1] for x in revanced_extended_app_ids ): setattr(self, app_name, []) for patch in extended_patches: for compatible_package, version in [ (x["name"], x["versions"]) for x in patch["compatiblePackages"] ]: if compatible_package in revanced_extended_app_ids: app_name = revanced_extended_app_ids[compatible_package][1] p = {x: patch[x] for x in ["name", "description"]} p["app"] = compatible_package p["version"] = version[-1] if version else "all" getattr(self, app_name).append(p) for app_name, app_id in revanced_extended_app_ids.values(): n_patches = len(getattr(self, app_id)) logger.debug(f"Total patches in {app_name} are {n_patches}") for app_name, app_id in revanced_app_ids.values(): n_patches = len(getattr(self, app_id)) logger.debug(f"Total patches in {app_name} are {n_patches}") def __init__(self, env: Env) -> None: self.env = env self.apps = env.list("PATCH_APPS", supported_apps) self.build_extended = env.bool("BUILD_EXTENDED", False) self.check_java() self.fetch_patches() self.extended_apps: List[str] = ["youtube", "youtube_music"] def get(self, app: str) -> Tuple[List[Dict[str, str]], str]: logger.debug("Getting patches for %s" % app) app_names = { "reddit": "_reddit", "tiktok": "_tiktok", "twitter": "_twitter", "warnwetter": "_warnwetter", "youtube": "_yt", "youtube_music": "_ytm", "spotify": "_spotify", } if not (app_name := app_names.get(app)): logger.debug("Invalid app name") sys.exit(-1) patches = getattr(self, app_name) version = "" if app in ("youtube", "youtube_music"): version = next(i["version"] for i in patches if i["version"] != "all") logger.debug(f"Recommended Version for patching {app} is {version}") else: logger.debug("No recommended version.") return patches, version def include_and_exclude_patches( self, app: str, arg_parser: Parser, app_patches: List[Any] ) -> None: logger.debug(f"Excluding patches for app {app}") if self.build_extended and app in self.extended_apps: excluded_patches = self.env.list( f"EXCLUDE_PATCH_{app}_EXTENDED".upper(), [] ) else: excluded_patches = self.env.list(f"EXCLUDE_PATCH_{app}".upper(), []) for patch in app_patches: arg_parser.include(patch["name"]) if patch[ "name" ] not in excluded_patches else arg_parser.exclude(patch["name"]) excluded = arg_parser.get_excluded_patches() if excluded: logger.debug(f"Excluded patches {excluded} for {app}") else: logger.debug(f"No excluded patches for {app}") def get_app_configs(self, app: str) -> Any: experiment = False total_patches, recommended_version = self.get(app=app) env_version = self.env.str(f"{app}_VERSION".upper(), None) if env_version: logger.debug(f"Picked {app} version {env_version} from env.") if env_version == "latest" or env_version > recommended_version: experiment = True recommended_version = env_version return total_patches, recommended_version, experiment