diff --git a/OqeePlus/OqeePlus-iOS/.gitignore b/OqeePlus/OqeePlus-iOS/.gitignore new file mode 100644 index 0000000..faf8687 --- /dev/null +++ b/OqeePlus/OqeePlus-iOS/.gitignore @@ -0,0 +1,3 @@ +.theos/ +packages/ +.DS_Store diff --git a/OqeePlus/OqeePlus-iOS/Makefile b/OqeePlus/OqeePlus-iOS/Makefile new file mode 100644 index 0000000..53f82ce --- /dev/null +++ b/OqeePlus/OqeePlus-iOS/Makefile @@ -0,0 +1,12 @@ +TARGET = iphone:latest:14.0 +ARCHS = arm64 +INSTALL_TARGET_PROCESSES = Oqee + +include $(THEOS)/makefiles/common.mk + +TWEAK_NAME = OqeePlus + +OqeePlus_FILES = Tweak.x +OqeePlus_CFLAGS = -fobjc-arc + +include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/OqeePlus/OqeePlus-iOS/OqeePlus.plist b/OqeePlus/OqeePlus-iOS/OqeePlus.plist new file mode 100644 index 0000000..f9b5c70 --- /dev/null +++ b/OqeePlus/OqeePlus-iOS/OqeePlus.plist @@ -0,0 +1,10 @@ +{ + Filter = { + Bundles = ( + "net.oqee.appleos", + ); + Executables = ( + App, + ); + }; +} \ No newline at end of file diff --git a/OqeePlus/OqeePlus-iOS/Tweak.x b/OqeePlus/OqeePlus-iOS/Tweak.x new file mode 100644 index 0000000..82e7d60 --- /dev/null +++ b/OqeePlus/OqeePlus-iOS/Tweak.x @@ -0,0 +1,143 @@ +#import +#import +#import +#import +#include +#include +#include + +#define TAG @"[OQAdsLogger]" + +%hook IMAAdsRequest +- (instancetype)initWithAdsResponse:(NSString *)adsResponse + adDisplayContainer:(id)adDisplayContainer + avPlayerVideoDisplay:(id)avPlayerVideoDisplay + pictureInPictureProxy:(id)pipProxy + userContext:(id)userContext { + + NSLog(@"%@-[IMAAdsRequest init] [PiP path]", TAG); + NSLog(@"%@ adDisplayContainer = %@", TAG, adDisplayContainer); + NSLog(@"%@ avPlayerVideoDisplay = %@", TAG, avPlayerVideoDisplay); + NSLog(@"%@ pictureInPictureProxy = %@", TAG, pipProxy); + NSLog(@"%@ VMAP payload (%lu bytes):\n%@", + TAG, (unsigned long)adsResponse.length, adsResponse); + + id result = %orig; + NSLog(@"%@ -> IMAAdsRequest = %p", TAG, result); + return result; +} + +// - (instancetype)initWithAdsResponse:(NSString *)adsResponse +// adDisplayContainer:(id)adDisplayContainer +// contentPlayhead:(id)contentPlayhead +// userContext:(id)userContext { + +// NSLog(@"%@-[IMAAdsRequest init] [non-PiP path]", TAG); +// NSLog(@"%@ adDisplayContainer = %@", TAG, adDisplayContainer); +// NSLog(@"%@ contentPlayhead = %@", TAG, contentPlayhead); +// NSLog(@"%@ VMAP payload (%lu bytes):\n%@", +// TAG, (unsigned long)adsResponse.length, adsResponse); + +// id result = %orig; +// NSLog(@"%@ -> IMAAdsRequest = %p", TAG, result); +// return result; +// } + +// - (instancetype)initWithAdsResponse:(NSString *)adsResponse +// adDisplayContainer:(id)adDisplayContainer +// contentPlayhead:(id)contentPlayhead +// userContext:(id)userContext { +// NSString *tweakedVMAP = @"\n" +// @"\n" +// @" \n" +// @" \n" +// @" \n" +// @" \n" +// @" \n" +// @" \n" +// @" VizChoice\n" +// @" Oqee Cine Break Intro\n" +// @" \n" +// @" \n" +// @" \n" +// @" 00:00:03\n" +// @" \n" +// @" https://noh.am/rick.mp4\n" +// @" https://replay-01.bzn.oqee.net/oqee-static/barkers/oqee-cine/2025-10-21/adaptative/playlist_214c3e5132137e02.mpd\n" +// @" https://replay-01.bzn.oqee.net/oqee-static/barkers/oqee-cine/2025-10-21/adaptative/playlist_214c3e5132137e02.m3u8\n" +// @" \n" +// @" \n" +// @" \n" +// @" \n" +// @" \n" +// @" \n" +// @" \n" +// @" \n" +// @" \n" +// @" \n" +// @"\n"; +// NSLog(@"%@ Replaced VMAP (%lu bytes) with tweaked document", TAG, adsResponse.length); +// return %orig(tweakedVMAP, adDisplayContainer, contentPlayhead, userContext); +// } + +- (instancetype)initWithAdsResponse:(NSString *)adsResponse + adDisplayContainer:(id)adDisplayContainer + contentPlayhead:(id)contentPlayhead + userContext:(id)userContext { + // Replace the VMAP with an empty document + NSString *emptyVMAP = @"" + @""; + NSLog(@"%@ Replaced VMAP (%lu bytes) with empty document", TAG, adsResponse.length); + return %orig(emptyVMAP, adDisplayContainer, contentPlayhead, userContext); +} +%end + +// IMAAdsLoader — confirms dispatch to IMA SDK +// +// Called from OQPlayerAdsLoader.requestAds(_:loader:) (sub_10008FC08) +// after Swift dynamic-cast guards pass. This is the point of no return — +// the IMA SDK takes ownership of the request and starts network I/O. + +%hook IMAAdsLoader +- (void)requestAdsWithRequest:(id)request { + NSLog(@"%@ -[IMAAdsLoader requestAdsWithRequest:]", TAG); + NSLog(@"%@ loader = %@", TAG, self); + NSLog(@"%@ request = %@", TAG, [request debugDescription]); + %orig; + NSLog(@"%@ requestAdsWithRequest dispatched ✓", TAG); +} +%end + +// IMAAdsManager — SDK parsed the VMAP, breaks are scheduled +// +// Called from the IMAAdsLoaderDelegate callback in OQImaManager +// At this point the IMA SDK has parsed the VMAP and knows all ad break +// positions. Passing nil for renderingSettings means OQEE uses defaults. + +%hook IMAAdsManager +- (void)initializeWithAdsRenderingSettings:(id)renderingSettings { + NSLog(@"%@ -[IMAAdsManager initializeWithAdsRenderingSettings:]", TAG); + NSLog(@"%@ adsManager = %@", TAG, self); + NSLog(@"%@ renderingSettings = %@", TAG, renderingSettings ?: @"(nil — default)"); + %orig; + NSLog(@"%@ VMAP parsed, ad breaks scheduled ✓", TAG); +} +%end + + +%hook VSSubscriptionRegistrationCenter +- (void)setCurrentSubscription:(id)subscription +{ + NSLog(@"Blocked VSSubscriptionRegistrationCenter"); + NSLog(@"Subscription: %@", subscription); + return; +} +%end + +%ctor { + // activate dev mode + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults setBool:YES forKey:@"tv.oqee.devModeEnabled"]; +} \ No newline at end of file diff --git a/OqeePlus/OqeePlus-iOS/control b/OqeePlus/OqeePlus-iOS/control new file mode 100644 index 0000000..8dcccf0 --- /dev/null +++ b/OqeePlus/OqeePlus-iOS/control @@ -0,0 +1,9 @@ +Package: xyz.nohamr.oqeeplus +Name: Oqee+ (iOS) +Version: 1.0 +Architecture: iphoneos-arm64 +Description: Oqee+ Ads blocker hook for iOS +Maintainer: NohamR +Author: NohamR +Section: Tweaks +Depends: mobilesubstrate (>= 0.9.5000) diff --git a/OqeePlus/OqeePlus-iOS/index.md b/OqeePlus/OqeePlus-iOS/index.md new file mode 100644 index 0000000..835bdfe --- /dev/null +++ b/OqeePlus/OqeePlus-iOS/index.md @@ -0,0 +1,22 @@ +# OqeePlus iOS + +Block ads initialization on Oqee. + +- **App**: [OqeePlus : Streaming, TV en Direct](https://apps.apple.com/fr/app/free-tv/id1542614107) +- **Tested version**: 2.40 +- **Target**: iOS + +## Build + +```sh +make package FINALPACKAGE=1 +``` + +## Inject + +```sh +cyan -i oqeeplus.ipa \ + -o oqeeplus_patched.ipa \ + -f xyz.nohamr.oqeeplus_1.0_iphoneos-arm64.deb \ + -u +``` diff --git a/OqeePlus/OqeePlus-tvOS/.gitignore b/OqeePlus/OqeePlus-tvOS/.gitignore new file mode 100644 index 0000000..faf8687 --- /dev/null +++ b/OqeePlus/OqeePlus-tvOS/.gitignore @@ -0,0 +1,3 @@ +.theos/ +packages/ +.DS_Store diff --git a/OqeePlus/OqeePlus-tvOS/Makefile b/OqeePlus/OqeePlus-tvOS/Makefile new file mode 100644 index 0000000..37d0070 --- /dev/null +++ b/OqeePlus/OqeePlus-tvOS/Makefile @@ -0,0 +1,13 @@ +TARGET = appletv:latest:18.3 +ARCHS = arm64 +INSTALL_TARGET_PROCESSES = Oqee +THEOS_PACKAGE_SCHEME = rootless + +include $(THEOS)/makefiles/common.mk + +TWEAK_NAME = OqeePlus + +OqeePlus_FILES = Tweak.x +OqeePlus_CFLAGS = -fobjc-arc + +include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/OqeePlus/OqeePlus-tvOS/OqeePlus.plist b/OqeePlus/OqeePlus-tvOS/OqeePlus.plist new file mode 100644 index 0000000..f9b5c70 --- /dev/null +++ b/OqeePlus/OqeePlus-tvOS/OqeePlus.plist @@ -0,0 +1,10 @@ +{ + Filter = { + Bundles = ( + "net.oqee.appleos", + ); + Executables = ( + App, + ); + }; +} \ No newline at end of file diff --git a/OqeePlus/OqeePlus-tvOS/Tweak.x b/OqeePlus/OqeePlus-tvOS/Tweak.x new file mode 100644 index 0000000..b677ab0 --- /dev/null +++ b/OqeePlus/OqeePlus-tvOS/Tweak.x @@ -0,0 +1,88 @@ +#import +#import +#import +#import +#include +#include +#include + +#define TAG @"[OQAdsLogger]" + +%hook IMAAdsRequest +- (instancetype)initWithAdsResponse:(NSString *)adsResponse + adDisplayContainer:(id)adDisplayContainer + avPlayerVideoDisplay:(id)avPlayerVideoDisplay + pictureInPictureProxy:(id)pipProxy + userContext:(id)userContext { + + NSLog(@"%@-[IMAAdsRequest init] [PiP path]", TAG); + NSLog(@"%@ adDisplayContainer = %@", TAG, adDisplayContainer); + NSLog(@"%@ avPlayerVideoDisplay = %@", TAG, avPlayerVideoDisplay); + NSLog(@"%@ pictureInPictureProxy = %@", TAG, pipProxy); + NSLog(@"%@ VMAP payload (%lu bytes):\n%@", + TAG, (unsigned long)adsResponse.length, adsResponse); + + id result = %orig; + NSLog(@"%@ -> IMAAdsRequest = %p", TAG, result); + return result; +} + +- (instancetype)initWithAdsResponse:(NSString *)adsResponse + adDisplayContainer:(id)adDisplayContainer + contentPlayhead:(id)contentPlayhead + userContext:(id)userContext { + // Replace the VMAP with an empty document + NSString *emptyVMAP = @"" + @""; + NSLog(@"%@ Replaced VMAP (%lu bytes) with empty document", TAG, adsResponse.length); + return %orig(emptyVMAP, adDisplayContainer, contentPlayhead, userContext); +} +%end + +// IMAAdsLoader — confirms dispatch to IMA SDK +// +// Called from OQPlayerAdsLoader.requestAds(_:loader:) (sub_10008FC08) +// after Swift dynamic-cast guards pass. This is the point of no return — +// the IMA SDK takes ownership of the request and starts network I/O. + +%hook IMAAdsLoader +- (void)requestAdsWithRequest:(id)request { + NSLog(@"%@ -[IMAAdsLoader requestAdsWithRequest:]", TAG); + NSLog(@"%@ loader = %@", TAG, self); + NSLog(@"%@ request = %@", TAG, [request debugDescription]); + %orig; + NSLog(@"%@ requestAdsWithRequest dispatched ✓", TAG); +} +%end + +// IMAAdsManager — SDK parsed the VMAP, breaks are scheduled +// +// Called from the IMAAdsLoaderDelegate callback in OQImaManager +// At this point the IMA SDK has parsed the VMAP and knows all ad break +// positions. Passing nil for renderingSettings means OQEE uses defaults. + +%hook IMAAdsManager +- (void)initializeWithAdsRenderingSettings:(id)renderingSettings { + NSLog(@"%@ -[IMAAdsManager initializeWithAdsRenderingSettings:]", TAG); + NSLog(@"%@ adsManager = %@", TAG, self); + NSLog(@"%@ renderingSettings = %@", TAG, renderingSettings ?: @"(nil — default)"); + %orig; + NSLog(@"%@ VMAP parsed, ad breaks scheduled ✓", TAG); +} +%end + + +%hook VSSubscriptionRegistrationCenter +- (void)setCurrentSubscription:(id)subscription +{ + NSLog(@"Blocked VSSubscriptionRegistrationCenter"); + NSLog(@"Subscription: %@", subscription); + return; +} +%end + +%ctor { + // activate dev mode + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults setBool:YES forKey:@"tv.oqee.devModeEnabled"]; +} \ No newline at end of file diff --git a/OqeePlus/OqeePlus-tvOS/control b/OqeePlus/OqeePlus-tvOS/control new file mode 100644 index 0000000..1597ca7 --- /dev/null +++ b/OqeePlus/OqeePlus-tvOS/control @@ -0,0 +1,9 @@ +Package: xyz.nohamr.oqeeplus +Name: Oqee+ (tvOS) +Version: 1.0 +Architecture: appletvos-arm64 +Description: Oqee+ Ads blocker hook for tvOS +Maintainer: NohamR +Author: NohamR +Section: Tweaks +Depends: mobilesubstrate (>= 0.9.5000) diff --git a/OqeePlus/OqeePlus-tvOS/index.md b/OqeePlus/OqeePlus-tvOS/index.md new file mode 100644 index 0000000..cc67919 --- /dev/null +++ b/OqeePlus/OqeePlus-tvOS/index.md @@ -0,0 +1,22 @@ +# OqeePlus tvOS + +Block ads initialization on Oqee. + +- **App**: [OqeePlus : Streaming, TV en Direct](https://apps.apple.com/fr/app/free-tv/id1542614107) +- **Tested version**: 2.40 +- **Target**: tvOS + +## Build + +```sh +make package FINALPACKAGE=1 +``` + +## Inject + +```sh +cyan -i oqeeplus.ipa \ + -o oqeeplus_patched.ipa \ + -f xyz.nohamr.oqeeplus_1.0_appletvos-arm64.deb \ + -u +``` diff --git a/README.md b/README.md index a373703..ea5fb36 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ iOS tweaks built with [Theos](https://theos.dev), injected into IPAs via [cyan]( | [Infuse (iOS)](Infuse/Infuse-iOS/index.md) | Infuse 8.4.2 | iOS 18+ | | [TF1+ (tvOS)](TF1Plus/TF1Plus-tvOS/index.md) | TF1+ 11.36.0 | tvOS | | [TF1+ (iOS)](TF1Plus/TF1Plus-iOS/index.md) | TF1+ 11.36.0 | iOS 14+ | +| [OqeePlus (tvOS)](OqeePlus/OqeePlus-tvOS/index.md) | Oqee 2.40 | tvOS 18.3 | +| [OqeePlus (iOS)](OqeePlus/OqeePlus-iOS/index.md) | Oqee 2.40 | iOS 18+ | ## Build