mirror of
https://github.com/sotam0316/docker-py-revanced.git
synced 2026-04-25 03:48:37 +09:00
✨ Per app config
This commit is contained in:
+1
-1
@@ -7,4 +7,4 @@ venv
|
|||||||
/revanced-cache/
|
/revanced-cache/
|
||||||
changelog.md
|
changelog.md
|
||||||
.idea
|
.idea
|
||||||
*patches.json
|
*.json
|
||||||
|
|||||||
@@ -6,86 +6,39 @@ from loguru import logger
|
|||||||
|
|
||||||
from src.config import RevancedConfig
|
from src.config import RevancedConfig
|
||||||
from src.downloader.factory import DownloaderFactory
|
from src.downloader.factory import DownloaderFactory
|
||||||
from src.downloader.utils import download_revanced
|
|
||||||
from src.parser import Parser
|
from src.parser import Parser
|
||||||
from src.patches import Patches
|
from src.patches import Patches
|
||||||
from src.utils import AppNotFound, PatcherDownloadFailed
|
from src.utils import AppNotFound, PatchesJsonFailed, check_java
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
"""Entry point."""
|
"""Entry point."""
|
||||||
|
from src.app import APP
|
||||||
|
|
||||||
env = Env()
|
env = Env()
|
||||||
config = RevancedConfig(env)
|
config = RevancedConfig(env)
|
||||||
|
check_java(config.dry_run)
|
||||||
|
|
||||||
patcher = Patches(config)
|
logger.info(f"Will Patch only {config.apps}")
|
||||||
try:
|
for app in config.apps:
|
||||||
download_revanced(config, patcher)
|
logger.info("Trying to build %s" % app)
|
||||||
except PatcherDownloadFailed as e:
|
|
||||||
logger.error(f"Failed to download {e}")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
logger.info(f"Will Patch only {patcher.config.apps}")
|
|
||||||
for app in patcher.config.apps:
|
|
||||||
try:
|
try:
|
||||||
logger.info("Trying to build %s" % app)
|
app = APP(app_name=app, config=config)
|
||||||
|
patcher = Patches(config, app)
|
||||||
parser = Parser(patcher, config)
|
parser = Parser(patcher, config)
|
||||||
app_all_patches, version, is_experimental = patcher.get_app_configs(app)
|
app_all_patches = patcher.get_app_configs(app)
|
||||||
patcher.include_exclude_patch(app, parser, app_all_patches)
|
patcher.include_exclude_patch(app, parser, app_all_patches)
|
||||||
downloader = DownloaderFactory.create_downloader(
|
downloader = DownloaderFactory.create_downloader(
|
||||||
app=app, patcher=patcher, config=config
|
app=app.app_name, patcher=patcher, config=config
|
||||||
)
|
)
|
||||||
downloader.download(version, app)
|
downloader.download(app.app_version, app.app_name)
|
||||||
config.app_versions[app] = version
|
parser.patch_app(app)
|
||||||
logger.info(f"Downloaded {app}, version {version}")
|
|
||||||
parser.patch_app(app=app, version=version, is_experimental=is_experimental)
|
|
||||||
except AppNotFound as e:
|
except AppNotFound as e:
|
||||||
logger.info(f"Invalid app requested to build {e}")
|
logger.info(f"Invalid app requested to build {e}")
|
||||||
|
except PatchesJsonFailed:
|
||||||
|
logger.exception("Patches.json not found")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception(f"Failed to build {app} because of {e}")
|
logger.exception(f"Failed to build {app} because of {e}")
|
||||||
if len(config.alternative_youtube_patches) and "youtube" in config.apps:
|
|
||||||
for alternative_patch in config.alternative_youtube_patches:
|
|
||||||
parser = Parser(patcher, config)
|
|
||||||
app_all_patches, version, is_experimental = patcher.get_app_configs(
|
|
||||||
"youtube"
|
|
||||||
)
|
|
||||||
patcher.include_exclude_patch("youtube", parser, app_all_patches)
|
|
||||||
was_inverted = parser.invert_patch(alternative_patch)
|
|
||||||
if was_inverted:
|
|
||||||
logger.info(
|
|
||||||
f"Rebuilding youtube with inverted {alternative_patch} patch."
|
|
||||||
)
|
|
||||||
parser.patch_app(
|
|
||||||
app="youtube",
|
|
||||||
version=config.app_versions.get("youtube", "latest"),
|
|
||||||
is_experimental=is_experimental,
|
|
||||||
output_prefix="-" + alternative_patch + "-",
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
logger.info(
|
|
||||||
f"Skipping Rebuilding youtube as {alternative_patch} patch was not found."
|
|
||||||
)
|
|
||||||
if len(config.alternative_youtube_music_patches) and "youtube_music" in config.apps:
|
|
||||||
for alternative_patch in config.alternative_youtube_music_patches:
|
|
||||||
parser = Parser(patcher, config)
|
|
||||||
app_all_patches, version, is_experimental = patcher.get_app_configs(
|
|
||||||
"youtube_music"
|
|
||||||
)
|
|
||||||
patcher.include_exclude_patch("youtube_music", parser, app_all_patches)
|
|
||||||
was_inverted = parser.invert_patch(alternative_patch)
|
|
||||||
if was_inverted:
|
|
||||||
logger.info(
|
|
||||||
f"Rebuilding youtube music with inverted {alternative_patch} patch."
|
|
||||||
)
|
|
||||||
parser.patch_app(
|
|
||||||
app="youtube_music",
|
|
||||||
version=config.app_versions.get("youtube_music", "latest"),
|
|
||||||
is_experimental=is_experimental,
|
|
||||||
output_prefix="-" + alternative_patch + "-",
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
logger.info(
|
|
||||||
f"Skipping Rebuilding youtube music as {alternative_patch} patch was not found."
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
+94
@@ -0,0 +1,94 @@
|
|||||||
|
"""Class to represent apk to be patched."""
|
||||||
|
import concurrent
|
||||||
|
import hashlib
|
||||||
|
import pathlib
|
||||||
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
from src.config import RevancedConfig
|
||||||
|
from src.utils import PatcherDownloadFailed, slugify
|
||||||
|
|
||||||
|
|
||||||
|
class APP(object):
|
||||||
|
"""Patched APK."""
|
||||||
|
|
||||||
|
def __init__(self, app_name: str, config: RevancedConfig):
|
||||||
|
self.app_name = app_name
|
||||||
|
self.app_version = config.env.str(f"{app_name}_VERSION".upper(), None)
|
||||||
|
self.experiment = False
|
||||||
|
self.cli_dl = config.env.str(f"{app_name}_CLI_DL".upper(), config.global_cli_dl)
|
||||||
|
self.patches_dl = config.env.str(
|
||||||
|
f"{app_name}_PATCHES_DL".upper(), config.global_patches_dl
|
||||||
|
)
|
||||||
|
self.integrations_dl = config.env.str(
|
||||||
|
f"{app_name}_INTEGRATION_DL".upper(), config.global_integrations_dl
|
||||||
|
)
|
||||||
|
self.exclude_request = config.env.list(f"EXCLUDE_PATCH_{app_name}".upper(), [])
|
||||||
|
self.include_request = config.env.list(f"INCLUDE_PATCH_{app_name}".upper(), [])
|
||||||
|
self.resource: Dict[str, str] = {}
|
||||||
|
self.no_of_patches = 0
|
||||||
|
self.download_patch_resources(config)
|
||||||
|
|
||||||
|
def get_output_file_name(self) -> str:
|
||||||
|
"""Get output file appended with version."""
|
||||||
|
return f"Re-{self.app_name}-{slugify(self.app_version)}.apk"
|
||||||
|
|
||||||
|
def set_recommended_version(self, version: str, exp: bool = False) -> None:
|
||||||
|
"""Update if cooking non-recommended."""
|
||||||
|
self.app_version = version
|
||||||
|
self.experiment = exp
|
||||||
|
|
||||||
|
def __str__(self: "APP") -> str:
|
||||||
|
attrs = vars(self)
|
||||||
|
return ", ".join("%s: %s" % item for item in attrs.items())
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def download(url: str, config: RevancedConfig, assets_filter: str = None) -> str: # type: ignore
|
||||||
|
"""Downloader."""
|
||||||
|
from src.downloader.download import Downloader
|
||||||
|
|
||||||
|
url = url.strip()
|
||||||
|
if url.startswith("https://github"):
|
||||||
|
from src.downloader.github import Github
|
||||||
|
|
||||||
|
url = Github.patch_resource(url, assets_filter)[0]
|
||||||
|
extension = pathlib.Path(url).suffix
|
||||||
|
file_name = APP.generate_filename(url) + extension
|
||||||
|
Downloader(None, config).direct_download(url, file_name) # type: ignore
|
||||||
|
return file_name
|
||||||
|
|
||||||
|
def download_patch_resources(self, config: RevancedConfig) -> None:
|
||||||
|
"""Download resource for patching."""
|
||||||
|
logger.info("Downloading resources for patching.")
|
||||||
|
# Create a list of resource download tasks
|
||||||
|
download_tasks = [
|
||||||
|
("cli", self.cli_dl, config),
|
||||||
|
("integrations", self.integrations_dl, config),
|
||||||
|
("patches", self.patches_dl, config, ".*jar"),
|
||||||
|
("patches_json", self.patches_dl, config, ".*json"),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Using a ThreadPoolExecutor for parallelism
|
||||||
|
with ThreadPoolExecutor() as executor:
|
||||||
|
futures = {
|
||||||
|
resource_name: executor.submit(self.download, *args)
|
||||||
|
for resource_name, *args in download_tasks
|
||||||
|
}
|
||||||
|
|
||||||
|
# Wait for all tasks to complete
|
||||||
|
concurrent.futures.wait(futures.values())
|
||||||
|
|
||||||
|
# Retrieve results from completed tasks
|
||||||
|
for resource_name, future in futures.items():
|
||||||
|
try:
|
||||||
|
self.resource[resource_name] = future.result()
|
||||||
|
except Exception as e:
|
||||||
|
raise PatcherDownloadFailed(f"An exception occurred: {e}")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def generate_filename(url: str) -> str:
|
||||||
|
"""Get file name from url."""
|
||||||
|
encoded_url: str = hashlib.sha256(url.encode()).hexdigest()
|
||||||
|
return encoded_url
|
||||||
+11
-24
@@ -1,23 +1,27 @@
|
|||||||
"""Revanced Configurations."""
|
"""Revanced Configurations."""
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, List
|
from typing import List
|
||||||
|
|
||||||
from environs import Env
|
from environs import Env
|
||||||
from requests import Session
|
from requests import Session
|
||||||
|
|
||||||
from src.utils import default_build
|
from src.utils import default_build
|
||||||
|
|
||||||
|
default_cli = "https://github.com/revanced/revanced-cli/releases/latest"
|
||||||
|
default_patches = "https://github.com/revanced/revanced-patches/releases/latest"
|
||||||
|
default_integrations = (
|
||||||
|
"https://github.com/revanced/revanced-integrations/releases/latest"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class RevancedConfig(object):
|
class RevancedConfig(object):
|
||||||
"""Revanced Configurations."""
|
"""Revanced Configurations."""
|
||||||
|
|
||||||
def __init__(self, env: Env) -> None:
|
def __init__(self, env: Env) -> None:
|
||||||
self.app_versions: Dict[str, str] = {}
|
|
||||||
self.env = env
|
self.env = env
|
||||||
self.temp_folder = Path("apks")
|
self.temp_folder = Path("apks")
|
||||||
self.session = Session()
|
self.session = Session()
|
||||||
self.session.headers["User-Agent"] = "anything"
|
self.session.headers["User-Agent"] = "anything"
|
||||||
self.build_extended = env.bool("BUILD_EXTENDED", False)
|
|
||||||
self.apk_mirror = "https://www.apkmirror.com"
|
self.apk_mirror = "https://www.apkmirror.com"
|
||||||
self.upto_down = [
|
self.upto_down = [
|
||||||
"spotify",
|
"spotify",
|
||||||
@@ -34,27 +38,7 @@ class RevancedConfig(object):
|
|||||||
self.keystore_name = env.str("KEYSTORE_FILE_NAME", "revanced.keystore")
|
self.keystore_name = env.str("KEYSTORE_FILE_NAME", "revanced.keystore")
|
||||||
self.ci_test = env.bool("CI_TEST", False)
|
self.ci_test = env.bool("CI_TEST", False)
|
||||||
self.apps = env.list("PATCH_APPS", default_build)
|
self.apps = env.list("PATCH_APPS", default_build)
|
||||||
self.extended_apps: List[str] = ["youtube", "youtube_music", "microg", "reddit"]
|
self.rip_libs_apps: List[str] = []
|
||||||
self.rip_libs_apps: List[str] = ["youtube"]
|
|
||||||
self.normal_cli_jar = "revanced-cli.jar"
|
|
||||||
self.normal_patches_jar = "revanced-patches.jar"
|
|
||||||
self.normal_integrations_apk = "revanced-integrations.apk"
|
|
||||||
self.normal_options_json = "options.json"
|
|
||||||
self.cli_jar = (
|
|
||||||
f"inotia00-{self.normal_cli_jar}"
|
|
||||||
if self.build_extended
|
|
||||||
else self.normal_cli_jar
|
|
||||||
)
|
|
||||||
self.patches_jar = (
|
|
||||||
f"inotia00-{self.normal_patches_jar}"
|
|
||||||
if self.build_extended
|
|
||||||
else self.normal_patches_jar
|
|
||||||
)
|
|
||||||
self.integrations_apk = (
|
|
||||||
f"inotia00-{self.normal_integrations_apk}"
|
|
||||||
if self.build_extended
|
|
||||||
else self.normal_integrations_apk
|
|
||||||
)
|
|
||||||
self.apk_mirror_urls = {
|
self.apk_mirror_urls = {
|
||||||
"reddit": f"{self.apk_mirror}/apk/redditinc/reddit/",
|
"reddit": f"{self.apk_mirror}/apk/redditinc/reddit/",
|
||||||
"twitter": f"{self.apk_mirror}/apk/x-corp/twitter/",
|
"twitter": f"{self.apk_mirror}/apk/x-corp/twitter/",
|
||||||
@@ -97,3 +81,6 @@ class RevancedConfig(object):
|
|||||||
self.existing_downloaded_apks = env.list("EXISTING_DOWNLOADED_APKS", [])
|
self.existing_downloaded_apks = env.list("EXISTING_DOWNLOADED_APKS", [])
|
||||||
self.personal_access_token = env.str("PERSONAL_ACCESS_TOKEN", None)
|
self.personal_access_token = env.str("PERSONAL_ACCESS_TOKEN", None)
|
||||||
self.dry_run = env.bool("DRY_RUN", False)
|
self.dry_run = env.bool("DRY_RUN", False)
|
||||||
|
self.global_cli_dl = env.str("GLOBAL_CLI_DL", default_cli)
|
||||||
|
self.global_patches_dl = env.str("GLOBAL_CLI_DL", default_patches)
|
||||||
|
self.global_integrations_dl = env.str("GLOBAL_CLI_DL", default_integrations)
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ class ApkMirror(Downloader):
|
|||||||
"p.notes:nth-child(3) > span:nth-child(1) > a:nth-child(1)"
|
"p.notes:nth-child(3) > span:nth-child(1) > a:nth-child(1)"
|
||||||
).attributes["href"]
|
).attributes["href"]
|
||||||
self._download(self.config.apk_mirror + href, f"{app}.apk")
|
self._download(self.config.apk_mirror + href, f"{app}.apk")
|
||||||
logger.debug("Finished Extracting link and downloading")
|
|
||||||
|
|
||||||
def get_download_page(self, parser: LexborHTMLParser, main_page: str) -> str:
|
def get_download_page(self, parser: LexborHTMLParser, main_page: str) -> str:
|
||||||
"""Function to get the download page in apk_mirror.
|
"""Function to get the download page in apk_mirror.
|
||||||
@@ -67,7 +66,6 @@ class ApkMirror(Downloader):
|
|||||||
:param version: Version of the application to download
|
:param version: Version of the application to download
|
||||||
:return: Version of downloaded apk
|
:return: Version of downloaded apk
|
||||||
"""
|
"""
|
||||||
logger.debug(f"Trying to download {app},specific version {version}")
|
|
||||||
version = version.replace(".", "-")
|
version = version.replace(".", "-")
|
||||||
main_page = f"{self.config.apk_mirror_version_urls.get(app)}-{version}-release/"
|
main_page = f"{self.config.apk_mirror_version_urls.get(app)}-{version}-release/"
|
||||||
parser = LexborHTMLParser(
|
parser = LexborHTMLParser(
|
||||||
@@ -75,7 +73,6 @@ class ApkMirror(Downloader):
|
|||||||
)
|
)
|
||||||
download_page = self.get_download_page(parser, main_page)
|
download_page = self.get_download_page(parser, main_page)
|
||||||
self.extract_download_link(download_page, app)
|
self.extract_download_link(download_page, app)
|
||||||
logger.debug(f"Downloaded {app} apk from apkmirror_specific_version")
|
|
||||||
|
|
||||||
def latest_version(self, app: str, **kwargs: Any) -> None:
|
def latest_version(self, app: str, **kwargs: Any) -> None:
|
||||||
"""Function to download whatever the latest version of app from
|
"""Function to download whatever the latest version of app from
|
||||||
@@ -105,4 +102,3 @@ class ApkMirror(Downloader):
|
|||||||
parser = LexborHTMLParser(self.config.session.get(main_page).text)
|
parser = LexborHTMLParser(self.config.session.get(main_page).text)
|
||||||
download_page = self.get_download_page(parser, main_page)
|
download_page = self.get_download_page(parser, main_page)
|
||||||
self.extract_download_link(download_page, app)
|
self.extract_download_link(download_page, app)
|
||||||
logger.debug(f"Downloaded {app} apk from apkmirror_specific_version in rt")
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
"""Downloader Class."""
|
"""Downloader Class."""
|
||||||
import os
|
import os
|
||||||
|
from pathlib import Path
|
||||||
from queue import PriorityQueue
|
from queue import PriorityQueue
|
||||||
from time import perf_counter
|
from time import perf_counter
|
||||||
from typing import Any, Tuple
|
from typing import Any, Tuple
|
||||||
@@ -23,14 +24,20 @@ class Downloader(object):
|
|||||||
self.config = config
|
self.config = config
|
||||||
self.patcher = patcher
|
self.patcher = patcher
|
||||||
|
|
||||||
def _download(self, url: str, file_name: str) -> None:
|
@staticmethod
|
||||||
if (
|
def file_status_check(file_name: Path, dry_run: bool, url: str) -> bool:
|
||||||
os.path.exists(self.config.temp_folder.joinpath(file_name))
|
"""Check if file already exists."""
|
||||||
or self.config.dry_run
|
if os.path.exists(file_name) or dry_run:
|
||||||
):
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"Skipping download of {file_name}. File already exists or dry running."
|
f"Skipping download of {file_name} from {url}. File already exists or dry running."
|
||||||
)
|
)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _download(self, url: str, file_name: str) -> None:
|
||||||
|
if self.file_status_check(
|
||||||
|
self.config.temp_folder.joinpath(file_name), self.config.dry_run, url
|
||||||
|
):
|
||||||
return
|
return
|
||||||
logger.info(f"Trying to download {file_name} from {url}")
|
logger.info(f"Trying to download {file_name} from {url}")
|
||||||
self._QUEUE_LENGTH += 1
|
self._QUEUE_LENGTH += 1
|
||||||
@@ -99,3 +106,7 @@ class Downloader(object):
|
|||||||
self.specific_version(app, version)
|
self.specific_version(app, version)
|
||||||
else:
|
else:
|
||||||
self.latest_version(app, **kwargs)
|
self.latest_version(app, **kwargs)
|
||||||
|
|
||||||
|
def direct_download(self, dl: str, file_name: str) -> None:
|
||||||
|
"""Download from DL."""
|
||||||
|
self._download(dl, file_name)
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
"""Github Downloader."""
|
"""Github Downloader."""
|
||||||
from typing import Dict
|
from typing import Dict, List
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
from lastversion import latest
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
from src.downloader.download import Downloader
|
from src.downloader.download import Downloader
|
||||||
@@ -41,3 +42,11 @@ class Github(Downloader):
|
|||||||
download_url = response.json()["assets"][0]["browser_download_url"]
|
download_url = response.json()["assets"][0]["browser_download_url"]
|
||||||
update_changelog(f"{owner}/{repo_name}", response.json())
|
update_changelog(f"{owner}/{repo_name}", response.json())
|
||||||
self._download(download_url, file_name=app)
|
self._download(download_url, file_name=app)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def patch_resource(repo_url: str, assets_filter: str) -> list[str]:
|
||||||
|
"""Fetch patch resource from repo url."""
|
||||||
|
latest_resource_version: List[str] = latest(
|
||||||
|
repo_url, assets_filter=assets_filter, output_format="assets"
|
||||||
|
)
|
||||||
|
return latest_resource_version
|
||||||
|
|||||||
@@ -1,63 +1,4 @@
|
|||||||
"""Utility class."""
|
"""Utility class."""
|
||||||
import os
|
|
||||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from src.config import RevancedConfig
|
|
||||||
from src.patches import Patches
|
|
||||||
from src.utils import PatcherDownloadFailed
|
|
||||||
|
|
||||||
implement_method = "Please implement the method"
|
implement_method = "Please implement the method"
|
||||||
|
|
||||||
|
|
||||||
def download_revanced(config: RevancedConfig, patcher: Patches) -> None:
|
|
||||||
"""Download Revanced and Extended Patches, Integration and CLI."""
|
|
||||||
from src.downloader.factory import DownloaderFactory
|
|
||||||
|
|
||||||
if os.path.exists("changelog.md") and not config.dry_run:
|
|
||||||
logger.debug("Deleting old changelog.md")
|
|
||||||
os.remove("changelog.md")
|
|
||||||
assets = [
|
|
||||||
["revanced", "revanced-cli", config.normal_cli_jar],
|
|
||||||
["revanced", "revanced-integrations", config.normal_integrations_apk],
|
|
||||||
["revanced", "revanced-patches", config.normal_patches_jar],
|
|
||||||
]
|
|
||||||
if config.build_extended:
|
|
||||||
assets += [
|
|
||||||
["inotia00", "revanced-cli", config.cli_jar],
|
|
||||||
["inotia00", "revanced-integrations", config.integrations_apk],
|
|
||||||
["inotia00", "revanced-patches", config.patches_jar],
|
|
||||||
]
|
|
||||||
if (
|
|
||||||
"youtube" in config.apps
|
|
||||||
or "youtube_music" in config.apps
|
|
||||||
or "microg" in config.apps
|
|
||||||
):
|
|
||||||
if config.build_extended and "microg" in config.apps:
|
|
||||||
assets += [
|
|
||||||
["inotia00", "mMicroG", "microg.apk"],
|
|
||||||
]
|
|
||||||
else:
|
|
||||||
assets += [
|
|
||||||
["inotia00", "mMicroG", "microg-output.apk"],
|
|
||||||
]
|
|
||||||
downloader = DownloaderFactory.create_downloader(
|
|
||||||
app="patches", patcher=patcher, config=config
|
|
||||||
)
|
|
||||||
with ThreadPoolExecutor(7) as executor:
|
|
||||||
futures = [
|
|
||||||
executor.submit(
|
|
||||||
downloader.download,
|
|
||||||
version="latest",
|
|
||||||
app=repo[2],
|
|
||||||
**{"owner": repo[0], "name": repo[1]},
|
|
||||||
)
|
|
||||||
for repo in assets
|
|
||||||
]
|
|
||||||
for future in as_completed(futures):
|
|
||||||
try:
|
|
||||||
future.result()
|
|
||||||
except Exception as e:
|
|
||||||
raise PatcherDownloadFailed(f"An exception occurred: {e}")
|
|
||||||
logger.info("Downloaded revanced microG ,cli, integrations and patches.")
|
|
||||||
|
|||||||
+13
-29
@@ -6,9 +6,10 @@ from typing import List
|
|||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
|
from src.app import APP
|
||||||
from src.config import RevancedConfig
|
from src.config import RevancedConfig
|
||||||
from src.patches import Patches
|
from src.patches import Patches
|
||||||
from src.utils import possible_archs, slugify
|
from src.utils import possible_archs
|
||||||
|
|
||||||
|
|
||||||
class Parser(object):
|
class Parser(object):
|
||||||
@@ -70,43 +71,29 @@ class Parser(object):
|
|||||||
# noinspection IncorrectFormatting
|
# noinspection IncorrectFormatting
|
||||||
def patch_app(
|
def patch_app(
|
||||||
self,
|
self,
|
||||||
app: str,
|
app: APP,
|
||||||
version: str,
|
|
||||||
is_experimental: bool = False,
|
|
||||||
output_prefix: str = "-",
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Revanced APP Patcher.
|
"""Revanced APP Patcher.
|
||||||
|
|
||||||
:param app: Name of the app
|
:param app: Name of the app
|
||||||
:param version: Version of the application
|
|
||||||
:param is_experimental: Whether to enable experimental support
|
|
||||||
:param output_prefix: Prefix to add to the output apks file name
|
|
||||||
"""
|
"""
|
||||||
cli = self.config.normal_cli_jar
|
|
||||||
patches = self.config.normal_patches_jar
|
|
||||||
integrations = self.config.normal_integrations_apk
|
|
||||||
options = self.config.normal_options_json
|
|
||||||
if self.config.build_extended and app in self.config.extended_apps:
|
|
||||||
cli = self.config.cli_jar
|
|
||||||
patches = self.config.patches_jar
|
|
||||||
integrations = self.config.integrations_apk
|
|
||||||
args = [
|
args = [
|
||||||
"-jar",
|
"-jar",
|
||||||
cli,
|
app.resource["cli"],
|
||||||
"-a",
|
"-a",
|
||||||
app + ".apk",
|
app.app_name + ".apk",
|
||||||
"-b",
|
"-b",
|
||||||
patches,
|
app.resource["patches"],
|
||||||
"-m",
|
"-m",
|
||||||
integrations,
|
app.resource["integrations"],
|
||||||
"-o",
|
"-o",
|
||||||
f"Re-{app}-{slugify(version)}{output_prefix}output.apk",
|
app.get_output_file_name(),
|
||||||
"--keystore",
|
"--keystore",
|
||||||
self.config.keystore_name,
|
self.config.keystore_name,
|
||||||
"--options",
|
"--options",
|
||||||
options,
|
"options.json",
|
||||||
]
|
]
|
||||||
if is_experimental:
|
if app.experiment:
|
||||||
logger.debug("Using experimental features")
|
logger.debug("Using experimental features")
|
||||||
args.append("--experimental")
|
args.append("--experimental")
|
||||||
args[1::2] = map(lambda i: self.config.temp_folder.joinpath(i), args[1::2])
|
args[1::2] = map(lambda i: self.config.temp_folder.joinpath(i), args[1::2])
|
||||||
@@ -114,11 +101,7 @@ class Parser(object):
|
|||||||
self.exclude_all_patches()
|
self.exclude_all_patches()
|
||||||
if self._PATCHES:
|
if self._PATCHES:
|
||||||
args.extend(self._PATCHES)
|
args.extend(self._PATCHES)
|
||||||
if (
|
if app.app_name in self.config.rip_libs_apps:
|
||||||
self.config.build_extended
|
|
||||||
and len(self.config.archs_to_build) > 0
|
|
||||||
and app in self.config.rip_libs_apps
|
|
||||||
):
|
|
||||||
excluded = set(possible_archs) - set(self.config.archs_to_build)
|
excluded = set(possible_archs) - set(self.config.archs_to_build)
|
||||||
for arch in excluded:
|
for arch in excluded:
|
||||||
args.append("--rip-lib")
|
args.append("--rip-lib")
|
||||||
@@ -126,8 +109,9 @@ class Parser(object):
|
|||||||
|
|
||||||
start = perf_counter()
|
start = perf_counter()
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"Sending request to revanced cli for building {app} revanced with args java {args}"
|
f"Sending request to revanced cli for building with args java {args}"
|
||||||
)
|
)
|
||||||
|
return
|
||||||
process = Popen(["java", *args], stdout=PIPE)
|
process = Popen(["java", *args], stdout=PIPE)
|
||||||
output = process.stdout
|
output = process.stdout
|
||||||
if not output:
|
if not output:
|
||||||
|
|||||||
+35
-121
@@ -1,13 +1,13 @@
|
|||||||
"""Revanced Patches."""
|
"""Revanced Patches."""
|
||||||
import json
|
import json
|
||||||
import subprocess
|
import os
|
||||||
from typing import Any, Dict, List, Tuple
|
from typing import Any, Dict, List, Tuple
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from requests import Session
|
|
||||||
|
|
||||||
|
from src.app import APP
|
||||||
from src.config import RevancedConfig
|
from src.config import RevancedConfig
|
||||||
from src.utils import AppNotFound, handle_response
|
from src.utils import AppNotFound, PatchesJsonFailed
|
||||||
|
|
||||||
|
|
||||||
class Patches(object):
|
class Patches(object):
|
||||||
@@ -50,59 +50,28 @@ class Patches(object):
|
|||||||
"ml.docilealligator.infinityforreddit": "infinity",
|
"ml.docilealligator.infinityforreddit": "infinity",
|
||||||
"me.ccrama.redditslide": "slide",
|
"me.ccrama.redditslide": "slide",
|
||||||
"com.onelouder.baconreader": "bacon",
|
"com.onelouder.baconreader": "bacon",
|
||||||
|
"com.google.android.youtube": "youtube",
|
||||||
|
"com.google.android.apps.youtube.music": "youtube_music",
|
||||||
|
"com.mgoogle.android.gms": "microg",
|
||||||
}
|
}
|
||||||
revanced_app_ids = {
|
revanced_app_ids = {
|
||||||
key: (value, "_" + value) for key, value in _revanced_app_ids.items()
|
key: (value, "_" + value) for key, value in _revanced_app_ids.items()
|
||||||
}
|
}
|
||||||
_revanced_extended_app_ids = {
|
|
||||||
"com.google.android.youtube": "youtube",
|
|
||||||
"com.google.android.apps.youtube.music": "youtube_music",
|
|
||||||
"com.mgoogle.android.gms": "microg",
|
|
||||||
"com.reddit.frontpage": "reddit",
|
|
||||||
}
|
|
||||||
revanced_extended_app_ids = {
|
|
||||||
key: (value, "_" + value) for key, value in _revanced_extended_app_ids.items()
|
|
||||||
}
|
|
||||||
|
|
||||||
@staticmethod
|
def scrap_patches(self, file_name: str) -> Any:
|
||||||
def support_app() -> Dict[str, str]:
|
"""Scrap Patches."""
|
||||||
"""Return supported apps."""
|
if os.path.exists(file_name):
|
||||||
return Patches._revanced_app_ids
|
with open(file_name) as f:
|
||||||
|
patches = json.load(f)
|
||||||
@staticmethod
|
return patches
|
||||||
def check_java(dry_run: bool) -> None:
|
raise PatchesJsonFailed()
|
||||||
"""Check if Java17 is installed."""
|
|
||||||
try:
|
|
||||||
if dry_run:
|
|
||||||
return
|
|
||||||
jd = subprocess.check_output(
|
|
||||||
["java", "-version"], stderr=subprocess.STDOUT
|
|
||||||
).decode("utf-8")
|
|
||||||
jd = jd[1:-1]
|
|
||||||
if "Runtime Environment" not in jd:
|
|
||||||
raise subprocess.CalledProcessError(-1, "java -version")
|
|
||||||
if "17" not in jd and "20" not in jd:
|
|
||||||
raise subprocess.CalledProcessError(-1, "java -version")
|
|
||||||
logger.debug("Cool!! Java is available")
|
|
||||||
except subprocess.CalledProcessError:
|
|
||||||
logger.debug("Java>= 17 Must be installed")
|
|
||||||
exit(-1)
|
|
||||||
|
|
||||||
# noinspection DuplicatedCode
|
# noinspection DuplicatedCode
|
||||||
def fetch_patches(self) -> None:
|
def fetch_patches(self, config: RevancedConfig, app: APP) -> None:
|
||||||
"""Function to fetch all patches."""
|
"""Function to fetch all patches."""
|
||||||
session = Session()
|
patches = self.scrap_patches(
|
||||||
if self.config.dry_run:
|
f'{config.temp_folder}/{app.resource["patches_json"]}'
|
||||||
logger.debug("fetching all patches from local file")
|
)
|
||||||
with open("patches.json") as f:
|
|
||||||
patches = json.load(f)
|
|
||||||
else:
|
|
||||||
url = "https://raw.githubusercontent.com/revanced/revanced-patches/main/patches.json"
|
|
||||||
logger.debug(f"fetching all patches from {url}")
|
|
||||||
response = session.get(url)
|
|
||||||
handle_response(response)
|
|
||||||
patches = response.json()
|
|
||||||
|
|
||||||
for app_name in (self.revanced_app_ids[x][1] for x in self.revanced_app_ids):
|
for app_name in (self.revanced_app_ids[x][1] for x in self.revanced_app_ids):
|
||||||
setattr(self, app_name, [])
|
setattr(self, app_name, [])
|
||||||
setattr(self, "universal_patch", [])
|
setattr(self, "universal_patch", [])
|
||||||
@@ -122,47 +91,11 @@ class Patches(object):
|
|||||||
p["app"] = compatible_package
|
p["app"] = compatible_package
|
||||||
p["version"] = version[-1] if version else "all"
|
p["version"] = version[-1] if version else "all"
|
||||||
getattr(self, app_name).append(p)
|
getattr(self, app_name).append(p)
|
||||||
if self.config.dry_run:
|
n_patches = len(getattr(self, f"_{app.app_name}"))
|
||||||
extended_patches = patches
|
app.no_of_patches = n_patches
|
||||||
else:
|
|
||||||
if self.config.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"
|
|
||||||
response = session.get(url)
|
|
||||||
handle_response(response)
|
|
||||||
extended_patches = response.json()
|
|
||||||
for app_name in (
|
|
||||||
self.revanced_extended_app_ids[x][1] for x in self.revanced_extended_app_ids
|
|
||||||
):
|
|
||||||
setattr(self, app_name, [])
|
|
||||||
|
|
||||||
for patch in extended_patches:
|
def __init__(self, config: RevancedConfig, app: APP) -> None:
|
||||||
for compatible_package, version in [
|
self.fetch_patches(config, app)
|
||||||
(x["name"], x["versions"]) for x in patch["compatiblePackages"]
|
|
||||||
]:
|
|
||||||
if compatible_package in self.revanced_extended_app_ids:
|
|
||||||
app_name = self.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 self.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 self.revanced_app_ids.values():
|
|
||||||
n_patches = len(getattr(self, app_id))
|
|
||||||
logger.debug(f"Total patches in {app_name} are {n_patches}")
|
|
||||||
n_patches = len(getattr(self, "universal_patch"))
|
|
||||||
logger.debug(f"Total universal patches are {n_patches}")
|
|
||||||
|
|
||||||
def __init__(self, config: RevancedConfig) -> None:
|
|
||||||
self.config = config
|
|
||||||
self.check_java(self.config.dry_run)
|
|
||||||
self.fetch_patches()
|
|
||||||
if self.config.dry_run:
|
|
||||||
self.config.apps = list(self._revanced_app_ids.values())
|
|
||||||
|
|
||||||
def get(self, app: str) -> Tuple[List[Dict[str, str]], str]:
|
def get(self, app: str) -> Tuple[List[Dict[str, str]], str]:
|
||||||
"""Get all patches for the given app.
|
"""Get all patches for the given app.
|
||||||
@@ -170,11 +103,7 @@ class Patches(object):
|
|||||||
:param app: Name of the application
|
:param app: Name of the application
|
||||||
:return: Patches
|
:return: Patches
|
||||||
"""
|
"""
|
||||||
logger.debug("Getting patches for %s" % app)
|
|
||||||
app_names = {value[0]: value[1] for value in self.revanced_app_ids.values()}
|
app_names = {value[0]: value[1] for value in self.revanced_app_ids.values()}
|
||||||
app_names.update(
|
|
||||||
{value[0]: value[1] for value in self.revanced_extended_app_ids.values()}
|
|
||||||
)
|
|
||||||
|
|
||||||
if not (app_name := app_names.get(app)):
|
if not (app_name := app_names.get(app)):
|
||||||
raise AppNotFound(app)
|
raise AppNotFound(app)
|
||||||
@@ -182,14 +111,13 @@ class Patches(object):
|
|||||||
version = "latest"
|
version = "latest"
|
||||||
try:
|
try:
|
||||||
version = next(i["version"] for i in patches if i["version"] != "all")
|
version = next(i["version"] for i in patches if i["version"] != "all")
|
||||||
logger.debug(f"Recommended Version for patching {app} is {version}")
|
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
pass
|
pass
|
||||||
return patches, version
|
return patches, version
|
||||||
|
|
||||||
# noinspection IncorrectFormatting
|
# noinspection IncorrectFormatting
|
||||||
def include_exclude_patch(
|
def include_exclude_patch(
|
||||||
self, app: str, parser: Any, patches: List[Dict[str, str]]
|
self, app: APP, parser: Any, patches: List[Dict[str, str]]
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Include and exclude patches for a given app.
|
"""Include and exclude patches for a given app.
|
||||||
|
|
||||||
@@ -197,34 +125,20 @@ class Patches(object):
|
|||||||
:param parser: Parser Obj
|
:param parser: Parser Obj
|
||||||
:param patches: All the patches of a given app
|
:param patches: All the patches of a given app
|
||||||
"""
|
"""
|
||||||
if self.config.build_extended and app in self.config.extended_apps:
|
|
||||||
excluded_patches = self.config.env.list(
|
|
||||||
f"EXCLUDE_PATCH_{app}_EXTENDED".upper(), []
|
|
||||||
)
|
|
||||||
included_patches = self.config.env.list(
|
|
||||||
f"INCLUDE_PATCH_{app}_EXTENDED".upper(), []
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
excluded_patches = self.config.env.list(f"EXCLUDE_PATCH_{app}".upper(), [])
|
|
||||||
included_patches = self.config.env.list(f"INCLUDE_PATCH_{app}".upper(), [])
|
|
||||||
for patch in patches:
|
for patch in patches:
|
||||||
normalized_patch = patch["name"].lower().replace(" ", "-")
|
normalized_patch = patch["name"].lower().replace(" ", "-")
|
||||||
parser.include(
|
parser.include(
|
||||||
normalized_patch
|
normalized_patch
|
||||||
) if normalized_patch not in excluded_patches else parser.exclude(
|
) if normalized_patch not in app.exclude_request else parser.exclude(
|
||||||
normalized_patch
|
normalized_patch
|
||||||
)
|
)
|
||||||
for normalized_patch in included_patches:
|
for normalized_patch in app.include_request:
|
||||||
parser.include(normalized_patch) if normalized_patch not in getattr(
|
parser.include(normalized_patch) if normalized_patch not in getattr(
|
||||||
self, "universal_patch", []
|
self, "universal_patch", []
|
||||||
) else ()
|
) else ()
|
||||||
excluded = parser.get_excluded_patches()
|
logger.info(app)
|
||||||
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) -> Tuple[List[Dict[str, str]], str, bool]:
|
def get_app_configs(self, app: "APP") -> List[Dict[str, str]]:
|
||||||
"""Get Configurations for a given app.
|
"""Get Configurations for a given app.
|
||||||
|
|
||||||
:param app: Name of the application
|
:param app: Name of the application
|
||||||
@@ -232,15 +146,15 @@ class Patches(object):
|
|||||||
experimental
|
experimental
|
||||||
"""
|
"""
|
||||||
experiment = False
|
experiment = False
|
||||||
total_patches, recommended_version = self.get(app=app)
|
total_patches, recommended_version = self.get(app=app.app_name)
|
||||||
env_version = self.config.env.str(f"{app}_VERSION".upper(), None)
|
if app.app_version:
|
||||||
if env_version:
|
logger.debug(f"Picked {app} version {app.app_version:} from env.")
|
||||||
logger.debug(f"Picked {app} version {env_version} from env.")
|
|
||||||
if (
|
if (
|
||||||
env_version == "latest"
|
app.app_version == "latest"
|
||||||
or env_version > recommended_version
|
or app.app_version > recommended_version
|
||||||
or env_version < recommended_version
|
or app.app_version < recommended_version
|
||||||
):
|
):
|
||||||
experiment = True
|
experiment = True
|
||||||
recommended_version = env_version
|
recommended_version = app.app_version
|
||||||
return total_patches, recommended_version, experiment
|
app.set_recommended_version(recommended_version, experiment)
|
||||||
|
return total_patches
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
"""Utilities."""
|
"""Utilities."""
|
||||||
import re
|
import re
|
||||||
|
import subprocess
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
@@ -50,6 +51,12 @@ class PatcherDownloadFailed(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PatchesJsonFailed(ValueError):
|
||||||
|
"""Patches failed."""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def handle_response(response: Response) -> None:
|
def handle_response(response: Response) -> None:
|
||||||
"""Handle Get Request Response."""
|
"""Handle Get Request Response."""
|
||||||
response_code = response.status_code
|
response_code = response.status_code
|
||||||
@@ -76,3 +83,22 @@ def slugify(string: str) -> str:
|
|||||||
string = string.strip("-")
|
string = string.strip("-")
|
||||||
|
|
||||||
return string
|
return string
|
||||||
|
|
||||||
|
|
||||||
|
def check_java(dry_run: bool) -> None:
|
||||||
|
"""Check if Java17 is installed."""
|
||||||
|
try:
|
||||||
|
if dry_run:
|
||||||
|
return
|
||||||
|
jd = subprocess.check_output(
|
||||||
|
["java", "-version"], stderr=subprocess.STDOUT
|
||||||
|
).decode("utf-8")
|
||||||
|
jd = jd[1:-1]
|
||||||
|
if "Runtime Environment" not in jd:
|
||||||
|
raise subprocess.CalledProcessError(-1, "java -version")
|
||||||
|
if "17" not in jd and "20" not in jd:
|
||||||
|
raise subprocess.CalledProcessError(-1, "java -version")
|
||||||
|
logger.debug("Cool!! Java is available")
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
logger.debug("Java>= 17 Must be installed")
|
||||||
|
exit(-1)
|
||||||
|
|||||||
Reference in New Issue
Block a user