forked from insanj/SaveGram
-
Notifications
You must be signed in to change notification settings - Fork 0
/
SaveGram.xm
285 lines (234 loc) · 12.2 KB
/
SaveGram.xm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
#import "SaveGram.h"
#import "MBProgressHUD.h"
#define SGLOG(fmt, ...) NSLog((@"[SaveGram] %s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
static NSString *kSaveGramSaveString = @"Save";
static NSString *kSaveGramAllowVersionDefaultsKey = @"SaveGram.LastAllowedVersion";
/*
_______ ______ ______ _______ __ __ _______ _______ _______ __ _
| _ || | | | | _ || | | || || || || | | |
| |_| || _ || _ | | |_| || | | ||_ _||_ _|| _ || |_| |
| || | | || | | | | || |_| | | | | | | | | || |
| || |_| || |_| | | _ | | | | | | | | |_| || _ |
| _ || || | | |_| || | | | | | | || | | |
|__| |__||______| |______| |_______||_______| |___| |___| |_______||_| |__|
*/
%group CurrentSupportPhase
%hook IGActionSheet
- (void)show {
AppDelegate *instagramAppDelegate = [UIApplication sharedApplication].delegate;
IGRootViewController *rootViewController = (IGRootViewController *)((IGShakeWindow *)instagramAppDelegate.window).rootViewController;
UIViewController *topMostViewController = rootViewController.topMostViewController;
// good classes = IGMainFeedViewController, IGSingleFeedViewController, IGDirectedPostViewController
// (some IGViewController, some IGFeedViewController)
BOOL isNotInWebViewController = ![topMostViewController isKindOfClass:[%c(IGWebViewController) class]];
BOOL isNotInProfileViewController = ![topMostViewController isKindOfClass:[%c(IGUserDetailViewController) class]];
if (isNotInWebViewController && isNotInProfileViewController) {
SGLOG(@"adding Save button to action sheet %@", self);
[[%c(IGActionSheet) sharedIGActionSheet] addButtonWithTitle:kSaveGramSaveString style:0];
}
%orig();
}
%end
/*
_______ _______ _______ _______ _______ _______ _______
| || || | | || || || |
| ___|| ___||_ _| | _ || _ || _____||_ _|
| | __ | |___ | | | |_| || | | || |_____ | |
| || || ___| | | | ___|| |_| ||_____ | | |
| |_| || |___ | | | | | | _____| | | |
|_______||_______| |___| |___| |_______||_______| |___|
&*/
/*
static NSURL * savegram_highestResolutionURLFromVersionArray(NSArray *versions) {
NSURL *highestResAvailableVersion;
CGFloat highResAvailableArea;
for (NSDictionary *versionDict in versions) {
CGFloat height = [versionDict[@"height"] floatValue];
CGFloat width = [versionDict[@"width"] floatValue];
CGFloat res = height * width;
if (res > highResAvailableArea) {
highResAvailableArea = res;
highestResAvailableVersion = [NSURL URLWithString:versionDict[@"url"]];
}
}
SGLOG(@"%@ has highest resolution available in %@", highestResAvailableVersion, versions);
return highestResAvailableVersion;
}
*/
static NSString * savegram_lastVersionUserConfirmedWasSupported() {
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
return [standardUserDefaults objectForKey:kSaveGramAllowVersionDefaultsKey];
}
static void savegram_setLastVersionUserConfirmedWasSupported(NSString *value) {
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
[standardUserDefaults setObject:value forKey:kSaveGramAllowVersionDefaultsKey];
}
static void inline savegram_saveMediaFromPost(IGPost *post) {
if ([%c(AFNetworkReachabilityManager) sharedManager].networkReachabilityStatus == AFNetworkReachabilityStatusNotReachable) {
SGLOG(@"networking not reachable");
UIAlertView *noInternetAlert = [[UIAlertView alloc] initWithTitle:@"SaveGram" message:@"Check your internet connection and try again, Instagram may also be having issues." delegate:nil cancelButtonTitle:@"Dismiss" otherButtonTitles:nil];
[noInternetAlert show];
[noInternetAlert release];
return;
}
UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
MBProgressHUD __block *saveGramHUD = [MBProgressHUD showHUDAddedTo:keyWindow animated:YES];
saveGramHUD.animationType = MBProgressHUDAnimationZoom;
saveGramHUD.labelText = @"Saving post...";
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSString* urlStr = nil;
if (post.mediaType == 1) { // photo
IGPhoto* photo = [post photo];
NSArray* imageVersions = [photo imageVersions];
IGTypedURL* url = [imageVersions lastObject];
urlStr = [(NSURL*)[url url] absoluteString];
NSURL *imageURL = [NSURL URLWithString:urlStr];
UIImage *postImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageURL]];
IGAssetWriter *postImageAssetWriter = [[%c(IGAssetWriter) alloc] initWithImage:postImage metadata:nil];
[postImageAssetWriter writeToInstagramAlbum];
SGLOG(@"wrote image %@ to Instagram album", postImage);
dispatch_async(dispatch_get_main_queue(), ^{
saveGramHUD.labelText = @"Saved!";
[saveGramHUD hide:YES afterDelay:1.0];
});
}
else { // video
IGVideo* video = [post video];
NSArray* videoVersions = [video videoVersions];
NSDictionary* urlDict = [videoVersions firstObject];
urlStr = [urlDict objectForKey:@"url"];
NSURL *videoURL = [NSURL URLWithString:urlStr];
NSURLSessionTask *videoDownloadTask = [[NSURLSession sharedSession] downloadTaskWithURL:videoURL completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *videoDocumentsURL = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject];
NSURL *videoSavedURL = [videoDocumentsURL URLByAppendingPathComponent:[videoURL lastPathComponent]];
[fileManager moveItemAtURL:location toURL:videoSavedURL error:&error];
[%c(IGAssetWriter) writeVideoToInstagramAlbum:videoSavedURL completion:nil];
SGLOG(@"wrote video %@ to Instagram album", videoSavedURL);
dispatch_async(dispatch_get_main_queue(), ^{
saveGramHUD.labelText = @"Saved!";
[saveGramHUD hide:YES afterDelay:1.0];
});
}];
[videoDownloadTask resume];
}
});
}
/*
______ ___ ______ _______ _______ _______
| | | | | _ | | || || |
| _ || | | | || | ___|| ||_ _|
| | | || | | |_||_ | |___ | | | |
| |_| || | | __ || ___|| _| | |
| || | | | | || |___ | |_ | |
|______| |___| |___| |_||_______||_______| |___|
*/
%hook IGDirectedPostViewController
- (void)actionSheetDismissedWithButtonTitled:(NSString *)title {
if ([title isEqualToString:kSaveGramSaveString]) {
SGLOG(@"saving media from Direct message");
IGPost *post = self.post;
savegram_saveMediaFromPost(post);
}
else {
%orig(title);
}
}
%end
%hook IGMediaManager
/*
_______ _______ _______ ______
| || || || |
| ___|| ___|| ___|| _ |
| |___ | |___ | |___ | | | |
| ___|| ___|| ___|| |_| |
| | | |___ | |___ | |
|___| |_______||_______||______|
*/
- (void)handleActionSheetDismissedWithButtonTitled:(id)title forFeedItem:(id)feedItem navigationController:(id)navController sourceName:(NSString*)source {
if ([title isEqualToString:kSaveGramSaveString]) {
SGLOG(@"saving media from Feed post");
IGFeedItem *post = feedItem;
savegram_saveMediaFromPost(post);
}
else {
%orig(title,feedItem,navController,source);
}
}
%end
%end // %group CurrentSupportPhase
/*
_______ _______ __ __ _______ _______ _______ ___ _______ ___ ___ ___ _______ __ __
| || || |_| || || _ || || | | _ || | | | | | | || | | |
| || _ || || _ || |_| ||_ _|| | | |_| || | | | | | |_ _|| |_| |
| || | | || || |_| || | | | | | | || | | | | | | | | |
| _|| |_| || || ___|| | | | | | | _ | | | | |___ | | | | |_ _|
| |_ | || ||_|| || | | _ | | | | | | |_| || | | || | | | | |
|_______||_______||_| |_||___| |__| |__| |___| |___| |_______||___| |_______||___| |___| |___|
*/
static NSInteger kSaveGramCompatibilityViewTag = 1213;
@interface SaveGramAlertViewDelegate : NSObject <UIAlertViewDelegate>
@end
@implementation SaveGramAlertViewDelegate
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex != alertView.cancelButtonIndex) {
if (alertView.tag != kSaveGramCompatibilityViewTag) {
if ([[alertView buttonTitleAtIndex:buttonIndex] isEqualToString:@"Cydia"]) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"cydia://package/com.insanj.savegram"]];
}
else {
NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
savegram_setLastVersionUserConfirmedWasSupported(version);
UIAlertView *compatibilityConfirmationView = [[[UIAlertView alloc] initWithTitle:@"SaveGram Compatibility" message:@"Instagram will close to run SaveGram. This is not recommended: be prepared to still downgrade to a compatibility package from Cydia, if needed." delegate:self cancelButtonTitle:@"Dismiss" otherButtonTitles:@"Restart", nil] autorelease];
compatibilityConfirmationView.tag = kSaveGramCompatibilityViewTag;
[compatibilityConfirmationView show];
}
}
else {
// BKSSystemService *backBoardService = [[%c(BKSSystemService) alloc] init];
// [backBoardService performSelector:@selector(openApplication:options:withResult:) withObject:@"com.burbn.instagram" afterDelay:0.5];
// [backBoardService openApplication:@"com.apple.mobilesafari" options:nil withResult:nil];
// [backBoardService openURL:[NSURL URLWithString:@"instagram://app"] application:@"com.burbn.instagram" options:0 clientPort:[backBoardService createClientPort] withResult:NULL];
exit(0);
}
}
}
@end
static SaveGramAlertViewDelegate * savegram_compatibilityAlertDelegate;
%group Compatibility
%hook AppDelegate
- (void)startMainAppWithMainFeedSource:(id)source animated:(BOOL)animated {
%orig();
SGLOG(@"");
savegram_compatibilityAlertDelegate = [[SaveGramAlertViewDelegate alloc] init];
UIAlertView *compatibilityWarningView = [[[UIAlertView alloc] initWithTitle:@"SaveGram Compatibility" message:@"You are running an out-of-date version of Instagram. Please downgrade to a previous SaveGram package in Cydia, or upgrade Instagram." delegate:savegram_compatibilityAlertDelegate cancelButtonTitle:@"Cancel" otherButtonTitles:@"Run", @"Cydia", nil] autorelease];
[compatibilityWarningView show];
}
%end
%end // %group Compatibility
/*
_______ _______ _______ ______
| || || || _ |
| ||_ _|| _ || | ||
| | | | | | | || |_||_
| _| | | | |_| || __ |
| |_ | | | || | | |
|_______| |___| |_______||___| |_|
*/
%ctor {
NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
NSComparisonResult newestWaveVersionComparisonResult = [version compare:@"7.1.1" options:NSNumericSearch];
SGLOG(@"Instagram %@, comparison result to last official supported build (7.1.1): %i", version, (int)newestWaveVersionComparisonResult);
// If the current version of Instagram is LOWER (not EQUAL TO or HIGHER) than 7.1.1, they should be running a compatibility package
if (newestWaveVersionComparisonResult == NSOrderedAscending) {
NSString *lastVersionConfirmed = savegram_lastVersionUserConfirmedWasSupported();
NSComparisonResult lastConfirmedCompatibilityResult = [version compare:savegram_lastVersionUserConfirmedWasSupported() options:NSNumericSearch];
SGLOG(@"Running out-of-date version of Instagram. Last version that we were allowed to run SaveGram on was %@, which compares to the current version as: %i", lastVersionConfirmed, (int)lastConfirmedCompatibilityResult);
// If the last time the user confirmed running an out-of-date Instagram was in a LOWER
if (!lastVersionConfirmed || lastConfirmedCompatibilityResult == NSOrderedDescending) {
%init(Compatibility);
return;
}
}
%init(CurrentSupportPhase);
}