Skip to content

Instantly share code, notes, and snippets.

@chsbuffer
Last active May 20, 2023 18:16
Show Gist options
  • Save chsbuffer/a0584f837f36f2a0da613df419f7a41b to your computer and use it in GitHub Desktop.
Save chsbuffer/a0584f837f36f2a0da613df419f7a41b to your computer and use it in GitHub Desktop.
Revanced script
# Revanced Script #
Download and Patch Youtube and Youtube Music with latest Revanced assets
prerequisite:
Python ^3.8 in PATH
JRE 17+ in PATH
python-requests ^2.28.1
python-bs4 / beautifulsoup4 ^4.11.1
usage:
$ python revanced-script.py
note:
Patched apk goes to $HOME/Downloads, or the script's directory if Downloads doesn't exist.
Working directory at $TEMP/revanced-script.
Put exist keystore next to the script to sign with it, otherwise go to working directory to gather the generated keystore.
Revanced assets are only updated once a day to avoid GitHub API rate limits.
termux usage:
1. $ pkg in openjdk-17 python; pip install requests beautifulsoup4
2. download https://github.com/revanced/revanced-manager/raw/main/android/app/src/main/jniLibs/arm64-v8a/libaapt2.so
move to the scripts directory and rename to 'aapt2'
4. $ chmod +x aapt2
5. $ python revanced-script.py
todo:
get target Youtube version
import os
import requests
import json
from bs4 import BeautifulSoup
import logging
from pathlib import Path
from datetime import datetime
import subprocess
import tempfile
import itertools
logging.basicConfig(level=logging.DEBUG)
def download_url(url, output, **kwargs):
resp = requests.get(url, **kwargs)
resp.raise_for_status()
with open(output, "wb") as f:
f.write(resp.content)
def download_github_asset(owner, repo, filename, output, prerelease=False):
url = f"https://api.github.com/repos/{owner}/{repo}/releases"
if not prerelease:
url += "/latest"
resp = requests.get(url)
data = json.loads(resp.text)
releases = [data]
if prerelease:
releases = data
for release in releases:
if prerelease and not release["prerelease"]:
continue
for asset in release["assets"]:
if asset["name"].startswith(filename):
url = asset["browser_download_url"]
break
break
download_url(url, output)
def download_apkmirror_apk(url, output, override=False):
logging.debug(f"{download_apkmirror_apk.__name__}: ({url}, {output}, {override})")
if not override and os.path.isfile(output):
return
apkmirror = "https://www.apkmirror.com"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"
}
resp = requests.get(url, headers=headers)
resp.raise_for_status()
dom = BeautifulSoup(resp.text, features="html.parser")
jump = dom.select_one(".downloadButton")["href"] # type: ignore
jump = f"{apkmirror}{jump}"
#
resp = requests.get(jump, headers=headers)
resp.raise_for_status()
dom = BeautifulSoup(resp.text, features="html.parser")
download = dom.select_one("a[rel=nofollow]")["href"] # type: ignore
download = f"{apkmirror}{download}"
#
download_url(download, output, **{"headers": headers})
class ApkMirrorUpdater:
def __init__(self) -> None:
self.baseUrl = "https://www.apkmirror.com"
self.appExists = "/wp-json/apkm/v1/app_exists/"
self.user = "api-apkupdater"
self.token = "rm5rcfruUjKy04sMpyMPJXW8"
self.userAgent = "APKUpdater-v" + "2.0.5"
def post(self, apps):
from requests.auth import HTTPBasicAuth
import requests
url = f"{self.baseUrl}{self.appExists}"
headers = {"User-Agent": self.userAgent}
resp = requests.post(
url,
auth=HTTPBasicAuth(self.user, self.token),
headers=headers,
json={"pnames": apps, "exclude": ["alpha", "beta"]},
)
resp.raise_for_status()
return resp.json()
def revanced_patch(apk, out, integration=False, exclude=None):
if exclude is None:
exclude = []
keystore = list(pwd.glob("*.keystore"))
args = (
["java", "-jar", work_dir / "revanced-cli.jar"]
+ ["--clean"]
+ ["--bundle", patches]
+ (["--merge", integrations] if integration else [])
+ (["--keystore", keystore[0]] if keystore else [])
+ ["--apk", apk]
+ ["--out", out]
+ list(itertools.chain(*[("--exclude", x) for x in exclude]))
+ (["--custom-aapt2-binary", "aapt2"] if os.getenv("TERMUX_VERSION") else [])
)
logging.debug(f"execute: {' '.join([str(x) for x in args])}")
subprocess.call(args)
def yt(ver):
apk = work_dir / f"youtube-{ver}.apk"
out = out_dir / f"revanced-{ver}.apk"
logging.info("Downloading Youtube")
_ytVer = ver.replace(".", "-")
download_apkmirror_apk(
f"https://www.apkmirror.com/apk/google-inc/youtube/youtube-{_ytVer}-release/youtube-{_ytVer}-android-apk-download/",
apk,
)
logging.info("Patching Youtube")
revanced_patch(apk, out, integration=True)
def yt_music(ver=None):
url = None
if ver:
_ver = ver.replace(".", "-")
url = f"https://www.apkmirror.com/apk/google-inc/youtube-music/youtube-music-{_ver}-release/youtube-music-{_ver}-4-android-apk-download/"
else:
logging.info("Get latest YT Music")
updater = ApkMirrorUpdater()
data = updater.post(["com.google.android.apps.youtube.music"])["data"]
if not data:
raise Exception("No YT Music APK found on ApkMirror")
data = data[0]
ver = data["release"]["version"]
logging.info(f"Found YT Music {ver}")
for x in data["apks"]:
if "arm64-v8a" in x["arches"]:
url = updater.baseUrl + x["link"]
break
apk = work_dir / f"ytmusic-{ver}.apk"
patched = out_dir / f"revanced-music-{ver}.apk"
logging.info("Download YT Music")
download_apkmirror_apk(url, apk)
logging.info("Patching YT Music")
revanced_patch(apk, patched)
# Get the path of the current working directory
pwd = Path(os.path.dirname(os.path.abspath(__file__)))
work_dir = Path(tempfile.gettempdir()) / f"revanced-script"
work_dir.mkdir(parents=False, exist_ok=True)
os.chdir(work_dir)
logging.info(f"work_dir: {work_dir}")
out_dir = Path.home() / "Downloads"
out_dir = out_dir if out_dir.exists() else pwd
logging.info(f"ouput_dir: {out_dir}")
cli = work_dir / "revanced-cli.jar"
patches = work_dir / "revanced-patches.jar"
integrations = work_dir / "revanced-integrations.jar"
if not os.path.isfile(patches) or datetime.fromtimestamp(os.path.getmtime(patches)).date() != datetime.today().date():
logging.info("update revanced")
download_github_asset("revanced", "revanced-cli", "revanced-cli", cli)
download_github_asset("revanced", "revanced-patches", "revanced-patches", patches, prerelease=True)
download_github_asset("revanced", "revanced-integrations", "revanced-integrations", integrations, prerelease=True)
yt("18.08.37")
yt_music()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment