Pyoncord changes
This commit is contained in:
parent
9c19178286
commit
87a567ad6a
20 changed files with 217 additions and 194 deletions
8
.github/workflows/build.yml
vendored
8
.github/workflows/build.yml
vendored
|
|
@ -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
3
.gitmodules
vendored
|
|
@ -1,3 +0,0 @@
|
|||
[submodule "VendettaXposed"]
|
||||
path = VendettaXposed
|
||||
url = https://github.com/vendetta-mod/VendettaXposed
|
||||
12
Makefile
12
Makefile
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
),
|
||||
]
|
||||
|
|
|
|||
26
README.md
26
README.md
|
|
@ -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 -->
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
globalThis.__vendetta_loader={name:"VendettaTweak",features:{loaderConfig:true,devtools:{prop:"__vendetta_rdc",version:"4.27.1"},themes:{prop:"__vendetta_theme"}}};
|
||||
5
Resources/payload-base.js
Normal file
5
Resources/payload-base.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
globalThis.__PYON_LOADER__ = {
|
||||
loaderName: "PyoncordTweak",
|
||||
hasThemeSupport: true,
|
||||
storedTheme: null
|
||||
}
|
||||
|
|
@ -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 {}
|
||||
}
|
||||
|
|
@ -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)!
|
||||
142
Sources/PyoncordTweak/Tweak.x.swift
Normal file
142
Sources/PyoncordTweak/Tweak.x.swift
Normal 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) }
|
||||
}
|
||||
}
|
||||
}
|
||||
16
Sources/PyoncordTweak/Utils.x.swift
Normal file
16
Sources/PyoncordTweak/Utils.x.swift
Normal 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
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
module VendettaTweakC {
|
||||
module PyoncordTweakC {
|
||||
umbrella "."
|
||||
export *
|
||||
}
|
||||
|
|
@ -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) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
6
control
6
control
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue