diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml
new file mode 100644
index 00000000..9827103f
--- /dev/null
+++ b/.github/workflows/ios.yml
@@ -0,0 +1,44 @@
+name: iOS starter workflow
+
+on:
+ push:
+ branches: [ "main" ]
+ pull_request:
+ branches: [ "main" ]
+
+jobs:
+ build:
+ name: Build and Test default scheme using any available iPhone simulator
+ runs-on: macos-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ - name: Set Default Scheme
+ run: |
+ scheme_list=$(xcodebuild -list -json | tr -d "\n")
+ default=$(echo $scheme_list | ruby -e "require 'json'; puts JSON.parse(STDIN.gets)['project']['targets'][0]")
+ echo $default | cat >default
+ echo Using default scheme: $default
+ - name: Build
+ env:
+ scheme: ${{ 'default' }}
+ platform: ${{ 'iOS Simulator' }}
+ run: |
+ # xcrun xctrace returns via stderr, not the expected stdout (see https://developer.apple.com/forums/thread/663959)
+ device=`xcrun xctrace list devices 2>&1 | grep -oE 'iPhone.*?[^\(]+' | head -1 | awk '{$1=$1;print}' | sed -e "s/ Simulator$//"`
+ if [ $scheme = default ]; then scheme=$(cat default); fi
+ if [ "`ls -A | grep -i \\.xcworkspace\$`" ]; then filetype_parameter="workspace" && file_to_build="`ls -A | grep -i \\.xcworkspace\$`"; else filetype_parameter="project" && file_to_build="`ls -A | grep -i \\.xcodeproj\$`"; fi
+ file_to_build=`echo $file_to_build | awk '{$1=$1;print}'`
+ xcodebuild build-for-testing -scheme "$scheme" -"$filetype_parameter" "$file_to_build" -destination "platform=$platform,name=$device"
+ - name: Test
+ env:
+ scheme: ${{ 'default' }}
+ platform: ${{ 'iOS Simulator' }}
+ run: |
+ # xcrun xctrace returns via stderr, not the expected stdout (see https://developer.apple.com/forums/thread/663959)
+ device=`xcrun xctrace list devices 2>&1 | grep -oE 'iPhone.*?[^\(]+' | head -1 | awk '{$1=$1;print}' | sed -e "s/ Simulator$//"`
+ if [ $scheme = default ]; then scheme=$(cat default); fi
+ if [ "`ls -A | grep -i \\.xcworkspace\$`" ]; then filetype_parameter="workspace" && file_to_build="`ls -A | grep -i \\.xcworkspace\$`"; else filetype_parameter="project" && file_to_build="`ls -A | grep -i \\.xcodeproj\$`"; fi
+ file_to_build=`echo $file_to_build | awk '{$1=$1;print}'`
+ xcodebuild test-without-building -scheme "$scheme" -"$filetype_parameter" "$file_to_build" -destination "platform=$platform,name=$device"
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 00000000..7b69fea1
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,440 @@
+name: Build IPA with tweaks
+on:
+ workflow_dispatch:
+ inputs:
+ repo:
+ description: 'Repository to build from'
+ required: true
+ default: 'Tonwalter888/YouMod'
+
+ branch:
+ description: 'Branch to build from'
+ required: true
+ default: 'main'
+
+ ipa_url:
+ description: "URL to the decrypted IPA file"
+ default: ""
+ required: true
+ type: string
+
+ display_name:
+ description: "App Name (Optional)"
+ default: "YouTube"
+ required: true
+ type: string
+
+ bundle_id:
+ description: "Bundle ID (Optional)"
+ default: "com.google.ios.youtube"
+ required: true
+ type: string
+
+ youpip:
+ description: "Integrate YouPiP"
+ default: true
+ required: false
+ type: boolean
+
+ ytuhd:
+ description: "Integrate YTUHD"
+ default: true
+ required: false
+ type: boolean
+
+ ryd:
+ description: "Integrate Return-YouTube-Dislikes"
+ default: true
+ required: false
+ type: boolean
+
+ abconfig:
+ description: "Integrate YTABConfig"
+ default: true
+ required: false
+ type: boolean
+
+ youquality:
+ description: "Integrate YouQuality"
+ default: false
+ required: false
+ type: boolean
+
+ demc:
+ description: "Integrate DontEatMyContent"
+ default: true
+ required: false
+ type: boolean
+
+ ytweaks:
+ description: "Integrate YTweaks"
+ default: true
+ required: false
+ type: boolean
+
+ youslider:
+ description: "Integrate YouSlider"
+ default: true
+ required: false
+ type: boolean
+
+ gonerino:
+ description: "Integrate Gonerino"
+ default: true
+ required: false
+ type: boolean
+
+ ytshare:
+ description: "Integrate youtube-native-share"
+ default: true
+ required: false
+ type: boolean
+
+ volboost:
+ description: "Integrate VolumeBoostYT (Require iOS 16+)"
+ default: true
+ required: false
+ type: boolean
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ build:
+ name: Build IPA with tweaks
+ runs-on: macos-latest
+ permissions:
+ contents: write
+
+ steps:
+ - name: Hide Sensitive Inputs
+ uses: levibostian/action-hide-sensitive-inputs@v1
+ with:
+ exclude_inputs: bundle_id,display_name,youpip,ytuhd,ryd,abconfig,ytweaks,youslider,gonerino,demc,volboost,repo,branch,youquality,ytshare
+
+ - name: Install MEGA downloader
+ if: ${{ startsWith(inputs.ipa_url, 'https://mega.nz/') }}
+ run: brew install megatools
+
+ - name: Download IPA from Mega share link
+ if: ${{ startsWith(inputs.ipa_url, 'https://mega.nz/') }}
+ env:
+ IPA_URL: ${{ inputs.ipa_url }}
+ run: |
+ megadl --no-progress --path youtube.ipa "$IPA_URL"
+
+ - name: Download IPA from direct URL
+ if: ${{ !startsWith(inputs.ipa_url, 'https://mega.nz/') }}
+ env:
+ IPA_URL: ${{ inputs.ipa_url }}
+ run: |
+ wget "$IPA_URL" --quiet --no-verbose -O youtube.ipa
+
+ - name: Validate IPA
+ run: |
+ file_type=$(file --mime-type -b youtube.ipa)
+
+ if [[ "$file_type" != "application/x-ios-app" && "$file_type" != "application/zip" ]]; then
+ echo "::error::Validation failed: The downloaded file is not a valid IPA. Detected type: $file_type."
+ exit 1
+ fi
+
+ - name: Get YouTube Version
+ run: |
+ unzip -q youtube.ipa -d ytextracted
+ echo "YT_VERSION=$(grep -A 1 'CFBundleVersion' ytextracted/Payload/YouTube.app/Info.plist | grep '' | awk -F'[><]' '{print $3}')" >> $GITHUB_ENV
+
+ - name: Install Dependencies
+ run: brew install make ldid gnu-sed autoconf automake libtool pkg-config
+
+ - name: Install Go
+ if: ${{ inputs.gonerino }}
+ run: brew install go
+
+ - name: Install Go
+ if: ${{ inputs.gonerino }}
+ run: brew install go
+
+ - name: Set PATH Environment Variables
+ run: |
+ echo "$(brew --prefix make)/libexec/gnubin" >> $GITHUB_PATH
+ echo "THEOS=${{ github.workspace }}/theos" >> $GITHUB_ENV
+
+ # Original from YTweaks
+ - name: Get tweaks commit
+ run: |
+ get_commit_hash() {
+ local repo_url=$1
+ git ls-remote "$repo_url" HEAD | awk '{print substr($1,1,7)}'
+ }
+ echo "THEOS_COMMIT=$(get_commit_hash "https://github.com/roothide/theos")" >> $GITHUB_ENV
+
+ - name: Cache Theos
+ id: cache-theos
+ uses: actions/cache@v6
+ with:
+ path: theos
+ key: 26.5-SDK-${{ env.THEOS_COMMIT }}
+
+ - name: Setup Theos
+ if: ${{ steps.cache-theos.outputs.cache-hit != 'true' }}
+ run: |
+ git clone --quiet --depth=1 --recurse-submodules https://github.com/roothide/theos.git
+ git clone --quiet --depth=1 -n --filter=tree:0 https://github.com/Tonwalter888/iOS-SDKs.git
+ cd iOS-SDKs
+ git sparse-checkout set --no-cone iPhoneOS26.5.sdk
+ git checkout --quiet
+ mv *.sdk "$THEOS/sdks"
+ cd ${{ github.workspace }}/theos/vendor/logos
+ git checkout a623700
+
+ - name: Clone headers
+ run: |
+ if [ ! -d "$THEOS/include/YouTubeHeader" ]; then
+ git clone --quiet --depth=1 https://github.com/PoomSmart/YouTubeHeader.git "$THEOS/include/YouTubeHeader"
+ else
+ cd $THEOS/include/YouTubeHeader
+ git pull --quiet --force
+ cd ${{ github.workspace }}
+ fi
+
+ if [ "${{ inputs.demc }}" = "true" ]; then
+ rm -fr "$THEOS/include/YTHeaders"
+ cp -r "$THEOS/include/YouTubeHeader" "$THEOS/include/YTHeaders"
+ fi
+
+ if [ ! -d "$THEOS/include/PSHeader" ]; then
+ git clone --quiet --depth=1 https://github.com/PoomSmart/PSHeader.git "$THEOS/include/PSHeader"
+ else
+ cd $THEOS/include/PSHeader
+ git pull --quiet --force
+ cd ${{ github.workspace }}
+ fi
+
+ - name: Fix Theos od broken pipe issue
+ run: sed -i '' 's/od -c "$i" | head/od -c "$i" 2>\/dev\/null | head/g' $THEOS/bin/convert_xml_plist.sh || true
+
+ - name: Install cyan
+ run: pipx install https://github.com/asdfzxcvbn/pyzule-rw/archive/main.zip
+
+ - name: Checkout YouMod
+ uses: actions/checkout@v7
+ with:
+ repository: ${{ inputs.repo }}
+ ref: ${{ inputs.branch }}
+ path: YouMod
+
+ - name: Clone Open in YouTube (Safari Extension)
+ run: |
+ git clone --quiet -n --depth=1 --filter=tree:0 https://github.com/BillyCurtis/OpenYouTubeSafariExtension.git
+ cd OpenYouTubeSafariExtension
+ git sparse-checkout set --no-cone OpenYouTubeSafariExtension.appex
+ git checkout --quiet
+ mv *.appex ${{ github.workspace }}
+
+ - name: Clone YouPiP
+ if: ${{ inputs.youpip }}
+ run: git clone --quiet --depth=1 https://github.com/PoomSmart/YouPiP.git
+
+ - name: Clone YTUHD
+ if: ${{ inputs.ytuhd }}
+ run: git clone --quiet --depth=1 --recurse-submodules https://github.com/PoomSmart/YTUHD.git
+
+ - name: Clone Return-YouTube-Dislikes
+ if: ${{ inputs.ryd }}
+ run: git clone --quiet --depth=1 https://github.com/PoomSmart/Return-YouTube-Dislikes.git
+
+ - name: Clone YouGroupSettings
+ run: git clone --quiet --depth=1 https://github.com/PoomSmart/YouGroupSettings.git
+
+ - name: Clone YTVideoOverlay
+ if: ${{ inputs.youpip || inputs.ytuhd || inputs.youquality }}
+ run: git clone --quiet --depth=1 https://github.com/PoomSmart/YTVideoOverlay.git
+
+ - name: Clone YTABConfig
+ if: ${{ inputs.abconfig }}
+ run: git clone --quiet --depth=1 https://github.com/PoomSmart/YTABConfig.git
+
+ - name: Clone UncappedAVPlayer
+ run: git clone --quiet --depth=1 https://github.com/PoomSmart/UncappedAVPlayer.git
+
+ - name: Clone DontEatMyContent
+ if: ${{ inputs.demc }}
+ run: git clone --quiet --depth=1 https://github.com/therealFoxster/DontEatMyContent.git
+
+ - name: Clone YouSlider
+ if: ${{ inputs.youslider }}
+ run: |
+ git clone --quiet --depth=1 https://github.com/PoomSmart/YouSlider.git
+ wget --no-verbose --quiet https://github.com/Tonwalter888/Tonwalter888.github.io/raw/refs/heads/main/debs/alderis.deb
+
+ - name: Clone YTweaks
+ if: ${{ inputs.ytweaks }}
+ run: git clone --quiet --depth=1 https://github.com/fosterbarnes/YTweaks.git
+
+ - name: Clone Gonerino
+ if: ${{ inputs.gonerino }}
+ run: git clone --quiet --depth=1 https://github.com/castdrian/Gonerino.git
+
+ - name: Clone youtube-native-share
+ if: ${{ inputs.ytshare }}
+ run: git clone --quiet --depth=1 https://github.com/jkhsjdhjs/youtube-native-share.git
+
+ - name: Clone VolumeBoostYT
+ if: ${{ inputs.volboost }}
+ run: git clone --quiet --depth=1 https://github.com/VasirakCalgux/VolumeBoostYT.git
+
+ - name: Clone YouQuality
+ if: ${{ inputs.youquality }}
+ run: git clone --quiet --depth=1 https://github.com/PoomSmart/YouQuality.git
+
+ - name: Restore FFmpegKit cache
+ id: cache-ffmpegkit
+ uses: actions/cache/restore@v6
+ with:
+ path: YouMod/modules/ffmpegkit
+ key: ffmpegkit-${{ runner.os }}-${{ hashFiles('YouMod/tools/fetch-ffmpegkit.sh') }}
+
+ - name: Build YouMod
+ run: |
+ cd YouMod
+ echo "YOUMOD_VERSION=$(grep '^Version:' control | cut -d ' ' -f2)" >> $GITHUB_ENV
+ make clean package DEBUG=0 FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless
+ mv packages/*.deb ${{ github.workspace }}/youmod.deb
+
+ - name: Save FFmpegKit cache
+ if: ${{ steps.cache-ffmpegkit.outputs.cache-hit != 'true' }}
+ uses: actions/cache/save@v6
+ with:
+ path: YouMod/modules/ffmpegkit
+ key: ${{ steps.cache-ffmpegkit.outputs.cache-primary-key }}
+
+ - name: Build YouPiP
+ if: ${{ inputs.youpip }}
+ run: |
+ cd YouPiP
+ make clean package DEBUG=0 FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless
+ mv packages/*.deb ${{ github.workspace }}/youpip.deb
+
+ - name: Build YTUHD
+ if: ${{ inputs.ytuhd }}
+ run: |
+ cd YTUHD
+ brew install meson ninja
+ make libvpx dav1d
+ make clean package DEBUG=0 FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless SIDELOAD=1
+ mv packages/*.deb ${{ github.workspace }}/ytuhd.deb
+
+ - name: Build Return-YouTube-Dislikes
+ if: ${{ inputs.ryd }}
+ run: |
+ cd Return-YouTube-Dislikes
+ make clean package DEBUG=0 FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless
+ mv packages/*.deb ${{ github.workspace }}/ryd.deb
+
+ - name: Build YouGroupSettings
+ run: |
+ cd YouGroupSettings
+ make clean package DEBUG=0 FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless
+ mv packages/*.deb ${{ github.workspace }}/ygs.deb
+
+ - name: Build YTVideoOverlay
+ if: ${{ inputs.youpip || inputs.ytuhd || inputs.youquality }}
+ run: |
+ cd YTVideoOverlay
+ make clean package DEBUG=0 FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless
+ mv packages/*.deb ${{ github.workspace }}/ytvo.deb
+
+ - name: Build YTABConfig
+ if: ${{ inputs.abconfig }}
+ run: |
+ cd YTABConfig
+ make clean package DEBUG=0 FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless
+ mv packages/*.deb ${{ github.workspace }}/ytabconfig.deb
+
+ - name: Build UncappedAVPlayer
+ run: |
+ cd UncappedAVPlayer
+ make clean package DEBUG=0 FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless ARCHS=arm64
+ mv packages/*.deb ${{ github.workspace }}/uncapavplayer.deb
+
+ - name: Build DontEatMyContent
+ if: ${{ inputs.demc }}
+ run: |
+ cd DontEatMyContent
+ make clean package DEBUG=0 FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless
+ mv packages/*.deb ${{ github.workspace }}/demc.deb
+
+ - name: Build YouSlider
+ if: ${{ inputs.youslider }}
+ run: |
+ cd YouSlider
+ make clean package DEBUG=0 FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless
+ mv packages/*.deb ${{ github.workspace }}/youslider.deb
+
+ - name: Build YTweaks
+ if: ${{ inputs.ytweaks }}
+ run: |
+ cd YTweaks
+ make clean package DEBUG=0 FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless
+ mv packages/*.deb ${{ github.workspace }}/ytweaks.deb
+
+ - name: Build Gonerino
+ if: ${{ inputs.gonerino }}
+ run: |
+ cd Gonerino
+ make clean package DEBUG=0 FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless
+ mv packages/*.deb ${{ github.workspace }}/gonerino.deb
+
+ - name: Build youtube-native-share
+ if: ${{ inputs.ytshare }}
+ run: |
+ cd youtube-native-share
+ git clone --quiet --depth=1 https://github.com/protocolbuffers/protobuf.git
+ make clean package DEBUG=0 FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless ARCHS=arm64
+ mv packages/*.deb ${{ github.workspace }}/ytnativeshare.deb
+
+ - name: Build VolumeBoostYT
+ if: ${{ inputs.volboost }}
+ run: |
+ cd VolumeBoostYT
+ make clean package DEBUG=0 FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless ARCHS=arm64
+ mv packages/*.deb ${{ github.workspace }}/volboostyt.deb
+
+ - name: Build YouQuality
+ if: ${{ inputs.youquality }}
+ run: |
+ cd YouQuality
+ make clean package DEBUG=0 FINALPACKAGE=1 THEOS_PACKAGE_SCHEME=rootless
+ mv packages/*.deb ${{ github.workspace }}/youquality.deb
+
+ - name: Inject Tweaks Into IPA
+ run: |
+ tweaks="OpenYouTubeSafariExtension.appex"
+
+ for f in *.deb; do
+ tweaks="$tweaks $f"
+ done
+
+ cyan -i youtube.ipa -o YouMod_${{ env.YT_VERSION }}_v${{ env.YOUMOD_VERSION }}.ipa -uwef $tweaks -n "${{ inputs.display_name }}" -b ${{ inputs.bundle_id }}
+
+ - name: Create a Draft Release
+ uses: softprops/action-gh-release@v3
+ with:
+ tag_name: youmod-ipa${{ github.run_number }}
+ name: YouMod_${{ env.YT_VERSION }}_v${{ env.YOUMOD_VERSION }} (${{ github.run_number }})
+ files: YouMod_${{ env.YT_VERSION }}_v${{ env.YOUMOD_VERSION }}.ipa
+ draft: true
+
+ - name: Job Summary - Build Complete
+ run: |
+ echo -e '### ๐ ๏ธ Build IPA with tweaks Complete!' >> $GITHUB_STEP_SUMMARY
+
+ - name: Job Summary - Output the Draft Release Link
+ run: |
+ echo -e '### ๐ Draft Release\n\nDraft release has been created successfully! You can view your release here: https://github.com/${{ github.repository }}/releases' >> $GITHUB_STEP_SUMMARY
+
+ - name: Job Summary - Cleanup
+ run: |
+ echo -e '### ๐งน Cleanup\n\nYou can remove previous GitHub Actions run here: https://github.com/${{ github.repository }}/actions/workflows/delete-old-workflows-run.yml And if you want to delelte old draft releases you have then here: https://github.com/${{ github.repository }}/actions/workflows/delete-old-draft-releases.yml' >> $GITHUB_STEP_SUMMARY