From 720b888d825196f6570d45dd4b3ec6af69496c14 Mon Sep 17 00:00:00 2001 From: Mario Cheung Date: Wed, 26 Aug 2020 19:48:14 +0800 Subject: [PATCH] Fix for iOS8/9 and add support to iOS11+ --- Makefile | 3 +- Tweak.xm | 302 ++++++++++++++++++++++---- notifymusicprefs/Makefile | 2 +- notifymusicprefs/Resources/Root.plist | 38 +++- 4 files changed, 297 insertions(+), 48 deletions(-) diff --git a/Makefile b/Makefile index 936e506..5d850e3 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,12 @@ ARCHS = armv7 arm64 -VALID_ARCHS = armv7 armv7s arm64 +VALID_ARCHS = armv7 armv7s arm64 arm64e include $(THEOS)/makefiles/common.mk TWEAK_NAME = NotifyMusic NotifyMusic_FILES = Tweak.xm NotifyMusic_FRAMEWORKS = UIKit +NotifyMusic_PRIVATE_FRAMEWORKS = MediaRemote NotifyMusic_LIBRARIES = bulletin include $(THEOS_MAKE_PATH)/tweak.mk diff --git a/Tweak.xm b/Tweak.xm index 209ea92..ac5458d 100644 --- a/Tweak.xm +++ b/Tweak.xm @@ -1,4 +1,12 @@ +#import "notify.h" #import +#import + +@interface JBBulletinManager : NSObject ++(id)sharedInstance; +-(id)showBulletinWithTitle:(NSString *)title message:(NSString *)message bundleID:(NSString *)bundleID; +-(id)showBulletinWithTitle:(NSString *)title message:(NSString *)message bundleID:(NSString *)bundleID hasSound:(BOOL)hasSound soundID:(int)soundID vibrateMode:(int)vibrate soundPath:(NSString *)soundPath attachmentImage:(UIImage *)attachmentImage overrideBundleImage:(UIImage *)overrideBundleImage; +@end @interface SpringBoard -(id)_accessibilityFrontMostApplication; @@ -15,53 +23,259 @@ @end @interface MPUNowPlayingController - @property bool isPlaying; - @property (nonatomic,readonly) NSString * nowPlayingAppDisplayID; - @property (nonatomic,readonly) UIImage * currentNowPlayingArtwork; - @property (nonatomic,readonly) NSDictionary * currentNowPlayingInfo; +@property bool isPlaying; +@property (nonatomic,readonly) NSString * nowPlayingAppDisplayID; +@property (nonatomic,readonly) UIImage * currentNowPlayingArtwork; +@property (nonatomic,readonly) NSDictionary * currentNowPlayingInfo; +@property (nonatomic,readonly) double currentElapsed; +@property (nonatomic,readonly) double currentDuration; +-(void)_updateCurrentNowPlaying; +-(void)_updatePlaybackState; +-(void)setShouldUpdateNowPlayingArtwork:(BOOL)arg1 ; @end -@interface JBBulletinManager : NSObject - +(id)sharedInstance; - -(id)showBulletinWithTitle:(NSString *)title message:(NSString *)message bundleID:(NSString *)bundleID; - -(id)showBulletinWithTitle:(NSString *)title message:(NSString *)message bundleID:(NSString *)bundleID hasSound:(BOOL)hasSound soundID:(int)soundID vibrateMode:(int)vibrate soundPath:(NSString *)soundPath attachmentImage:(UIImage *)attachmentImage overrideBundleImage:(UIImage *)overrideBundleImage; +@interface SBMediaController +@property (retain) NSDictionary * currentNowPlayingInfo; +-(id/*SBApplication **/)nowPlayingApplication; +-(void)setNowPlayingInfo:(NSDictionary *)arg1 ; +-(BOOL)isPlaying; +@end + +@interface NotifyMusic : NSObject { + int token; + + BOOL notifyMusicPrefsLoaded; + BOOL enablewhilelocked; + BOOL showalbumname; + BOOL albumastitle; + BOOL enableinapp; + BOOL showagainwhenartavail; + + BOOL isInProgress; + SBMediaController *cachedMediaController; + MPUNowPlayingController *cachedNowPlayingController; + NSString *cachedMediaInfo; + double durationMod; + BOOL isArtworkUpdated; +} ++(NotifyMusic *)sharedInstance; +-(void)dealloc; +-(void)_updateNotifyMusicPrefs; +-(BOOL)isPlaying; +-(NSString *)nowPlayingAppDisplayID; +-(UIImage *)currentNowPlayingArtwork; +-(NSDictionary *)currentNowPlayingInfo; +-(double)currentDuration; +-(BOOL)_shouldShowNotifyMusic; +-(void)_showNotifyMusic; +@end + +@implementation NotifyMusic ++(NotifyMusic *)sharedInstance { + static NotifyMusic *instance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + instance = [[self alloc] init]; + }); + return instance; +} + +-(id)init { + if (self = [super init]) { + notify_register_dispatch("com.gilshahar7.notifymusicprefs", &token, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(int token) { + [self _updateNotifyMusicPrefs]; + }); + } + return self; +} + +-(void)dealloc { + notify_cancel(token); + [super dealloc]; +} + +-(void)_updateNotifyMusicPrefs { + NSString *settingsPath = @"/var/mobile/Library/Preferences/com.gilshahar7.notifymusicprefs.plist"; + NSMutableDictionary *prefs = [[NSMutableDictionary alloc] initWithContentsOfFile:settingsPath]; + enablewhilelocked = [[prefs objectForKey:@"enablewhilelocked"] boolValue]; + showalbumname = [[prefs objectForKey:@"showalbumname"] boolValue]; + albumastitle = [[prefs objectForKey:@"albumastitle"] boolValue]; + enableinapp = [[prefs objectForKey:@"enableinapp"] boolValue]; + showagainwhenartavail = [[prefs objectForKey:@"showagainwhenartavail"] boolValue]; +} + +-(void)_updateDependencyInjectionWithMC:(SBMediaController *)mediaController NPC:(MPUNowPlayingController *)nowPlayingController { + cachedMediaController = mediaController; + cachedNowPlayingController = nowPlayingController; +} + +-(BOOL)isPlaying { + if (cachedNowPlayingController) return [cachedNowPlayingController isPlaying]; + else if (cachedMediaController) return [cachedMediaController isPlaying]; + return NO; +} + +-(NSString *)nowPlayingAppDisplayID { + if (cachedNowPlayingController) return [cachedNowPlayingController nowPlayingAppDisplayID]; + else if (cachedMediaController) return [[cachedMediaController nowPlayingApplication] bundleIdentifier]; + return NULL; +} + +-(UIImage *)currentNowPlayingArtwork { + if (cachedNowPlayingController) { + [cachedNowPlayingController setShouldUpdateNowPlayingArtwork:YES]; + return [cachedNowPlayingController currentNowPlayingArtwork]; + } + else if (cachedMediaController) { + if (![cachedMediaController currentNowPlayingInfo]) return NULL; + NSData *artworkData = [cachedMediaController currentNowPlayingInfo][(__bridge NSString *)kMRMediaRemoteNowPlayingInfoArtworkData]; + if (!artworkData) return NULL; + return [UIImage imageWithData:artworkData]; + } + return NULL; +} + +-(NSDictionary *)currentNowPlayingInfo { + if (cachedNowPlayingController) return [cachedNowPlayingController currentNowPlayingInfo]; + else if (cachedMediaController) return [cachedMediaController currentNowPlayingInfo]; + return NULL; +} + +-(double)currentDuration { + if (cachedNowPlayingController) return [cachedNowPlayingController currentDuration]; + else if (cachedMediaController) { + if (![cachedMediaController currentNowPlayingInfo]) return 0; + if (![cachedMediaController currentNowPlayingInfo][(__bridge NSString *)kMRMediaRemoteNowPlayingInfoDuration]) return 0; + return [[cachedMediaController currentNowPlayingInfo][(__bridge NSString *)kMRMediaRemoteNowPlayingInfoDuration] doubleValue]; + } + return 0; +} + +-(BOOL)_shouldShowNotifyMusic { + if (!notifyMusicPrefsLoaded) [self _updateNotifyMusicPrefs]; + NSString *frontMost = [[(SpringBoard *)[UIApplication sharedApplication] _accessibilityFrontMostApplication] bundleIdentifier]; + if(!enablewhilelocked && [[%c(SBLockScreenManager) sharedInstance] isUILocked]) return NO; + if(!enableinapp && [self.nowPlayingAppDisplayID isEqualToString:frontMost]) + return NO; + return YES; +} + +-(void)_showNotifyMusic { + //%orig; + //if (![self _shouldShowNotifyMusic]) return; + + if (isInProgress) return; + if (!self.isPlaying) return; + double currentDuration = self.currentDuration; + if (!currentDuration || currentDuration <= 0) return; + isInProgress = YES; + + NSString *_title = self.currentNowPlayingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoTitle]; + NSString *_artist = self.currentNowPlayingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoArtist]; + NSString *_album = self.currentNowPlayingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoAlbum]; + NSString *_mediaInfo = [NSString stringWithFormat:@"%@:%@:%@:%@:%d", self.nowPlayingAppDisplayID, _title, _artist, _album, (int)currentDuration]; + if (![_mediaInfo isEqualToString:cachedMediaInfo]) durationMod = currentDuration - (int)currentDuration; + + BOOL hasArtwork = [self.currentNowPlayingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoArtworkMIMEType] containsString:@"image"]; + double delayInSeconds = 0.5; + if (hasArtwork) delayInSeconds = 2; + if (hasArtwork && self.currentNowPlayingArtwork == nil) delayInSeconds = 4; + if (currentDuration - (int)currentDuration != durationMod) delayInSeconds = 8; + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); + dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ + NSString *nowPlayingAppDisplayID = self.nowPlayingAppDisplayID; + NSString *title = self.currentNowPlayingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoTitle]; + NSString *artist = self.currentNowPlayingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoArtist]; + NSString *album = self.currentNowPlayingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoAlbum]; + NSString *mediaInfo = [NSString stringWithFormat:@"%@:%@:%@:%@:%d", nowPlayingAppDisplayID, title, artist, album, (int)self.currentDuration]; + if (![mediaInfo isEqualToString:_mediaInfo]) return; + UIImage *artwork = self.currentNowPlayingArtwork; + if ([mediaInfo isEqualToString:cachedMediaInfo] && (artwork == nil || !showagainwhenartavail || isArtworkUpdated)) return; + //if (artwork) artwork = [artwork copy]; + cachedMediaInfo = [mediaInfo copy]; + isArtworkUpdated = artwork != nil; + if (![self _shouldShowNotifyMusic]) return; + if(!showalbumname){ + album = @"Now Playing"; + } + if (showalbumname) { + NSString *_title, *_message; + if (albumastitle) { + _title = album; + _message = [NSString stringWithFormat: @"%@\n%@", title, artist]; + } else { + _title = title; + _message = [NSString stringWithFormat: @"%@\n%@", artist, album]; + } + if(artwork != nil){ + [[%c(JBBulletinManager) sharedInstance] showBulletinWithTitle:_title message:_message bundleID:nowPlayingAppDisplayID hasSound:false soundID:0 vibrateMode:0 soundPath:@"" attachmentImage:artwork overrideBundleImage:nil]; + }else{ + [[%c(JBBulletinManager) sharedInstance] showBulletinWithTitle:_title message:_message bundleID:nowPlayingAppDisplayID]; + } + } else { + if ([album length] <= 0) { + album = @"Now Playing"; + } + if(artwork != nil){ + [[%c(JBBulletinManager) sharedInstance] showBulletinWithTitle:album message:[NSString stringWithFormat: @"%@\n%@", title, artist] bundleID:nowPlayingAppDisplayID hasSound:false soundID:0 vibrateMode:0 soundPath:@"" attachmentImage:artwork overrideBundleImage:nil]; + }else{ + [[%c(JBBulletinManager) sharedInstance] showBulletinWithTitle:album message:[NSString stringWithFormat: @"%@\n%@", title, artist] bundleID:nowPlayingAppDisplayID]; + } + } + }); + isInProgress = NO; +} @end %hook MPUNowPlayingController - static NSString *cachedTitle; - static NSString *artist; - static NSString *album; - -(void)_updateCurrentNowPlaying{ - %orig; - NSString *settingsPath = @"/var/mobile/Library/Preferences/com.gilshahar7.notifymusicprefs.plist"; - NSMutableDictionary *prefs = [[NSMutableDictionary alloc] initWithContentsOfFile:settingsPath]; - BOOL enablewhilelocked = [[prefs objectForKey:@"enablewhilelocked"] boolValue]; - BOOL showalbumname = [[prefs objectForKey:@"showalbumname"] boolValue]; - BOOL enableinapp = [[prefs objectForKey:@"enableinapp"] boolValue]; - - double delayInSeconds = 0.5; - dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); - dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ - if(![cachedTitle isEqualToString:self.currentNowPlayingInfo[@"kMRMediaRemoteNowPlayingInfoTitle"]]){ - cachedTitle = [self.currentNowPlayingInfo[@"kMRMediaRemoteNowPlayingInfoTitle"] copy]; - NSString *frontMost = [[(SpringBoard *)[UIApplication sharedApplication] _accessibilityFrontMostApplication] bundleIdentifier]; - if((enablewhilelocked || (![[%c(SBLockScreenManager) sharedInstance] isUILocked])) && self.isPlaying){ - if(enableinapp || (![self.nowPlayingAppDisplayID isEqualToString:frontMost])){ - artist = [NSString stringWithFormat: @"\n%@", self.currentNowPlayingInfo[@"kMRMediaRemoteNowPlayingInfoArtist"]]; - - if([self.currentNowPlayingInfo[@"kMRMediaRemoteNowPlayingInfoAlbum"] length] > 1 && showalbumname){ - album = self.currentNowPlayingInfo[@"kMRMediaRemoteNowPlayingInfoAlbum"]; - }else{ - album = @"Now Playing"; - } - if(self.currentNowPlayingArtwork != nil){ - [[objc_getClass("JBBulletinManager") sharedInstance] showBulletinWithTitle:album message:[NSString stringWithFormat: @"%@%@", self.currentNowPlayingInfo[@"kMRMediaRemoteNowPlayingInfoTitle"], artist] bundleID:self.nowPlayingAppDisplayID hasSound:false soundID:0 vibrateMode:0 soundPath:@"" attachmentImage:self.currentNowPlayingArtwork overrideBundleImage:nil]; - }else{ - [[objc_getClass("JBBulletinManager") sharedInstance] showBulletinWithTitle:album message:[NSString stringWithFormat: @"%@%@", self.currentNowPlayingInfo[@"kMRMediaRemoteNowPlayingInfoTitle"], artist] bundleID:self.nowPlayingAppDisplayID]; - } - } - } - } - }); - } +static int token; + +-(id)init { + self = %orig; + if (self) { + notify_register_dispatch("com.gilshahar7.notifymusic", &token, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(int token) { + [self _updatePlaybackState]; + }); + } + return self; +} + +-(void)dealloc { + notify_cancel(token); + %orig; +} + +/*-(void)_updateCurrentNowPlaying{ + %orig; + [[NotifyMusic sharedInstance] _updateDependencyInjectionWithMC:nil NPC:self]; + [[NotifyMusic sharedInstance] _showNotifyMusic]; +}*/ + +-(void)_updatePlaybackState { + %orig; + [[NotifyMusic sharedInstance] _updateDependencyInjectionWithMC:nil NPC:self]; + [[NotifyMusic sharedInstance] _showNotifyMusic]; +} +%end + +%hook SBMediaController +%property (retain) NSDictionary * currentNowPlayingInfo; + +-(void)setNowPlayingInfo:(NSDictionary *)arg1 { + %orig; + if (UIDevice.currentDevice.systemVersion.floatValue >= 11.0) { + MRMediaRemoteGetNowPlayingInfo(dispatch_get_main_queue(), ^(CFDictionaryRef nowPlayingInfo) { + if (self.currentNowPlayingInfo) [self.currentNowPlayingInfo release]; + self.currentNowPlayingInfo = [(__bridge NSDictionary *)nowPlayingInfo copy]; + [[NotifyMusic sharedInstance] _updateDependencyInjectionWithMC:self NPC:nil]; + [[NotifyMusic sharedInstance] _showNotifyMusic]; + }); + } + else notify_post("com.gilshahar7.notifymusic"); +} + +-(void)_nowPlayingAppIsPlayingDidChange { + %orig; + [self setNowPlayingInfo:[self _nowPlayingInfo]]; +} %end diff --git a/notifymusicprefs/Makefile b/notifymusicprefs/Makefile index 2ea0301..abf07e5 100644 --- a/notifymusicprefs/Makefile +++ b/notifymusicprefs/Makefile @@ -1,4 +1,4 @@ -ARCHS = armv7 arm64 +ARCHS = armv7 arm64 arm64e include $(THEOS)/makefiles/common.mk BUNDLE_NAME = notifymusicprefs diff --git a/notifymusicprefs/Resources/Root.plist b/notifymusicprefs/Resources/Root.plist index 3b548df..70e1071 100644 --- a/notifymusicprefs/Resources/Root.plist +++ b/notifymusicprefs/Resources/Root.plist @@ -11,6 +11,8 @@ NotifyMusic + PostNotification + com.gilshahar7.notifymusicprefs cell PSSwitchCell default @@ -22,7 +24,9 @@ label Enable while locked - + + PostNotification + com.gilshahar7.notifymusicprefs cell PSSwitchCell default @@ -35,6 +39,8 @@ Enable inside now playing app + PostNotification + com.gilshahar7.notifymusicprefs cell PSSwitchCell default @@ -44,7 +50,35 @@ key showalbumname label - Show album name in title + Show album name + + + PostNotification + com.gilshahar7.notifymusicprefs + cell + PSSwitchCell + default + + defaults + com.gilshahar7.notifymusicprefs + key + albumastitle + label + Album name as title + + + PostNotification + com.gilshahar7.notifymusicprefs + cell + PSSwitchCell + default + + defaults + com.gilshahar7.notifymusicprefs + key + showagainwhenartavail + label + Show again when albumart become available title