Pyoncord changes

This commit is contained in:
amsyarasyiq 2024-03-15 08:10:25 +08:00
parent 9c19178286
commit 87a567ad6a
20 changed files with 217 additions and 194 deletions

View file

@ -1,6 +1,8 @@
name: Build
on: [push]
on:
push:
workflow_dispatch:
jobs:
build:
@ -30,7 +32,7 @@ jobs:
with:
orion: "true"
- name: Build package
- name: Build rootful package
run: |
rm -f packages/*
make package FINALPACKAGE=1
@ -38,7 +40,7 @@ jobs:
- name: Upload package
uses: actions/upload-artifact@v3
with:
name: "Package built by ${{ matrix.os }}"
name: "Rootful package built by ${{ matrix.os }}"
path: ${{ github.workspace }}/packages/*-arm.deb
- name: Build rootless package

3
.gitmodules vendored
View file

@ -1,3 +0,0 @@
[submodule "VendettaXposed"]
path = VendettaXposed
url = https://github.com/vendetta-mod/VendettaXposed

View file

@ -7,13 +7,13 @@ endif
include $(THEOS)/makefiles/common.mk
TWEAK_NAME = VendettaTweak
TWEAK_NAME = PyoncordTweak
VendettaTweak_FILES = $(shell find Sources/VendettaTweak -name '*.swift') $(shell find Sources/VendettaTweakC -name '*.m' -o -name '*.c' -o -name '*.mm' -o -name '*.cpp')
VendettaTweak_SWIFTFLAGS = -ISources/VendettaTweakC/include
VendettaTweak_CFLAGS = -fobjc-arc -ISources/VendettaTweakC/include
PyoncordTweak_FILES = $(shell find Sources/PyoncordTweak -name '*.swift') $(shell find Sources/PyoncordTweakC -name '*.m' -o -name '*.c' -o -name '*.mm' -o -name '*.cpp')
PyoncordTweak_SWIFTFLAGS = -ISources/PyoncordTweakC/include
PyoncordTweak_CFLAGS = -fobjc-arc -ISources/PyoncordTweakC/include
VendettaTweak_BUNDLE_NAME = VendettaPatches
VendettaTweak_BUNDLE_RESOURCE_DIRS = VendettaXposed/App/src/main/assets/js Resources
PyoncordTweak_BUNDLE_NAME = PyoncordPatches
PyoncordTweak_BUNDLE_RESOURCE_DIRS = Resources
include $(THEOS_MAKE_PATH)/tweak.mk

View file

@ -65,23 +65,23 @@ let swiftFlags: [String] = libFlags + [
]
let package = Package(
name: "VendettaTweak",
name: "PyoncordTweak",
platforms: [.iOS(deploymentTarget)],
products: [
.library(
name: "VendettaTweak",
targets: ["VendettaTweak"]
name: "PyoncordTweak",
targets: ["PyoncordTweak"]
),
],
targets: [
.target(
name: "VendettaTweakC",
name: "PyoncordTweakC",
cSettings: [.unsafeFlags(cFlags)],
cxxSettings: [.unsafeFlags(cxxFlags)]
),
.target(
name: "VendettaTweak",
dependencies: ["VendettaTweakC"],
name: "PyoncordTweak",
dependencies: ["PyoncordTweakC"],
swiftSettings: [.unsafeFlags(swiftFlags)]
),
]

View file

@ -1,29 +1,29 @@
> [!IMPORTANT]
> As of 06/02/24, Vendetta and related projects have been discontinued.
> [!NOTE]
> This tweak was desperately forked from VendettaTweak. I may not have the expertise to maintain or expand this tweak beyond its current state
# VendettaTweak
# PyoncordTweak
A rootful/rootless tweak to inject Vendetta into Discord.
A rootful/rootless tweak to inject [Bunny](https://github.com/pyoncord/Bunny) into Discord. Forked [VendettaTweak](https://github.com/vendetta-mod/VendettaTweak), modified to match with [PyoncordXposed](https://github.com/pyoncord/PyoncordXposed) behavior. There are still slight differences between these two, and this tweak may be missing some loader features.
## Installation
### Jailbroken (Rootful/Rootless)
1. Install Orion runtime via your preferred package manager, by adding `https://repo.chariz.com/` to your sources, then finding `Orion Runtime`.
1. Install Vendetta by downloading the appropriate `.deb` file (or by building your own, see [Building VendettaTweak locally](#building-vendettatweak-locally)). Use the file ending in `arm.deb` for rootful jailbreaks, and the file ending in `arm64.deb` for rootless jailbreaks.
1. Install Bunny by downloading the appropriate `.deb` file (or by building your own, see [Building PyoncordTweak locally](#building-pyoncordtweak-locally)). Use the file ending in `arm.deb` for rootful jailbreaks, and the file ending in `arm64.deb` for rootless jailbreaks.
### Non-Jailbroken
1. Download Orion from [here](https://github.com/theos/orion/releases). You will need the `deb` file ending in `arm.deb` NOT `arm64.deb`.
1. Download the rootful Vendetta `.deb` file (file ending in `arm.deb`) or build your own by following the [Building VendettaTweak locally](#building-vendettatweak-locally) steps.
1. Download the rootful PyoncordTweak `.deb` file (file ending in `arm.deb`) or build your own by following the [Building PyoncordTweak locally](#building-pyoncordtweak-locally) steps.
1. Clone [azule](https://github.com/Al4ise/Azule/tree/main) into a folder and `cd` into it.
1. Extract or obtain a decrypted Discord IPA. To extract the IPA from a jailbroken iDevice, we recommend [bagbak](https://github.com/ChiChou/bagbak).
1. Run `./azule -i <path to decrypted IPA> -o <path to output folder> -f <path to Orion deb> <path to Vendetta deb>`. Make sure to provide the full paths to the files (you cannot use relative paths unfortunately). Example: `./azule -i /Users/vendetta/IPA/Discord.ipa -o /Users/vendetta/IPA/VendettaDiscord -f /Users/vendetta/IPA/dev.theos.orion14_1.0.1_iphoneos-arm.deb /Users/vendetta/IPA/dev.beefers.vendetta_0.0.2_iphoneos-arm.deb`
1. Run `./azule -i <path to decrypted IPA> -o <path to output folder> -f <path to Orion deb> <path to PyoncordTweak deb>`. Make sure to provide the full paths to the files (you cannot use relative paths unfortunately). Example: `./azule -i ~/Users/vendetta/IPA/Discord.ipa -o ~/Users/vendetta/IPA/outputs -f ~/Users/vendetta/IPA/dev.theos.orion14_1.0.1_iphoneos-arm.deb ~/Users/vendetta/IPA/com.pyoncord.bunny_0.0.1_iphoneos-arm.deb`
1. Install the generated IPA using your preferred sideloading method (at the time of writing this, only Sideloadly works).
## Building VendettaTweak locally
## Building PyoncordTweak locally
> **Note**
> [!NOTE]
> These steps assume you use MacOS.
1. Install Xcode from the App Store. If you've previously installed the `Command Line Utilities` package, you will need to run `sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer` to make sure you're using the Xcode tools instead.
@ -32,7 +32,7 @@ A rootful/rootless tweak to inject Vendetta into Discord.
2. Install the required dependencies. You can do this by running `brew install make ldid` in your terminal. If you do not have brew installed, follow the instructions [here](https://brew.sh/).
3. Setup your path accordingly. We recommend you run the following before running the next commands, as well as any time you want to build VendettaTweak.
3. Setup your path accordingly. We recommend you run the following before running the next commands, as well as any time you want to build PyoncordTweak.
```bash
export PATH="$(brew --prefix make)/libexec/gnubin:$PATH"
@ -48,9 +48,9 @@ bash -c "$(curl -fsSL https://raw.githubusercontent.com/theos/theos/master/bin/i
If you've already installed theos, you can run `$THEOS/bin/update-theos` to make sure it's up to date.
5. Clone this repository with `git clone git@github.com:vendetta-mod/VendettaTweak.git --recurse-submodules` and `cd` into it. Replace the URL with your fork if you've forked this repository.
5. Clone this repository with `git clone git@github.com:pyoncord/PyoncordTweak.git` and `cd` into it. Replace the URL with your fork if you've forked this repository.
6. To build VendettaTweak, you can run `rm -rf packages && make clean && make package FINALPACKAGE=1 && make package FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless`. The first command will remove any previous packages, the second will clean the project, the third will build the rootful package (which is denoted by the `arm.deb` ending), and the fourth will build the rootless package (which is denoted by the `arm64.deb` ending).
6. To build PyoncordTweak, you can run `rm -rf packages && make clean && make package FINALPACKAGE=1 && make package FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless`. The first command will remove any previous packages, the second will clean the project, the third will build the rootful package (which is denoted by the `arm.deb` ending), and the fourth will build the rootless package (which is denoted by the `arm64.deb` ending).
The first time you run this, it might take a bit longer, but subsequent builds should be much faster.
@ -58,6 +58,6 @@ The resulting `.deb` files will be in the `packages` folder. As a reminder, `*ar
## Contributing
If you want to contribute, you will basically need to follow the steps for [Building VendettaTweak locally](#building-vendettatweak-locally), as well as run `make spm` for the Swift LSP to work.
If you want to contribute, you will basically need to follow the steps for [Building PyoncordTweak locally](#building-pyoncordtweak-locally), as well as run `make spm` for the Swift LSP to work.
<!-- @vladdy was here, battling all these steps so you don't have to. Have fun! :3 -->

View file

@ -1 +0,0 @@
globalThis.__vendetta_loader={name:"VendettaTweak",features:{loaderConfig:true,devtools:{prop:"__vendetta_rdc",version:"4.27.1"},themes:{prop:"__vendetta_theme"}}};

View file

@ -0,0 +1,5 @@
globalThis.__PYON_LOADER__ = {
loaderName: "PyoncordTweak",
hasThemeSupport: true,
storedTheme: null
}

View file

@ -13,21 +13,22 @@ struct CustomLoadUrl: Codable {
struct LoaderConfig: Codable {
let customLoadUrl: CustomLoadUrl
let loadReactDevTools: Bool
var loadPyoncord: Bool? = nil
}
let defaultLoaderConfig = LoaderConfig(
customLoadUrl: CustomLoadUrl(
enabled: false,
url: URL(string: "http://localhost:4040/vendetta.js")!
url: URL(string: "http://localhost:4040/bunny.js")!
),
loadReactDevTools: false
)
let documentDirectory = getDocumentDirectory()
let loaderConfigUrl = documentDirectory.appendingPathComponent("vendetta_loader.json")
let pyoncordDirectory = getPyoncordDirectory()
let loaderConfigUrl = pyoncordDirectory.appendingPathComponent("loader.json")
func getLoaderConfig() -> LoaderConfig {
os_log("Getting loader config", log: vendettaLog, type: .debug)
os_log("Getting loader config", log: pyoncordLog, type: .debug)
let fileManager = FileManager.default
do {
@ -35,24 +36,15 @@ func getLoaderConfig() -> LoaderConfig {
let data = try Data(contentsOf: loaderConfigUrl)
let loaderConfig = try JSONDecoder().decode(LoaderConfig.self, from: data)
os_log("Got loader config", log: vendettaLog, type: .debug)
os_log("Got loader config", log: pyoncordLog, type: .debug)
return loaderConfig
} else {
throw LoaderConfigError.doesNotExist
}
} catch {
os_log("Couldn't get loader config", log: vendettaLog, type: .error)
createLoaderConfig()
os_log("Couldn't get loader config", log: pyoncordLog, type: .error)
return defaultLoaderConfig
}
}
func createLoaderConfig() {
do {
let encodedConfig = try JSONEncoder().encode(defaultLoaderConfig)
try encodedConfig.write(to: loaderConfigUrl)
os_log("Created loader config", log: vendettaLog, type: .debug)
} catch {}
}

View file

@ -1,6 +1,6 @@
import Orion
import UIKit
import VendettaTweakC
import PyoncordTweakC
import os
struct Author: Codable {
@ -56,7 +56,7 @@ func hexToUIColor(_ hex: String) -> UIColor? {
}
func swizzleDCDThemeColor(_ semanticColors: [String: [String]]) {
os_log("Swizzling DCDThemeColor", log: vendettaLog, type: .info)
os_log("Swizzling DCDThemeColor", log: pyoncordLog, type: .info)
let DCDTheme: AnyClass = NSClassFromString("DCDTheme")!
let dcdThemeTarget: AnyClass = object_getClass(DCDTheme)!
@ -68,25 +68,25 @@ func swizzleDCDThemeColor(_ semanticColors: [String: [String]]) {
let themeIndex: ThemeIndexType = unsafeBitCast(themeIndexImpl, to: ThemeIndexType.self)
let DCDThemeColor: AnyClass = NSClassFromString("DCDThemeColor")!
os_log("Found instance of DCDThemeColor", log: vendettaLog, type: .debug)
os_log("Found instance of DCDThemeColor", log: pyoncordLog, type: .debug)
let target: AnyClass = object_getClass(DCDThemeColor)!
os_log("Found DCDThemeColor", log: vendettaLog, type: .debug)
os_log("Found DCDThemeColor", log: pyoncordLog, type: .debug)
var methodCount: UInt32 = 0
let methods = class_copyMethodList(target, &methodCount)!
os_log("DCDThemeColor has %{public}d methods", log: vendettaLog, type: .debug, methodCount)
os_log("DCDThemeColor has %{public}d methods", log: pyoncordLog, type: .debug, methodCount)
for i in 0..<Int(methodCount) {
let method = methods[i]
let selector = method_getName(method)
let methodName = NSStringFromSelector(selector)
os_log(
"Found method %{public}@", log: vendettaLog, type: .debug, methodName)
"Found method %{public}@", log: pyoncordLog, type: .debug, methodName)
if let semanticColor = semanticColors[methodName] {
os_log(
"Swizzling %{public}@", log: vendettaLog, type: .debug, methodName)
"Swizzling %{public}@", log: pyoncordLog, type: .debug, methodName)
let originalImpl = method_getImplementation(method)
typealias OriginalType = @convention(c) (AnyObject, Selector) -> UIColor
@ -115,28 +115,28 @@ func swizzleDCDThemeColor(_ semanticColors: [String: [String]]) {
}
func swizzleUIColor(_ rawColors: [String: String]) {
os_log("Swizzling UIColor", log: vendettaLog, type: .info)
os_log("Swizzling UIColor", log: pyoncordLog, type: .info)
let UIColor: AnyClass = NSClassFromString("UIColor")!
os_log("Found instance of UIColor", log: vendettaLog, type: .debug)
os_log("Found instance of UIColor", log: pyoncordLog, type: .debug)
let target: AnyClass = object_getClass(UIColor)!
os_log("Found UIColor", log: vendettaLog, type: .debug)
os_log("Found UIColor", log: pyoncordLog, type: .debug)
var methodCount: UInt32 = 0
let methods = class_copyMethodList(target, &methodCount)!
os_log("UIColor has %{public}d methods", log: vendettaLog, type: .debug, methodCount)
os_log("UIColor has %{public}d methods", log: pyoncordLog, type: .debug, methodCount)
for i in 0..<Int(methodCount) {
let method = methods[i]
let selector = method_getName(method)
let methodName = NSStringFromSelector(selector)
os_log(
"Found method %{public}@", log: vendettaLog, type: .debug, methodName)
"Found method %{public}@", log: pyoncordLog, type: .debug, methodName)
if let rawColor = rawColors[methodName] {
os_log(
"Swizzling %{public}@", log: vendettaLog, type: .debug, methodName)
"Swizzling %{public}@", log: pyoncordLog, type: .debug, methodName)
let rawColorBlock: @convention(block) (AnyObject) -> UIColor = {
(self: AnyObject) -> UIColor in
return hexToUIColor(rawColor)!

View file

@ -0,0 +1,142 @@
import Orion
import PyoncordTweakC
import os
let pyoncordLog = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "pyoncord")
let source = URL(string: "bunny")!
let install_prefix = String(cString: get_install_prefix())
let isJailbroken = FileManager.default.fileExists(atPath: "\(install_prefix)/Library/Application Support/PyoncordTweak/PyoncordPatches.bundle")
let pyoncordPatchesBundlePath = isJailbroken ? "\(install_prefix)/Library/Application Support/PyoncordTweak/PyoncordPatches.bundle" : "\(Bundle.main.bundleURL.path)/PyoncordPatches.bundle"
class FileManagerLoadHook: ClassHook<FileManager> {
func containerURLForSecurityApplicationGroupIdentifier(_ groupIdentifier: NSString?) -> URL? {
os_log("containerURLForSecurityApplicationGroupIdentifier called! %{public}@ groupIdentifier", log: pyoncordLog, type: .debug, groupIdentifier ?? "nil")
if (isJailbroken) {
return orig.containerURLForSecurityApplicationGroupIdentifier(groupIdentifier)
}
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let lastPath = paths.last!
return lastPath.appendingPathComponent("AppGroup")
}
}
class LoadHook: ClassHook<RCTCxxBridge> {
func executeApplicationScript(_ script: Data, url: URL, async: Bool) {
os_log("executeApplicationScript called!", log: pyoncordLog, type: .debug)
let loaderConfig = getLoaderConfig()
let pyoncordPatchesBundle = Bundle(path: pyoncordPatchesBundlePath)!
if let patchPath = pyoncordPatchesBundle.url(forResource: "payload-base", withExtension: "js") {
let patchData = try! Data(contentsOf: patchPath)
os_log("Executing payload base", log: pyoncordLog, type: .debug)
orig.executeApplicationScript(patchData, url: source, async: true)
}
let pyoncordDirectory = getPyoncordDirectory()
var bundle = try? Data(contentsOf: pyoncordDirectory.appendingPathComponent("bunny.js"))
let group = DispatchGroup()
group.enter()
var bundleUrl: URL
if loaderConfig.customLoadUrl.enabled {
os_log(
"Custom load URL enabled, with URL %{public}@ ", log: pyoncordLog, type: .info,
loaderConfig.customLoadUrl.url.absoluteString)
bundleUrl = loaderConfig.customLoadUrl.url
} else {
if loaderConfig.loadPyoncord == true {
bundleUrl = URL(
string: "https://raw.githubusercontent.com/pyoncord/pyoncord/builds/pyoncord.js")!
} else {
bundleUrl = URL(
string: "https://raw.githubusercontent.com/pyoncord/detta-builds/main/bunny.js")!
}
}
os_log("Fetching JS bundle", log: pyoncordLog, type: .info)
var bundleRequest = URLRequest(
url: bundleUrl, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 3.0)
if let bundleEtag = try? String(
contentsOf: pyoncordDirectory.appendingPathComponent("etag.txt")), bundle != nil
{
bundleRequest.addValue(bundleEtag, forHTTPHeaderField: "If-None-Match")
}
let fetchTask = URLSession.shared.dataTask(with: bundleRequest) { data, response, error in
if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 {
os_log("Successfully fetched JS Bundle", log: pyoncordLog, type: .debug)
bundle = data
try? bundle?.write(to: pyoncordDirectory.appendingPathComponent("bunny.js"))
let etag = httpResponse.allHeaderFields["Etag"] as? String
try? etag?.write(
to: pyoncordDirectory.appendingPathComponent("etag.txt"), atomically: true,
encoding: .utf8)
}
group.leave()
}
fetchTask.resume()
group.wait()
if let themeString = try? String(
contentsOf: pyoncordDirectory.appendingPathComponent("current-theme.json"))
{
orig.executeApplicationScript(
"globalThis.__PYON_LOADER__.storedTheme=\(themeString)".data(using: .utf8)!, url: source, async: async)
}
let preloadsDirectory = pyoncordDirectory.appendingPathComponent("preloads")
if FileManager.default.fileExists(atPath: preloadsDirectory.path) {
do {
let contents = try FileManager.default.contentsOfDirectory(
at: preloadsDirectory, includingPropertiesForKeys: nil, options: [])
for fileURL in contents {
if fileURL.pathExtension == "js" {
os_log(
"Executing preload JS file %{public}@ ", log: pyoncordLog, type: .info, fileURL.absoluteString)
if let data = try? Data(contentsOf: fileURL) {
orig.executeApplicationScript(data, url: source, async: async)
}
}
}
} catch {
os_log("Error reading contents of preloads directory", log: pyoncordLog, type: .error)
}
}
if bundle != nil {
os_log("Executing JS bundle", log: pyoncordLog, type: .info)
orig.executeApplicationScript(bundle!, url: source, async: async)
} else {
os_log("Unable to fetch JS bundle", log: pyoncordLog, type: .error)
}
os_log("Executing original script", log: pyoncordLog, type: .info)
orig.executeApplicationScript(script, url: url, async: async)
}
}
struct PyoncordTweak: Tweak {
func tweakDidActivate() {
if let themeData = try? Data(
contentsOf: pyoncordDirectory.appendingPathComponent("current-theme.json")) {
let theme = try? JSONDecoder().decode(Theme.self, from: themeData)
if let semanticColors = theme?.data.semanticColors { swizzleDCDThemeColor(semanticColors) }
if let rawColors = theme?.data.rawColors { swizzleUIColor(rawColors) }
}
}
}

View file

@ -0,0 +1,16 @@
import Foundation
func getPyoncordDirectory() -> URL {
let documentDirectoryURL = try! FileManager.default.url(
for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let pyoncordFolderURL = documentDirectoryURL.appendingPathComponent("pyoncord")
// Create the "pyoncord" folder if it doesn't exist
if !FileManager.default.fileExists(atPath: pyoncordFolderURL.path) {
try! FileManager.default.createDirectory(
at: pyoncordFolderURL, withIntermediateDirectories: true, attributes: nil)
}
return pyoncordFolderURL
}

View file

@ -1,4 +1,4 @@
module VendettaTweakC {
module PyoncordTweakC {
umbrella "."
export *
}

View file

@ -1,123 +0,0 @@
import Orion
import VendettaTweakC
import os
let vendettaLog = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "vendetta")
let source = URL(string: "vendetta")!
let install_prefix = String(cString: get_install_prefix())
let isJailbroken = FileManager.default.fileExists(atPath: "\(install_prefix)/Library/Application Support/VendettaTweak/VendettaPatches.bundle")
let vendettaPatchesBundlePath = isJailbroken ? "\(install_prefix)/Library/Application Support/VendettaTweak/VendettaPatches.bundle" : "\(Bundle.main.bundleURL.path)/VendettaPatches.bundle"
class FileManagerLoadHook: ClassHook<FileManager> {
func containerURLForSecurityApplicationGroupIdentifier(_ groupIdentifier: NSString?) -> URL? {
os_log("containerURLForSecurityApplicationGroupIdentifier called! %{public}@ groupIdentifier", log: vendettaLog, type: .debug, groupIdentifier ?? "nil")
if (isJailbroken) {
return orig.containerURLForSecurityApplicationGroupIdentifier(groupIdentifier)
}
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let lastPath = paths.last!
return lastPath.appendingPathComponent("AppGroup")
}
}
class LoadHook: ClassHook<RCTCxxBridge> {
func executeApplicationScript(_ script: Data, url: URL, async: Bool) {
os_log("executeApplicationScript called!", log: vendettaLog, type: .debug)
let loaderConfig = getLoaderConfig()
let vendettaPatchesBundle = Bundle(path: vendettaPatchesBundlePath)!
var patches = ["modules", "identity"]
if loaderConfig.loadReactDevTools {
os_log("DevTools patch enabled", log: vendettaLog, type: .info)
patches.append("devtools")
}
os_log("Executing patches", log: vendettaLog, type: .info)
for patch in patches {
if let patchPath = vendettaPatchesBundle.url(forResource: patch, withExtension: "js") {
let patchData = try! Data(contentsOf: patchPath)
os_log("Executing %{public}@ patch", log: vendettaLog, type: .debug, patch)
orig.executeApplicationScript(patchData, url: source, async: true)
}
}
let documentDirectory = getDocumentDirectory()
var vendetta = try? Data(contentsOf: documentDirectory.appendingPathComponent("vendetta.js"))
let group = DispatchGroup()
group.enter()
var vendettaUrl: URL
if loaderConfig.customLoadUrl.enabled {
os_log(
"Custom load URL enabled, with URL %{public}@ ", log: vendettaLog, type: .info,
loaderConfig.customLoadUrl.url.absoluteString)
vendettaUrl = loaderConfig.customLoadUrl.url
} else {
vendettaUrl = URL(
string: "https://raw.githubusercontent.com/vendetta-mod/builds/master/vendetta.js")!
}
os_log("Fetching vendetta.js", log: vendettaLog, type: .info)
var vendettaRequest = URLRequest(
url: vendettaUrl, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 3.0)
if let vendettaEtag = try? String(
contentsOf: documentDirectory.appendingPathComponent("vendetta_etag.txt")), vendetta != nil
{
vendettaRequest.addValue(vendettaEtag, forHTTPHeaderField: "If-None-Match")
}
let vendettaTask = URLSession.shared.dataTask(with: vendettaRequest) { data, response, error in
if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 {
os_log("Successfully fetched vendetta.js", log: vendettaLog, type: .debug)
vendetta = data
try? vendetta?.write(to: documentDirectory.appendingPathComponent("vendetta.js"))
let etag = httpResponse.allHeaderFields["Etag"] as? String
try? etag?.write(
to: documentDirectory.appendingPathComponent("vendetta_etag.txt"), atomically: true,
encoding: .utf8)
}
group.leave()
}
vendettaTask.resume()
group.wait()
os_log("Executing original script", log: vendettaLog, type: .info)
orig.executeApplicationScript(script, url: url, async: async)
if let themeString = try? String(
contentsOf: documentDirectory.appendingPathComponent("vendetta_theme.json"))
{
orig.executeApplicationScript(
"globalThis.__vendetta_theme=\(themeString)".data(using: .utf8)!, url: source, async: async)
}
if vendetta != nil {
os_log("Executing vendetta.js", log: vendettaLog, type: .info)
orig.executeApplicationScript(vendetta!, url: source, async: async)
} else {
os_log("Unable to fetch vendetta.js", log: vendettaLog, type: .error)
}
}
}
struct VendettaTweak: Tweak {
func tweakDidActivate() {
if let themeData = try? Data(
contentsOf: documentDirectory.appendingPathComponent("vendetta_theme.json")) {
let theme = try? JSONDecoder().decode(Theme.self, from: themeData)
if let semanticColors = theme?.data.semanticColors { swizzleDCDThemeColor(semanticColors) }
if let rawColors = theme?.data.rawColors { swizzleUIColor(rawColors) }
}
}
}

View file

@ -1,6 +0,0 @@
import Foundation
func getDocumentDirectory() -> URL {
return try! FileManager.default.url(
for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
}

@ -1 +0,0 @@
Subproject commit 0df9aaeb7bcf6eda8f405b1c959a4618c539fca3

View file

@ -1,6 +1,6 @@
Package: dev.beefers.vendetta
Name: Vendetta
Version: 0.0.2
Package: com.pyoncord.bunny
Name: bunny
Version: 0.0.1
Architecture: iphoneos-arm
Description: A mod for Discord's mobile apps.
Maintainer: FieryFlames