diff --git a/Makefile b/Makefile index 03cdcce..38ae426 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ endif DEBUG=0 FINALPACKAGE=1 ARCHS = arm64 -PACKAGE_VERSION = 1.0 +PACKAGE_VERSION = 2.0 TARGET := iphone:clang:latest:11.0 include $(THEOS)/makefiles/common.mk @@ -13,6 +13,6 @@ include $(THEOS)/makefiles/common.mk TWEAK_NAME = YTLite $(TWEAK_NAME)_FRAMEWORKS = UIKit Foundation $(TWEAK_NAME)_CFLAGS = -fobjc-arc -DTWEAK_VERSION=$(PACKAGE_VERSION) -$(TWEAK_NAME)_FILES = YTLite.x Settings.x +$(TWEAK_NAME)_FILES = YTLite.x Settings.x Sideloading.x include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/Settings.x b/Settings.x index 45064cf..11d508c 100644 --- a/Settings.x +++ b/Settings.x @@ -6,6 +6,12 @@ static const NSInteger YTLiteSection = 789; +static void resetYTLiteSettings() { + NSString *prefsPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:@"YTLite.plist"]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + [fileManager removeItemAtPath:prefsPath error:nil]; +} + NSBundle *YTLiteBundle() { static NSBundle *bundle = nil; static dispatch_once_t onceToken; @@ -51,6 +57,19 @@ NSBundle *YTLiteBundle() { CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("com.dvntm.ytlite.prefschanged"), NULL, NULL, YES); } +%new +- (void)updateIntegerPrefsForKey:(NSString *)key intValue:(NSInteger)intValue { + NSString *prefsPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:@"YTLite.plist"]; + NSMutableDictionary *prefs = [NSMutableDictionary dictionaryWithContentsOfFile:prefsPath]; + + if (!prefs) prefs = [NSMutableDictionary dictionary]; + + [prefs setObject:@(intValue) forKey:key]; + [prefs writeToFile:prefsPath atomically:NO]; + + CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("com.dvntm.ytlite.prefschanged"), NULL, NULL, YES); +} + static YTSettingsSectionItem *createSwitchItem(NSString *title, NSString *titleDescription, NSString *key, BOOL *value, id selfObject) { Class YTSettingsSectionItemClass = %c(YTSettingsSectionItem); YTSettingsSectionItem *item = [YTSettingsSectionItemClass switchItemWithTitle:title @@ -72,6 +91,8 @@ static YTSettingsSectionItem *createSwitchItem(NSString *title, NSString *titleD YTSettingsViewController *settingsViewController = [self valueForKey:@"_settingsViewControllerDelegate"]; id selfObject = self; + YTSettingsSectionItem *space = [%c(YTSettingsSectionItem) itemWithTitle:nil accessibilityIdentifier:nil detailTextBlock:nil selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) { return YES; }]; + YTSettingsSectionItem *general = [YTSettingsSectionItemClass itemWithTitle:LOC(@"General") accessibilityIdentifier:nil detailTextBlock:^NSString *() { @@ -101,12 +122,108 @@ static YTSettingsSectionItem *createSwitchItem(NSString *title, NSString *titleD createSwitchItem(LOC(@"RemoveSearch"), LOC(@"RemoveSearchDesc"), @"removeSearchButton", &kNoSearchButton, selfObject) ]; + if (kAdvancedMode) { + YTSettingsSectionItem *addStickyNavbar = createSwitchItem(LOC(@"StickyNavbar"), LOC(@"StickyNavbarDesc"), @"stickyNavbar", &kStickyNavbar, selfObject); + rows = [rows arrayByAddingObject:addStickyNavbar]; + + YTSettingsSectionItem *addNoSubbar = createSwitchItem(LOC(@"NoSubbar"), LOC(@"NoSubbarDesc"), @"noSubbar", &kNoSubbar, selfObject); + rows = [rows arrayByAddingObject:addNoSubbar]; + + YTSettingsSectionItem *addNoYTLogo = createSwitchItem(LOC(@"NoYTLogo"), LOC(@"NoYTLogoDesc"), @"noYTLogo", &kNoYTLogo, selfObject); + rows = [rows arrayByAddingObject:addNoYTLogo]; + } + YTSettingsPickerViewController *picker = [[%c(YTSettingsPickerViewController) alloc] initWithNavTitle:LOC(@"Navbar") pickerSectionTitle:nil rows:rows selectedItemIndex:NSNotFound parentResponder:[self parentResponder]]; [settingsViewController pushViewController:picker]; return YES; }]; [sectionItems addObject:navbar]; + if (kAdvancedMode) { + YTSettingsSectionItem *overlay = [YTSettingsSectionItemClass itemWithTitle:LOC(@"Overlay") + accessibilityIdentifier:nil + detailTextBlock:^NSString *() { + return @"‣"; + } + selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) { + NSArray *rows = @[ + createSwitchItem(LOC(@"HideAutoplay"), LOC(@"HideAutoplayDesc"), @"hideAutoplay", &kHideAutoplay, selfObject), + createSwitchItem(LOC(@"HideSubs"), LOC(@"HideSubsDesc"), @"hideSubs", &kHideSubs, selfObject), + createSwitchItem(LOC(@"NoHUDMsgs"), LOC(@"NoHUDMsgsDesc"), @"noHUDMsgs", &kNoHUDMsgs, selfObject), + createSwitchItem(LOC(@"HidePrevNext"), LOC(@"HidePrevNextDesc"), @"hidePrevNext", &kHidePrevNext, selfObject), + createSwitchItem(LOC(@"ReplacePrevNext"), LOC(@"ReplacePrevNextDesc"), @"replacePrevNext", &kReplacePrevNext, selfObject), + createSwitchItem(LOC(@"NoDarkBg"), LOC(@"NoDarkBgDesc"), @"noDarkBg", &kNoDarkBg, selfObject), + createSwitchItem(LOC(@"NoEndScreenCards"), LOC(@"NoEndScreenCardsDesc"), @"noEndScreenCards", &kEndScreenCards, selfObject), + createSwitchItem(LOC(@"NoFullscreenActions"), LOC(@"NoFullscreenActionsDesc"), @"noFullscreenActions", &kNoFullscreenActions, selfObject), + createSwitchItem(LOC(@"NoRelatedVids"), LOC(@"NoRelatedVidsDesc"), @"noRelatedVids", &kNoRelatedVids, selfObject), + createSwitchItem(LOC(@"NoPromotionCards"), LOC(@"NoPromotionCardsDesc"), @"noPromotionCards", &kNoPromotionCards, selfObject), + createSwitchItem(LOC(@"NoWatermarks"), LOC(@"NoWatermarksDesc"), @"noWatermarks", &kNoWatermarks, selfObject) + ]; + + YTSettingsPickerViewController *picker = [[%c(YTSettingsPickerViewController) alloc] initWithNavTitle:LOC(@"Overlay") pickerSectionTitle:nil rows:rows selectedItemIndex:NSNotFound parentResponder:[self parentResponder]]; + [settingsViewController pushViewController:picker]; + return YES; + }]; + [sectionItems addObject:overlay]; + + YTSettingsSectionItem *player = [YTSettingsSectionItemClass itemWithTitle:LOC(@"Player") + accessibilityIdentifier:nil + detailTextBlock:^NSString *() { + return @"‣"; + } + selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) { + NSArray *rows = @[ + createSwitchItem(LOC(@"Miniplayer"), LOC(@"MiniplayerDesc"), @"miniplayer", &kMiniplayer, selfObject), + createSwitchItem(LOC(@"DisableAutoplay"), LOC(@"DisableAutoplayDesc"), @"disableAutoplay", &kDisableAutoplay, selfObject), + createSwitchItem(LOC(@"NoContentWarning"), LOC(@"NoContentWarningDesc"), @"noContentWarning", &kNoContentWarning, selfObject), + createSwitchItem(LOC(@"ClassicQuality"), LOC(@"ClassicQualityDesc"), @"classicQuality", &kClassicQuality, selfObject), + createSwitchItem(LOC(@"DontSnap2Chapter"), LOC(@"DontSnap2ChapterDesc"), @"dontSnapToChapter", &kDontSnapToChapter, selfObject), + createSwitchItem(LOC(@"RedProgressBar"), LOC(@"RedProgressBarDesc"), @"redProgressBar", &kRedProgressBar, selfObject), + createSwitchItem(LOC(@"NoHints"), LOC(@"NoHintsDesc"), @"noHints", &kNoHints, selfObject), + createSwitchItem(LOC(@"NoFreeZoom"), LOC(@"NoFreeZoomDesc"), @"noFreeZoom", &kNoFreeZoom, selfObject), + createSwitchItem(LOC(@"ExitFullscreen"), LOC(@"ExitFullscreenDesc"), @"exitFullscreen", &kExitFullscreen, selfObject), + createSwitchItem(LOC(@"NoDoubleTap2Seek"), LOC(@"NoDoubleTap2SeekDesc"), @"noDoubleTapToSeek", &kNoDoubleTapToSeek, selfObject) + ]; + + YTSettingsPickerViewController *picker = [[%c(YTSettingsPickerViewController) alloc] initWithNavTitle:LOC(@"Player") pickerSectionTitle:nil rows:rows selectedItemIndex:NSNotFound parentResponder:[self parentResponder]]; + [settingsViewController pushViewController:picker]; + return YES; + }]; + [sectionItems addObject:player]; + + YTSettingsSectionItem *shorts = [YTSettingsSectionItemClass itemWithTitle:LOC(@"Shorts") + accessibilityIdentifier:nil + detailTextBlock:^NSString *() { + return @"‣"; + } + selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) { + NSArray *rows = @[ + createSwitchItem(LOC(@"HideShorts"), LOC(@"HideShortsDesc"), @"hideShorts", &kHideShorts, selfObject), + createSwitchItem(LOC(@"ShortsProgress"), LOC(@"ShortsProgressDesc"), @"shortsProgress", &kShortsProgress, selfObject), + createSwitchItem(LOC(@"ResumeShorts"), LOC(@"ResumeShortsDesc"), @"resumeShorts", &kResumeShorts, selfObject), + createSwitchItem(LOC(@"HideShortsLogo"), LOC(@"HideShortsLogoDesc"), @"hideShortsLogo", &kHideShortsLogo, selfObject), + createSwitchItem(LOC(@"HideShortsSearch"), LOC(@"HideShortsSearchDesc"), @"hideShortsSearch", &kHideShortsSearch, selfObject), + createSwitchItem(LOC(@"HideShortsCamera"), LOC(@"HideShortsCameraDesc"), @"hideShortsCamera", &kHideShortsCamera, selfObject), + createSwitchItem(LOC(@"HideShortsMore"), LOC(@"HideShortsMoreDesc"), @"hideShortsMore", &kHideShortsMore, selfObject), + createSwitchItem(LOC(@"HideShortsSubscriptions"), LOC(@"HideShortsSubscriptionsDesc"), @"hideShortsSubscriptions", &kHideShortsSubscriptions, selfObject), + createSwitchItem(LOC(@"HideShortsLike"), LOC(@"HideShortsLikeDesc"), @"hideShortsLike", &kHideShortsLike, selfObject), + createSwitchItem(LOC(@"HideShortsDislike"), LOC(@"HideShortsDislikeDesc"), @"hideShortsDislike", &kHideShortsDislike, selfObject), + createSwitchItem(LOC(@"HideShortsComments"), LOC(@"HideShortsCommentsDesc"), @"hideShortsComments", &kHideShortsComments, selfObject), + createSwitchItem(LOC(@"HideShortsRemix"), LOC(@"HideShortsRemixDesc"), @"hideShortsRemix", &kHideShortsRemix, selfObject), + createSwitchItem(LOC(@"HideShortsShare"), LOC(@"HideShortsShareDesc"), @"hideShortsShare", &kHideShortsShare, selfObject), + createSwitchItem(LOC(@"HideShortsAvatars"), LOC(@"HideShortsAvatarsDesc"), @"hideShortsAvatars", &kHideShortsAvatars, selfObject), + createSwitchItem(LOC(@"HideShortsThanks"), LOC(@"HideShortsThanksDesc"), @"hideShortsThanks", &kHideShortsThanks, selfObject), + createSwitchItem(LOC(@"HideShortsChannelName"), LOC(@"HideShortsChannelNameDesc"), @"hideShortsChannelName", &kHideShortsChannelName, selfObject), + createSwitchItem(LOC(@"HideShortsDescription"), LOC(@"HideShortsDescriptionDesc"), @"hideShortsDescription", &kHideShortsDescription, selfObject), + createSwitchItem(LOC(@"HideShortsAudioTrack"), LOC(@"HideShortsAudioTrackDesc"), @"hideShortsAudioTrack", &kHideShortsAudioTrack, selfObject) + ]; + YTSettingsPickerViewController *picker = [[%c(YTSettingsPickerViewController) alloc] initWithNavTitle:LOC(@"Shorts") pickerSectionTitle:nil rows:rows selectedItemIndex:NSNotFound parentResponder:[self parentResponder]]; + [settingsViewController pushViewController:picker]; + return YES; + }]; + [sectionItems addObject:shorts]; + } + YTSettingsSectionItem *tabbar = [YTSettingsSectionItemClass itemWithTitle:LOC(@"Tabbar") accessibilityIdentifier:nil detailTextBlock:^NSString *() { @@ -115,6 +232,7 @@ static YTSettingsSectionItem *createSwitchItem(NSString *title, NSString *titleD selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) { NSArray *rows = @[ createSwitchItem(LOC(@"RemoveLabels"), LOC(@"RemoveLabelsDesc"), @"removeLabels", &kRemoveLabels, selfObject), + createSwitchItem(LOC(@"ReExplore"), LOC(@"ReExploreDesc"), @"reExplore", &kReExplore, selfObject), createSwitchItem(LOC(@"HideShortsTab"), LOC(@"HideShortsTabDesc"), @"removeShorts", &kRemoveShorts, selfObject), createSwitchItem(LOC(@"HideSubscriptionsTab"), LOC(@"HideSubscriptionsTabDesc"), @"removeSubscriptions", &kRemoveSubscriptions, selfObject), createSwitchItem(LOC(@"HideUploadButton"), LOC(@"HideUploadButtonDesc"), @"removeUploads", &kRemoveUploads, selfObject), @@ -127,21 +245,116 @@ static YTSettingsSectionItem *createSwitchItem(NSString *title, NSString *titleD }]; [sectionItems addObject:tabbar]; - YTSettingsSectionItem *ps = [%c(YTSettingsSectionItem) itemWithTitle:@"PoomSmart" titleDescription:@"YouTube-X, YTNoPremium, YouTubeHeaders" accessibilityIdentifier:nil detailTextBlock:nil selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) { + if (kAdvancedMode) { + [sectionItems addObject:space]; + + YTSettingsSectionItem *startup = [YTSettingsSectionItemClass itemWithTitle:LOC(@"Startup") + accessibilityIdentifier:nil + detailTextBlock:^NSString *() { + switch (kPivotIndex) { + case 1: + return LOC(@"ShortsTab"); + case 2: + return LOC(@"Subscriptions"); + case 3: + return LOC(@"Library"); + case 0: + default: + return LOC(@"Home"); + } + } + selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) { + NSArray *rows = @[ + [YTSettingsSectionItemClass checkmarkItemWithTitle:LOC(@"Home") titleDescription:nil selectBlock:^BOOL (YTSettingsCell *home, NSUInteger arg1) { + kPivotIndex = 0; + [settingsViewController reloadData]; + [self updateIntegerPrefsForKey:@"pivotIndex" intValue:kPivotIndex]; + return YES; + }], + [YTSettingsSectionItemClass checkmarkItemWithTitle:LOC(@"ShortsTab") titleDescription:nil selectBlock:^BOOL (YTSettingsCell *shorts, NSUInteger arg1) { + if (kRemoveShorts) { + YTAlertView *alertView = [%c(YTAlertView) infoDialog]; + alertView.title = LOC(@"Warning"); + alertView.subtitle = LOC(@"TabIsHidden"); + [alertView show]; + return NO; + } else { + kPivotIndex = 1; + [settingsViewController reloadData]; + [self updateIntegerPrefsForKey:@"pivotIndex" intValue:kPivotIndex]; + return YES; + } + }], + [YTSettingsSectionItemClass checkmarkItemWithTitle:LOC(@"Subscriptions") titleDescription:nil selectBlock:^BOOL (YTSettingsCell *subscriptions, NSUInteger arg1) { + if (kRemoveSubscriptions) { + YTAlertView *alertView = [%c(YTAlertView) infoDialog]; + alertView.title = LOC(@"Warning"); + alertView.subtitle = LOC(@"TabIsHidden"); + [alertView show]; + return NO; + } else { + kPivotIndex = 2; + [settingsViewController reloadData]; + [self updateIntegerPrefsForKey:@"pivotIndex" intValue:kPivotIndex]; + return YES; + } + }], + [YTSettingsSectionItemClass checkmarkItemWithTitle:LOC(@"Library") titleDescription:nil selectBlock:^BOOL (YTSettingsCell *library, NSUInteger arg1) { + if (kRemoveLibrary) { + YTAlertView *alertView = [%c(YTAlertView) infoDialog]; + alertView.title = LOC(@"Warning"); + alertView.subtitle = LOC(@"TabIsHidden"); + [alertView show]; + return NO; + } else { + kPivotIndex = 3; + [settingsViewController reloadData]; + [self updateIntegerPrefsForKey:@"pivotIndex" intValue:kPivotIndex]; + return YES; + } + }] + ]; + YTSettingsPickerViewController *picker = [[%c(YTSettingsPickerViewController) alloc] initWithNavTitle:LOC(@"Startup") pickerSectionTitle:nil rows:rows selectedItemIndex:kPivotIndex parentResponder:[self parentResponder]]; + [settingsViewController pushViewController:picker]; + return YES; + }]; + [sectionItems addObject:startup]; + } + + [sectionItems addObject:space]; + + YTSettingsSectionItem *ps = [%c(YTSettingsSectionItem) itemWithTitle:@"PoomSmart" titleDescription:@"YouTube-X, YTNoPremium, YTClassicVideoQuality, YTShortsProgress, YTReExplore, SkipContentWarning, YouTubeHeaders" accessibilityIdentifier:nil detailTextBlock:nil selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) { return [%c(YTUIUtils) openURL:[NSURL URLWithString:@"https://github.com/PoomSmart/"]]; }]; + YTSettingsSectionItem *miro = [%c(YTSettingsSectionItem) itemWithTitle:@"MiRO92" titleDescription:@"YTNoShorts" accessibilityIdentifier:nil detailTextBlock:nil selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) { + return [%c(YTUIUtils) openURL:[NSURL URLWithString:@"https://github.com/MiRO92/"]]; + }]; + YTSettingsSectionItem *dayanch96 = [%c(YTSettingsSectionItem) itemWithTitle:@"Dayanch96" titleDescription:LOC(@"Developer") accessibilityIdentifier:nil detailTextBlock:nil selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) { return [%c(YTUIUtils) openURL:[NSURL URLWithString:@"https://github.com/Dayanch96/"]]; }]; + YTSettingsSectionItem *reset = [%c(YTSettingsSectionItem) itemWithTitle:LOC(@"ResetSettings") titleDescription:nil accessibilityIdentifier:nil detailTextBlock:nil selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) { + YTAlertView *alertView = [%c(YTAlertView) confirmationDialogWithAction:^{ + resetYTLiteSettings(); + exit(0); + } + actionTitle:LOC(@"Yes") + cancelTitle:LOC(@"No")]; + alertView.title = LOC(@"Warning"); + alertView.subtitle = LOC(@"ResetMessage"); + [alertView show]; + return YES; + }]; + YTSettingsSectionItem *version = [YTSettingsSectionItemClass itemWithTitle:LOC(@"Version") accessibilityIdentifier:nil detailTextBlock:^NSString *() { return @(OS_STRINGIFY(TWEAK_VERSION)); } selectBlock:^BOOL (YTSettingsCell *cell, NSUInteger arg1) { - NSArray *rows = @[ps, dayanch96]; + NSArray *rows = @[ps, miro, dayanch96, space, createSwitchItem(LOC(@"Advanced"), nil, @"advancedMode", &kAdvancedMode, selfObject), reset]; YTSettingsPickerViewController *picker = [[%c(YTSettingsPickerViewController) alloc] initWithNavTitle:LOC(@"About") pickerSectionTitle:LOC(@"Credits") rows:rows selectedItemIndex:NSNotFound parentResponder:[self parentResponder]]; [settingsViewController pushViewController:picker]; @@ -158,4 +371,4 @@ static YTSettingsSectionItem *createSwitchItem(NSString *title, NSString *titleD return; } %orig; } -%end +%end \ No newline at end of file diff --git a/Sideloading.x b/Sideloading.x new file mode 100644 index 0000000..561457b --- /dev/null +++ b/Sideloading.x @@ -0,0 +1,138 @@ +#import +#import +#import + +#define YT_BUNDLE_ID @"com.google.ios.youtube" +#define YT_NAME @"YouTube" + +@interface SSOConfiguration : NSObject +@end + +%group gSideloading +// Keychain patching +static NSString *accessGroupID() { + NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys: + (__bridge NSString *)kSecClassGenericPassword, (__bridge NSString *)kSecClass, + @"bundleSeedID", kSecAttrAccount, + @"", kSecAttrService, + (id)kCFBooleanTrue, kSecReturnAttributes, + nil]; + CFDictionaryRef result = nil; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result); + if (status == errSecItemNotFound) + status = SecItemAdd((__bridge CFDictionaryRef)query, (CFTypeRef *)&result); + if (status != errSecSuccess) + return nil; + NSString *accessGroup = [(__bridge NSDictionary *)result objectForKey:(__bridge NSString *)kSecAttrAccessGroup]; + + return accessGroup; +} + +// IAmYouTube (https://github.com/PoomSmart/IAmYouTube/) +%hook YTVersionUtils ++ (NSString *)appName { return YT_NAME; } ++ (NSString *)appID { return YT_BUNDLE_ID; } +%end + +%hook GCKBUtils ++ (NSString *)appIdentifier { return YT_BUNDLE_ID; } +%end + +%hook GPCDeviceInfo ++ (NSString *)bundleId { return YT_BUNDLE_ID; } +%end + +%hook OGLBundle ++ (NSString *)shortAppName { return YT_NAME; } +%end + +%hook GVROverlayView ++ (NSString *)appName { return YT_NAME; } +%end + +%hook OGLPhenotypeFlagServiceImpl +- (NSString *)bundleId { return YT_BUNDLE_ID; } +%end + +%hook APMAEU ++ (BOOL)isFAS { return YES; } +%end + +%hook GULAppEnvironmentUtil ++ (BOOL)isFromAppStore { return YES; } +%end + +%hook SSOConfiguration +- (id)initWithClientID:(id)clientID supportedAccountServices:(id)supportedAccountServices { + self = %orig; + [self setValue:YT_NAME forKey:@"_shortAppName"]; + [self setValue:YT_BUNDLE_ID forKey:@"_applicationIdentifier"]; + return self; +} +%end + +%hook NSBundle +- (NSString *)bundleIdentifier { + NSArray *address = [NSThread callStackReturnAddresses]; + Dl_info info = {0}; + if (dladdr((void *)[address[2] longLongValue], &info) == 0) + return %orig; + NSString *path = [NSString stringWithUTF8String:info.dli_fname]; + if ([path hasPrefix:NSBundle.mainBundle.bundlePath]) + return YT_BUNDLE_ID; + return %orig; +} +- (id)objectForInfoDictionaryKey:(NSString *)key { + if ([key isEqualToString:@"CFBundleIdentifier"]) + return YT_BUNDLE_ID; + if ([key isEqualToString:@"CFBundleDisplayName"] || [key isEqualToString:@"CFBundleName"]) + return YT_NAME; + return %orig; +} +// Fix Google Sign in by @PoomSmart and @level3tjg (qnblackcat/uYouPlus#684) +- (NSDictionary *)infoDictionary { + NSMutableDictionary *info = %orig.mutableCopy; + NSString *altBundleIdentifier = info[@"ALTBundleIdentifier"]; + if (altBundleIdentifier) info[@"CFBundleIdentifier"] = altBundleIdentifier; + return info; +} +%end + +// Fix login for YouTube 18.13.2 and higher +%hook SSOKeychainHelper ++ (NSString *)accessGroup { + return accessGroupID(); +} ++ (NSString *)sharedAccessGroup { + return accessGroupID(); +} +%end + +// Fix login for YouTube 17.33.2 and higher +%hook SSOKeychainCore ++ (NSString *)accessGroup { + return accessGroupID(); +} + ++ (NSString *)sharedAccessGroup { + return accessGroupID(); +} +%end + +// Fix App Group Directory by moving it to documents directory +%hook NSFileManager +- (NSURL *)containerURLForSecurityApplicationGroupIdentifier:(NSString *)groupIdentifier { + if (groupIdentifier != nil) { + NSArray *paths = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]; + NSURL *documentsURL = [paths lastObject]; + return [documentsURL URLByAppendingPathComponent:@"AppGroup"]; + } + return %orig(groupIdentifier); +} +%end +%end + +%ctor { + NSString *embeddedMobileProvisionPath = [[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"]; + if ([[NSFileManager defaultManager] fileExistsAtPath:embeddedMobileProvisionPath]) %init(gSideloading); +} diff --git a/YTLite.h b/YTLite.h index 93fbb59..c17cb4c 100644 --- a/YTLite.h +++ b/YTLite.h @@ -1,10 +1,17 @@ #import #import #import +#import "../YouTubeHeader/YTIGuideResponse.h" +#import "../YouTubeHeader/YTIGuideResponseSupportedRenderers.h" #import "../YouTubeHeader/YTIPivotBarSupportedRenderers.h" #import "../YouTubeHeader/YTIPivotBarRenderer.h" +#import "../YouTubeHeader/YTIBrowseRequest.h" #import "../YouTubeHeader/YTISectionListRenderer.h" #import "../YouTubeHeader/YTQTMButton.h" +#import "../YouTubeHeader/YTVideoQualitySwitchOriginalController.h" +#import "../YouTubeHeader/YTPlayerViewController.h" +#import "../YouTubeHeader/YTPlayerOverlay.h" +#import "../YouTubeHeader/YTPlayerOverlayProvider.h" #import "../YouTubeHeader/YTSettingsViewController.h" #import "../YouTubeHeader/YTSettingsSectionItem.h" #import "../YouTubeHeader/YTSettingsSectionItemManager.h" @@ -23,16 +30,62 @@ BOOL kBackgroundPlayback; BOOL kNoCast; BOOL kNoNotifsButton; BOOL kNoSearchButton; +BOOL kStickyNavbar; +BOOL kNoSubbar; +BOOL kNoYTLogo; +BOOL kHideAutoplay; +BOOL kHideSubs; +BOOL kNoHUDMsgs; +BOOL kHidePrevNext; +BOOL kReplacePrevNext; +BOOL kNoDarkBg; +BOOL kEndScreenCards; +BOOL kNoFullscreenActions; +BOOL kNoRelatedVids; +BOOL kNoPromotionCards; +BOOL kNoWatermarks; +BOOL kMiniplayer; +BOOL kDisableAutoplay; +BOOL kNoContentWarning; +BOOL kClassicQuality; +BOOL kDontSnapToChapter; +BOOL kRedProgressBar; +BOOL kNoHints; +BOOL kNoFreeZoom; +BOOL kExitFullscreen; +BOOL kNoDoubleTapToSeek; +BOOL kHideShorts; +BOOL kShortsProgress; +BOOL kResumeShorts; +BOOL kHideShortsLogo; +BOOL kHideShortsSearch; +BOOL kHideShortsCamera; +BOOL kHideShortsMore; +BOOL kHideShortsSubscriptions; +BOOL kHideShortsLike; +BOOL kHideShortsDislike; +BOOL kHideShortsComments; +BOOL kHideShortsRemix; +BOOL kHideShortsShare; +BOOL kHideShortsAvatars; +BOOL kHideShortsThanks; +BOOL kHideShortsChannelName; +BOOL kHideShortsDescription; +BOOL kHideShortsAudioTrack; BOOL kRemoveLabels; +BOOL kReExplore; BOOL kRemoveShorts; BOOL kRemoveSubscriptions; BOOL kRemoveUploads; BOOL kRemoveLibrary; +BOOL kAdvancedMode; +int kPivotIndex; @interface YTSettingsSectionItemManager (Custom) @property (nonatomic, strong) NSMutableDictionary *prefs; @property (nonatomic, strong) NSString *prefsPath; - (void)updatePrefsForKey:(NSString *)key enabled:(BOOL)enabled; +- (void)updateIntegerPrefsForKey:(NSString *)key intValue:(NSInteger)intValue; @end @interface YTPivotBarView : UIView @@ -41,7 +94,53 @@ BOOL kRemoveLibrary; @interface YTPivotBarItemView : UIView @end +@interface YTPivotBarViewController : UIViewController +- (void)selectItemWithPivotIdentifier:(id)pivotIndentifier; +@end + @interface YTRightNavigationButtons : UIView @property (nonatomic, strong) YTQTMButton *notificationButton; @property (nonatomic, strong) YTQTMButton *searchButton; @end + +@interface YTNavigationBarTitleView : UIView +@end + +@interface YTSegmentableInlinePlayerBarView +@property (nonatomic, assign, readwrite) BOOL enableSnapToChapter; +@end + +@interface YTPlayabilityResolutionUserActionUIController : NSObject +- (void)confirmAlertDidPressConfirm; +@end + +@interface YTReelPlayerButton : UIButton +@end + +@interface ELMCellNode +@end + +@interface _ASCollectionViewCell : UICollectionViewCell +- (id)node; +@end + +@interface YTAsyncCollectionView : UICollectionView +- (void)removeShortsCellAtIndexPath:(NSIndexPath *)indexPath; +@end + +@interface YTReelWatchPlaybackOverlayView : UIView +@end + +@interface YTReelTransparentStackView : UIView +@end + +@interface YTReelWatchHeaderView : UIView +@end + +@interface YTAlertView : UIView +@property (nonatomic, copy, readwrite) NSString *title; +@property (nonatomic, copy, readwrite) NSString *subtitle; ++ (instancetype)infoDialog; ++ (instancetype)confirmationDialogWithAction:(void (^)(void))action actionTitle:(NSString *)actionTitle cancelTitle:(NSString *)cancelTitle; +- (void)show; +@end \ No newline at end of file diff --git a/YTLite.x b/YTLite.x index a4bb1b2..51fe467 100644 --- a/YTLite.x +++ b/YTLite.x @@ -120,6 +120,254 @@ BOOL isAd(YTIElementRenderer *self) { } %end +// Hide YouTube Logo +%hook YTNavigationBarTitleView +- (void)layoutSubviews { %orig; if (kNoYTLogo && self.subviews.count > 1 && [self.subviews[1].accessibilityIdentifier isEqualToString:@"id.yoodle.logo"]) self.subviews[1].hidden = YES; } +%end + +// Stick Navigation bar +%hook YTHeaderView +- (BOOL)stickyNavHeaderEnabled { return kStickyNavbar ? YES : NO; } +%end + +// Remove Subbar +%hook YTMySubsFilterHeaderView +- (void)setChipFilterView:(id)arg1 { if (!kNoSubbar) %orig; } +%end + +%hook YTHeaderContentComboView +- (void)enableSubheaderBarWithView:(id)arg1 { if (!kNoSubbar) %orig; } +%end + +%hook YTHeaderContentComboView +- (void)setFeedHeaderScrollMode:(int)arg1 { kNoSubbar ? %orig(0) : %orig; } +%end + +// Hide Autoplay Switch and Subs Button +%hook YTMainAppControlsOverlayView +- (void)setAutoplaySwitchButtonRenderer:(id)arg1 { if (!kHideAutoplay) %orig; } +- (void)setClosedCaptionsOrSubtitlesButtonAvailable:(BOOL)arg1 { kHideSubs ? %orig(NO) : %orig; } +%end + +// Remove HUD Messages +%hook YTHUDMessageView +- (id)initWithMessage:(id)arg1 dismissHandler:(id)arg2 { return kNoHUDMsgs ? nil : %orig; } +%end + + +%hook YTColdConfig +// Hide Next & Previous buttons +- (BOOL)removeNextPaddleForSingletonVideos { return kHidePrevNext ? YES : NO; } +- (BOOL)removePreviousPaddleForSingletonVideos { return kHidePrevNext ? YES : NO; } +// Replace Next & Previous with Fast Forward & Rewind buttons +- (BOOL)replaceNextPaddleWithFastForwardButtonForSingletonVods { return kReplacePrevNext ? YES : NO; } +- (BOOL)replacePreviousPaddleWithRewindButtonForSingletonVods { return kReplacePrevNext ? YES : NO; } +// Disable Free Zoom +- (BOOL)videoZoomFreeZoomEnabledGlobalConfig { return kNoFreeZoom ? NO : YES; } +// Use System Theme +- (BOOL)shouldUseAppThemeSetting { return YES; } +// Dismiss Panel By Swiping in Fullscreen Mode +- (BOOL)isLandscapeEngagementPanelSwipeRightToDismissEnabled { return YES; } +// Remove Video in Playlist By Swiping To The Right +- (BOOL)enableSwipeToRemoveInPlaylistWatchEp { return YES; } +%end + +// Remove Dark Background in Overlay +%hook YTMainAppVideoPlayerOverlayView +- (void)setBackgroundVisible:(BOOL)arg1 { kNoDarkBg ? %orig(NO) : %orig; } +%end + +// No Endscreen Cards +%hook YTCreatorEndscreenView +- (void)setHidden:(BOOL)arg1 { kEndScreenCards ? %orig(YES) : %orig; } +%end + +// Disable Fullscreen Actions +%hook YTFullscreenActionsView +- (BOOL)enabled { return kNoFullscreenActions ? NO : YES; } +- (void)setEnabled:(BOOL)arg1 { kNoFullscreenActions ? %orig(NO) : %orig; } +%end + +// Dont Show Related Videos on Finish +%hook YTFullscreenEngagementOverlayController +- (void)setRelatedVideosVisible:(BOOL)arg1 { kNoRelatedVids ? %orig(NO) : %orig; } +%end + +// Hide Paid Promotion Cards +%hook YTMainAppVideoPlayerOverlayViewController +- (void)setPaidContentWithPlayerData:(id)data { if (!kNoPromotionCards) %orig; } +- (void)playerOverlayProvider:(YTPlayerOverlayProvider *)provider didInsertPlayerOverlay:(YTPlayerOverlay *)overlay { + if ([[overlay overlayIdentifier] isEqualToString:@"player_overlay_paid_content"] && kNoPromotionCards) return; + %orig; +} +%end + +%hook YTInlineMutedPlaybackPlayerOverlayViewController +- (void)setPaidContentWithPlayerData:(id)data { if (!kNoPromotionCards) %orig; } +%end + +// Remove Watermarks +%hook YTAnnotationsViewController +- (void)loadFeaturedChannelWatermark { if (!kNoWatermarks) %orig; } +%end + +// Forcibly Enable Miniplayer +%hook YTWatchMiniBarViewController +- (void)updateMiniBarPlayerStateFromRenderer { if (!kMiniplayer) %orig; } +%end + +// Disable Autoplay +%hook YTPlaybackConfig +- (void)setStartPlayback:(BOOL)arg1 { kDisableAutoplay ? %orig(NO) : %orig; } +%end + +// Skip Content Warning (https://github.com/qnblackcat/uYouPlus/blob/main/uYouPlus.xm#L452-L454) +%hook YTPlayabilityResolutionUserActionUIController +- (void)showConfirmAlert { if (kNoContentWarning) [self confirmAlertDidPressConfirm]; } +%end + +// Classic Video Quality (https://github.com/PoomSmart/YTClassicVideoQuality) +%hook YTVideoQualitySwitchControllerFactory +- (id)videoQualitySwitchControllerWithParentResponder:(id)responder { + Class originalClass = %c(YTVideoQualitySwitchOriginalController); + if (kClassicQuality) { + return originalClass ? [[originalClass alloc] initWithParentResponder:responder] : %orig; + } return %orig; +} +%end + +// Disable Snap To Chapter (https://github.com/qnblackcat/uYouPlus/blob/main/uYouPlus.xm#L457-464) +%hook YTSegmentableInlinePlayerBarView +- (void)didMoveToWindow { %orig; if (kDontSnapToChapter) self.enableSnapToChapter = NO; } +%end + +// Red Progress Bar and Gray Buffer Progress +%hook YTInlinePlayerBarContainerView +- (id)quietProgressBarColor { return kRedProgressBar ? [UIColor redColor] : %orig; } +%end + +%hook YTSegmentableInlinePlayerBarView +- (void)setBufferedProgressBarColor:(id)arg1 { if (kNoRelatedVids) %orig([UIColor colorWithRed:0.65 green:0.65 blue:0.65 alpha:0.60]); } +%end + +// Disable Hints +%hook YTSettings +- (BOOL)areHintsDisabled { return kNoHints ? YES : NO; } +- (void)setHintsDisabled:(BOOL)arg1 { kNoHints ? %orig(YES) : %orig; } +%end + +%hook YTUserDefaults +- (BOOL)areHintsDisabled { return kNoHints ? YES : NO; } +- (void)setHintsDisabled:(BOOL)arg1 { kNoHints ? %orig(YES) : %orig; } +%end + +// Exit Fullscreen on Finish +%hook YTWatchFlowController +- (BOOL)shouldExitFullScreenOnFinish { return kExitFullscreen ? YES : NO; } +%end + +// Disable Double Tap To Seek +%hook YTDoubleTapToSeekController +- (void)enableDoubleTapToSeek:(BOOL)arg1 { kNoDoubleTapToSeek ? %orig(NO) : %orig; } +%end + +// Remove Shorts (https://github.com/MiRO92/YTNoShorts) +%hook YTAsyncCollectionView +- (id)cellForItemAtIndexPath:(NSIndexPath *)indexPath { + if (kHideShorts) { + UICollectionViewCell *cell = %orig; + if ([cell isKindOfClass:NSClassFromString(@"_ASCollectionViewCell")]) { + _ASCollectionViewCell *cell = %orig; + if ([cell respondsToSelector:@selector(node)]) { + if ([[[cell node] accessibilityIdentifier] isEqualToString:@"eml.shorts-shelf"]) { + [self removeShortsCellAtIndexPath:indexPath]; + } + } + } else if ([cell isKindOfClass:NSClassFromString(@"YTReelShelfCell")]) { + [self removeShortsCellAtIndexPath:indexPath]; + } return %orig; + } return %orig; +} + +%new +- (void)removeShortsCellAtIndexPath:(NSIndexPath *)indexPath { + [self deleteItemsAtIndexPaths:[NSArray arrayWithObject:indexPath]]; +} +%end + +// Shorts Progress Bar (https://github.com/PoomSmart/YTShortsProgress) +%hook YTReelPlayerViewController +- (BOOL)shouldEnablePlayerBar { return kShortsProgress ? YES : NO; } +- (BOOL)shouldAlwaysEnablePlayerBar { return kShortsProgress ? YES : NO; } +- (BOOL)shouldEnablePlayerBarOnlyOnPause { return kShortsProgress ? NO : YES; } +%end + +%hook YTReelPlayerViewControllerSub +- (BOOL)shouldEnablePlayerBar { return kShortsProgress ? YES : NO; } +- (BOOL)shouldAlwaysEnablePlayerBar { return kShortsProgress ? YES : NO; } +- (BOOL)shouldEnablePlayerBarOnlyOnPause { return kShortsProgress ? NO : YES; } +%end + +%hook YTColdConfig +- (BOOL)iosEnableVideoPlayerScrubber { return kShortsProgress ? YES : NO; } +- (BOOL)mobileShortsTabInlined { return kShortsProgress ? YES : NO; } +%end + +%hook YTHotConfig +- (BOOL)enablePlayerBarForVerticalVideoWhenControlsHiddenInFullscreen { return kShortsProgress ? YES : NO; } +%end + +// Dont Startup Shorts +%hook YTShortsStartupCoordinator +- (id)evaluateResumeToShorts { return kResumeShorts ? nil : %orig; } +%end + +// Hide Shorts Elements +%hook YTReelPausedStateCarouselView +- (void)setPausedStateCarouselVisible:(BOOL)arg1 animated:(BOOL)arg2 { kHideShortsSubscriptions ? %orig(arg1 = NO, arg2) : %orig; } +%end + +%hook YTReelWatchPlaybackOverlayView +- (void)setReelLikeButton:(id)arg1 { if (!kHideShortsLike) %orig; } +- (void)setReelDislikeButton:(id)arg1 { if (!kHideShortsDislike) %orig; } +- (void)setViewCommentButton:(id)arg1 { if (!kHideShortsComments) %orig; } +- (void)setRemixButton:(id)arg1 { if (!kHideShortsRemix) %orig; } +- (void)setShareButton:(id)arg1 { if (!kHideShortsShare) %orig; } +- (void)layoutSubviews { + %orig; + + for (UIView *subview in self.subviews) { + if (kHideShortsAvatars && [NSStringFromClass([subview class]) isEqualToString:@"YTELMView"]) { + subview.hidden = YES; + break; + } + } +} +%end + +%hook YTReelHeaderView +- (void)setTitleLabelVisible:(BOOL)arg1 animated:(BOOL)arg2 { kHideShortsLogo ? %orig(arg1 = NO, arg2) : %orig; } +%end + +%hook YTReelTransparentStackView +- (void)layoutSubviews { + %orig; + if (kHideShortsSearch && self.subviews.count >= 3 && [self.subviews[0].accessibilityIdentifier isEqualToString:@"id.ui.generic.button"]) self.subviews[0].hidden = YES; + if (kHideShortsCamera && self.subviews.count >= 3 && [self.subviews[1].accessibilityIdentifier isEqualToString:@"id.ui.generic.button"]) self.subviews[1].hidden = YES; + if (kHideShortsMore && self.subviews.count >= 3 && [self.subviews[2].accessibilityIdentifier isEqualToString:@"id.ui.generic.button"]) self.subviews[2].hidden = YES; +} +%end + +%hook YTReelWatchHeaderView +- (void)layoutSubviews { + %orig; + if (kHideShortsDescription && [self.subviews[2].accessibilityIdentifier isEqualToString:@"id.reels_smv_player_title_label"]) self.subviews[2].hidden = YES; + if (kHideShortsThanks && [self.subviews[self.subviews.count - 3].accessibilityIdentifier isEqualToString:@"id.elements.components.suggested_action"]) self.subviews[self.subviews.count - 3].hidden = YES; + if (kHideShortsChannelName) self.subviews[self.subviews.count - 2].hidden = YES; + if (kHideShortsAudioTrack) self.subviews.lastObject.hidden = YES; +} +%end + // Remove Tabs %hook YTPivotBarView - (void)setRenderer:(YTIPivotBarRenderer *)renderer { @@ -149,6 +397,39 @@ BOOL isAd(YTIElementRenderer *self) { } %end +// Replace Shorts with Explore tab (https://github.com/PoomSmart/YTReExplore) +static void replaceTab(YTIGuideResponse *response) { + NSMutableArray *renderers = [response itemsArray]; + for (YTIGuideResponseSupportedRenderers *guideRenderers in renderers) { + YTIPivotBarRenderer *pivotBarRenderer = [guideRenderers pivotBarRenderer]; + NSMutableArray *items = [pivotBarRenderer itemsArray]; + NSUInteger shortIndex = [items indexOfObjectPassingTest:^BOOL(YTIPivotBarSupportedRenderers *renderers, NSUInteger idx, BOOL *stop) { + return [[[renderers pivotBarItemRenderer] pivotIdentifier] isEqualToString:@"FEshorts"]; + }]; + if (shortIndex != NSNotFound) { + [items removeObjectAtIndex:shortIndex]; + NSUInteger exploreIndex = [items indexOfObjectPassingTest:^BOOL(YTIPivotBarSupportedRenderers *renderers, NSUInteger idx, BOOL *stop) { + return [[[renderers pivotBarItemRenderer] pivotIdentifier] isEqualToString:[%c(YTIBrowseRequest) browseIDForExploreTab]]; + }]; + if (exploreIndex == NSNotFound) { + YTIPivotBarSupportedRenderers *exploreTab = [%c(YTIPivotBarRenderer) pivotSupportedRenderersWithBrowseId:[%c(YTIBrowseRequest) browseIDForExploreTab] title:LOC(@"Explore") iconType:292]; + [items insertObject:exploreTab atIndex:1]; + } + } + } +} + +%hook YTGuideServiceCoordinator +- (void)handleResponse:(YTIGuideResponse *)response withCompletion:(id)completion { + if (kReExplore) replaceTab(response); + %orig(response, completion); +} +- (void)handleResponse:(YTIGuideResponse *)response error:(id)error completion:(id)completion { + if (kReExplore) replaceTab(response); + %orig(response, error, completion); +} +%end + // Hide Tab Labels BOOL hasHomeBar = NO; CGFloat pivotBarViewHeight; @@ -168,14 +449,14 @@ CGFloat pivotBarViewHeight; if (kRemoveLabels) { for (UIView *subview in self.subviews) { - if ([subview isKindOfClass:NSClassFromString(@"YTPivotBarItemViewAccessibilityControl")]) { + if ([subview isKindOfClass:objc_lookUpClass("YTPivotBarItemViewAccessibilityControl")]) { pivotBarAccessibilityControlWidth = CGRectGetWidth(subview.frame); break; } } for (UIView *subview in self.subviews) { - if ([subview isKindOfClass:NSClassFromString(@"YTQTMButton")]) { + if ([subview isKindOfClass:objc_lookUpClass("YTQTMButton")]) { for (UIView *buttonSubview in subview.subviews) { if ([buttonSubview isKindOfClass:[UILabel class]]) { [buttonSubview removeFromSuperview]; @@ -224,6 +505,36 @@ CGFloat pivotBarViewHeight; } %end +// Startup Tab +BOOL isTabSelected = NO; +%hook YTPivotBarViewController +- (void)viewDidAppear:(BOOL)animated { + %orig(); + + if (!isTabSelected) { + NSString *pivotIdentifier; + switch (kPivotIndex) { + case 0: + pivotIdentifier = @"FEwhat_to_watch"; + break; + case 1: + pivotIdentifier = @"FEshorts"; + break; + case 2: + pivotIdentifier = @"FEsubscriptions"; + break; + case 3: + pivotIdentifier = @"FElibrary"; + break; + default: + return; + } + [self selectItemWithPivotIdentifier:pivotIdentifier]; + isTabSelected = YES; + } +} +%end + static void reloadPrefs() { NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject stringByAppendingPathComponent:@"YTLite.plist"]; NSDictionary *prefs = [NSDictionary dictionaryWithContentsOfFile:path]; @@ -233,11 +544,56 @@ static void reloadPrefs() { kNoCast = [prefs[@"noCast"] boolValue] ?: NO; kNoNotifsButton = [prefs[@"removeNotifsButton"] boolValue] ?: NO; kNoSearchButton = [prefs[@"removeSearchButton"] boolValue] ?: NO; + kStickyNavbar = [prefs[@"stickyNavbar"] boolValue] ?: NO; + kNoSubbar = [prefs[@"noSubbar"] boolValue] ?: NO; + kNoYTLogo = [prefs[@"noYTLogo"] boolValue] ?: NO; + kHideAutoplay = [prefs[@"hideAutoplay"] boolValue] ?: NO; + kHideSubs = [prefs[@"hideSubs"] boolValue] ?: NO; + kNoHUDMsgs = [prefs[@"noHUDMsgs"] boolValue] ?: NO; + kHidePrevNext = [prefs[@"hidePrevNext"] boolValue] ?: NO; + kReplacePrevNext = [prefs[@"replacePrevNext"] boolValue] ?: NO; + kNoDarkBg = [prefs[@"noDarkBg"] boolValue] ?: NO; + kEndScreenCards = [prefs[@"endScreenCards"] boolValue] ?: NO; + kNoFullscreenActions = [prefs[@"noFullscreenActions"] boolValue] ?: NO; + kNoRelatedVids = [prefs[@"noRelatedVids"] boolValue] ?: NO; + kNoPromotionCards = [prefs[@"noPromotionCards"] boolValue] ?: NO; + kNoWatermarks = [prefs[@"noWatermarks"] boolValue] ?: NO; + kMiniplayer = [prefs[@"miniplayer"] boolValue] ?: NO; + kDisableAutoplay = [prefs[@"disableAutoplay"] boolValue] ?: NO; + kNoContentWarning = [prefs[@"noContentWarning"] boolValue] ?: NO; + kClassicQuality = [prefs[@"classicQuality"] boolValue] ?: NO; + kDontSnapToChapter = [prefs[@"dontSnapToChapter"] boolValue] ?: NO; + kRedProgressBar = [prefs[@"redProgressBar"] boolValue] ?: NO; + kNoHints = [prefs[@"noHints"] boolValue] ?: NO; + kNoFreeZoom = [prefs[@"noFreeZoom"] boolValue] ?: NO; + kExitFullscreen = [prefs[@"exitFullscreen"] boolValue] ?: NO; + kNoDoubleTapToSeek = [prefs[@"noDoubleTapToSeek"] boolValue] ?: NO; + kHideShorts = [prefs[@"hideShorts"] boolValue] ?: NO; + kShortsProgress = [prefs[@"shortsProgress"] boolValue] ?: NO; + kResumeShorts = [prefs[@"resumeShorts"] boolValue] ?: NO; + kHideShortsLogo = [prefs[@"hideShortsLogo"] boolValue] ?: NO; + kHideShortsSearch = [prefs[@"hideShortsSearch"] boolValue] ?: NO; + kHideShortsCamera = [prefs[@"hideShortsCamera"] boolValue] ?: NO; + kHideShortsMore = [prefs[@"hideShortsMore"] boolValue] ?: NO; + kHideShortsSubscriptions = [prefs[@"hideShortsSubscriptions"] boolValue] ?: NO; + kHideShortsLike = [prefs[@"hideShortsLike"] boolValue] ?: NO; + kHideShortsDislike = [prefs[@"hideShortsDislike"] boolValue] ?: NO; + kHideShortsComments = [prefs[@"hideShortsComments"] boolValue] ?: NO; + kHideShortsRemix = [prefs[@"hideShortsRemix"] boolValue] ?: NO; + kHideShortsShare = [prefs[@"hideShortsShare"] boolValue] ?: NO; + kHideShortsAvatars = [prefs[@"hideShortsAvatars"] boolValue] ?: NO; + kHideShortsThanks = [prefs[@"hideShortsThanks"] boolValue] ?: NO; + kHideShortsChannelName = [prefs[@"hideShortsChannelName"] boolValue] ?: NO; + kHideShortsDescription = [prefs[@"hideShortsDescription"] boolValue] ?: NO; + kHideShortsAudioTrack = [prefs[@"hideShortsAudioTrack"] boolValue] ?: NO; kRemoveLabels = [prefs[@"removeLabels"] boolValue] ?: NO; + kReExplore = [prefs[@"reExplore"] boolValue] ?: NO; kRemoveShorts = [prefs[@"removeShorts"] boolValue] ?: NO; kRemoveSubscriptions = [prefs[@"removeSubscriptions"] boolValue] ?: NO; kRemoveUploads = (prefs[@"removeUploads"] != nil) ? [prefs[@"removeUploads"] boolValue] : YES; kRemoveLibrary = [prefs[@"removeLibrary"] boolValue] ?: NO; + kPivotIndex = (prefs[@"pivotIndex"] != nil) ? [prefs[@"pivotIndex"] intValue] : 0; + kAdvancedMode = [prefs[@"advancedMode"] boolValue] ?: NO; NSDictionary *newSettings = @{ @"noAds" : @(kNoAds), @@ -245,11 +601,56 @@ static void reloadPrefs() { @"noCast" : @(kNoCast), @"removeNotifsButton" : @(kNoNotifsButton), @"removeSearchButton" : @(kNoSearchButton), + @"stickyNavbar" : @(kStickyNavbar), + @"noSubbar" : @(kNoSubbar), + @"noYTLogo" : @(kNoYTLogo), + @"hideAutoplay" : @(kHideAutoplay), + @"hideSubs" : @(kHideSubs), + @"noHUDMsgs" : @(kNoHUDMsgs), + @"hidePrevNext" : @(kHidePrevNext), + @"replacePrevNext" : @(kReplacePrevNext), + @"noDarkBg" : @(kNoDarkBg), + @"endScreenCards" : @(kEndScreenCards), + @"noFullscreenActions" : @(kNoFullscreenActions), + @"noRelatedVids" : @(kNoRelatedVids), + @"noPromotionCards" : @(kNoPromotionCards), + @"noWatermarks" : @(kNoWatermarks), + @"miniplayer" : @(kMiniplayer), + @"disableAutoplay" : @(kDisableAutoplay), + @"noContentWarning" : @(kNoContentWarning), + @"classicQuality" : @(kClassicQuality), + @"dontSnapToChapter" : @(kDontSnapToChapter), + @"redProgressBar" : @(kRedProgressBar), + @"noHints" : @(kNoHints), + @"noFreeZoom" : @(kNoFreeZoom), + @"exitFullscreen" : @(kExitFullscreen), + @"noDoubleTapToSeek" : @(kNoDoubleTapToSeek), + @"hideShorts" : @(kHideShorts), + @"shortsProgress" : @(kShortsProgress), + @"resumeShorts" : @(kResumeShorts), + @"hideShortsLogo" : @(kHideShortsLogo), + @"hideShortsSearch" : @(kHideShortsSearch), + @"hideShortsCamera" : @(kHideShortsCamera), + @"hideShortsMore" : @(kHideShortsMore), + @"hideShortsSubscriptions" : @(kHideShortsSubscriptions), + @"hideShortsLike" : @(kHideShortsLike), + @"hideShortsDislike" : @(kHideShortsDislike), + @"hideShortsComments" : @(kHideShortsComments), + @"hideShortsRemix" : @(kHideShortsRemix), + @"hideShortsShare" : @(kHideShortsShare), + @"hideShortsAvatars" : @(kHideShortsAvatars), + @"hideShortsThanks" : @(kHideShortsThanks), + @"hideShortsChannelName" : @(kHideShortsChannelName), + @"hideShortsDescription" : @(kHideShortsDescription), + @"hideShortsAudioTrack" : @(kHideShortsAudioTrack), @"removeLabels" : @(kRemoveLabels), + @"reExplore" : @(kReExplore), @"removeShorts" : @(kRemoveShorts), @"removeSubscriptions" : @(kRemoveSubscriptions), @"removeUploads" : @(kRemoveUploads), - @"removeLibrary" : @(kRemoveLibrary) + @"removeLibrary" : @(kRemoveLibrary), + @"pivotIndex" : @(kPivotIndex), + @"advancedMode" : @(kAdvancedMode) }; if (![newSettings isEqualToDictionary:prefs]) [newSettings writeToFile:path atomically:NO]; @@ -262,5 +663,4 @@ static void prefsChanged(CFNotificationCenterRef center, void *observer, CFStrin %ctor { CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)prefsChanged, CFSTR("com.dvntm.ytlite.prefschanged"), NULL, CFNotificationSuspensionBehaviorCoalesce); reloadPrefs(); - %init; } diff --git a/layout/Library/Application Support/YTLite.bundle/en.lproj/Localizable.strings b/layout/Library/Application Support/YTLite.bundle/en.lproj/Localizable.strings index 56893ac..196df2f 100644 --- a/layout/Library/Application Support/YTLite.bundle/en.lproj/Localizable.strings +++ b/layout/Library/Application Support/YTLite.bundle/en.lproj/Localizable.strings @@ -11,10 +11,64 @@ "RemoveNotificationsDesc" = "Hides Notifications button from the Navigation bar."; "RemoveSearch" = "Hide Search button"; "RemoveSearchDesc" = "Hides Search button from the Navigation bar."; +"StickyNavbar" = "Sticky Navigation bar"; +"StickyNavbarDesc" = "Pins the Navigation bar so that it remains visible when scrolling down."; +"NoSubbar" = "Hide Subbar"; +"NoSubbarDesc" = "Hides Subbar (All, New to you, Live etc.) under the Navigation bar."; +"NoYTLogo" = "Remove YouTube logo"; +"NoYTLogoDesc" = "Removes YouTube logo in the Navigation bar."; + +"Overlay" = "Overlay"; +"HideAutoplay" = "Hide Autoplay switch"; +"HideAutoplayDesc" = "Hides Autoplay switch from the overlay."; +"HideSubs" = "Hide Subtitles button"; +"HideSubsDesc" = "Hides Subtitles button from the overlay."; +"NoHUDMsgs" = "Hide HUD Messages"; +"NoHUDMsgsDesc" = "Hides all feature messages from the player. Example: CC is turned on/off, Video loop is on, etc."; +"HidePrevNext" = "Hide Previous and Next buttons"; +"HidePrevNextDesc" = "Hides Previous and Next video buttons from overlay."; +"ReplacePrevNext" = "Fast forward and Rewind buttons"; +"ReplacePrevNextDesc" = "Replaces Previous and Next video buttons to Fast forward and Rewind buttons in overlay."; +"NoDarkBg" = "Remove dark background"; +"NoDarkBgDesc" = "Removes overlay dark background."; +"NoEndScreenCards" = "Hide End screens hover cards"; +"NoEndScreenCardsDesc" = "Hides End screens (thumbnails) at the end of videos."; +"NoFullscreenActions" = "Disable fullscreen actions"; +"NoFullscreenActionsDesc" = "Disables actions panel in fullscreen mode."; +"NoRelatedVids" = "No related videos in overlay"; +"NoRelatedVidsDesc" = "Removes related videos displayed in the overlay by swiping up."; +"NoPromotionCards" = "Hide Paid Promotion cards"; +"NoPromotionCardsDesc" = "Hides \"Includes Paid Promotions\" card in promotions included videos."; +"NoWatermarks" = "Hide Watermarks"; +"NoWatermarksDesc" = "Hides channel watermarks from the player."; + +"Player" = "Player"; +"Miniplayer" = "Enable mini player"; +"MiniplayerDesc" = "Enables the mini player for videos that were not originally designed for it, such as videos targeted for children."; +"DisableAutoplay" = "Disable Autoplay videos"; +"DisableAutoplayDesc" = "Prevents video playback after opening."; +"NoContentWarning" = "Skip content warning"; +"NoContentWarningDesc" = "Skips sensitive content warning message."; +"ClassicQuality" = "Classic video quality"; +"ClassicQualityDesc" = "Brings back classic video quality selection menu."; +"DontSnap2Chapter" = "Disable snap to chapter"; +"DontSnap2ChapterDesc" = "Disables skipping to the next episode by double-tap gesture."; +"RedProgressBar" = "Red progress bar"; +"RedProgressBarDesc" = "Brings back red progress bar."; +"NoHints" = "Disable hints"; +"NoHintsDesc" = "Disables hints by author which appears at the top-right corner during playback."; +"NoFreeZoom" = "Disable free zoom gesture"; +"NoFreeZoomDesc" = "Disables new free zoom gestures."; +"ExitFullscreen" = "Exit fullscreen mode on finish"; +"ExitFullscreenDesc" = "Exits fullscreen mode at the end of video playback."; +"NoDoubleTap2Seek" = "Disable double tap to seek"; +"NoDoubleTap2SeekDesc" = "Disables double tap to seek gesture."; "Tabbar" = "Tab bar"; "RemoveLabels" = "Remove labels"; "RemoveLabelsDesc" = "Removes tab labels."; +"ReExplore" = "Replace Shorts tab with Explore tab"; +"ReExploreDesc" = "Shows Explore tab instead of Shorts tab as on old YouTube versions."; "HideShortsTab" = "Hide Shorts tab"; "HideShortsTabDesc" = "Hides Shorts tab from the Tab bar"; "HideSubscriptionsTab" = "Hide Subscriptions tab"; @@ -24,7 +78,59 @@ "HideLibraryTab" = "Hide Library tab"; "HideLibraryTabDesc" = "Hides Library tab from the Tab bar"; +"Shorts" = "Shorts"; +"HideShorts" = "Hide Shorts videos"; +"HideShortsDesc" = "Hides Shorts videos from Homepage, Recommended etc. (Not applied to Watch history)"; +"ShortsProgress" = "Enable progress bar"; +"ShortsProgressDesc" = "Displays progress bar in the Shorts overlay."; +"ResumeShorts" = "Don't start from Shorts tab"; +"ResumeShortsDesc" = "Prevents starting from Shorts videos at the opening app, which happens if YouTube was closed while watching Shorts."; +"HideShortsLogo" = "Hide Shorts logo"; +"HideShortsLogoDesc" = "Hides Shorts logo in the top left corner."; +"HideShortsSearch" = "Hide Search button"; +"HideShortsSearchDesc" = "Hides Search button from the Shorts overlay."; +"HideShortsCamera" = "Hide Camera button"; +"HideShortsCameraDesc" = "Hides Camera button from the Shorts overlay."; +"HideShortsMore" = "Hide More (⋮) button"; +"HideShortsMoreDesc" = "Hides More (⋮) button from the Shorts overlay. It's also accessible by long-pressing the screen."; +"HideShortsSubscriptions" = "Hide Subscriptions button"; +"HideShortsSubscriptionsDesc" = "Hides Subscriptions button which appears when Shorts paused."; +"HideShortsLike" = "Hide Like button"; +"HideShortsLikeDesc" = "Hides Like button from the Shorts overlay."; +"HideShortsDislike" = "Hide Dislike button"; +"HideShortsDislikeDesc" = "Hides Dislike button from the Shorts overlay."; +"HideShortsComments" = "Hide Comments button"; +"HideShortsCommentsDesc" = "Hides Comments button from the Shorts overlay."; +"HideShortsRemix" = "Hide Remix button"; +"HideShortsRemixDesc" = "Hides Remix button from the Shorts overlay."; +"HideShortsShare" = "Hide Share button"; +"HideShortsShareDesc" = "Hides Share button from the Shorts overlay."; +"HideShortsAvatars" = "Hide channels avatar"; +"HideShortsAvatarsDesc" = "Hides profile picture in the bottom right corner."; +"HideShortsThanks" = "Hide Superthanks button"; +"HideShortsThanksDesc" = "Hides Superthanks (Donate) button from the Shorts overlay."; +"HideShortsChannelName" = "Hide Channel name"; +"HideShortsChannelNameDesc" = "Hides Channel name and Subscribe button from the Shorts overlay."; +"HideShortsDescription" = "Hide Description"; +"HideShortsDescriptionDesc" = "Hides Shorts description under channel name."; +"HideShortsAudioTrack" = "Hide AudioTrack"; +"HideShortsAudioTrackDesc" = "Hides AudioTrack under Shorts description."; + +"Startup" = "Startup page"; +"Home" = "Home"; +"Explore" = "Explore"; +"ShortsTab" = "Shorts"; +"Subscriptions" = "Subscriptions"; +"Library" = "Library"; +"Warning" = "Warning"; +"TabIsHidden" = "Hidden tab cannot be selected as startup page"; + "Version" = "Version"; "About" = "About"; "Credits" = "Credits"; -"Developer" = "YTLite developer"; \ No newline at end of file +"Developer" = "YTLite developer"; +"Advanced" = "Advanced mode"; +"ResetSettings" = "Reset YTLite settings"; +"ResetMessage" = "This option will reset YTLite settings to default and close YouTube.\n\nAre you sure you want to continue?"; +"Yes" = "Yes"; +"No" = "No"; \ No newline at end of file diff --git a/layout/Library/Application Support/YTLite.bundle/ru.lproj/Localizable.strings b/layout/Library/Application Support/YTLite.bundle/ru.lproj/Localizable.strings index c05defb..aa4b8f4 100644 --- a/layout/Library/Application Support/YTLite.bundle/ru.lproj/Localizable.strings +++ b/layout/Library/Application Support/YTLite.bundle/ru.lproj/Localizable.strings @@ -11,10 +11,64 @@ "RemoveNotificationsDesc" = "Скрывает кнопку уведомлений с панели навигации."; "RemoveSearch" = "Скрыть «Поиск»"; "RemoveSearchDesc" = "Скрвыает кнопку поиска с панели навигации."; +"StickyNavbar" = "Закрепить панель навигации"; +"StickyNavbarDesc" = "Закрепляет панель навигации в верхней части экрана, запрещая ему скрываться во время скролла страницы вниз."; +"NoSubbar" = "Скрыть наклейки"; +"NoSubbarDesc" = "Скрывает панель с наклейками (Все, Новое для вас, Сейчас в эфире и т.д.) под панелью навигации."; +"NoYTLogo" = "Скрыть логотип YouTube"; +"NoYTLogoDesc" = "Убирает логотип YouTube с панели навигации."; + +"Overlay" = "Настройки оверлея"; +"HideAutoplay" = "Скрыть «Автовоспроизведение»"; +"HideAutoplayDesc" = "Скрывает тумблер «Автовоспроизведение» с оверлея плеера."; +"HideSubs" = "Скрыть «Субтитры»"; +"HideSubsDesc" = "Скрывает кнопку субтитров с оверлея плеера."; +"NoHUDMsgs" = "Скрыть сообщения плеера"; +"NoHUDMsgsDesc" = "Скрывает надписи YouTube, появляющиеся поверх видео."; +"HidePrevNext" = "Скрыть «След.» и «Пред.»"; +"HidePrevNextDesc" = "Убирает переключатели «Следующий» и «Предыдущий» с плеера"; +"ReplacePrevNext" = "Перемотка вместо «След.» и «Пред.»"; +"ReplacePrevNextDesc" = "Заменяет переключатели «Следующий» и «Предыдущий» на перемотку на 10 сек. в окне плеера."; +"NoDarkBg" = "Не затемнять фон плеера"; +"NoDarkBgDesc" = "Убирает затемнение экрана под кнопками управления плеером."; +"NoEndScreenCards" = "Скрыть рекомендации"; +"NoEndScreenCardsDesc" = "Скрывает эскизы, отображаемые по окончанию видеоролика."; +"NoFullscreenActions" = "Отключить панель действий"; +"NoFullscreenActionsDesc" = "Отключает панель действий, отображающуюся под прогресс-баром плеера."; +"NoRelatedVids" = "Скрыть рекомендации в оверлее"; +"NoRelatedVidsDesc" = "Скрывает рекомендации, отображаемые по свайпу вверх в плеере."; +"NoPromotionCards" = "Скрыть сообщение «Есть реклама»"; +"NoPromotionCardsDesc" = "Скрывает всплывающее сообщение «Есть реклама» в роликах со спонсорской рекламой."; +"NoWatermarks" = "Скрыть водяные знаки"; +"NoWatermarksDesc" = "Скрывает значки каналов в плеере."; + +"Player" = "Настройки плеера"; +"Miniplayer" = "Разрешить миниплеер"; +"MiniplayerDesc" = "Принудительно активирует миниплеер для видео, в которых изначально не был предназначен (например, видеоролики для детей)."; +"DisableAutoplay" = "Запретить автовоспроизведение"; +"DisableAutoplayDesc" = "Принудительно запрещает автовоспроизведение видео при его открытии."; +"NoContentWarning" = "Пропускать предупреждения"; +"NoContentWarningDesc" = "Пропускает предупреждения, всплывающие перед воспроизведением некоторого контента."; +"ClassicQuality" = "Классический выбор качества"; +"ClassicQualityDesc" = "Возвращает классическое меню выбора качества в меню плеера."; +"DontSnap2Chapter" = "Не перематывать эпизоды"; +"DontSnap2ChapterDesc" = "Отключает жест перемотки к следующему эпизоду двойным нажатием."; +"RedProgressBar" = "Красный прогресс-бар"; +"RedProgressBarDesc" = "Возвращает красный прогресс-бар вместо нового, серого цвета."; +"NoHints" = "Отключить подсказки"; +"NoHintsDesc" = "Скрывает подсказки от авторов видео, появляющиеся в правом верхнем углу."; +"NoFreeZoom" = "Отключить жесты для зума"; +"NoFreeZoomDesc" = "Отключает жесты приближения для нового зума."; +"ExitFullscreen" = "Автовыход из полноэкранного режима"; +"ExitFullscreenDesc" = "Выходит из полноэкранного режима по окончанию воспроизведения."; +"NoDoubleTap2Seek" = "Отключить перемотку двойным тапом"; +"NoDoubleTap2SeekDesc" = "Отключает перемотку двойным тапом в плеере."; "Tabbar" = "Панель вкладок"; "RemoveLabels" = "Скрыть названия"; "RemoveLabelsDesc" = "Скрывает названия вкладок."; +"ReExplore" = "Вкладка «Навигация» вместо «Shorts»"; +"ReExploreDesc" = "Заменяет вкладку «Shorts» на привычную нам «Навигацию»."; "HideShortsTab" = "Скрыть «Shorts»"; "HideShortsTabDesc" = "Скрывает вкладку «Shorts» с панели вкладок."; "HideSubscriptionsTab" = "Скрыть «Подписки»"; @@ -24,7 +78,59 @@ "HideLibraryTab" = "Скрыть «Библиотеку»"; "HideLibraryTabDesc" = "Скрывает вкладку «Библиотека» с панели вкладок."; +"Shorts" = "Настройки Shorts"; +"HideShorts" = "Скрыть видеоролики Shorts"; +"HideShortsDesc" = "Скрывает видеоролики, помеченные как Shorts с Главного экрана, Рекомендаций и т.д. (Не применяется к истории просмотров)"; +"ShortsProgress" = "Показывать прогресс-бар"; +"ShortsProgressDesc" = "Отображает прогресс-бар в плеере Shorts."; +"ResumeShorts" = "Всегда запускать с Главной страницы"; +"ResumeShortsDesc" = "Предотвращает запуск видеороликов Shorts при открытии YouTube. Это происходит, если закрыть YouTube при просмотре Shorts."; +"HideShortsLogo" = "Скрыть логотип Shorts"; +"HideShortsLogoDesc" = "Скрывает логотип Shorts, расположенный в верхнем левом углу."; +"HideShortsSearch" = "Скрыть кнопку «Поиск»"; +"HideShortsSearchDesc" = "Скрывает кнопку поиска с плеера Shorts."; +"HideShortsCamera" = "Скрыть кнопку «Камера»"; +"HideShortsCameraDesc" = "Скрывает кнопку камеры с плеера Shorts."; +"HideShortsMore" = "Скрыть кнопку «⋮»"; +"HideShortsMoreDesc" = "Скрывает кнопку «Еще» (⋮) с плеера Shorts. Данное меню также доступно долгим нажатием по экрану."; +"HideShortsSubscriptions" = "Скрыть «Подписки»"; +"HideShortsSubscriptionsDesc" = "Скрывает кнопку «Подписки», появляющуюся при остановке воспроизведения."; +"HideShortsLike" = "Скрыть кнопку «Лайк»"; +"HideShortsLikeDesc" = "Скрывает кнопку лайка с плеера Shorts."; +"HideShortsDislike" = "Скрыть кнопку «Дизлайк»"; +"HideShortsDislikeDesc" = "Скрывает кнопку дизлайка с плеера Shorts."; +"HideShortsComments" = "Скрыть кнопку «Комментарии»"; +"HideShortsCommentsDesc" = "Скрывает кнопку комментариев с плеера Shorts."; +"HideShortsRemix" = "Скрыть кнопку «Ремикс»"; +"HideShortsRemixDesc" = "Скрывает кнопку для создания ремикса с плеера Shorts."; +"HideShortsShare" = "Скрыть кнопку «Поделиться»"; +"HideShortsShareDesc" = "Скрывает кнопку поделиться с плеера Shorts."; +"HideShortsAvatars" = "Скрыть аватарку"; +"HideShortsAvatarsDesc" = "Скрывает аватарку пользователя в правом нижнем углу."; +"HideShortsThanks" = "Скрыть «Суперспасибо»"; +"HideShortsThanksDesc" = "Скрывает кнопку отправки доната (суперспасибо) с плеера Shorts."; +"HideShortsChannelName" = "Скрыть название канала"; +"HideShortsChannelNameDesc" = "Скрывает название канала и кнопку «Подписаться» с плеера Shorts."; +"HideShortsDescription" = "Скрыть описание ролика"; +"HideShortsDescriptionDesc" = "Скрывает описание ролика, отображающееся под названием канала."; +"HideShortsAudioTrack" = "Скрыть аудиодорожку"; +"HideShortsAudioTrackDesc" = "Скрывает информацию об аудиодорожке в нижней части плеера."; + +"Startup" = "Начальная страница"; +"Home" = "Главная"; +"Explore" = "Навигация"; +"ShortsTab" = "Shorts"; +"Subscriptions" = "Подписки"; +"Library" = "Библиотека"; +"Warning" = "Внимание"; +"TabIsHidden" = "Скрытая вкладка не может быть выбрана в качестве начальной страницы"; + "Version" = "Версия"; "About" = "О твике"; "Credits" = "Авторы"; "Developer" = "Разработчик твика"; +"Advanced" = "Расширенный режим"; +"ResetSettings" = "Сбросить настройки твика"; +"ResetMessage" = "Данное действие сбросит настройки YTLite к значениям по умолчанию и закроет YouTube.\n\nУверены, что хотите продолжить?"; +"Yes" = "Да"; +"No" = "Нет"; diff --git a/layout/Library/Application Support/YTLite.bundle/zh-Hans.lproj/Localizable.strings b/layout/Library/Application Support/YTLite.bundle/zh-Hans.lproj/Localizable.strings new file mode 100644 index 0000000..1458566 --- /dev/null +++ b/layout/Library/Application Support/YTLite.bundle/zh-Hans.lproj/Localizable.strings @@ -0,0 +1,136 @@ +"General" = "常规"; +"RemoveAds" = "移除广告"; +"RemoveAdsDesc" = "删除程序内的广告"; +"BackgroundPlayback" = "后台播放"; +"BackgroundPlaybackDesc" = "启用后台播放"; + +"Navbar" = "导航栏"; +"RemoveCast" = "隐藏投射按钮"; +"RemoveCastDesc" = "从导航栏中隐藏投射按钮"; +"RemoveNotifications" = "隐藏通知按钮"; +"RemoveNotificationsDesc" = "从导航栏中隐藏通知按钮"; +"RemoveSearch" = "隐藏搜索按钮"; +"RemoveSearchDesc" = "从导航栏中隐藏搜索按钮"; +"StickyNavbar" = "Sticky Navigation bar"; +"StickyNavbarDesc" = "Pins the Navigation bar so that it remains visible when scrolling down."; +"NoSubbar" = "Hide Subbar"; +"NoSubbarDesc" = "Hides Subbar (All, New to you, Live etc.) under the Navigation bar."; +"NoYTLogo" = "Remove YouTube logo"; +"NoYTLogoDesc" = "Removes YouTube logo in the Navigation bar."; + +"Overlay" = "Overlay"; +"HideAutoplay" = "Hide Autoplay switch"; +"HideAutoplayDesc" = "Hides Autoplay switch from the overlay."; +"HideSubs" = "Hide Subtitles button"; +"HideSubsDesc" = "Hides Subtitles button from the overlay."; +"NoHUDMsgs" = "Hide HUD Messages"; +"NoHUDMsgsDesc" = "Hides all feature messages from the player. Example: CC is turned on/off, Video loop is on, etc."; +"HidePrevNext" = "Hide Previous and Next buttons"; +"HidePrevNextDesc" = "Hides Previous and Next video buttons from overlay."; +"ReplacePrevNext" = "Fast forward and Rewind buttons"; +"ReplacePrevNextDesc" = "Replaces Previous and Next video buttons to Fast forward and Rewind buttons in overlay."; +"NoDarkBg" = "Remove dark background"; +"NoDarkBgDesc" = "Removes overlay dark background."; +"NoEndScreenCards" = "Hide End screens hover cards"; +"NoEndScreenCardsDesc" = "Hides End screens (thumbnails) at the end of videos."; +"NoFullscreenActions" = "Disable fullscreen actions"; +"NoFullscreenActionsDesc" = "Disables actions panel in fullscreen mode."; +"NoRelatedVids" = "No related videos in overlay"; +"NoRelatedVidsDesc" = "Removes related videos displayed in the overlay by swiping up."; +"NoPromotionCards" = "Hide Paid Promotion cards"; +"NoPromotionCardsDesc" = "Hides \"Includes Paid Promotions\" card in promotions included videos."; +"NoWatermarks" = "Hide Watermarks"; +"NoWatermarksDesc" = "Hides channel watermarks from the player."; + +"Player" = "Player"; +"Miniplayer" = "Enable mini player"; +"MiniplayerDesc" = "Enables the mini player for videos that were not originally designed for it, such as videos targeted for children."; +"DisableAutoplay" = "Disable Autoplay videos"; +"DisableAutoplayDesc" = "Prevents video playback after opening."; +"NoContentWarning" = "Skip content warning"; +"NoContentWarningDesc" = "Skips sensitive content warning message."; +"ClassicQuality" = "Classic video quality"; +"ClassicQualityDesc" = "Brings back classic video quality selection menu."; +"DontSnap2Chapter" = "Disable snap to chapter"; +"DontSnap2ChapterDesc" = "Disables skipping to the next episode by double-tap gesture."; +"RedProgressBar" = "Red progress bar"; +"RedProgressBarDesc" = "Brings back red progress bar."; +"NoHints" = "Disable hints"; +"NoHintsDesc" = "Disables hints by author which appears at the top-right corner during playback."; +"NoFreeZoom" = "Disable free zoom gesture"; +"NoFreeZoomDesc" = "Disables new free zoom gestures."; +"ExitFullscreen" = "Exit fullscreen mode on finish"; +"ExitFullscreenDesc" = "Exits fullscreen mode at the end of video playback."; +"NoDoubleTap2Seek" = "Disable double tap to seek"; +"NoDoubleTap2SeekDesc" = "Disables double tap to seek gesture."; + +"Tabbar" = "选项卡栏"; +"RemoveLabels" = "移除标签"; +"RemoveLabelsDesc" = "删除选项卡标签"; +"ReExplore" = "Replace Shorts tab with Explore tab"; +"ReExploreDesc" = "Shows Explore tab instead of Shorts tab as on old YouTube versions."; +"HideShortsTab" = "隐藏短视频"; +"HideShortsTabDesc" = "从选项卡栏中隐藏短视频"; +"HideSubscriptionsTab" = "隐藏订阅内容"; +"HideSubscriptionsTabDesc" = "从选项卡栏中隐藏订阅内容"; +"HideUploadButton" = "隐藏上传按钮"; +"HideUploadButtonDesc" = "从选项卡栏中隐藏上传按钮"; +"HideLibraryTab" = "隐藏媒体库"; +"HideLibraryTabDesc" = "从选项卡栏中隐藏媒体库"; + +"Shorts" = "Shorts"; +"HideShorts" = "Hide Shorts videos"; +"HideShortsDesc" = "Hides Shorts videos from Homepage, Recommended etc. (Not applied to Watch history)"; +"ShortsProgress" = "Enable progress bar"; +"ShortsProgressDesc" = "Displays progress bar in the Shorts overlay."; +"ResumeShorts" = "Don't start from Shorts tab"; +"ResumeShortsDesc" = "Prevents starting from Shorts videos at the opening app, which happens if YouTube was closed while watching Shorts."; +"HideShortsLogo" = "Hide Shorts logo"; +"HideShortsLogoDesc" = "Hides Shorts logo in the top left corner."; +"HideShortsSearch" = "Hide Search button"; +"HideShortsSearchDesc" = "Hides Search button from the Shorts overlay."; +"HideShortsCamera" = "Hide Camera button"; +"HideShortsCameraDesc" = "Hides Camera button from the Shorts overlay."; +"HideShortsMore" = "Hide More (⋮) button"; +"HideShortsMoreDesc" = "Hides More (⋮) button from the Shorts overlay. It's also accessible by long-pressing the screen."; +"HideShortsSubscriptions" = "Hide Subscriptions button"; +"HideShortsSubscriptionsDesc" = "Hides Subscriptions button which appears when Shorts paused."; +"HideShortsLike" = "Hide Like button"; +"HideShortsLikeDesc" = "Hides Like button from the Shorts overlay."; +"HideShortsDislike" = "Hide Dislike button"; +"HideShortsDislikeDesc" = "Hides Dislike button from the Shorts overlay."; +"HideShortsComments" = "Hide Comments button"; +"HideShortsCommentsDesc" = "Hides Comments button from the Shorts overlay."; +"HideShortsRemix" = "Hide Remix button"; +"HideShortsRemixDesc" = "Hides Remix button from the Shorts overlay."; +"HideShortsShare" = "Hide Share button"; +"HideShortsShareDesc" = "Hides Share button from the Shorts overlay."; +"HideShortsAvatars" = "Hide channels avatar"; +"HideShortsAvatarsDesc" = "Hides profile picture in the bottom right corner."; +"HideShortsThanks" = "Hide Superthanks button"; +"HideShortsThanksDesc" = "Hides Superthanks (Donate) button from the Shorts overlay."; +"HideShortsChannelName" = "Hide Channel name"; +"HideShortsChannelNameDesc" = "Hides Channel name and Subscribe button from the Shorts overlay."; +"HideShortsDescription" = "Hide Description"; +"HideShortsDescriptionDesc" = "Hides Shorts description under channel name."; +"HideShortsAudioTrack" = "Hide AudioTrack"; +"HideShortsAudioTrackDesc" = "Hides AudioTrack under Shorts description."; + +"Startup" = "Startup page"; +"Home" = "Home"; +"Explore" = "Explore"; +"ShortsTab" = "Shorts"; +"Subscriptions" = "Subscriptions"; +"Library" = "Library"; +"Warning" = "Warning"; +"TabIsHidden" = "Hidden tab cannot be selected as startup page"; + +"Version" = "版本"; +"About" = "关于"; +"Credits" = "信息"; +"Developer" = "YTLite开发者"; +"Advanced" = "Advanced mode"; +"ResetSettings" = "Reset YTLite settings"; +"ResetMessage" = "This option will reset YTLite settings to default and close YouTube.\n\nAre you sure you want to continue?"; +"Yes" = "Yes"; +"No" = "No"; \ No newline at end of file diff --git a/packages/com.dvntm.ytlite_2.0_iphoneos-arm.deb b/packages/com.dvntm.ytlite_2.0_iphoneos-arm.deb new file mode 100644 index 0000000..66d440d Binary files /dev/null and b/packages/com.dvntm.ytlite_2.0_iphoneos-arm.deb differ diff --git a/packages/com.dvntm.ytlite_2.0_iphoneos-arm64.deb b/packages/com.dvntm.ytlite_2.0_iphoneos-arm64.deb new file mode 100644 index 0000000..4227945 Binary files /dev/null and b/packages/com.dvntm.ytlite_2.0_iphoneos-arm64.deb differ