From b0793740f5d4d01997bec75c74359bb1ce8735bc Mon Sep 17 00:00:00 2001 From: pylix <82711525+pylixonly@users.noreply.github.com> Date: Wed, 18 Sep 2024 07:51:38 +0800 Subject: [PATCH 01/15] feat: swap pyzule for cyan and pass some additional flags --- .github/workflows/build.yml | 11 ++++++----- .github/workflows/release.yml | 7 ++++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0559493..d5bab14 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -122,12 +122,13 @@ jobs: DEB_FILE_NAME="${PACKAGE}_${VERSION}_iphoneos-arm.deb" echo "DEB_FILE_NAME=$DEB_FILE_NAME" >> $GITHUB_ENV echo "APP_NAME=$NAME" >> $GITHUB_ENV - + + - name: Install cyan + run: pip install --force-reinstall https://github.com/asdfzxcvbn/pyzule-rw/archive/main.zip Pillow + - name: Inject tweak - run: | - bash -c "$(curl https://raw.githubusercontent.com/asdfzxcvbn/pyzule/main/install-pyzule.sh)" - pyzule -n ${{ env.APP_NAME }} -k PyoncordIcon60x60@2x.png -d -i discord.ipa -o ${{ github.workspace }}/${{ env.APP_NAME }}.ipa -f ${{ github.workspace }}/${{ env.DEB_FILE_NAME }} - + run: cyan -n ${{ env.APP_NAME }} -k PyoncordIcon60x60@2x.png -d -i discord.ipa -o ${{ github.workspace }}/${{ env.APP_NAME }}.ipa -f ${{ github.workspace }}/${{ env.DEB_FILE_NAME }} -uwsg + - name: Upload ipa as artifact uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 24deecb..747981b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -125,10 +125,11 @@ jobs: echo "ROOTLESS_DEB_FILE_NAME=$ROOTLESS_DEB_FILE_NAME" >> $GITHUB_ENV echo "APP_NAME=$NAME" >> $GITHUB_ENV + - name: Install cyan + run: pip install --force-reinstall https://github.com/asdfzxcvbn/pyzule-rw/archive/main.zip Pillow + - name: Inject tweak - run: | - bash -c "$(curl https://raw.githubusercontent.com/asdfzxcvbn/pyzule/main/install-pyzule.sh)" - pyzule -n ${{ env.APP_NAME }} -k PyoncordIcon60x60@2x.png -d -i discord.ipa -o ${{ github.workspace }}/${{ env.APP_NAME }}.ipa -f ${{ github.workspace }}/${{ env.DEB_FILE_NAME }} + run: cyan -n ${{ env.APP_NAME }} -k PyoncordIcon60x60@2x.png -d -i discord.ipa -o ${{ github.workspace }}/${{ env.APP_NAME }}.ipa -f ${{ github.workspace }}/${{ env.DEB_FILE_NAME }} -uwsg - name: Upload ipa as artifact uses: actions/upload-artifact@v4 From 8eec8a761c09ed8cb0c21502401f9c083a38343c Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 18 Sep 2024 00:07:17 +0000 Subject: [PATCH 02/15] chore: update app-repo.json --- app-repo.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app-repo.json b/app-repo.json index d6504c9..7c37964 100644 --- a/app-repo.json +++ b/app-repo.json @@ -12,6 +12,12 @@ "subtitle": "A client mod for Discord", "tintColor": "7289da", "versions": [ + { + "version": "247.0", + "date": "2024-09-18", + "size": 96629525, + "downloadURL": "https://github.com/pyoncord/BunnyTweak/releases/download/v247.0/Bunny.ipa" + }, { "version": "246.0", "date": "2024-09-14", From c0889328cceb12e7e1587bb2fa4a5ef30ac6d304 Mon Sep 17 00:00:00 2001 From: pylix <82711525+pylixonly@users.noreply.github.com> Date: Fri, 20 Sep 2024 14:29:40 +0000 Subject: [PATCH 03/15] Revert "feat: swap pyzule for cyan " This reverts commit b0793740f5d4d01997bec75c74359bb1ce8735bc. --- .github/workflows/build.yml | 11 +++++------ .github/workflows/release.yml | 7 +++---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d5bab14..0559493 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -122,13 +122,12 @@ jobs: DEB_FILE_NAME="${PACKAGE}_${VERSION}_iphoneos-arm.deb" echo "DEB_FILE_NAME=$DEB_FILE_NAME" >> $GITHUB_ENV echo "APP_NAME=$NAME" >> $GITHUB_ENV - - - name: Install cyan - run: pip install --force-reinstall https://github.com/asdfzxcvbn/pyzule-rw/archive/main.zip Pillow - + - name: Inject tweak - run: cyan -n ${{ env.APP_NAME }} -k PyoncordIcon60x60@2x.png -d -i discord.ipa -o ${{ github.workspace }}/${{ env.APP_NAME }}.ipa -f ${{ github.workspace }}/${{ env.DEB_FILE_NAME }} -uwsg - + run: | + bash -c "$(curl https://raw.githubusercontent.com/asdfzxcvbn/pyzule/main/install-pyzule.sh)" + pyzule -n ${{ env.APP_NAME }} -k PyoncordIcon60x60@2x.png -d -i discord.ipa -o ${{ github.workspace }}/${{ env.APP_NAME }}.ipa -f ${{ github.workspace }}/${{ env.DEB_FILE_NAME }} + - name: Upload ipa as artifact uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 747981b..24deecb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -125,11 +125,10 @@ jobs: echo "ROOTLESS_DEB_FILE_NAME=$ROOTLESS_DEB_FILE_NAME" >> $GITHUB_ENV echo "APP_NAME=$NAME" >> $GITHUB_ENV - - name: Install cyan - run: pip install --force-reinstall https://github.com/asdfzxcvbn/pyzule-rw/archive/main.zip Pillow - - name: Inject tweak - run: cyan -n ${{ env.APP_NAME }} -k PyoncordIcon60x60@2x.png -d -i discord.ipa -o ${{ github.workspace }}/${{ env.APP_NAME }}.ipa -f ${{ github.workspace }}/${{ env.DEB_FILE_NAME }} -uwsg + run: | + bash -c "$(curl https://raw.githubusercontent.com/asdfzxcvbn/pyzule/main/install-pyzule.sh)" + pyzule -n ${{ env.APP_NAME }} -k PyoncordIcon60x60@2x.png -d -i discord.ipa -o ${{ github.workspace }}/${{ env.APP_NAME }}.ipa -f ${{ github.workspace }}/${{ env.DEB_FILE_NAME }} - name: Upload ipa as artifact uses: actions/upload-artifact@v4 From 7c1e53ab1d5d953007c5f63f9ff6395f85b07711 Mon Sep 17 00:00:00 2001 From: pylix <82711525+pylixonly@users.noreply.github.com> Date: Fri, 20 Sep 2024 15:09:05 +0000 Subject: [PATCH 04/15] feat: add some flags for pyzule --- .github/workflows/build.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0559493..308d8a1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -126,7 +126,7 @@ jobs: - name: Inject tweak run: | bash -c "$(curl https://raw.githubusercontent.com/asdfzxcvbn/pyzule/main/install-pyzule.sh)" - pyzule -n ${{ env.APP_NAME }} -k PyoncordIcon60x60@2x.png -d -i discord.ipa -o ${{ github.workspace }}/${{ env.APP_NAME }}.ipa -f ${{ github.workspace }}/${{ env.DEB_FILE_NAME }} + pyzule -n ${{ env.APP_NAME }} -k PyoncordIcon60x60@2x.png -duwsg -i discord.ipa -o ${{ github.workspace }}/${{ env.APP_NAME }}.ipa -f ${{ github.workspace }}/${{ env.DEB_FILE_NAME }} - name: Upload ipa as artifact uses: actions/upload-artifact@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 24deecb..0fcaadf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -128,7 +128,7 @@ jobs: - name: Inject tweak run: | bash -c "$(curl https://raw.githubusercontent.com/asdfzxcvbn/pyzule/main/install-pyzule.sh)" - pyzule -n ${{ env.APP_NAME }} -k PyoncordIcon60x60@2x.png -d -i discord.ipa -o ${{ github.workspace }}/${{ env.APP_NAME }}.ipa -f ${{ github.workspace }}/${{ env.DEB_FILE_NAME }} + pyzule -n ${{ env.APP_NAME }} -k PyoncordIcon60x60@2x.png -duwsg -i discord.ipa -o ${{ github.workspace }}/${{ env.APP_NAME }}.ipa -f ${{ github.workspace }}/${{ env.DEB_FILE_NAME }} - name: Upload ipa as artifact uses: actions/upload-artifact@v4 From 586861569e6c651a9042bd372a5860de387a7faa Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 15:27:22 +0000 Subject: [PATCH 05/15] chore: update app-repo.json --- app-repo.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app-repo.json b/app-repo.json index 7c37964..35c3005 100644 --- a/app-repo.json +++ b/app-repo.json @@ -12,6 +12,12 @@ "subtitle": "A client mod for Discord", "tintColor": "7289da", "versions": [ + { + "version": "247.2", + "date": "2024-09-20", + "size": 96426195, + "downloadURL": "https://github.com/pyoncord/BunnyTweak/releases/download/v247.2/Bunny.ipa" + }, { "version": "247.0", "date": "2024-09-18", From d177bc57fb3353e7d13fa2fed43e149b4ed39280 Mon Sep 17 00:00:00 2001 From: pylix <82711525+pylixonly@users.noreply.github.com> Date: Fri, 20 Sep 2024 16:43:54 +0000 Subject: [PATCH 06/15] chore: meddling with patcher --- .github/workflows/build.yml | 13 ++++++++++--- .github/workflows/release.yml | 13 ++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 308d8a1..98d0a9f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -112,7 +112,6 @@ jobs: - name: Download IPA icons run: | curl -L -o ipa-icons.zip https://raw.githubusercontent.com/pyoncord/assets/main/ipa-icons.zip - unzip ipa-icons.zip - name: Extract Values run: | @@ -123,10 +122,18 @@ jobs: echo "DEB_FILE_NAME=$DEB_FILE_NAME" >> $GITHUB_ENV echo "APP_NAME=$NAME" >> $GITHUB_ENV + - name: Run patcher + run: | + curl -L -o patcher https://github.com/amsyarasyiq/bunny-ipa-patcher/releases/download/release-pyon/patcher.mac-amd64 + chmod +x patcher + ./patcher -d ./discord.ipa -o ./discord.ipa -i ./ipa-icons.zip + + - name: Install cyan + run: pip install --force-reinstall https://github.com/asdfzxcvbn/pyzule-rw/archive/main.zip Pillow + - name: Inject tweak run: | - bash -c "$(curl https://raw.githubusercontent.com/asdfzxcvbn/pyzule/main/install-pyzule.sh)" - pyzule -n ${{ env.APP_NAME }} -k PyoncordIcon60x60@2x.png -duwsg -i discord.ipa -o ${{ github.workspace }}/${{ env.APP_NAME }}.ipa -f ${{ github.workspace }}/${{ env.DEB_FILE_NAME }} + cyan -duws -i discord.ipa -o ${{ github.workspace }}/${{ env.APP_NAME }}.ipa -f ${{ github.workspace }}/${{ env.DEB_FILE_NAME }} - name: Upload ipa as artifact uses: actions/upload-artifact@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0fcaadf..c8e969f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -112,7 +112,6 @@ jobs: - name: Download IPA icons run: | curl -L -o ipa-icons.zip https://raw.githubusercontent.com/pyoncord/assets/main/ipa-icons.zip - unzip ipa-icons.zip - name: Extract Values run: | @@ -125,10 +124,18 @@ jobs: echo "ROOTLESS_DEB_FILE_NAME=$ROOTLESS_DEB_FILE_NAME" >> $GITHUB_ENV echo "APP_NAME=$NAME" >> $GITHUB_ENV + - name: Install cyan + run: pip install --force-reinstall https://github.com/asdfzxcvbn/pyzule-rw/archive/main.zip Pillow + - name: Inject tweak run: | - bash -c "$(curl https://raw.githubusercontent.com/asdfzxcvbn/pyzule/main/install-pyzule.sh)" - pyzule -n ${{ env.APP_NAME }} -k PyoncordIcon60x60@2x.png -duwsg -i discord.ipa -o ${{ github.workspace }}/${{ env.APP_NAME }}.ipa -f ${{ github.workspace }}/${{ env.DEB_FILE_NAME }} + cyan -duws -i discord.ipa -o ${{ github.workspace }}/${{ env.APP_NAME }}.ipa -f ${{ github.workspace }}/${{ env.DEB_FILE_NAME }} + + - name: Run patcher + run: | + curl -L -o patcher https://github.com/amsyarasyiq/bunny-ipa-patcher/releases/download/release-pyon/patcher.mac-amd64 + chmod +x patcher + ./patcher -d ${{ github.workspace }}/${{ env.APP_NAME }}.ipa -o ${{ github.workspace }}/${{ env.APP_NAME }}.ipa -i ./ipa-icons.zip - name: Upload ipa as artifact uses: actions/upload-artifact@v4 From 82e3c078dda28f4a9debe97e11ec3c43c36aedd0 Mon Sep 17 00:00:00 2001 From: pylixonly <82711525+pylixonly@users.noreply.github.com> Date: Sat, 9 Nov 2024 13:44:30 +0800 Subject: [PATCH 07/15] chore: bump ver to 0.3.2 for testing --- Resources/payload-base.js | 2 +- control | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/payload-base.js b/Resources/payload-base.js index 298e5af..a4b8743 100644 --- a/Resources/payload-base.js +++ b/Resources/payload-base.js @@ -1,6 +1,6 @@ globalThis.__PYON_LOADER__ = { loaderName: "BunnyTweak", - loaderVersion: "0.3.1", + loaderVersion: "0.3.2", hasThemeSupport: true, storedTheme: null, fontPatch: 2 diff --git a/control b/control index 6506668..a9f574d 100644 --- a/control +++ b/control @@ -1,6 +1,6 @@ Package: io.github.pyoncord.app Name: Bunny -Version: 0.3.1 +Version: 0.3.2 Architecture: iphoneos-arm Description: A mod for Discord's mobile apps. Maintainer: Pylix From 0b929c9bf04301285e09ba6a47a70e66e9d1cba4 Mon Sep 17 00:00:00 2001 From: pylixonly <82711525+pylixonly@users.noreply.github.com> Date: Sat, 9 Nov 2024 15:21:00 +0800 Subject: [PATCH 08/15] refactor: merge workflow scripts --- .github/workflows/build.yml | 142 ------------------ .github/workflows/{release.yml => deploy.yml} | 24 ++- 2 files changed, 16 insertions(+), 150 deletions(-) delete mode 100644 .github/workflows/build.yml rename .github/workflows/{release.yml => deploy.yml} (94%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 98d0a9f..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,142 +0,0 @@ -name: Build - -on: - workflow_dispatch: - inputs: - ipa_url: - description: "Direct link to the decrypted IPA" - default: "" - required: true - type: string - -env: - GH_TOKEN: ${{ github.token }} - -jobs: - build-tweak: - runs-on: macos-14 - - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - submodules: true - - - name: Download Tweak - run: | - set +e - - release_info=$(gh api --header 'Accept: application/vnd.github+json' repos/${{ github.repository }}/releases/latest) - status_code=$(echo $release_info | jq -r ".status") - - if [ "$status_code" != "null" ]; then - echo "No releases found or request failed, status code: $status_code" - echo "DEB_DOWNLOADED=false" >> $GITHUB_ENV - exit 0 - fi - - set -e - - release_version=$(echo "$release_info" | jq -r '.assets[] | select(.name | contains("iphoneos-arm.deb")) | .name' | grep -o '_[0-9.]\+_' | tr -d '_') - control_version=$(grep '^Version:' control | cut -d ' ' -f 2) - - if [ "$release_version" = "$control_version" ]; then - echo "Versions match. Downloading DEB files..." - echo "$release_info" | jq -r '.assets[] | select(.name | endswith(".deb")) | .browser_download_url' | xargs -I {} curl -L -O {} - echo "DEB_DOWNLOADED=true" >> $GITHUB_ENV - else - echo "Versions do not match. No files will be downloaded." - echo "DEB_DOWNLOADED=false" >> $GITHUB_ENV - exit 0 - fi - - - name: Check cache - if: env.DEB_DOWNLOADED == 'false' - run: echo upstream_heads=`git ls-remote https://github.com/theos/theos | head -n 1 | cut -f 1`-`git ls-remote https://github.com/theos/sdks | head -n 1 | cut -f 1` >> $GITHUB_ENV - - - name: Use cache - if: env.DEB_DOWNLOADED == 'false' - id: cache - uses: actions/cache@v4 - with: - path: ${{ github.workspace }}/theos - key: ${{ runner.os }}-${{ env.upstream_heads }} - - - name: Prepare Theos - if: env.DEB_DOWNLOADED == 'false' - uses: Randomblock1/theos-action@v1 - - - name: Build packages - if: env.DEB_DOWNLOADED == 'false' - run: make package FINALPACKAGE=1 && make package FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless - - - name: Set DEB path - run: | - if [ "${{ env.DEB_DOWNLOADED }}" == "true" ]; then - echo "DEB_PATH=${{ github.workspace }}/*-arm.deb" >> $GITHUB_ENV - echo "ROOTLESS_DEB_PATH=${{ github.workspace }}/*-arm64.deb" >> $GITHUB_ENV - else - echo "DEB_PATH=${{ github.workspace }}/packages/*-arm.deb" >> $GITHUB_ENV - echo "ROOTLESS_DEB_PATH=${{ github.workspace }}/packages/*-arm64.deb" >> $GITHUB_ENV - fi - - - name: Upload package - uses: actions/upload-artifact@v4 - with: - name: package - path: ${{ env.DEB_PATH }} - - - name: Upload rootless package - uses: actions/upload-artifact@v4 - with: - name: rootless package - path: ${{ env.ROOTLESS_DEB_PATH }} - - build-ipa: - runs-on: macos-14 - needs: build-tweak - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Download build artifacts - uses: actions/download-artifact@v4 - with: - merge-multiple: true - - - name: Download Discord IPA - run: | - curl -L -o discord.ipa ${{ github.event.inputs.ipa_url }} - - - name: Download IPA icons - run: | - curl -L -o ipa-icons.zip https://raw.githubusercontent.com/pyoncord/assets/main/ipa-icons.zip - - - name: Extract Values - run: | - NAME=$(grep '^Name:' control | cut -d ' ' -f 2) - PACKAGE=$(grep '^Package:' control | cut -d ' ' -f 2) - VERSION=$(grep '^Version:' control | cut -d ' ' -f 2) - DEB_FILE_NAME="${PACKAGE}_${VERSION}_iphoneos-arm.deb" - echo "DEB_FILE_NAME=$DEB_FILE_NAME" >> $GITHUB_ENV - echo "APP_NAME=$NAME" >> $GITHUB_ENV - - - name: Run patcher - run: | - curl -L -o patcher https://github.com/amsyarasyiq/bunny-ipa-patcher/releases/download/release-pyon/patcher.mac-amd64 - chmod +x patcher - ./patcher -d ./discord.ipa -o ./discord.ipa -i ./ipa-icons.zip - - - name: Install cyan - run: pip install --force-reinstall https://github.com/asdfzxcvbn/pyzule-rw/archive/main.zip Pillow - - - name: Inject tweak - run: | - cyan -duws -i discord.ipa -o ${{ github.workspace }}/${{ env.APP_NAME }}.ipa -f ${{ github.workspace }}/${{ env.DEB_FILE_NAME }} - - - name: Upload ipa as artifact - uses: actions/upload-artifact@v4 - with: - name: ipa - path: ${{ github.workspace }}/${{ env.APP_NAME }}.ipa diff --git a/.github/workflows/release.yml b/.github/workflows/deploy.yml similarity index 94% rename from .github/workflows/release.yml rename to .github/workflows/deploy.yml index c8e969f..a3e7d7a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/deploy.yml @@ -1,4 +1,5 @@ -name: Release +name: Deploy +run-name: ${{ github.event.inputs.release == true && 'Release' || 'Build' }} for ${{ github.event.inputs.ipa_url }} on: workflow_dispatch: @@ -8,10 +9,15 @@ on: default: "" required: true type: string + release: + description: 'Release the build' + required: true + type: boolean env: GH_TOKEN: ${{ github.token }} + jobs: build-tweak: runs-on: macos-14 @@ -123,7 +129,13 @@ jobs: ROOTLESS_DEB_FILE_NAME="${PACKAGE}_${VERSION}_iphoneos-arm64.deb" echo "ROOTLESS_DEB_FILE_NAME=$ROOTLESS_DEB_FILE_NAME" >> $GITHUB_ENV echo "APP_NAME=$NAME" >> $GITHUB_ENV - + + - name: Run patcher + run: | + curl -L -o patcher https://github.com/amsyarasyiq/bunny-ipa-patcher/releases/download/release-pyon/patcher.mac-amd64 + chmod +x patcher + ./patcher -d discord.ipa -o discord.ipa -i ./ipa-icons.zip + - name: Install cyan run: pip install --force-reinstall https://github.com/asdfzxcvbn/pyzule-rw/archive/main.zip Pillow @@ -131,12 +143,6 @@ jobs: run: | cyan -duws -i discord.ipa -o ${{ github.workspace }}/${{ env.APP_NAME }}.ipa -f ${{ github.workspace }}/${{ env.DEB_FILE_NAME }} - - name: Run patcher - run: | - curl -L -o patcher https://github.com/amsyarasyiq/bunny-ipa-patcher/releases/download/release-pyon/patcher.mac-amd64 - chmod +x patcher - ./patcher -d ${{ github.workspace }}/${{ env.APP_NAME }}.ipa -o ${{ github.workspace }}/${{ env.APP_NAME }}.ipa -i ./ipa-icons.zip - - name: Upload ipa as artifact uses: actions/upload-artifact@v4 with: @@ -144,6 +150,7 @@ jobs: path: ${{ github.workspace }}/${{ env.APP_NAME }}.ipa release-app: + if: ${{ github.event.inputs.release == true }} runs-on: macos-14 needs: build-ipa permissions: @@ -190,6 +197,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} app-repo: + if: ${{ github.event.inputs.release == true }} continue-on-error: true runs-on: macos-14 needs: release-app From a71b1b9a7d5901692e2cc17af9515c552898d11b Mon Sep 17 00:00:00 2001 From: pylixonly <82711525+pylixonly@users.noreply.github.com> Date: Sat, 9 Nov 2024 16:29:20 +0800 Subject: [PATCH 09/15] fix(ci): properly check release condition https://github.com/actions/runner/issues/1483 --- .github/workflows/deploy.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index a3e7d7a..4765412 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,5 +1,5 @@ name: Deploy -run-name: ${{ github.event.inputs.release == true && 'Release' || 'Build' }} for ${{ github.event.inputs.ipa_url }} +run-name: ${{ github.event.inputs.release == 'true' && 'Release' || 'Build' }} for ${{ github.event.inputs.ipa_url }} on: workflow_dispatch: @@ -150,7 +150,7 @@ jobs: path: ${{ github.workspace }}/${{ env.APP_NAME }}.ipa release-app: - if: ${{ github.event.inputs.release == true }} + if: ${{ github.event.inputs.release == 'true' }} runs-on: macos-14 needs: build-ipa permissions: @@ -197,7 +197,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} app-repo: - if: ${{ github.event.inputs.release == true }} + if: ${{ github.event.inputs.release == 'true' }} continue-on-error: true runs-on: macos-14 needs: release-app From c568969333ae20bbbb6e924f6404e4f02fb65fd7 Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Thu, 14 Nov 2024 11:15:18 +0100 Subject: [PATCH 10/15] feat: rewrite from orion to logos --- .vscode/settings.json | 9 +- .vscode/tasks.json | 35 ++++ BunnyTweak.plist => Bunny.plist | 0 Headers/Font.h | 5 + Headers/LoaderConfig.h | 8 + Headers/Logger.h | 4 + .../include => Headers}/RCTCxxBridge.h | 6 +- Headers/Theme.h | 5 + Headers/Utils.h | 6 + Makefile | 35 ++-- Package.swift | 88 --------- README.md | 14 +- Sources/BunnyTweak/Fonts.x.swift | 99 ---------- Sources/BunnyTweak/LoaderConfig.x.swift | 47 ----- Sources/BunnyTweak/Themes.x.swift | 152 --------------- Sources/BunnyTweak/Tweak.x.swift | 143 -------------- Sources/BunnyTweak/Utils.x.swift | 16 -- Sources/BunnyTweakC/Tweak.m | 11 -- Sources/BunnyTweakC/include/Tweak.h | 3 - Sources/BunnyTweakC/include/module.modulemap | 4 - Sources/Font.x | 96 ++++++++++ Sources/LoaderConfig.m | 55 ++++++ Sources/Logger.m | 1 + Sources/Theme.m | 82 ++++++++ Sources/Tweak.x | 177 ++++++++++++++++++ Sources/Utils.m | 69 +++++++ .../payload-base.template.js | 6 +- control | 10 +- 28 files changed, 590 insertions(+), 596 deletions(-) create mode 100644 .vscode/tasks.json rename BunnyTweak.plist => Bunny.plist (100%) create mode 100644 Headers/Font.h create mode 100644 Headers/LoaderConfig.h create mode 100644 Headers/Logger.h rename {Sources/BunnyTweakC/include => Headers}/RCTCxxBridge.h (81%) create mode 100644 Headers/Theme.h create mode 100644 Headers/Utils.h delete mode 100644 Package.swift delete mode 100644 Sources/BunnyTweak/Fonts.x.swift delete mode 100644 Sources/BunnyTweak/LoaderConfig.x.swift delete mode 100644 Sources/BunnyTweak/Themes.x.swift delete mode 100644 Sources/BunnyTweak/Tweak.x.swift delete mode 100644 Sources/BunnyTweak/Utils.x.swift delete mode 100644 Sources/BunnyTweakC/Tweak.m delete mode 100644 Sources/BunnyTweakC/include/Tweak.h delete mode 100644 Sources/BunnyTweakC/include/module.modulemap create mode 100644 Sources/Font.x create mode 100644 Sources/LoaderConfig.m create mode 100644 Sources/Logger.m create mode 100644 Sources/Theme.m create mode 100644 Sources/Tweak.x create mode 100644 Sources/Utils.m rename Resources/payload-base.js => Sources/payload-base.template.js (56%) diff --git a/.vscode/settings.json b/.vscode/settings.json index 22a409b..2cf9559 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,5 +3,12 @@ "MD029": false, "MD033": false, "MD045": false, - } + }, + "VsCodeTaskButtons.tasks": [ + { + "label": "$(tools) Make and Copy", + "task": "Make and Copy Tweak", + "tooltip": "Make and copy Tweak" + } + ], } diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..4980d74 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,35 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "shell", + "label": "Make and Copy Tweak", + "command": "zsh", + "args": [ + "-c", + "rm -rf packages && make clean && make package FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless && cp ./packages/app.pyoncord_*arm64.deb ~/Library/Mobile\\ Documents/com~apple~CloudDocs/" + ], + "problemMatcher": { + "owner": "cpp", + "pattern": { + "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + }, + "group": { + "kind": "build", + "isDefault": true + }, + "presentation": { + "panel": "shared", + "showReuseMessage": false, + "clear": true, + "close": true + } + } + ] +} \ No newline at end of file diff --git a/BunnyTweak.plist b/Bunny.plist similarity index 100% rename from BunnyTweak.plist rename to Bunny.plist diff --git a/Headers/Font.h b/Headers/Font.h new file mode 100644 index 0000000..d1d1228 --- /dev/null +++ b/Headers/Font.h @@ -0,0 +1,5 @@ +#import +#import + +extern NSMutableDictionary *fontMap; +void patchFonts(NSDictionary *mainFonts, NSString *fontDefName); \ No newline at end of file diff --git a/Headers/LoaderConfig.h b/Headers/LoaderConfig.h new file mode 100644 index 0000000..6c63fa8 --- /dev/null +++ b/Headers/LoaderConfig.h @@ -0,0 +1,8 @@ +#import + +@interface LoaderConfig : NSObject +@property (nonatomic, assign) BOOL customLoadUrlEnabled; +@property (nonatomic, strong) NSURL *customLoadUrl; ++ (instancetype)defaultConfig; ++ (instancetype)getLoaderConfig; +@end \ No newline at end of file diff --git a/Headers/Logger.h b/Headers/Logger.h new file mode 100644 index 0000000..fce7b0e --- /dev/null +++ b/Headers/Logger.h @@ -0,0 +1,4 @@ +#import + +#define LOG_PREFIX @"[Bunny]" +#define BunnyLog(fmt, ...) NSLog((LOG_PREFIX @" " fmt), ##__VA_ARGS__) \ No newline at end of file diff --git a/Sources/BunnyTweakC/include/RCTCxxBridge.h b/Headers/RCTCxxBridge.h similarity index 81% rename from Sources/BunnyTweakC/include/RCTCxxBridge.h rename to Headers/RCTCxxBridge.h index d5bfd27..47093cc 100644 --- a/Sources/BunnyTweakC/include/RCTCxxBridge.h +++ b/Headers/RCTCxxBridge.h @@ -1,7 +1,3 @@ -@import Foundation; - @interface RCTCxxBridge : NSObject - - (void)executeApplicationScript:(NSData *)script url:(NSURL *)url async:(BOOL)async; - -@end +@end \ No newline at end of file diff --git a/Headers/Theme.h b/Headers/Theme.h new file mode 100644 index 0000000..b3be04f --- /dev/null +++ b/Headers/Theme.h @@ -0,0 +1,5 @@ +#import +#import + +void swizzleDCDThemeColor(NSDictionary *> *semanticColors); +void swizzleUIColor(NSDictionary *rawColors); \ No newline at end of file diff --git a/Headers/Utils.h b/Headers/Utils.h new file mode 100644 index 0000000..0b1fb2f --- /dev/null +++ b/Headers/Utils.h @@ -0,0 +1,6 @@ +#import +#import + +NSURL *getPyoncordDirectory(void); +UIColor *hexToUIColor(NSString *hex); +void showErrorAlert(NSString *title, NSString *message); \ No newline at end of file diff --git a/Makefile b/Makefile index 0b88da2..e8a9450 100644 --- a/Makefile +++ b/Makefile @@ -1,19 +1,30 @@ -ifeq ($(THEOS_PACKAGE_SCHEME),rootless) - TARGET := iphone:clang:latest:15.0 -else - TARGET := iphone:clang:latest:12.2 -endif - +TARGET := iphone:clang:latest:14.0 +ARCHS = arm64 +INSTALL_TARGET_PROCESSES = Discord include $(THEOS)/makefiles/common.mk -TWEAK_NAME = BunnyTweak +TWEAK_NAME = Bunny +BUNDLE_NAME = BunnyResources -BunnyTweak_FILES = $(shell find Sources/BunnyTweak -name '*.swift') $(shell find Sources/BunnyTweakC -name '*.m' -o -name '*.c' -o -name '*.mm' -o -name '*.cpp') -BunnyTweak_SWIFTFLAGS = -ISources/BunnyTweakC/include -BunnyTweak_CFLAGS = -fobjc-arc -ISources/BunnyTweakC/include +Bunny_FILES = $(shell find Sources -name "*.x" && find Sources -name "*.m") +Bunny_CFLAGS = -fobjc-arc -DPACKAGE_VERSION='@"$(THEOS_PACKAGE_BASE_VERSION)"' -I$(THEOS_PROJECT_DIR)/Headers +Bunny_FRAMEWORKS = Foundation UIKit CoreGraphics -BunnyTweak_BUNDLE_NAME = BunnyPatches -BunnyTweak_BUNDLE_RESOURCE_DIRS = Resources +BunnyResources_INSTALL_PATH = "/Library/Application\ Support/" +BunnyResources_RESOURCE_DIRS = Resources include $(THEOS_MAKE_PATH)/tweak.mk +include $(THEOS_MAKE_PATH)/bundle.mk + +before-all:: + $(ECHO_NOTHING)mkdir -p Resources$(ECHO_END) + $(ECHO_NOTHING)sed -e 's/@PACKAGE_VERSION@/$(THEOS_PACKAGE_BASE_VERSION)/g' \ + -e 's/@TWEAK_NAME@/$(TWEAK_NAME)/g' \ + Sources/payload-base.template.js > Resources/payload-base.js$(ECHO_END) + +after-stage:: + $(ECHO_NOTHING)find $(THEOS_STAGING_DIR) -name ".DS_Store" -delete$(ECHO_END) + +after-package:: + $(ECHO_NOTHING)rm -rf Resources$(ECHO_END) diff --git a/Package.swift b/Package.swift deleted file mode 100644 index 1e010ca..0000000 --- a/Package.swift +++ /dev/null @@ -1,88 +0,0 @@ -// swift-tools-version:5.2 - -import PackageDescription -import Foundation - -let projectDir = URL(fileURLWithPath: #filePath).deletingLastPathComponent() - -@dynamicMemberLookup struct TheosConfiguration { - private let dict: [String: String] - init(at path: String) { - let configURL = URL(fileURLWithPath: path, relativeTo: projectDir) - guard let infoString = try? String(contentsOf: configURL) else { - fatalError(""" - Could not find Theos SPM config. Have you run `make spm` yet? - """) - } - let pairs = infoString.split(separator: "\n").map { - $0.split( - separator: "=", maxSplits: 1, - omittingEmptySubsequences: false - ).map(String.init) - }.map { ($0[0], $0[1]) } - dict = Dictionary(uniqueKeysWithValues: pairs) - } - subscript( - key: String, - or defaultValue: @autoclosure () -> String? = nil - ) -> String { - if let value = dict[key] { - return value - } else if let def = defaultValue() { - return def - } else { - fatalError(""" - Could not get value of key '\(key)' from Theos SPM config. \ - Try running `make spm` again. - """) - } - } - subscript(dynamicMember key: String) -> String { self[key] } -} -let conf = TheosConfiguration(at: ".theos/spm_config") - -let theosPath = conf.theos -let sdk = conf.sdk -let resourceDir = conf.swiftResourceDir -let deploymentTarget = conf.deploymentTarget -let triple = "arm64-apple-ios\(deploymentTarget)" - -let libFlags: [String] = [ - "-F\(theosPath)/vendor/lib", "-F\(theosPath)/lib", - "-I\(theosPath)/vendor/include", "-I\(theosPath)/include" -] - -let cFlags: [String] = libFlags + [ - "-target", triple, "-isysroot", sdk, - "-Wno-unused-command-line-argument", "-Qunused-arguments", -] - -let cxxFlags: [String] = [ -] - -let swiftFlags: [String] = libFlags + [ - "-target", triple, "-sdk", sdk, "-resource-dir", resourceDir, -] - -let package = Package( - name: "BunnyTweak", - platforms: [.iOS(deploymentTarget)], - products: [ - .library( - name: "BunnyTweak", - targets: ["BunnyTweak"] - ), - ], - targets: [ - .target( - name: "BunnyTweakC", - cSettings: [.unsafeFlags(cFlags)], - cxxSettings: [.unsafeFlags(cxxFlags)] - ), - .target( - name: "BunnyTweak", - dependencies: ["BunnyTweakC"], - swiftSettings: [.unsafeFlags(swiftFlags)] - ), - ] -) diff --git a/README.md b/README.md index 5203363..5b87c66 100644 --- a/README.md +++ b/README.md @@ -3,22 +3,22 @@ Tweak to inject [Bunny](https://github.com/pyoncord/Bunny) into Discord. Forked [VendettaTweak](https://github.com/vendetta-mod/VendettaTweak), modified to match with [BunnyXposed](https://github.com/pyoncord/BunnyXposed) behavior. There are still slight differences between these two, and this tweak may be missing some loader features. > [!NOTE] -> As of right now this tweak does not encompass some functionalities when running in a jailed environment with a wildcard certificate \ +> As of right now this tweak does not encompass some functionalities when running in a jailed environment with a distribution certificate that has a different App ID \ > If you value these features sign the application with a local dev certificate: -> - setAlternateAppIcon does not work, thus breaking dynamic app icons -> - sharing files to the application/selecting items via the Files app does not work +> +> - setAlternateAppIcon does not work, thus breaking dynamic app icons (unlikely to be able to be fixed unless iOS behavior changes) +> - sharing files to the application/selecting items via the Files app does not work (this might be more of a keychain/app group issue) ## Installation Builds can be found in the [Releases](https://github.com/pyoncord/BunnyTweak/releases/latest) tab. > [!NOTE] -> Raw decrypted IPAs which are used to provide prepatched IPAs are sourced from the [Enmity](https://github.com/enmity-mod/) community. These raw decrypted IPAs are also used throughout Enmity related projects such as [enmity-mod/tweak](https://github.com/enmity-mod/tweak/) and [acquitelol/rosiecord](https://github.com/acquitelol/rosiecord).\ -> All credits are attributed to the owner(s) of the raw IPAs. +> Decrypted IPAs are sourced from the [Enmity](https://github.com/enmity-mod/) community. These are also used throughout Enmity related projects such as [enmity-mod/tweak](https://github.com/enmity-mod/tweak/) and [acquitelol/rosiecord](https://github.com/acquitelol/rosiecord).\ +> All credits are attributed to the owner(s). ### Jailbroken -1. Install the Orion runtime via your preferred package manager, by adding `https://repo.chariz.com/` to your sources, then finding `Orion Runtime`. 1. Install Bunny by downloading the appropriate Debian package (or by building your own, see [Building BunnyTweak locally](#building-bunnytweak-locally)) and adding it to your package manager. Use the file ending in `arm.deb` for rootful jailbreaks, and the file ending in `arm64.deb` for rootless jailbreaks. ### Jailed @@ -34,7 +34,7 @@ Builds can be found in the [Releases](https://github.com/pyoncord/BunnyTweak/rel ## Building BunnyTweak locally > [!NOTE] -> These steps assume you use MacOS. +> 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. diff --git a/Sources/BunnyTweak/Fonts.x.swift b/Sources/BunnyTweak/Fonts.x.swift deleted file mode 100644 index acb6b16..0000000 --- a/Sources/BunnyTweak/Fonts.x.swift +++ /dev/null @@ -1,99 +0,0 @@ -import BunnyTweakC -import Orion -import UIKit -import os -import Foundation - -// This is not the full implementation, we only take what we need in here -// For full definition, find it from the core codebase (JS side) -struct FontDefinition: Codable { - let name: String - let main: [String: String]? -} - -var fontMap: [String: String] = [:] - -class FontsHook: ClassHook { - class func fontWithName(_ name: String, size: CGFloat) -> UIFont { - if let replacementName = fontMap[name] { - let replacementDescriptor = UIFontDescriptor(name: replacementName, size: size) - let fallbackDescriptor = replacementDescriptor.addingAttributes([.name: [name]]) - let finalDescriptor = replacementDescriptor.addingAttributes([.cascadeList: [fallbackDescriptor]]) - - return orig.fontWithDescriptor(finalDescriptor, size: size) - } - - return orig.fontWithName(name, size: size) - } - class func fontWithDescriptor(_ descriptor: UIFontDescriptor, size: CGFloat) -> UIFont { - if let replacementName = fontMap[descriptor.postscriptName] { - let replacementDescriptor = UIFontDescriptor(name: replacementName, size: size) - let finalDescriptor = replacementDescriptor.addingAttributes([.cascadeList: [descriptor]]) - - return orig.fontWithDescriptor(finalDescriptor, size: size) - } - - return orig.fontWithDescriptor(descriptor, size: size) - } -} - -func patchFonts(_ main: [String: String], fontDefName: String) { - for (fontName, url) in main { - os_log("Replacing font %{public}@ with URL: %{public}@", log: bunnyLog, type: .info, fontName, url) - - let fontExtension = URL(string: url)!.pathExtension - let fontCachePath = pyoncordDirectory - .appendingPathComponent("downloads", isDirectory: true) - .appendingPathComponent("fonts", isDirectory: true) - .appendingPathComponent(fontDefName, isDirectory: true) - .appendingPathComponent("\(fontName).\(fontExtension)") - - do { - os_log("Attempting to register font %{public}@ from %{public}@", log: bunnyLog, type: .info, fontName, url) - - let parent = fontCachePath.deletingLastPathComponent() - if !FileManager.default.fileExists(atPath: parent.path) { - os_log("Creating parent directory: %{public}@", log: bunnyLog, type: .debug, parent.path) - try FileManager.default.createDirectory( - at: parent, withIntermediateDirectories: true, attributes: nil) - } - - // JS side should download these already, but just in case... - if !FileManager.default.fileExists(atPath: fontCachePath.path) { - os_log("Downloading font %{public}@ from %{public}@", log: bunnyLog, type: .debug, fontName, url) - if let data = try? Data(contentsOf: URL(string: url)!) { - os_log("Writing font data to: %{public}@", log: bunnyLog, type: .debug, fontCachePath.path) - try? data.write(to: fontCachePath) - } - } - - if let data = try? Data(contentsOf: fontCachePath) { - os_log("Registering font %{public}@ with provider", log: bunnyLog, type: .debug, fontName) - let provider = CGDataProvider(data: data as CFData) - let font = CGFont(provider!) - var error: Unmanaged? - - // This does not work with system/app fonts unfortunately. Throws a CTFontManagerError.systemRequired - if let existingFont = CGFont(font!.postScriptName!) { - var unregisterError: Unmanaged? - if !CTFontManagerUnregisterGraphicsFont(existingFont, &unregisterError) { - os_log("Failed to deregister font %{public}@: %{public}@", log: bunnyLog, type: .error, - font!.postScriptName! as String, - String(describing: unregisterError!.takeUnretainedValue())) - } - } - - if CTFontManagerRegisterGraphicsFont(font!, &error) { - fontMap[fontName] = font!.postScriptName! as String - os_log("Successfully registered font %{public}@ to %{public}@", log: bunnyLog, type: .info, fontName, font!.postScriptName! as String) - } else { - os_log("Failed to register font %{public}@: %{public}@", log: bunnyLog, type: .error, fontName, String(describing: error!.takeUnretainedValue())) - } - } else { - os_log("Failed to read font data from: %{public}@", log: bunnyLog, type: .error, fontCachePath.path) - } - } catch { - os_log("Failed to register font %{public}@: %{public}@", log: bunnyLog, type: .error, fontName, error.localizedDescription) - } - } -} \ No newline at end of file diff --git a/Sources/BunnyTweak/LoaderConfig.x.swift b/Sources/BunnyTweak/LoaderConfig.x.swift deleted file mode 100644 index 729e3ba..0000000 --- a/Sources/BunnyTweak/LoaderConfig.x.swift +++ /dev/null @@ -1,47 +0,0 @@ -import Foundation -import os - -enum LoaderConfigError: Error { - case doesNotExist -} - -struct CustomLoadUrl: Codable { - let enabled: Bool - let url: URL -} - -struct LoaderConfig: Codable { - let customLoadUrl: CustomLoadUrl -} - -let defaultLoaderConfig = LoaderConfig( - customLoadUrl: CustomLoadUrl( - enabled: false, - url: URL(string: "http://localhost:4040/bunny.js")! - ) -) - -let pyoncordDirectory = getPyoncordDirectory() -let loaderConfigUrl = pyoncordDirectory.appendingPathComponent("loader.json") - -func getLoaderConfig() -> LoaderConfig { - os_log("Getting loader config", log: bunnyLog, type: .debug) - let fileManager = FileManager.default - - do { - if fileManager.fileExists(atPath: loaderConfigUrl.path) { - let data = try Data(contentsOf: loaderConfigUrl) - let loaderConfig = try JSONDecoder().decode(LoaderConfig.self, from: data) - - os_log("Got loader config", log: bunnyLog, type: .debug) - - return loaderConfig - } else { - throw LoaderConfigError.doesNotExist - } - } catch { - os_log("Couldn't get loader config", log: bunnyLog, type: .error) - - return defaultLoaderConfig - } -} diff --git a/Sources/BunnyTweak/Themes.x.swift b/Sources/BunnyTweak/Themes.x.swift deleted file mode 100644 index 3eb8277..0000000 --- a/Sources/BunnyTweak/Themes.x.swift +++ /dev/null @@ -1,152 +0,0 @@ -import Orion -import UIKit -import BunnyTweakC -import os - -struct Author: Codable { - let name: String - let id: String? -} - -struct ThemeData: Codable { - let name: String - let description: String? - let authors: [Author]? - let spec: Int - let semanticColors: [String: [String]]? - let rawColors: [String: String]? -} - -struct Theme: Codable { - let id: String - let selected: Bool - let data: ThemeData -} - -func hexToUIColor(_ hex: String) -> UIColor? { - let r: CGFloat - let g: CGFloat - let b: CGFloat - let a: CGFloat - - if hex.hasPrefix("#") { - let start = hex.index(hex.startIndex, offsetBy: 1) - var hexColor = String(hex[start...]) - - if hexColor.count == 6 { - hexColor.append("ff") - } - - if hexColor.count == 8 { - let scanner = Scanner(string: hexColor) - var hexNumber: UInt64 = 0 - - if scanner.scanHexInt64(&hexNumber) { - r = CGFloat((hexNumber & 0xff00_0000) >> 24) / 255 - g = CGFloat((hexNumber & 0x00ff_0000) >> 16) / 255 - b = CGFloat((hexNumber & 0x0000_ff00) >> 8) / 255 - a = CGFloat(hexNumber & 0x0000_00ff) / 255 - - return UIColor(red: r, green: g, blue: b, alpha: a) - } - } - } - - return nil -} - -func swizzleDCDThemeColor(_ semanticColors: [String: [String]]) { - os_log("Swizzling DCDThemeColor", log: bunnyLog, type: .info) - - let DCDTheme: AnyClass = NSClassFromString("DCDTheme")! - let dcdThemeTarget: AnyClass = object_getClass(DCDTheme)! - - let themeIndexSelector = NSSelectorFromString("themeIndex") - let themeIndexMethod = class_getClassMethod(dcdThemeTarget, themeIndexSelector)! - let themeIndexImpl = method_getImplementation(themeIndexMethod) - typealias ThemeIndexType = @convention(c) (AnyObject, Selector) -> Int - let themeIndex: ThemeIndexType = unsafeBitCast(themeIndexImpl, to: ThemeIndexType.self) - - let DCDThemeColor: AnyClass = NSClassFromString("DCDThemeColor")! - os_log("Found instance of DCDThemeColor", log: bunnyLog, type: .debug) - let target: AnyClass = object_getClass(DCDThemeColor)! - - os_log("Found DCDThemeColor", log: bunnyLog, type: .debug) - - var methodCount: UInt32 = 0 - let methods = class_copyMethodList(target, &methodCount)! - - os_log("DCDThemeColor has %{public}d methods", log: bunnyLog, type: .debug, methodCount) - - for i in 0.. UIColor - let original = unsafeBitCast(originalImpl, to: OriginalType.self) - let semanticColorBlock: @convention(block) (AnyObject) -> UIColor = { - (self: AnyObject) -> UIColor in - let themeIndexVal = themeIndex(dcdThemeTarget, themeIndexSelector) - if semanticColor.count - 1 >= themeIndexVal { - if let semanticUIColor = hexToUIColor( - semanticColor[themeIndexVal]) - { - return semanticUIColor - } - } - - return original(target, selector) - } - let semanticColorImplementation = imp_implementationWithBlock( - unsafeBitCast(semanticColorBlock, to: AnyObject.self)) - method_setImplementation( - method, semanticColorImplementation) - - } - } - free(methods) -} - -func swizzleUIColor(_ rawColors: [String: String]) { - os_log("Swizzling UIColor", log: bunnyLog, type: .info) - - let UIColor: AnyClass = NSClassFromString("UIColor")! - os_log("Found instance of UIColor", log: bunnyLog, type: .debug) - let target: AnyClass = object_getClass(UIColor)! - - os_log("Found UIColor", log: bunnyLog, type: .debug) - - var methodCount: UInt32 = 0 - let methods = class_copyMethodList(target, &methodCount)! - - os_log("UIColor has %{public}d methods", log: bunnyLog, type: .debug, methodCount) - - for i in 0.. UIColor = { - (self: AnyObject) -> UIColor in - return hexToUIColor(rawColor)! - } - let rawColorImplementation = imp_implementationWithBlock( - unsafeBitCast(rawColorBlock, to: AnyObject.self)) - method_setImplementation( - method, rawColorImplementation) - - } - } - free(methods) -} diff --git a/Sources/BunnyTweak/Tweak.x.swift b/Sources/BunnyTweak/Tweak.x.swift deleted file mode 100644 index cde4f6b..0000000 --- a/Sources/BunnyTweak/Tweak.x.swift +++ /dev/null @@ -1,143 +0,0 @@ -import Orion -import BunnyTweakC -import os - -let bunnyLog = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "bunny") -let source = URL(string: "bunny")! - -let install_prefix = String(cString: get_install_prefix()) -let isJailbroken = FileManager.default.fileExists(atPath: "\(install_prefix)/Library/Application Support/BunnyTweak/BunnyPatches.bundle") - -let bunnyPatchesBundlePath = isJailbroken ? "\(install_prefix)/Library/Application Support/BunnyTweak/BunnyPatches.bundle" : "\(Bundle.main.bundleURL.path)/BunnyPatches.bundle" - -class FileManagerLoadHook: ClassHook { - func containerURLForSecurityApplicationGroupIdentifier(_ groupIdentifier: NSString?) -> URL? { - os_log("containerURLForSecurityApplicationGroupIdentifier called! %{public}@ groupIdentifier", log: bunnyLog, 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 { - func executeApplicationScript(_ script: Data, url: URL, async: Bool) { - os_log("executeApplicationScript called!", log: bunnyLog, type: .debug) - - let loaderConfig = getLoaderConfig() - - let bunnyPatchesBundle = Bundle(path: bunnyPatchesBundlePath)! - - if let patchPath = bunnyPatchesBundle.url(forResource: "payload-base", withExtension: "js") { - let patchData = try! Data(contentsOf: patchPath) - os_log("Executing payload base", log: bunnyLog, type: .debug) - orig.executeApplicationScript(patchData, url: source, async: true) - } - - let pyoncordDirectory = getPyoncordDirectory() - - var bundle = try? Data(contentsOf: pyoncordDirectory.appendingPathComponent("bundle.js")) - - let group = DispatchGroup() - - group.enter() - var bundleUrl: URL - if loaderConfig.customLoadUrl.enabled { - os_log( - "Custom load URL enabled, with URL %{public}@ ", log: bunnyLog, type: .info, - loaderConfig.customLoadUrl.url.absoluteString) - bundleUrl = loaderConfig.customLoadUrl.url - } else { - bundleUrl = URL( - string: "https://raw.githubusercontent.com/pyoncord/bunny-builds/main/bunny.js")! - } - - os_log("Fetching JS bundle", log: bunnyLog, 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: bunnyLog, type: .debug) - bundle = data - try? bundle?.write(to: pyoncordDirectory.appendingPathComponent("bundle.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: bunnyLog, 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: bunnyLog, type: .error) - } - } - - if bundle != nil { - os_log("Executing JS bundle", log: bunnyLog, type: .info) - orig.executeApplicationScript(bundle!, url: source, async: async) - } else { - os_log("Unable to fetch JS bundle", log: bunnyLog, type: .error) - } - - os_log("Executing original script", log: bunnyLog, type: .info) - orig.executeApplicationScript(script, url: url, async: async) - } -} - -struct BunnyTweak: 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) } - } - - if let fontData = try? Data( - contentsOf: pyoncordDirectory.appendingPathComponent("fonts.json")) { - let fonts = try? JSONDecoder().decode(FontDefinition.self, from: fontData) - if let main = fonts?.main { patchFonts(main, fontDefName: fonts!.name) } - } - } -} diff --git a/Sources/BunnyTweak/Utils.x.swift b/Sources/BunnyTweak/Utils.x.swift deleted file mode 100644 index 48a0702..0000000 --- a/Sources/BunnyTweak/Utils.x.swift +++ /dev/null @@ -1,16 +0,0 @@ -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 -} diff --git a/Sources/BunnyTweakC/Tweak.m b/Sources/BunnyTweakC/Tweak.m deleted file mode 100644 index 94f9277..0000000 --- a/Sources/BunnyTweakC/Tweak.m +++ /dev/null @@ -1,11 +0,0 @@ -#import - -const char * const _Nonnull get_install_prefix(void) { - return THEOS_PACKAGE_INSTALL_PREFIX; -} - -__attribute__((constructor)) static void init() { - // Initialize Orion - do not remove this line. - orion_init(); - // Custom initialization code goes here. -} diff --git a/Sources/BunnyTweakC/include/Tweak.h b/Sources/BunnyTweakC/include/Tweak.h deleted file mode 100644 index 0429e20..0000000 --- a/Sources/BunnyTweakC/include/Tweak.h +++ /dev/null @@ -1,3 +0,0 @@ -#import "RCTCxxBridge.h" - -const char * const _Nonnull get_install_prefix(void); diff --git a/Sources/BunnyTweakC/include/module.modulemap b/Sources/BunnyTweakC/include/module.modulemap deleted file mode 100644 index 2e175d3..0000000 --- a/Sources/BunnyTweakC/include/module.modulemap +++ /dev/null @@ -1,4 +0,0 @@ -module BunnyTweakC { - umbrella "." - export * -} diff --git a/Sources/Font.x b/Sources/Font.x new file mode 100644 index 0000000..35e71ec --- /dev/null +++ b/Sources/Font.x @@ -0,0 +1,96 @@ +#import "Font.h" +#import "Utils.h" +#import "Logger.h" +#import +#import + +NSMutableDictionary *fontMap; + +%hook UIFont + ++ (UIFont *)fontWithName:(NSString *)name size:(CGFloat)size { + NSString *replacementName = fontMap[name]; + if (replacementName) { + return %orig(replacementName, size); + } + return %orig; +} + ++ (UIFont *)fontWithDescriptor:(UIFontDescriptor *)descriptor size:(CGFloat)size { + NSString *replacementName = fontMap[descriptor.postscriptName]; + if (replacementName) { + UIFontDescriptor *replacementDescriptor = [UIFontDescriptor fontDescriptorWithName:replacementName size:size]; + UIFontDescriptor *finalDescriptor = [replacementDescriptor fontDescriptorByAddingAttributes:@{UIFontDescriptorCascadeListAttribute: @[descriptor]}]; + + return [UIFont fontWithDescriptor:finalDescriptor size:size]; + } + return %orig; +} + +%end + +void patchFonts(NSDictionary *mainFonts, NSString *fontDefName) { + if (!fontMap) { + fontMap = [NSMutableDictionary dictionary]; + } + + for (NSString *fontName in mainFonts) { + NSString *url = mainFonts[fontName]; + BunnyLog(@"Replacing font %@ with URL: %@", fontName, url); + + NSURL *fontURL = [NSURL URLWithString:url]; + NSString *fontExtension = fontURL.pathExtension; + + NSURL *fontCachePath = [[[getPyoncordDirectory() + URLByAppendingPathComponent:@"downloads" isDirectory:YES] + URLByAppendingPathComponent:@"fonts" isDirectory:YES] + URLByAppendingPathComponent:fontDefName isDirectory:YES]; + + fontCachePath = [fontCachePath URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", fontName, fontExtension]]; + + NSURL *parentDir = [fontCachePath URLByDeletingLastPathComponent]; + if (![[NSFileManager defaultManager] fileExistsAtPath:parentDir.path]) { + BunnyLog(@"Creating parent directory: %@", parentDir.path); + [[NSFileManager defaultManager] createDirectoryAtURL:parentDir + withIntermediateDirectories:YES + attributes:nil + error:nil]; + } + + if (![[NSFileManager defaultManager] fileExistsAtPath:fontCachePath.path]) { + BunnyLog(@"Downloading font %@ from %@", fontName, url); + NSData *data = [NSData dataWithContentsOfURL:fontURL]; + if (data) { + BunnyLog(@"Writing font data to: %@", fontCachePath.path); + [data writeToURL:fontCachePath atomically:YES]; + } + } + + NSData *fontData = [NSData dataWithContentsOfURL:fontCachePath]; + if (fontData) { + BunnyLog(@"Registering font %@ with provider", fontName); + CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)fontData); + CGFontRef font = CGFontCreateWithDataProvider(provider); + + if (font) { + CFStringRef postScriptName = CGFontCopyPostScriptName(font); + + CFErrorRef error = NULL; + if (CTFontManagerRegisterGraphicsFont(font, &error)) { + fontMap[fontName] = (__bridge NSString *)postScriptName; + BunnyLog(@"Successfully registered font %@ to %@", fontName, (__bridge NSString *)postScriptName); + } else { + NSString *errorDesc = error ? (__bridge NSString *)CFErrorCopyDescription(error) : @"Unknown error"; + BunnyLog(@"Failed to register font %@: %@", fontName, errorDesc); + if (error) { + CFRelease(error); + } + } + + CFRelease(postScriptName); + CFRelease(font); + } + CGDataProviderRelease(provider); + } + } +} \ No newline at end of file diff --git a/Sources/LoaderConfig.m b/Sources/LoaderConfig.m new file mode 100644 index 0000000..bfc31f4 --- /dev/null +++ b/Sources/LoaderConfig.m @@ -0,0 +1,55 @@ +#import "LoaderConfig.h" +#import "Utils.h" +#import "Logger.h" + +@implementation LoaderConfig + ++ (instancetype)defaultConfig { + LoaderConfig *config = [[LoaderConfig alloc] init]; + config.customLoadUrlEnabled = NO; + config.customLoadUrl = [NSURL URLWithString:@"http://localhost:4040/bunny.js"]; + return config; +} + ++ (instancetype)getLoaderConfig { + BunnyLog(@"Getting loader config"); + + NSURL *loaderConfigUrl = [getPyoncordDirectory() URLByAppendingPathComponent:@"loader.json"]; + + if ([[NSFileManager defaultManager] fileExistsAtPath:loaderConfigUrl.path]) { + NSError *error = nil; + NSData *data = [NSData dataWithContentsOfURL:loaderConfigUrl]; + NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; + + if (json && !error) { + LoaderConfig *config = [[LoaderConfig alloc] init]; + NSDictionary *customLoadUrl = json[@"customLoadUrl"]; + if (customLoadUrl) { + config.customLoadUrlEnabled = [customLoadUrl[@"enabled"] boolValue]; + NSString *urlString = customLoadUrl[@"url"]; + if (urlString) { + config.customLoadUrl = [NSURL URLWithString:urlString]; + } + } + return config; + } + } + + BunnyLog(@"Couldn't get loader config"); + return [LoaderConfig defaultConfig]; +} + +- (BOOL)saveConfig { + NSURL *loaderConfigUrl = [getPyoncordDirectory() URLByAppendingPathComponent:@"loader.json"]; + NSDictionary *json = @{ + @"customLoadUrl": @{ + @"enabled": @(self.customLoadUrlEnabled), + @"url": self.customLoadUrl.absoluteString + } + }; + + NSData *data = [NSJSONSerialization dataWithJSONObject:json options:0 error:nil]; + return [data writeToURL:loaderConfigUrl atomically:YES]; +} + +@end \ No newline at end of file diff --git a/Sources/Logger.m b/Sources/Logger.m new file mode 100644 index 0000000..9daa597 --- /dev/null +++ b/Sources/Logger.m @@ -0,0 +1 @@ +#import "Logger.h" diff --git a/Sources/Theme.m b/Sources/Theme.m new file mode 100644 index 0000000..a31c654 --- /dev/null +++ b/Sources/Theme.m @@ -0,0 +1,82 @@ +#import "Theme.h" +#import "Utils.h" +#import "Logger.h" +#import + +void swizzleDCDThemeColor(NSDictionary *> *semanticColors) { + BunnyLog(@"Swizzling DCDThemeColor"); + + Class DCDTheme = NSClassFromString(@"DCDTheme"); + Class dcdThemeTarget = object_getClass(DCDTheme); + + SEL themeIndexSelector = NSSelectorFromString(@"themeIndex"); + Method themeIndexMethod = class_getClassMethod(dcdThemeTarget, themeIndexSelector); + IMP themeIndexImpl = method_getImplementation(themeIndexMethod); + int (*themeIndex)(id, SEL) = (int (*)(id, SEL))themeIndexImpl; + + Class DCDThemeColor = NSClassFromString(@"DCDThemeColor"); + Class target = object_getClass(DCDThemeColor); + + unsigned int methodCount; + Method *methods = class_copyMethodList(target, &methodCount); + + for (unsigned int i = 0; i < methodCount; i++) { + Method method = methods[i]; + SEL selector = method_getName(method); + NSString *methodName = NSStringFromSelector(selector); + + NSArray *semanticColor = semanticColors[methodName]; + if (semanticColor) { + BunnyLog(@"Swizzling %@", methodName); + + IMP originalImpl = method_getImplementation(method); + UIColor *(*original)(id, SEL) = (UIColor *(*)(id, SEL))originalImpl; + + id block = ^UIColor *(id self) { + int themeIndexVal = themeIndex(dcdThemeTarget, themeIndexSelector); + if (semanticColor.count - 1 >= themeIndexVal) { + UIColor *semanticUIColor = hexToUIColor(semanticColor[themeIndexVal]); + if (semanticUIColor) { + return semanticUIColor; + } + } + return original(target, selector); + }; + + IMP newImpl = imp_implementationWithBlock(block); + method_setImplementation(method, newImpl); + } + } + + free(methods); +} + +void swizzleUIColor(NSDictionary *rawColors) { + BunnyLog(@"Swizzling UIColor"); + + Class UIColorClass = NSClassFromString(@"UIColor"); + Class target = object_getClass(UIColorClass); + + unsigned int methodCount; + Method *methods = class_copyMethodList(target, &methodCount); + + for (unsigned int i = 0; i < methodCount; i++) { + Method method = methods[i]; + SEL selector = method_getName(method); + NSString *methodName = NSStringFromSelector(selector); + + NSString *rawColor = rawColors[methodName]; + if (rawColor) { + BunnyLog(@"Swizzling %@", methodName); + + id block = ^UIColor *(id self) { + return hexToUIColor(rawColor); + }; + + IMP newImpl = imp_implementationWithBlock(block); + method_setImplementation(method, newImpl); + } + } + + free(methods); +} \ No newline at end of file diff --git a/Sources/Tweak.x b/Sources/Tweak.x new file mode 100644 index 0000000..36ef121 --- /dev/null +++ b/Sources/Tweak.x @@ -0,0 +1,177 @@ +#import +#import +#import "Utils.h" +#import "Logger.h" +#import "Theme.h" +#import "Font.h" +#import "LoaderConfig.h" + +static NSURL *source; +static BOOL isJailbroken; +static NSString *bunnyPatchesBundlePath; +static NSURL *pyoncordDirectory; +static LoaderConfig *loaderConfig; + +%hook NSFileManager + +- (NSURL *)containerURLForSecurityApplicationGroupIdentifier:(NSString *)groupIdentifier { + BunnyLog(@"containerURLForSecurityApplicationGroupIdentifier called! %@", + groupIdentifier ?: @"nil"); + + if (isJailbroken) { + return %orig(groupIdentifier); + } + + NSArray *paths = [self URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]; + NSURL *lastPath = [paths lastObject]; + return [lastPath URLByAppendingPathComponent:@"AppGroup"]; +} + +%end + +%hook RCTCxxBridge + +- (void)executeApplicationScript:(NSData *)script url:(NSURL *)url async:(BOOL)async { + if (![url.absoluteString containsString:@"main.jsbundle"]) { + return %orig; + } + + NSBundle *bunnyPatchesBundle = [NSBundle bundleWithPath:bunnyPatchesBundlePath]; + if (!bunnyPatchesBundle) { + BunnyLog(@"Failed to load BunnyPatches bundle from path: %@", bunnyPatchesBundlePath); + showErrorAlert(@"Loader Error", @"Failed to initialize mod loader. Please reinstall the tweak."); + return %orig; + } + + NSURL *patchPath = [bunnyPatchesBundle URLForResource:@"payload-base" withExtension:@"js"]; + if (!patchPath) { + BunnyLog(@"Failed to find payload-base.js in bundle"); + showErrorAlert(@"Loader Error", @"Failed to initialize mod loader. Please reinstall the tweak."); + return %orig; + } + + NSData *patchData = [NSData dataWithContentsOfURL:patchPath]; + BunnyLog(@"Injecting loader"); + %orig(patchData, source, YES); + + __block NSData *bundle = [NSData dataWithContentsOfURL:[pyoncordDirectory URLByAppendingPathComponent:@"bundle.js"]]; + + dispatch_group_t group = dispatch_group_create(); + dispatch_group_enter(group); + + NSURL *bundleUrl; + if (loaderConfig.customLoadUrlEnabled && loaderConfig.customLoadUrl) { + bundleUrl = loaderConfig.customLoadUrl; + BunnyLog(@"Using custom load URL: %@", bundleUrl.absoluteString); + } else { + bundleUrl = [NSURL URLWithString:@"https://raw.githubusercontent.com/bunny-mod/builds/main/bunny.min.js"]; + BunnyLog(@"Using default bundle URL: %@", bundleUrl.absoluteString); + } + + NSMutableURLRequest *bundleRequest = [NSMutableURLRequest requestWithURL:bundleUrl + cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData + timeoutInterval:3.0]; + + NSString *bundleEtag = [NSString stringWithContentsOfURL:[pyoncordDirectory URLByAppendingPathComponent:@"etag.txt"] + encoding:NSUTF8StringEncoding + error:nil]; + if (bundleEtag && bundle) { + [bundleRequest setValue:bundleEtag forHTTPHeaderField:@"If-None-Match"]; + } + + NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; + [[session dataTaskWithRequest:bundleRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + if ([response isKindOfClass:[NSHTTPURLResponse class]]) { + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; + if (httpResponse.statusCode == 200) { + bundle = data; + [bundle writeToURL:[pyoncordDirectory URLByAppendingPathComponent:@"bundle.js"] atomically:YES]; + + NSString *etag = [httpResponse.allHeaderFields objectForKey:@"Etag"]; + if (etag) { + [etag writeToURL:[pyoncordDirectory URLByAppendingPathComponent:@"etag.txt"] + atomically:YES + encoding:NSUTF8StringEncoding + error:nil]; + } + } + } + dispatch_group_leave(group); + }] resume]; + + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + + NSString *themeString = [NSString stringWithContentsOfURL:[pyoncordDirectory URLByAppendingPathComponent:@"current-theme.json"] + encoding:NSUTF8StringEncoding + error:nil]; + if (themeString) { + NSString *jsCode = [NSString stringWithFormat:@"globalThis.__PYON_LOADER__.storedTheme=%@", themeString]; + %orig([jsCode dataUsingEncoding:NSUTF8StringEncoding], source, async); + } + + if (bundle) { + BunnyLog(@"Executing JS bundle"); + %orig(bundle, source, async); + } + + NSURL *preloadsDirectory = [pyoncordDirectory URLByAppendingPathComponent:@"preloads"]; + if ([[NSFileManager defaultManager] fileExistsAtPath:preloadsDirectory.path]) { + NSError *error = nil; + NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:preloadsDirectory + includingPropertiesForKeys:nil + options:0 + error:&error]; + if (!error) { + for (NSURL *fileURL in contents) { + if ([[fileURL pathExtension] isEqualToString:@"js"]) { + BunnyLog(@"Executing preload JS file %@", fileURL.absoluteString); + NSData *data = [NSData dataWithContentsOfURL:fileURL]; + if (data) { + %orig(data, source, async); + } + } + } + } else { + BunnyLog(@"Error reading contents of preloads directory"); + } + } + + %orig(script, url, async); +} + +%end + +%ctor { + @autoreleasepool { + source = [NSURL URLWithString:@"bunny"]; + + NSString *install_prefix = @"/var/jb"; + isJailbroken = [[NSFileManager defaultManager] fileExistsAtPath:install_prefix]; + + NSString *bundlePath = [NSString stringWithFormat:@"%@/Library/Application Support/BunnyResources.bundle", install_prefix]; + BunnyLog(@"Is jailbroken: %d", isJailbroken); + BunnyLog(@"Bundle path for jailbroken: %@", bundlePath); + + NSString *jailedPath = [[NSBundle mainBundle].bundleURL.path stringByAppendingPathComponent:@"BunnyResources.bundle"]; + BunnyLog(@"Bundle path for jailed: %@", jailedPath); + + bunnyPatchesBundlePath = isJailbroken ? bundlePath : jailedPath; + BunnyLog(@"Selected bundle path: %@", bunnyPatchesBundlePath); + + BOOL bundleExists = [[NSFileManager defaultManager] fileExistsAtPath:bunnyPatchesBundlePath]; + BunnyLog(@"Bundle exists at path: %d", bundleExists); + + NSError *error = nil; + NSArray *bundleContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:bunnyPatchesBundlePath error:&error]; + if (error) { + BunnyLog(@"Error listing bundle contents: %@", error); + } else { + BunnyLog(@"Bundle contents: %@", bundleContents); + } + + pyoncordDirectory = getPyoncordDirectory(); + loaderConfig = [[LoaderConfig alloc] init]; + + %init; + } +} \ No newline at end of file diff --git a/Sources/Utils.m b/Sources/Utils.m new file mode 100644 index 0000000..e370a54 --- /dev/null +++ b/Sources/Utils.m @@ -0,0 +1,69 @@ +#import "Utils.h" + +NSURL *getPyoncordDirectory(void) { + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSURL *documentDirectoryURL = [[fileManager URLsForDirectory:NSDocumentDirectory + inDomains:NSUserDomainMask] lastObject]; + + NSURL *pyoncordFolderURL = [documentDirectoryURL URLByAppendingPathComponent:@"pyoncord"]; + + if (![fileManager fileExistsAtPath:pyoncordFolderURL.path]) { + [fileManager createDirectoryAtURL:pyoncordFolderURL + withIntermediateDirectories:YES + attributes:nil + error:nil]; + } + + return pyoncordFolderURL; +} + +UIColor *hexToUIColor(NSString *hex) { + if (![hex hasPrefix:@"#"]) { + return nil; + } + + NSString *hexColor = [hex substringFromIndex:1]; + if (hexColor.length == 6) { + hexColor = [hexColor stringByAppendingString:@"ff"]; + } + + if (hexColor.length == 8) { + unsigned int hexNumber; + NSScanner *scanner = [NSScanner scannerWithString:hexColor]; + if ([scanner scanHexInt:&hexNumber]) { + CGFloat r = ((hexNumber & 0xFF000000) >> 24) / 255.0; + CGFloat g = ((hexNumber & 0x00FF0000) >> 16) / 255.0; + CGFloat b = ((hexNumber & 0x0000FF00) >> 8) / 255.0; + CGFloat a = (hexNumber & 0x000000FF) / 255.0; + + return [UIColor colorWithRed:r green:g blue:b alpha:a]; + } + } + + return nil; +} + +void showErrorAlert(NSString *title, NSString *message) { + dispatch_async(dispatch_get_main_queue(), ^{ + UIAlertController *alert = [UIAlertController alertControllerWithTitle:title + message:message + preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" + style:UIAlertActionStyleDefault + handler:nil]; + + [alert addAction:okAction]; + + UIWindow *window = nil; + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *w in windows) { + if (w.isKeyWindow) { + window = w; + break; + } + } + + [window.rootViewController presentViewController:alert animated:YES completion:nil]; + }); +} \ No newline at end of file diff --git a/Resources/payload-base.js b/Sources/payload-base.template.js similarity index 56% rename from Resources/payload-base.js rename to Sources/payload-base.template.js index a4b8743..7b0e1f2 100644 --- a/Resources/payload-base.js +++ b/Sources/payload-base.template.js @@ -1,7 +1,7 @@ globalThis.__PYON_LOADER__ = { - loaderName: "BunnyTweak", - loaderVersion: "0.3.2", + loaderName: "@TWEAK_NAME@", + loaderVersion: "@PACKAGE_VERSION@", hasThemeSupport: true, storedTheme: null, fontPatch: 2 -} +} \ No newline at end of file diff --git a/control b/control index a9f574d..7c3f94f 100644 --- a/control +++ b/control @@ -1,11 +1,11 @@ -Package: io.github.pyoncord.app +Package: app.pyoncord Name: Bunny -Version: 0.3.2 +Version: 0.4.0 Architecture: iphoneos-arm -Description: A mod for Discord's mobile apps. +Description: A client modification for Discord's mobile app. Maintainer: Pylix -Author: Pylix, FieryFlames +Author: Pylix, Adrian Castro, FieryFlames Icon: https://avatars.githubusercontent.com/u/132727175 Section: Tweaks -Depends: ${ORION}, firmware (>= 13.0) +Depends: mobilesubstrate (>= 0.9.5000) Conflicts: app.enmity, mod.vendetta From bdf3792be9617e0326efee526e5cc353c618513c Mon Sep 17 00:00:00 2001 From: Adrian Castro <22133246+castdrian@users.noreply.github.com> Date: Thu, 14 Nov 2024 22:50:08 +0100 Subject: [PATCH 11/15] feat: finish font impl --- Headers/{Font.h => Fonts.h} | 0 Makefile | 4 +-- Sources/{Font.x => Fonts.x} | 64 ++++++++++++++++++++++++++++++++++--- Sources/Tweak.x | 12 ++++++- 4 files changed, 72 insertions(+), 8 deletions(-) rename Headers/{Font.h => Fonts.h} (100%) rename Sources/{Font.x => Fonts.x} (59%) diff --git a/Headers/Font.h b/Headers/Fonts.h similarity index 100% rename from Headers/Font.h rename to Headers/Fonts.h diff --git a/Makefile b/Makefile index e8a9450..4f79052 100644 --- a/Makefile +++ b/Makefile @@ -7,9 +7,9 @@ include $(THEOS)/makefiles/common.mk TWEAK_NAME = Bunny BUNDLE_NAME = BunnyResources -Bunny_FILES = $(shell find Sources -name "*.x" && find Sources -name "*.m") +Bunny_FILES = $(wildcard Sources/*.x Sources/*.m Sources/**/*.x Sources/**/*.m) Bunny_CFLAGS = -fobjc-arc -DPACKAGE_VERSION='@"$(THEOS_PACKAGE_BASE_VERSION)"' -I$(THEOS_PROJECT_DIR)/Headers -Bunny_FRAMEWORKS = Foundation UIKit CoreGraphics +Bunny_FRAMEWORKS = Foundation UIKit CoreGraphics CoreText CoreFoundation BunnyResources_INSTALL_PATH = "/Library/Application\ Support/" BunnyResources_RESOURCE_DIRS = Resources diff --git a/Sources/Font.x b/Sources/Fonts.x similarity index 59% rename from Sources/Font.x rename to Sources/Fonts.x index 35e71ec..e3ae4ee 100644 --- a/Sources/Font.x +++ b/Sources/Fonts.x @@ -1,8 +1,9 @@ -#import "Font.h" +#import "Fonts.h" #import "Utils.h" #import "Logger.h" #import #import +#import NSMutableDictionary *fontMap; @@ -11,7 +12,11 @@ NSMutableDictionary *fontMap; + (UIFont *)fontWithName:(NSString *)name size:(CGFloat)size { NSString *replacementName = fontMap[name]; if (replacementName) { - return %orig(replacementName, size); + UIFontDescriptor *replacementDescriptor = [UIFontDescriptor fontDescriptorWithName:replacementName size:size]; + UIFontDescriptor *fallbackDescriptor = [replacementDescriptor fontDescriptorByAddingAttributes:@{UIFontDescriptorNameAttribute: @[name]}]; + UIFontDescriptor *finalDescriptor = [replacementDescriptor fontDescriptorByAddingAttributes:@{UIFontDescriptorCascadeListAttribute: @[fallbackDescriptor]}]; + + return [UIFont fontWithDescriptor:finalDescriptor size:size]; } return %orig; } @@ -27,13 +32,39 @@ NSMutableDictionary *fontMap; return %orig; } ++ (UIFont *)systemFontOfSize:(CGFloat)size { + NSString *replacementName = fontMap[@"systemFont"]; + if (replacementName) { + return [UIFont fontWithName:replacementName size:size]; + } + return %orig; +} + ++ (UIFont *)preferredFontForTextStyle:(UIFontTextStyle)style { + NSString *replacementName = fontMap[@"systemFont"]; + if (replacementName) { + return [UIFont fontWithName:replacementName size:[UIFont systemFontSize]]; + } + return %orig; +} + %end void patchFonts(NSDictionary *mainFonts, NSString *fontDefName) { + BunnyLog(@"patchFonts called with fonts: %@ and def name: %@", mainFonts, fontDefName); + if (!fontMap) { + BunnyLog(@"Creating new fontMap"); fontMap = [NSMutableDictionary dictionary]; } + NSString *fontJson = [NSString stringWithContentsOfURL:[getPyoncordDirectory() URLByAppendingPathComponent:@"fonts.json"] + encoding:NSUTF8StringEncoding + error:nil]; + if (fontJson) { + BunnyLog(@"Found existing fonts.json: %@", fontJson); + } + for (NSString *fontName in mainFonts) { NSString *url = mainFonts[fontName]; BunnyLog(@"Replacing font %@ with URL: %@", fontName, url); @@ -75,16 +106,31 @@ void patchFonts(NSDictionary *mainFonts, NSString *fontD if (font) { CFStringRef postScriptName = CGFontCopyPostScriptName(font); + CTFontRef existingFont = CTFontCreateWithName(postScriptName, 0, NULL); + if (existingFont) { + CFErrorRef unregisterError = NULL; + if (!CTFontManagerUnregisterGraphicsFont(font, &unregisterError)) { + BunnyLog(@"Failed to deregister font %@: %@", (__bridge NSString *)postScriptName, + unregisterError ? (__bridge NSString *)CFErrorCopyDescription(unregisterError) : @"Unknown error"); + if (unregisterError) CFRelease(unregisterError); + } + CFRelease(existingFont); + } + CFErrorRef error = NULL; if (CTFontManagerRegisterGraphicsFont(font, &error)) { fontMap[fontName] = (__bridge NSString *)postScriptName; BunnyLog(@"Successfully registered font %@ to %@", fontName, (__bridge NSString *)postScriptName); + + NSError *jsonError; + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:fontMap options:0 error:&jsonError]; + if (!jsonError) { + [jsonData writeToURL:[getPyoncordDirectory() URLByAppendingPathComponent:@"fontMap.json"] atomically:YES]; + } } else { NSString *errorDesc = error ? (__bridge NSString *)CFErrorCopyDescription(error) : @"Unknown error"; BunnyLog(@"Failed to register font %@: %@", fontName, errorDesc); - if (error) { - CFRelease(error); - } + if (error) CFRelease(error); } CFRelease(postScriptName); @@ -93,4 +139,12 @@ void patchFonts(NSDictionary *mainFonts, NSString *fontD CGDataProviderRelease(provider); } } +} + +%ctor { + @autoreleasepool { + fontMap = [NSMutableDictionary dictionary]; + BunnyLog(@"Font hooks initialized"); + %init; + } } \ No newline at end of file diff --git a/Sources/Tweak.x b/Sources/Tweak.x index 36ef121..26f995f 100644 --- a/Sources/Tweak.x +++ b/Sources/Tweak.x @@ -3,7 +3,7 @@ #import "Utils.h" #import "Logger.h" #import "Theme.h" -#import "Font.h" +#import "Fonts.h" #import "LoaderConfig.h" static NSURL *source; @@ -109,6 +109,16 @@ static LoaderConfig *loaderConfig; %orig([jsCode dataUsingEncoding:NSUTF8StringEncoding], source, async); } + NSData *fontData = [NSData dataWithContentsOfURL:[pyoncordDirectory URLByAppendingPathComponent:@"fonts.json"]]; + if (fontData) { + NSError *jsonError; + NSDictionary *fontDict = [NSJSONSerialization JSONObjectWithData:fontData options:0 error:&jsonError]; + if (!jsonError && fontDict[@"main"]) { + BunnyLog(@"Found font configuration, applying..."); + patchFonts(fontDict[@"main"], fontDict[@"name"]); + } + } + if (bundle) { BunnyLog(@"Executing JS bundle"); %orig(bundle, source, async); From 0effa1ae2524ff97e35de016e7b5fccb8e339446 Mon Sep 17 00:00:00 2001 From: Cristiandis <112336919+Cristiandis@users.noreply.github.com> Date: Fri, 15 Nov 2024 09:47:28 +0100 Subject: [PATCH 12/15] rebase from upstream --- README.md | 80 +++++++++++++++++------ Sources/LoaderConfig.m | 14 ++-- Sources/Tweak.x | 46 ++++++------- app-repo.json | 80 +++++++---------------- assets/logo/logo-dark.svg | 4 ++ assets/logo/logo-light.svg | 4 ++ assets/wordmark/wordmark+slogan-dark.svg | 6 ++ assets/wordmark/wordmark+slogan-light.svg | 6 ++ control | 16 ++--- 9 files changed, 139 insertions(+), 117 deletions(-) create mode 100644 assets/logo/logo-dark.svg create mode 100644 assets/logo/logo-light.svg create mode 100644 assets/wordmark/wordmark+slogan-dark.svg create mode 100644 assets/wordmark/wordmark+slogan-light.svg diff --git a/README.md b/README.md index 5b87c66..64ef504 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,78 @@ -# BunnyTweak +

+ + + + +
+ + + + + +        + + + + + +        + + + + + +        -Tweak to inject [Bunny](https://github.com/pyoncord/Bunny) into Discord. Forked [VendettaTweak](https://github.com/vendetta-mod/VendettaTweak), modified to match with [BunnyXposed](https://github.com/pyoncord/BunnyXposed) behavior. There are still slight differences between these two, and this tweak may be missing some loader features. + +

+ +# 💊 RevengeTweak + +![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/revenge-mod/revenge-tweak/release.yml) +![Open Software License 3](https://img.shields.io/badge/License-OSL%20v3-yellow.svg) + +Tweak to inject [Revenge](https://github.com/revenge-mod/Revenge) into Discord. Forked [BunnyTweak](https://github.com/pyoncord/BunnyTweak), modified to match with [RevengeXposed](https://github.com/revenge-mod/Revenge-xposed) behavior. There are still slight differences between these two, and this tweak may be missing some loader features. > [!NOTE] -> As of right now this tweak does not encompass some functionalities when running in a jailed environment with a distribution certificate that has a different App ID \ +> As of right now this tweak does not encompass some functionalities when running in a jailed environment with a wildcard certificate \ > If you value these features sign the application with a local dev certificate: -> -> - setAlternateAppIcon does not work, thus breaking dynamic app icons (unlikely to be able to be fixed unless iOS behavior changes) -> - sharing files to the application/selecting items via the Files app does not work (this might be more of a keychain/app group issue) +> - setAlternateAppIcon does not work, thus breaking dynamic app icons +> - sharing files to the application/selecting items via the Files app does not work -## Installation +## 🔽 Installation -Builds can be found in the [Releases](https://github.com/pyoncord/BunnyTweak/releases/latest) tab. +Builds can be found in the [Releases](https://github.com/revenge-mod/revenge-tweak/releases/latest) tab. > [!NOTE] -> Decrypted IPAs are sourced from the [Enmity](https://github.com/enmity-mod/) community. These are also used throughout Enmity related projects such as [enmity-mod/tweak](https://github.com/enmity-mod/tweak/) and [acquitelol/rosiecord](https://github.com/acquitelol/rosiecord).\ -> All credits are attributed to the owner(s). +> Raw decrypted IPAs which are used to provide prepatched IPAs are sourced from the [Enmity](https://github.com/enmity-mod/) community. These raw decrypted IPAs are also used throughout Enmity related projects such as [enmity-mod/tweak](https://github.com/enmity-mod/tweak/) and [acquitelol/rosiecord](https://github.com/acquitelol/rosiecord).\ +> All credits are attributed to the owner(s) of the raw IPAs. ### Jailbroken -1. Install Bunny by downloading the appropriate Debian package (or by building your own, see [Building BunnyTweak locally](#building-bunnytweak-locally)) and adding it to your package manager. Use the file ending in `arm.deb` for rootful jailbreaks, and the file ending in `arm64.deb` for rootless jailbreaks. +1. Install the Orion runtime via your preferred package manager, by adding `https://repo.chariz.com/` to your sources, then finding `Orion Runtime`. +1. Install Revenge by downloading the appropriate Debian package (or by building your own, see [Building RevengeTweak locally](#building-revengetweak-locally)) and adding it to your package manager. Use the file ending in `arm.deb` for rootful jailbreaks, and the file ending in `arm64.deb` for rootless jailbreaks. ### Jailed - - + + > [!NOTE] > TrollStore may display an encryption warning, which you can disregard. -1. Download and install [Bunny.ipa](https://github.com/pyoncord/BunnyTweak/releases/latest/download/Bunny.ipa) using your preferred sideloading method. +1. Download and install [Revenge.ipa](https://github.com/revenge-mod/revenge-tweak/releases/latest/download/Revenge.ipa) using your preferred sideloading method. -## Building BunnyTweak locally +## 🛠️ Building RevengeTweak locally > [!NOTE] -> These steps assume you use macOS. +> 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. @@ -42,7 +80,7 @@ Builds can be found in the [Releases](https://github.com/pyoncord/BunnyTweak/rel 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 BunnyTweak. +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 RevengeTweak. ```bash export PATH="$(brew --prefix make)/libexec/gnubin:$PATH" @@ -58,17 +96,17 @@ 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:pyoncord/BunnyTweak.git` 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:revenge-mod/RevengeTweak.git` and `cd` into it. Replace the URL with your fork if you've forked this repository. -6. To build BunnyTweak, 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 RevengeTweak, 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. The resulting `.deb` files will be in the `packages` folder. As a reminder, `*arm.deb` is for rootful jailbreaks and sideloading, and `*arm64.deb` is for rootless jailbreaks. -## Contributing +## 📙 Contributing -If you want to contribute, you will basically need to follow the steps for [Building BunnyTweak locally](#building-bunnytweak-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 RevengeTweak locally](#building-revengetweak-locally), as well as run `make spm` for the Swift LSP to work. diff --git a/Sources/LoaderConfig.m b/Sources/LoaderConfig.m index bfc31f4..b04530b 100644 --- a/Sources/LoaderConfig.m +++ b/Sources/LoaderConfig.m @@ -7,20 +7,20 @@ + (instancetype)defaultConfig { LoaderConfig *config = [[LoaderConfig alloc] init]; config.customLoadUrlEnabled = NO; - config.customLoadUrl = [NSURL URLWithString:@"http://localhost:4040/bunny.js"]; + config.customLoadUrl = [NSURL URLWithString:@"http://localhost:4040/revenge.js"]; return config; } + (instancetype)getLoaderConfig { BunnyLog(@"Getting loader config"); - + NSURL *loaderConfigUrl = [getPyoncordDirectory() URLByAppendingPathComponent:@"loader.json"]; - + if ([[NSFileManager defaultManager] fileExistsAtPath:loaderConfigUrl.path]) { NSError *error = nil; NSData *data = [NSData dataWithContentsOfURL:loaderConfigUrl]; NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; - + if (json && !error) { LoaderConfig *config = [[LoaderConfig alloc] init]; NSDictionary *customLoadUrl = json[@"customLoadUrl"]; @@ -34,7 +34,7 @@ return config; } } - + BunnyLog(@"Couldn't get loader config"); return [LoaderConfig defaultConfig]; } @@ -47,9 +47,9 @@ @"url": self.customLoadUrl.absoluteString } }; - + NSData *data = [NSJSONSerialization dataWithJSONObject:json options:0 error:nil]; return [data writeToURL:loaderConfigUrl atomically:YES]; } -@end \ No newline at end of file +@end diff --git a/Sources/Tweak.x b/Sources/Tweak.x index 26f995f..ceec006 100644 --- a/Sources/Tweak.x +++ b/Sources/Tweak.x @@ -15,13 +15,13 @@ static LoaderConfig *loaderConfig; %hook NSFileManager - (NSURL *)containerURLForSecurityApplicationGroupIdentifier:(NSString *)groupIdentifier { - BunnyLog(@"containerURLForSecurityApplicationGroupIdentifier called! %@", + BunnyLog(@"containerURLForSecurityApplicationGroupIdentifier called! %@", groupIdentifier ?: @"nil"); - + if (isJailbroken) { return %orig(groupIdentifier); } - + NSArray *paths = [self URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]; NSURL *lastPath = [paths lastObject]; return [lastPath URLByAppendingPathComponent:@"AppGroup"]; @@ -55,7 +55,7 @@ static LoaderConfig *loaderConfig; %orig(patchData, source, YES); __block NSData *bundle = [NSData dataWithContentsOfURL:[pyoncordDirectory URLByAppendingPathComponent:@"bundle.js"]]; - + dispatch_group_t group = dispatch_group_create(); dispatch_group_enter(group); @@ -64,16 +64,16 @@ static LoaderConfig *loaderConfig; bundleUrl = loaderConfig.customLoadUrl; BunnyLog(@"Using custom load URL: %@", bundleUrl.absoluteString); } else { - bundleUrl = [NSURL URLWithString:@"https://raw.githubusercontent.com/bunny-mod/builds/main/bunny.min.js"]; + bundleUrl = [NSURL URLWithString:@"https://github.com/revenge-mod/revenge-bundle/releases/latest/download/revenge.min.js"]; BunnyLog(@"Using default bundle URL: %@", bundleUrl.absoluteString); } - NSMutableURLRequest *bundleRequest = [NSMutableURLRequest requestWithURL:bundleUrl - cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData + NSMutableURLRequest *bundleRequest = [NSMutableURLRequest requestWithURL:bundleUrl + cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:3.0]; - NSString *bundleEtag = [NSString stringWithContentsOfURL:[pyoncordDirectory URLByAppendingPathComponent:@"etag.txt"] - encoding:NSUTF8StringEncoding + NSString *bundleEtag = [NSString stringWithContentsOfURL:[pyoncordDirectory URLByAppendingPathComponent:@"etag.txt"] + encoding:NSUTF8StringEncoding error:nil]; if (bundleEtag && bundle) { [bundleRequest setValue:bundleEtag forHTTPHeaderField:@"If-None-Match"]; @@ -86,12 +86,12 @@ static LoaderConfig *loaderConfig; if (httpResponse.statusCode == 200) { bundle = data; [bundle writeToURL:[pyoncordDirectory URLByAppendingPathComponent:@"bundle.js"] atomically:YES]; - + NSString *etag = [httpResponse.allHeaderFields objectForKey:@"Etag"]; if (etag) { - [etag writeToURL:[pyoncordDirectory URLByAppendingPathComponent:@"etag.txt"] - atomically:YES - encoding:NSUTF8StringEncoding + [etag writeToURL:[pyoncordDirectory URLByAppendingPathComponent:@"etag.txt"] + atomically:YES + encoding:NSUTF8StringEncoding error:nil]; } } @@ -152,25 +152,25 @@ static LoaderConfig *loaderConfig; %end %ctor { - @autoreleasepool { + @autoreleasepool { source = [NSURL URLWithString:@"bunny"]; - + NSString *install_prefix = @"/var/jb"; isJailbroken = [[NSFileManager defaultManager] fileExistsAtPath:install_prefix]; - + NSString *bundlePath = [NSString stringWithFormat:@"%@/Library/Application Support/BunnyResources.bundle", install_prefix]; BunnyLog(@"Is jailbroken: %d", isJailbroken); BunnyLog(@"Bundle path for jailbroken: %@", bundlePath); - + NSString *jailedPath = [[NSBundle mainBundle].bundleURL.path stringByAppendingPathComponent:@"BunnyResources.bundle"]; BunnyLog(@"Bundle path for jailed: %@", jailedPath); - + bunnyPatchesBundlePath = isJailbroken ? bundlePath : jailedPath; BunnyLog(@"Selected bundle path: %@", bunnyPatchesBundlePath); - + BOOL bundleExists = [[NSFileManager defaultManager] fileExistsAtPath:bunnyPatchesBundlePath]; BunnyLog(@"Bundle exists at path: %d", bundleExists); - + NSError *error = nil; NSArray *bundleContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:bunnyPatchesBundlePath error:&error]; if (error) { @@ -178,10 +178,10 @@ static LoaderConfig *loaderConfig; } else { BunnyLog(@"Bundle contents: %@", bundleContents); } - + pyoncordDirectory = getPyoncordDirectory(); loaderConfig = [[LoaderConfig alloc] init]; - + %init; } -} \ No newline at end of file +} diff --git a/app-repo.json b/app-repo.json index 35c3005..5c6b0cd 100644 --- a/app-repo.json +++ b/app-repo.json @@ -1,76 +1,40 @@ { - "name": "Pyoncord App Repo", - "identifier": "io.github.pyoncord.repo", - "iconURL": "https://pyoncord.github.io/assets/icon-altstore.png", + "name": "Revenge App Repo", + "identifier": "io.github.revenge-mod.repo", + "iconURL": "https://avatars.githubusercontent.com/u/159218871?s=200&v=4", "apps": [ { - "name": "Bunny", + "name": "Revenge", "bundleIdentifier": "com.hammerandchisel.discord", - "developerName": "Pylix", - "iconURL": "https://pyoncord.github.io/assets/icon-altstore.png", + "developerName": "Cristiandis", + "iconURL": "https://avatars.githubusercontent.com/u/159218871?s=200&v=4", "localizedDescription": "A client mod for Discord", "subtitle": "A client mod for Discord", "tintColor": "7289da", "versions": [ { - "version": "247.2", - "date": "2024-09-20", - "size": 96426195, - "downloadURL": "https://github.com/pyoncord/BunnyTweak/releases/download/v247.2/Bunny.ipa" + "version": "250.0", + "date": "2024-10-20", + "size": 101218873, + "downloadURL": "https://github.com/revenge-mod/revenge-tweak/releases/download/v250.0/Revenge.ipa" }, { - "version": "247.0", - "date": "2024-09-18", - "size": 96629525, - "downloadURL": "https://github.com/pyoncord/BunnyTweak/releases/download/v247.0/Bunny.ipa" + "version": "250.0", + "date": "2024-10-17", + "size": 101218840, + "downloadURL": "https://github.com/revenge-mod/revenge-tweak/releases/download/v250.0/Revenge.ipa" + }, + { + "version": "246.0", + "date": "2024-09-15", + "size": 102811465, + "downloadURL": "https://github.com/revenge-mod/RevengeTweak/releases/download/v246.0/Revenge.ipa" }, { "version": "246.0", "date": "2024-09-14", - "size": 103195545, - "downloadURL": "https://github.com/pyoncord/BunnyTweak/releases/download/v246.0/Bunny.ipa" - }, - { - "version": "237.0", - "date": "2024-07-13", - "size": 114323285, - "downloadURL": "https://github.com/pyoncord/BunnyTweak/releases/download/v237.0/Bunny.ipa" - }, - { - "version": "235.0", - "date": "2024-06-27", - "size": 112173273, - "downloadURL": "https://github.com/pyoncord/BunnyTweak/releases/download/v235.0/Bunny.ipa" - }, - { - "version": "234.0", - "date": "2024-06-24", - "size": 111671815, - "downloadURL": "https://github.com/pyoncord/BunnyTweak/releases/download/v234.0/Bunny.ipa" - }, - { - "version": "230.0", - "date": "2024-05-18", - "size": 102457139, - "downloadURL": "https://github.com/pyoncord/BunnyTweak/releases/download/v230.0/Bunny.ipa" - }, - { - "version": "229.0", - "date": "2024-05-16", - "size": 103776118, - "downloadURL": "https://github.com/pyoncord/BunnyTweak/releases/download/v229.0/Bunny.ipa" - }, - { - "version": "226.1", - "date": "2024-04-30", - "size": 102705408, - "downloadURL": "https://github.com/pyoncord/BunnyTweak/releases/download/v226.1/Pyoncord.ipa" - }, - { - "version": "223.0", - "date": "2024-04-08", - "size": 106082919, - "downloadURL": "https://github.com/pyoncord/BunnyTweak/releases/download/v223.0/Pyoncord.ipa" + "size": 103194076, + "downloadURL": "https://github.com/revenge-mod/RevengeTweak/releases/download/v246.0/Revenge.ipa" } ], "appPermissions": {} diff --git a/assets/logo/logo-dark.svg b/assets/logo/logo-dark.svg new file mode 100644 index 0000000..cb34519 --- /dev/null +++ b/assets/logo/logo-dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/logo/logo-light.svg b/assets/logo/logo-light.svg new file mode 100644 index 0000000..b16e22f --- /dev/null +++ b/assets/logo/logo-light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/wordmark/wordmark+slogan-dark.svg b/assets/wordmark/wordmark+slogan-dark.svg new file mode 100644 index 0000000..2f3c148 --- /dev/null +++ b/assets/wordmark/wordmark+slogan-dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/assets/wordmark/wordmark+slogan-light.svg b/assets/wordmark/wordmark+slogan-light.svg new file mode 100644 index 0000000..eefd512 --- /dev/null +++ b/assets/wordmark/wordmark+slogan-light.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/control b/control index 7c3f94f..d1a45b9 100644 --- a/control +++ b/control @@ -1,11 +1,11 @@ -Package: app.pyoncord -Name: Bunny -Version: 0.4.0 +Package: io.github.revenge-mod.app +Name: Revenge +Version: 2.0.0 Architecture: iphoneos-arm -Description: A client modification for Discord's mobile app. -Maintainer: Pylix -Author: Pylix, Adrian Castro, FieryFlames -Icon: https://avatars.githubusercontent.com/u/132727175 +Description: A mod for Discord's mobile apps. +Maintainer: Cristiandis +Author: Pylix, Adrian Castro, FieryFlames, Cristiandis +Icon: https://avatars.githubusercontent.com/u/159218871 Section: Tweaks Depends: mobilesubstrate (>= 0.9.5000) -Conflicts: app.enmity, mod.vendetta +Conflicts: app.enmity, mod.vendetta, app.bunny From 0a9bfdbce35d91adbec1ef9e334c92b7edf1515b Mon Sep 17 00:00:00 2001 From: Cristiandis <112336919+Cristiandis@users.noreply.github.com> Date: Fri, 15 Nov 2024 11:17:44 +0100 Subject: [PATCH 13/15] update bunny.plist and makefile --- Makefile | 4 ++-- Bunny.plist => Revenge.plist | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename Bunny.plist => Revenge.plist (100%) diff --git a/Makefile b/Makefile index 4f79052..7cb86c8 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,8 @@ INSTALL_TARGET_PROCESSES = Discord include $(THEOS)/makefiles/common.mk -TWEAK_NAME = Bunny -BUNDLE_NAME = BunnyResources +TWEAK_NAME = Revenge +BUNDLE_NAME = RevengeResources Bunny_FILES = $(wildcard Sources/*.x Sources/*.m Sources/**/*.x Sources/**/*.m) Bunny_CFLAGS = -fobjc-arc -DPACKAGE_VERSION='@"$(THEOS_PACKAGE_BASE_VERSION)"' -I$(THEOS_PROJECT_DIR)/Headers diff --git a/Bunny.plist b/Revenge.plist similarity index 100% rename from Bunny.plist rename to Revenge.plist From 3f5723ea209663cac93a3923057c235228fe3c37 Mon Sep 17 00:00:00 2001 From: Cristiandis <112336919+Cristiandis@users.noreply.github.com> Date: Fri, 15 Nov 2024 11:45:12 +0100 Subject: [PATCH 14/15] Change bunny to revenge --- Headers/Logger.h | 4 +-- Makefile | 10 +++---- Sources/Fonts.x | 60 +++++++++++++++++++++--------------------- Sources/LoaderConfig.m | 4 +-- Sources/Theme.m | 44 +++++++++++++++---------------- Sources/Tweak.x | 54 ++++++++++++++++++------------------- 6 files changed, 88 insertions(+), 88 deletions(-) diff --git a/Headers/Logger.h b/Headers/Logger.h index fce7b0e..fddd86c 100644 --- a/Headers/Logger.h +++ b/Headers/Logger.h @@ -1,4 +1,4 @@ #import -#define LOG_PREFIX @"[Bunny]" -#define BunnyLog(fmt, ...) NSLog((LOG_PREFIX @" " fmt), ##__VA_ARGS__) \ No newline at end of file +#define LOG_PREFIX @"[Revenge]" +#define RevengeLog(fmt, ...) NSLog((LOG_PREFIX @" " fmt), ##__VA_ARGS__) diff --git a/Makefile b/Makefile index 7cb86c8..c8e6c8a 100644 --- a/Makefile +++ b/Makefile @@ -7,12 +7,12 @@ include $(THEOS)/makefiles/common.mk TWEAK_NAME = Revenge BUNDLE_NAME = RevengeResources -Bunny_FILES = $(wildcard Sources/*.x Sources/*.m Sources/**/*.x Sources/**/*.m) -Bunny_CFLAGS = -fobjc-arc -DPACKAGE_VERSION='@"$(THEOS_PACKAGE_BASE_VERSION)"' -I$(THEOS_PROJECT_DIR)/Headers -Bunny_FRAMEWORKS = Foundation UIKit CoreGraphics CoreText CoreFoundation +Revenge_FILES = $(wildcard Sources/*.x Sources/*.m Sources/**/*.x Sources/**/*.m) +Revenge_CFLAGS = -fobjc-arc -DPACKAGE_VERSION='@"$(THEOS_PACKAGE_BASE_VERSION)"' -I$(THEOS_PROJECT_DIR)/Headers +Revenge_FRAMEWORKS = Foundation UIKit CoreGraphics CoreText CoreFoundation -BunnyResources_INSTALL_PATH = "/Library/Application\ Support/" -BunnyResources_RESOURCE_DIRS = Resources +RevengeResources_INSTALL_PATH = "/Library/Application\ Support/" +RevengeResources_RESOURCE_DIRS = Resources include $(THEOS_MAKE_PATH)/tweak.mk include $(THEOS_MAKE_PATH)/bundle.mk diff --git a/Sources/Fonts.x b/Sources/Fonts.x index e3ae4ee..01a3cd4 100644 --- a/Sources/Fonts.x +++ b/Sources/Fonts.x @@ -15,7 +15,7 @@ NSMutableDictionary *fontMap; UIFontDescriptor *replacementDescriptor = [UIFontDescriptor fontDescriptorWithName:replacementName size:size]; UIFontDescriptor *fallbackDescriptor = [replacementDescriptor fontDescriptorByAddingAttributes:@{UIFontDescriptorNameAttribute: @[name]}]; UIFontDescriptor *finalDescriptor = [replacementDescriptor fontDescriptorByAddingAttributes:@{UIFontDescriptorCascadeListAttribute: @[fallbackDescriptor]}]; - + return [UIFont fontWithDescriptor:finalDescriptor size:size]; } return %orig; @@ -26,7 +26,7 @@ NSMutableDictionary *fontMap; if (replacementName) { UIFontDescriptor *replacementDescriptor = [UIFontDescriptor fontDescriptorWithName:replacementName size:size]; UIFontDescriptor *finalDescriptor = [replacementDescriptor fontDescriptorByAddingAttributes:@{UIFontDescriptorCascadeListAttribute: @[descriptor]}]; - + return [UIFont fontWithDescriptor:finalDescriptor size:size]; } return %orig; @@ -51,77 +51,77 @@ NSMutableDictionary *fontMap; %end void patchFonts(NSDictionary *mainFonts, NSString *fontDefName) { - BunnyLog(@"patchFonts called with fonts: %@ and def name: %@", mainFonts, fontDefName); - + RevengeLog(@"patchFonts called with fonts: %@ and def name: %@", mainFonts, fontDefName); + if (!fontMap) { - BunnyLog(@"Creating new fontMap"); + RevengeLog(@"Creating new fontMap"); fontMap = [NSMutableDictionary dictionary]; } - + NSString *fontJson = [NSString stringWithContentsOfURL:[getPyoncordDirectory() URLByAppendingPathComponent:@"fonts.json"] encoding:NSUTF8StringEncoding error:nil]; if (fontJson) { - BunnyLog(@"Found existing fonts.json: %@", fontJson); + RevengeLog(@"Found existing fonts.json: %@", fontJson); } - + for (NSString *fontName in mainFonts) { NSString *url = mainFonts[fontName]; - BunnyLog(@"Replacing font %@ with URL: %@", fontName, url); - + RevengeLog(@"Replacing font %@ with URL: %@", fontName, url); + NSURL *fontURL = [NSURL URLWithString:url]; NSString *fontExtension = fontURL.pathExtension; - + NSURL *fontCachePath = [[[getPyoncordDirectory() URLByAppendingPathComponent:@"downloads" isDirectory:YES] URLByAppendingPathComponent:@"fonts" isDirectory:YES] URLByAppendingPathComponent:fontDefName isDirectory:YES]; - + fontCachePath = [fontCachePath URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", fontName, fontExtension]]; - + NSURL *parentDir = [fontCachePath URLByDeletingLastPathComponent]; if (![[NSFileManager defaultManager] fileExistsAtPath:parentDir.path]) { - BunnyLog(@"Creating parent directory: %@", parentDir.path); + RevengeLog(@"Creating parent directory: %@", parentDir.path); [[NSFileManager defaultManager] createDirectoryAtURL:parentDir withIntermediateDirectories:YES attributes:nil error:nil]; } - + if (![[NSFileManager defaultManager] fileExistsAtPath:fontCachePath.path]) { - BunnyLog(@"Downloading font %@ from %@", fontName, url); + RevengeLog(@"Downloading font %@ from %@", fontName, url); NSData *data = [NSData dataWithContentsOfURL:fontURL]; if (data) { - BunnyLog(@"Writing font data to: %@", fontCachePath.path); + RevengeLog(@"Writing font data to: %@", fontCachePath.path); [data writeToURL:fontCachePath atomically:YES]; } } - + NSData *fontData = [NSData dataWithContentsOfURL:fontCachePath]; if (fontData) { - BunnyLog(@"Registering font %@ with provider", fontName); + RevengeLog(@"Registering font %@ with provider", fontName); CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)fontData); CGFontRef font = CGFontCreateWithDataProvider(provider); - + if (font) { CFStringRef postScriptName = CGFontCopyPostScriptName(font); - + CTFontRef existingFont = CTFontCreateWithName(postScriptName, 0, NULL); if (existingFont) { CFErrorRef unregisterError = NULL; if (!CTFontManagerUnregisterGraphicsFont(font, &unregisterError)) { - BunnyLog(@"Failed to deregister font %@: %@", (__bridge NSString *)postScriptName, + RevengeLog(@"Failed to deregister font %@: %@", (__bridge NSString *)postScriptName, unregisterError ? (__bridge NSString *)CFErrorCopyDescription(unregisterError) : @"Unknown error"); if (unregisterError) CFRelease(unregisterError); } CFRelease(existingFont); } - + CFErrorRef error = NULL; if (CTFontManagerRegisterGraphicsFont(font, &error)) { fontMap[fontName] = (__bridge NSString *)postScriptName; - BunnyLog(@"Successfully registered font %@ to %@", fontName, (__bridge NSString *)postScriptName); - + RevengeLog(@"Successfully registered font %@ to %@", fontName, (__bridge NSString *)postScriptName); + NSError *jsonError; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:fontMap options:0 error:&jsonError]; if (!jsonError) { @@ -129,22 +129,22 @@ void patchFonts(NSDictionary *mainFonts, NSString *fontD } } else { NSString *errorDesc = error ? (__bridge NSString *)CFErrorCopyDescription(error) : @"Unknown error"; - BunnyLog(@"Failed to register font %@: %@", fontName, errorDesc); + RevengeLog(@"Failed to register font %@: %@", fontName, errorDesc); if (error) CFRelease(error); } - + CFRelease(postScriptName); CFRelease(font); } CGDataProviderRelease(provider); } } -} +} %ctor { @autoreleasepool { fontMap = [NSMutableDictionary dictionary]; - BunnyLog(@"Font hooks initialized"); + RevengeLog(@"Font hooks initialized"); %init; } -} \ No newline at end of file +} diff --git a/Sources/LoaderConfig.m b/Sources/LoaderConfig.m index b04530b..11037ef 100644 --- a/Sources/LoaderConfig.m +++ b/Sources/LoaderConfig.m @@ -12,7 +12,7 @@ } + (instancetype)getLoaderConfig { - BunnyLog(@"Getting loader config"); + RevengeLog(@"Getting loader config"); NSURL *loaderConfigUrl = [getPyoncordDirectory() URLByAppendingPathComponent:@"loader.json"]; @@ -35,7 +35,7 @@ } } - BunnyLog(@"Couldn't get loader config"); + RevengeLog(@"Couldn't get loader config"); return [LoaderConfig defaultConfig]; } diff --git a/Sources/Theme.m b/Sources/Theme.m index a31c654..aff9daa 100644 --- a/Sources/Theme.m +++ b/Sources/Theme.m @@ -4,34 +4,34 @@ #import void swizzleDCDThemeColor(NSDictionary *> *semanticColors) { - BunnyLog(@"Swizzling DCDThemeColor"); - + RevengeLog(@"Swizzling DCDThemeColor"); + Class DCDTheme = NSClassFromString(@"DCDTheme"); Class dcdThemeTarget = object_getClass(DCDTheme); - + SEL themeIndexSelector = NSSelectorFromString(@"themeIndex"); Method themeIndexMethod = class_getClassMethod(dcdThemeTarget, themeIndexSelector); IMP themeIndexImpl = method_getImplementation(themeIndexMethod); int (*themeIndex)(id, SEL) = (int (*)(id, SEL))themeIndexImpl; - + Class DCDThemeColor = NSClassFromString(@"DCDThemeColor"); Class target = object_getClass(DCDThemeColor); - + unsigned int methodCount; Method *methods = class_copyMethodList(target, &methodCount); - + for (unsigned int i = 0; i < methodCount; i++) { Method method = methods[i]; SEL selector = method_getName(method); NSString *methodName = NSStringFromSelector(selector); - + NSArray *semanticColor = semanticColors[methodName]; if (semanticColor) { - BunnyLog(@"Swizzling %@", methodName); - + RevengeLog(@"Swizzling %@", methodName); + IMP originalImpl = method_getImplementation(method); UIColor *(*original)(id, SEL) = (UIColor *(*)(id, SEL))originalImpl; - + id block = ^UIColor *(id self) { int themeIndexVal = themeIndex(dcdThemeTarget, themeIndexSelector); if (semanticColor.count - 1 >= themeIndexVal) { @@ -42,41 +42,41 @@ void swizzleDCDThemeColor(NSDictionary *> *seman } return original(target, selector); }; - + IMP newImpl = imp_implementationWithBlock(block); method_setImplementation(method, newImpl); } } - + free(methods); } void swizzleUIColor(NSDictionary *rawColors) { - BunnyLog(@"Swizzling UIColor"); - + RevengeLog(@"Swizzling UIColor"); + Class UIColorClass = NSClassFromString(@"UIColor"); Class target = object_getClass(UIColorClass); - + unsigned int methodCount; Method *methods = class_copyMethodList(target, &methodCount); - + for (unsigned int i = 0; i < methodCount; i++) { Method method = methods[i]; SEL selector = method_getName(method); NSString *methodName = NSStringFromSelector(selector); - + NSString *rawColor = rawColors[methodName]; if (rawColor) { - BunnyLog(@"Swizzling %@", methodName); - + RevengeLog(@"Swizzling %@", methodName); + id block = ^UIColor *(id self) { return hexToUIColor(rawColor); }; - + IMP newImpl = imp_implementationWithBlock(block); method_setImplementation(method, newImpl); } } - + free(methods); -} \ No newline at end of file +} diff --git a/Sources/Tweak.x b/Sources/Tweak.x index ceec006..d543993 100644 --- a/Sources/Tweak.x +++ b/Sources/Tweak.x @@ -8,14 +8,14 @@ static NSURL *source; static BOOL isJailbroken; -static NSString *bunnyPatchesBundlePath; +static NSString *revengePatchesBundlePath; static NSURL *pyoncordDirectory; static LoaderConfig *loaderConfig; %hook NSFileManager - (NSURL *)containerURLForSecurityApplicationGroupIdentifier:(NSString *)groupIdentifier { - BunnyLog(@"containerURLForSecurityApplicationGroupIdentifier called! %@", + RevengeLog(@"containerURLForSecurityApplicationGroupIdentifier called! %@", groupIdentifier ?: @"nil"); if (isJailbroken) { @@ -36,22 +36,22 @@ static LoaderConfig *loaderConfig; return %orig; } - NSBundle *bunnyPatchesBundle = [NSBundle bundleWithPath:bunnyPatchesBundlePath]; - if (!bunnyPatchesBundle) { - BunnyLog(@"Failed to load BunnyPatches bundle from path: %@", bunnyPatchesBundlePath); + NSBundle *revengePatchesBundle = [NSBundle bundleWithPath:revengePatchesBundlePath]; + if (!revengePatchesBundle) { + RevengeLog(@"Failed to load RevengePatches bundle from path: %@", revengePatchesBundlePath); showErrorAlert(@"Loader Error", @"Failed to initialize mod loader. Please reinstall the tweak."); return %orig; } - NSURL *patchPath = [bunnyPatchesBundle URLForResource:@"payload-base" withExtension:@"js"]; + NSURL *patchPath = [revengePatchesBundle URLForResource:@"payload-base" withExtension:@"js"]; if (!patchPath) { - BunnyLog(@"Failed to find payload-base.js in bundle"); + RevengeLog(@"Failed to find payload-base.js in bundle"); showErrorAlert(@"Loader Error", @"Failed to initialize mod loader. Please reinstall the tweak."); return %orig; } NSData *patchData = [NSData dataWithContentsOfURL:patchPath]; - BunnyLog(@"Injecting loader"); + RevengeLog(@"Injecting loader"); %orig(patchData, source, YES); __block NSData *bundle = [NSData dataWithContentsOfURL:[pyoncordDirectory URLByAppendingPathComponent:@"bundle.js"]]; @@ -62,10 +62,10 @@ static LoaderConfig *loaderConfig; NSURL *bundleUrl; if (loaderConfig.customLoadUrlEnabled && loaderConfig.customLoadUrl) { bundleUrl = loaderConfig.customLoadUrl; - BunnyLog(@"Using custom load URL: %@", bundleUrl.absoluteString); + RevengeLog(@"Using custom load URL: %@", bundleUrl.absoluteString); } else { bundleUrl = [NSURL URLWithString:@"https://github.com/revenge-mod/revenge-bundle/releases/latest/download/revenge.min.js"]; - BunnyLog(@"Using default bundle URL: %@", bundleUrl.absoluteString); + RevengeLog(@"Using default bundle URL: %@", bundleUrl.absoluteString); } NSMutableURLRequest *bundleRequest = [NSMutableURLRequest requestWithURL:bundleUrl @@ -114,13 +114,13 @@ static LoaderConfig *loaderConfig; NSError *jsonError; NSDictionary *fontDict = [NSJSONSerialization JSONObjectWithData:fontData options:0 error:&jsonError]; if (!jsonError && fontDict[@"main"]) { - BunnyLog(@"Found font configuration, applying..."); + RevengeLog(@"Found font configuration, applying..."); patchFonts(fontDict[@"main"], fontDict[@"name"]); } } if (bundle) { - BunnyLog(@"Executing JS bundle"); + RevengeLog(@"Executing JS bundle"); %orig(bundle, source, async); } @@ -134,7 +134,7 @@ static LoaderConfig *loaderConfig; if (!error) { for (NSURL *fileURL in contents) { if ([[fileURL pathExtension] isEqualToString:@"js"]) { - BunnyLog(@"Executing preload JS file %@", fileURL.absoluteString); + RevengeLog(@"Executing preload JS file %@", fileURL.absoluteString); NSData *data = [NSData dataWithContentsOfURL:fileURL]; if (data) { %orig(data, source, async); @@ -142,7 +142,7 @@ static LoaderConfig *loaderConfig; } } } else { - BunnyLog(@"Error reading contents of preloads directory"); + RevengeLog(@"Error reading contents of preloads directory"); } } @@ -153,30 +153,30 @@ static LoaderConfig *loaderConfig; %ctor { @autoreleasepool { - source = [NSURL URLWithString:@"bunny"]; + source = [NSURL URLWithString:@"revenge"]; NSString *install_prefix = @"/var/jb"; isJailbroken = [[NSFileManager defaultManager] fileExistsAtPath:install_prefix]; - NSString *bundlePath = [NSString stringWithFormat:@"%@/Library/Application Support/BunnyResources.bundle", install_prefix]; - BunnyLog(@"Is jailbroken: %d", isJailbroken); - BunnyLog(@"Bundle path for jailbroken: %@", bundlePath); + NSString *bundlePath = [NSString stringWithFormat:@"%@/Library/Application Support/RevengeResources.bundle", install_prefix]; + RevengeLog(@"Is jailbroken: %d", isJailbroken); + RevengeLog(@"Bundle path for jailbroken: %@", bundlePath); - NSString *jailedPath = [[NSBundle mainBundle].bundleURL.path stringByAppendingPathComponent:@"BunnyResources.bundle"]; - BunnyLog(@"Bundle path for jailed: %@", jailedPath); + NSString *jailedPath = [[NSBundle mainBundle].bundleURL.path stringByAppendingPathComponent:@"RevengeResources.bundle"]; + RevengeLog(@"Bundle path for jailed: %@", jailedPath); - bunnyPatchesBundlePath = isJailbroken ? bundlePath : jailedPath; - BunnyLog(@"Selected bundle path: %@", bunnyPatchesBundlePath); + revengePatchesBundlePath = isJailbroken ? bundlePath : jailedPath; + RevengeLog(@"Selected bundle path: %@", revengePatchesBundlePath); - BOOL bundleExists = [[NSFileManager defaultManager] fileExistsAtPath:bunnyPatchesBundlePath]; - BunnyLog(@"Bundle exists at path: %d", bundleExists); + BOOL bundleExists = [[NSFileManager defaultManager] fileExistsAtPath:revengePatchesBundlePath]; + RevengeLog(@"Bundle exists at path: %d", bundleExists); NSError *error = nil; - NSArray *bundleContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:bunnyPatchesBundlePath error:&error]; + NSArray *bundleContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:revengePatchesBundlePath error:&error]; if (error) { - BunnyLog(@"Error listing bundle contents: %@", error); + RevengeLog(@"Error listing bundle contents: %@", error); } else { - BunnyLog(@"Bundle contents: %@", bundleContents); + RevengeLog(@"Bundle contents: %@", bundleContents); } pyoncordDirectory = getPyoncordDirectory(); From ecfe3647cbe48ca09e1cfdbd2302fd0a3586a8ae Mon Sep 17 00:00:00 2001 From: Cristiandis <112336919+Cristiandis@users.noreply.github.com> Date: Fri, 15 Nov 2024 12:02:20 +0100 Subject: [PATCH 15/15] change ipa-patcher to revenge --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f8dc152..3aae016 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -132,7 +132,7 @@ jobs: - name: Run patcher run: | - curl -L -o patcher https://github.com/amsyarasyiq/bunny-ipa-patcher/releases/download/release-pyon/patcher.mac-amd64 + curl -L -o patcher https://github.com/Cristiandis/ipa-patcher/releases/download/release-pyon/patcher.mac-amd64 chmod +x patcher ./patcher -d discord.ipa -o discord.ipa -i ./ipa-icons.zip