From 3086c3c01c91cbb5885501d5b59122bbaf142ac0 Mon Sep 17 00:00:00 2001 From: Thomas Willson Date: Sat, 18 Oct 2014 23:51:05 -0700 Subject: [PATCH] Made several changes regarding the flow of getName as well as the Cache Update index number updating code to improve the support for PID-only downloads. Also, fixed the indenting in the AppController. --- AppController.m | 3550 ++++++++++++++++++++++++----------------------- Programme.h | 1 + Programme.m | 617 ++++---- 3 files changed, 2096 insertions(+), 2072 deletions(-) diff --git a/AppController.m b/AppController.m index 62873c2f..5f9b61e6 100644 --- a/AppController.m +++ b/AppController.m @@ -29,1570 +29,1572 @@ @implementation AppController #pragma mark Overriden Methods - (id)description { - return @"AppController"; + return @"AppController"; } - (id)init { - //Initialization - if (!(self = [super init])) return nil; - sharedController = self; - - NSNotificationCenter *nc; - nc = [NSNotificationCenter defaultCenter]; - - //Initialize Arrays for Controllers - searchResultsArray = [NSMutableArray array]; - pvrSearchResultsArray = [NSMutableArray array]; - pvrQueueArray = [NSMutableArray array]; - queueArray = [NSMutableArray array]; - - //Look for Start notifications for ASS - [nc addObserver:self selector:@selector(applescriptStartDownloads) name:@"StartDownloads" object:nil]; - - //Register Default Preferences - NSMutableDictionary *defaultValues = [[NSMutableDictionary alloc] init]; - - NSString *defaultDownloadDirectory = @"~/Movies/TV Shows"; - defaultValues[@"DownloadPath"] = [defaultDownloadDirectory stringByExpandingTildeInPath]; - defaultValues[@"Proxy"] = @"Provided"; - defaultValues[@"CustomProxy"] = @""; - defaultValues[@"AutoRetryFailed"] = @YES; - defaultValues[@"AutoRetryTime"] = @"30"; - defaultValues[@"AddCompletedToiTunes"] = @YES; - defaultValues[@"DefaultBrowser"] = @"Safari"; - defaultValues[@"DefaultFormat"] = @"iPhone"; - defaultValues[@"AlternateFormat"] = @"Flash - Standard"; - defaultValues[@"CacheBBC_TV"] = @YES; - defaultValues[@"CacheITV_TV"] = @YES; - defaultValues[@"CacheBBC_Radio"] = @NO; - defaultValues[@"CacheBBC_Podcasts"] = @NO; - defaultValues[@"CacheExpiryTime"] = @"4"; - defaultValues[@"Verbose"] = @NO; - defaultValues[@"SeriesLinkStartup"] = @YES; - defaultValues[@"DownloadSubtitles"] = @NO; - defaultValues[@"AlwaysUseProxy"] = @NO; - defaultValues[@"XBMC_naming"] = @NO; - defaultValues[@"KeepSeriesFor"] = @"30"; - defaultValues[@"RemoveOldSeries"] = @NO; - defaultValues[@"QuickCache"] = @YES; - defaultValues[@"TagShows"] = @YES; - // TODO: remove 4oD - // set 4oD off by default - defaultValues[@"Cache4oD_TV"] = @NO; - defaultValues[@"TestProxy"] = @YES; - defaultValues[@"ShowDownloadedInSearch"] = @YES; - - defaultValues[@"AudioDescribedNew"] = @NO; - defaultValues[@"SignedNew"] = @NO; - - [[NSUserDefaults standardUserDefaults] registerDefaults:defaultValues]; - defaultValues = nil; - - //Migrate old AudioDescribed option - if ([[NSUserDefaults standardUserDefaults] objectForKey:@"AudioDescribed"]) { - [[NSUserDefaults standardUserDefaults] setObject:@YES forKey:@"AudioDescribedNew"]; - [[NSUserDefaults standardUserDefaults] setObject:@YES forKey:@"SignedNew"]; - [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"AudioDescribed"]; - } - - //Make sure Application Support folder exists - NSString *folder = @"~/Library/Application Support/Get iPlayer Automator/"; - folder = [folder stringByExpandingTildeInPath]; - NSFileManager *fileManager = [NSFileManager defaultManager]; - if (![fileManager fileExistsAtPath:folder]) - { - [fileManager createDirectoryAtPath:folder withIntermediateDirectories:NO attributes:nil error:nil]; - } - [fileManager changeCurrentDirectoryPath:folder]; - - //Install Plugins If Needed - NSString *pluginPath = [folder stringByAppendingPathComponent:@"plugins"]; - if (/*![fileManager fileExistsAtPath:pluginPath]*/TRUE) - { - [logger addToLog:@"Installing/Updating Get_iPlayer Plugins..." :self]; - NSString *providedPath = [[NSBundle mainBundle] bundlePath]; - if ([fileManager fileExistsAtPath:pluginPath]) [fileManager removeItemAtPath:pluginPath error:NULL]; - providedPath = [providedPath stringByAppendingPathComponent:@"/Contents/Resources/plugins"]; - [fileManager copyItemAtPath:providedPath toPath:pluginPath error:nil]; - } - - - //Initialize Arguments - getiPlayerPath = [[NSString alloc] initWithString:[[NSBundle mainBundle] bundlePath]]; - getiPlayerPath = [getiPlayerPath stringByAppendingString:@"/Contents/Resources/get_iplayer.pl"]; - runScheduled=NO; - quickUpdateFailed=NO; - nilToEmptyStringTransformer = [[NilToStringTransformer alloc] init]; - nilToAsteriskTransformer = [[NilToStringTransformer alloc] initWithString:@"*"]; - [NSValueTransformer setValueTransformer:nilToEmptyStringTransformer forName:@"NilToEmptyStringTransformer"]; - [NSValueTransformer setValueTransformer:nilToAsteriskTransformer forName:@"NilToAsteriskTransformer"]; - verbose = [[NSUserDefaults standardUserDefaults] boolForKey:@"Verbose"]; - return self; + //Initialization + if (!(self = [super init])) return nil; + sharedController = self; + + NSNotificationCenter *nc; + nc = [NSNotificationCenter defaultCenter]; + + //Initialize Arrays for Controllers + searchResultsArray = [NSMutableArray array]; + pvrSearchResultsArray = [NSMutableArray array]; + pvrQueueArray = [NSMutableArray array]; + queueArray = [NSMutableArray array]; + + //Look for Start notifications for ASS + [nc addObserver:self selector:@selector(applescriptStartDownloads) name:@"StartDownloads" object:nil]; + + //Register Default Preferences + NSMutableDictionary *defaultValues = [[NSMutableDictionary alloc] init]; + + NSString *defaultDownloadDirectory = @"~/Movies/TV Shows"; + defaultValues[@"DownloadPath"] = [defaultDownloadDirectory stringByExpandingTildeInPath]; + defaultValues[@"Proxy"] = @"Provided"; + defaultValues[@"CustomProxy"] = @""; + defaultValues[@"AutoRetryFailed"] = @YES; + defaultValues[@"AutoRetryTime"] = @"30"; + defaultValues[@"AddCompletedToiTunes"] = @YES; + defaultValues[@"DefaultBrowser"] = @"Safari"; + defaultValues[@"DefaultFormat"] = @"iPhone"; + defaultValues[@"AlternateFormat"] = @"Flash - Standard"; + defaultValues[@"CacheBBC_TV"] = @YES; + defaultValues[@"CacheITV_TV"] = @YES; + defaultValues[@"CacheBBC_Radio"] = @NO; + defaultValues[@"CacheBBC_Podcasts"] = @NO; + defaultValues[@"CacheExpiryTime"] = @"4"; + defaultValues[@"Verbose"] = @NO; + defaultValues[@"SeriesLinkStartup"] = @YES; + defaultValues[@"DownloadSubtitles"] = @NO; + defaultValues[@"AlwaysUseProxy"] = @NO; + defaultValues[@"XBMC_naming"] = @NO; + defaultValues[@"KeepSeriesFor"] = @"30"; + defaultValues[@"RemoveOldSeries"] = @NO; + defaultValues[@"QuickCache"] = @YES; + defaultValues[@"TagShows"] = @YES; + // TODO: remove 4oD + // set 4oD off by default + defaultValues[@"Cache4oD_TV"] = @NO; + defaultValues[@"TestProxy"] = @YES; + defaultValues[@"ShowDownloadedInSearch"] = @YES; + + defaultValues[@"AudioDescribedNew"] = @NO; + defaultValues[@"SignedNew"] = @NO; + + [[NSUserDefaults standardUserDefaults] registerDefaults:defaultValues]; + defaultValues = nil; + + //Migrate old AudioDescribed option + if ([[NSUserDefaults standardUserDefaults] objectForKey:@"AudioDescribed"]) { + [[NSUserDefaults standardUserDefaults] setObject:@YES forKey:@"AudioDescribedNew"]; + [[NSUserDefaults standardUserDefaults] setObject:@YES forKey:@"SignedNew"]; + [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"AudioDescribed"]; + } + + //Make sure Application Support folder exists + NSString *folder = @"~/Library/Application Support/Get iPlayer Automator/"; + folder = [folder stringByExpandingTildeInPath]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + if (![fileManager fileExistsAtPath:folder]) + { + [fileManager createDirectoryAtPath:folder withIntermediateDirectories:NO attributes:nil error:nil]; + } + [fileManager changeCurrentDirectoryPath:folder]; + + //Install Plugins If Needed + NSString *pluginPath = [folder stringByAppendingPathComponent:@"plugins"]; + if (/*![fileManager fileExistsAtPath:pluginPath]*/TRUE) + { + [logger addToLog:@"Installing/Updating Get_iPlayer Plugins..." :self]; + NSString *providedPath = [[NSBundle mainBundle] bundlePath]; + if ([fileManager fileExistsAtPath:pluginPath]) [fileManager removeItemAtPath:pluginPath error:NULL]; + providedPath = [providedPath stringByAppendingPathComponent:@"/Contents/Resources/plugins"]; + [fileManager copyItemAtPath:providedPath toPath:pluginPath error:nil]; + } + + + //Initialize Arguments + getiPlayerPath = [[NSString alloc] initWithString:[[NSBundle mainBundle] bundlePath]]; + getiPlayerPath = [getiPlayerPath stringByAppendingString:@"/Contents/Resources/get_iplayer.pl"]; + runScheduled=NO; + quickUpdateFailed=NO; + nilToEmptyStringTransformer = [[NilToStringTransformer alloc] init]; + nilToAsteriskTransformer = [[NilToStringTransformer alloc] initWithString:@"*"]; + [NSValueTransformer setValueTransformer:nilToEmptyStringTransformer forName:@"NilToEmptyStringTransformer"]; + [NSValueTransformer setValueTransformer:nilToAsteriskTransformer forName:@"NilToAsteriskTransformer"]; + verbose = [[NSUserDefaults standardUserDefaults] boolForKey:@"Verbose"]; + return self; } #pragma mark Delegate Methods - (void)awakeFromNib { #ifdef __x86_64__ - [itvTVCheckbox setEnabled:YES]; + [itvTVCheckbox setEnabled:YES]; #else - [itvTVCheckbox setEnabled:NO]; - [itvTVCheckbox setState:NSOffState]; - [[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:NO] forKey:@"CacheITV_TV"]; + [itvTVCheckbox setEnabled:NO]; + [itvTVCheckbox setState:NSOffState]; + [[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:NO] forKey:@"CacheITV_TV"]; #endif - - //Initialize Search Results Click Actions - [searchResultsTable setTarget:self]; - [searchResultsTable setDoubleAction:@selector(addToQueue:)]; - - - //Read Queue & Series-Link from File - NSFileManager *fileManager = [NSFileManager defaultManager]; - - NSString *folder = @"~/Library/Application Support/Get iPlayer Automator/"; - folder = [folder stringByExpandingTildeInPath]; - if ([fileManager fileExistsAtPath: folder] == NO) - { - [fileManager createDirectoryAtPath:folder withIntermediateDirectories:NO attributes:nil error:nil]; - } - - // TODO: remove 4oD - // disable 4oD and delete CH4 cache - [[NSUserDefaults standardUserDefaults] setValue:@NO forKey:@"Cache4oD_TV"]; - [ch4TVCheckbox setState:NSOffState]; - [ch4TVCheckbox setEnabled:NO]; - [fileManager removeItemAtPath:[folder stringByAppendingPathComponent:@"ch4.cache"] error:nil]; - - NSString *filename = @"Queue.automatorqueue"; - NSString *filePath = [folder stringByAppendingPathComponent:filename]; - - NSDictionary * rootObject; - @try - { - rootObject = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; - NSArray *tempQueue = [rootObject valueForKey:@"queue"]; - NSArray *tempSeries = [rootObject valueForKey:@"serieslink"]; - lastUpdate = [rootObject valueForKey:@"lastUpdate"]; - [queueController addObjects:tempQueue]; - [pvrQueueController addObjects:tempSeries]; - } - @catch (NSException *e) - { - [fileManager removeItemAtPath:filePath error:nil]; - NSLog(@"Unable to load saved application data. Deleted the data file."); - rootObject=nil; - } - - //Read Format Preferences - - filename = @"Formats.automatorqueue"; - filePath = [folder stringByAppendingPathComponent:filename]; - - @try - { - rootObject = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; - [radioFormatController addObjects:[rootObject valueForKey:@"radioFormats"]]; - [tvFormatController addObjects:[rootObject valueForKey:@"tvFormats"]]; - } - @catch (NSException *e) - { - [fileManager removeItemAtPath:filePath error:nil]; - NSLog(@"Unable to load saved application data. Deleted the data file."); - rootObject=nil; - } - if (!tvFormats || !radioFormats) { - [BBCDownload initFormats]; - } - // clear obsolete formats - NSMutableArray *tempTVFormats = [[NSMutableArray alloc] initWithArray:[tvFormatController arrangedObjects]]; - for (TVFormat *tvFormat in tempTVFormats) { - if (!tvFormats[[tvFormat format]]) { - [tvFormatController removeObject:tvFormat]; - } - } - NSMutableArray *tempRadioFormats = [[NSMutableArray alloc] initWithArray:[radioFormatController arrangedObjects]]; - for (RadioFormat *radioFormat in tempRadioFormats) { - if (!radioFormats[[radioFormat format]]) { - [radioFormatController removeObject:radioFormat]; - } - } - - // TODO: Remove 4oD - BOOL hasCached4oD = [[rootObject valueForKey:@"hasUpdatedCacheFor4oD"] boolValue]; - - filename = @"ITVFormats.automator"; - filePath = [folder stringByAppendingPathComponent:filename]; - @try { - rootObject = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; - [itvFormatController addObjects:[rootObject valueForKey:@"itvFormats"]]; - } - @catch (NSException *exception) { - [fileManager removeItemAtPath:filePath error:nil]; - rootObject=nil; - } - - //Adds Defaults to Type Preferences - if ([[tvFormatController arrangedObjects] count] == 0) - { - TVFormat *format1 = [[TVFormat alloc] init]; - [format1 setFormat:@"Flash - HD"]; - TVFormat *format2 = [[TVFormat alloc] init]; - [format2 setFormat:@"Flash - Very High"]; + + //Initialize Search Results Click Actions + [searchResultsTable setTarget:self]; + [searchResultsTable setDoubleAction:@selector(addToQueue:)]; + + + //Read Queue & Series-Link from File + NSFileManager *fileManager = [NSFileManager defaultManager]; + + NSString *folder = @"~/Library/Application Support/Get iPlayer Automator/"; + folder = [folder stringByExpandingTildeInPath]; + if ([fileManager fileExistsAtPath: folder] == NO) + { + [fileManager createDirectoryAtPath:folder withIntermediateDirectories:NO attributes:nil error:nil]; + } + + // TODO: remove 4oD + // disable 4oD and delete CH4 cache + [[NSUserDefaults standardUserDefaults] setValue:@NO forKey:@"Cache4oD_TV"]; + [ch4TVCheckbox setState:NSOffState]; + [ch4TVCheckbox setEnabled:NO]; + [fileManager removeItemAtPath:[folder stringByAppendingPathComponent:@"ch4.cache"] error:nil]; + + NSString *filename = @"Queue.automatorqueue"; + NSString *filePath = [folder stringByAppendingPathComponent:filename]; + + NSDictionary * rootObject; + @try + { + rootObject = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + NSArray *tempQueue = [rootObject valueForKey:@"queue"]; + NSArray *tempSeries = [rootObject valueForKey:@"serieslink"]; + lastUpdate = [rootObject valueForKey:@"lastUpdate"]; + [queueController addObjects:tempQueue]; + [pvrQueueController addObjects:tempSeries]; + } + @catch (NSException *e) + { + [fileManager removeItemAtPath:filePath error:nil]; + NSLog(@"Unable to load saved application data. Deleted the data file."); + rootObject=nil; + } + + //Read Format Preferences + + filename = @"Formats.automatorqueue"; + filePath = [folder stringByAppendingPathComponent:filename]; + + @try + { + rootObject = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + [radioFormatController addObjects:[rootObject valueForKey:@"radioFormats"]]; + [tvFormatController addObjects:[rootObject valueForKey:@"tvFormats"]]; + } + @catch (NSException *e) + { + [fileManager removeItemAtPath:filePath error:nil]; + NSLog(@"Unable to load saved application data. Deleted the data file."); + rootObject=nil; + } + if (!tvFormats || !radioFormats) { + [BBCDownload initFormats]; + } + // clear obsolete formats + NSMutableArray *tempTVFormats = [[NSMutableArray alloc] initWithArray:[tvFormatController arrangedObjects]]; + for (TVFormat *tvFormat in tempTVFormats) { + if (!tvFormats[[tvFormat format]]) { + [tvFormatController removeObject:tvFormat]; + } + } + NSMutableArray *tempRadioFormats = [[NSMutableArray alloc] initWithArray:[radioFormatController arrangedObjects]]; + for (RadioFormat *radioFormat in tempRadioFormats) { + if (!radioFormats[[radioFormat format]]) { + [radioFormatController removeObject:radioFormat]; + } + } + + // TODO: Remove 4oD + BOOL hasCached4oD = [[rootObject valueForKey:@"hasUpdatedCacheFor4oD"] boolValue]; + + filename = @"ITVFormats.automator"; + filePath = [folder stringByAppendingPathComponent:filename]; + @try { + rootObject = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath]; + [itvFormatController addObjects:[rootObject valueForKey:@"itvFormats"]]; + } + @catch (NSException *exception) { + [fileManager removeItemAtPath:filePath error:nil]; + rootObject=nil; + } + + //Adds Defaults to Type Preferences + if ([[tvFormatController arrangedObjects] count] == 0) + { + TVFormat *format1 = [[TVFormat alloc] init]; + [format1 setFormat:@"Flash - HD"]; + TVFormat *format2 = [[TVFormat alloc] init]; + [format2 setFormat:@"Flash - Very High"]; TVFormat *format3 = [[TVFormat alloc] init]; [format3 setFormat:@"Flash - High"]; - [tvFormatController addObjects:@[format1,format2,format3]]; - } - if ([[radioFormatController arrangedObjects] count] == 0) - { - RadioFormat *format1 = [[RadioFormat alloc] init]; - [format1 setFormat:@"Flash AAC - High"]; - RadioFormat *format2 = [[RadioFormat alloc] init]; - [format2 setFormat:@"Flash AAC - Standard"]; - RadioFormat *format3 = [[RadioFormat alloc] init]; - [format3 setFormat:@"Flash - MP3"]; - [radioFormatController addObjects:@[format1,format2,format3]]; - } - if ([[itvFormatController arrangedObjects] count] == 0) - { - TVFormat *format1 = [[TVFormat alloc] init]; - [format1 setFormat:@"Flash - High"]; - TVFormat *format2 = [[TVFormat alloc] init]; - [format2 setFormat:@"Flash - Standard"]; - TVFormat *format3 = [[TVFormat alloc] init]; - [format3 setFormat:@"Flash - Low"]; - TVFormat *format4 = [[TVFormat alloc] init]; - [format4 setFormat:@"Flash - Very Low"]; - [itvFormatController addObjects:@[format1,format2,format3,format4]]; - } - - //Growl Initialization - @try { - [GrowlApplicationBridge setGrowlDelegate:(id)@""]; - } - @catch (NSException *e) { - NSLog(@"ERROR: Growl initialisation failed: %@: %@", [e name], [e description]); - [logger addToLog:[NSString stringWithFormat:@"ERROR: Growl initialisation failed: %@: %@", [e name], [e description]]]; - } - - //Populate Live TV Channel List - LiveTVChannel *bbcOne = [[LiveTVChannel alloc] initWithChannelName:@"BBC One"]; - LiveTVChannel *bbcTwo = [[LiveTVChannel alloc] initWithChannelName:@"BBC Two"]; - LiveTVChannel *bbcNews24 = [[LiveTVChannel alloc] initWithChannelName:@"BBC News 24"]; - [liveTVChannelController setContent:@[bbcOne,bbcTwo,bbcNews24]]; - [liveTVTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO]; - - //Remove SWFinfo - NSString *infoPath = @"~/.swfinfo"; - infoPath = [infoPath stringByExpandingTildeInPath]; - if ([fileManager fileExistsAtPath:infoPath]) [fileManager removeItemAtPath:infoPath error:nil]; - - if (hasCached4oD) - [self updateCache:nil]; - else - [self updateCache:@""]; + [tvFormatController addObjects:@[format1,format2,format3]]; + } + if ([[radioFormatController arrangedObjects] count] == 0) + { + RadioFormat *format1 = [[RadioFormat alloc] init]; + [format1 setFormat:@"Flash AAC - High"]; + RadioFormat *format2 = [[RadioFormat alloc] init]; + [format2 setFormat:@"Flash AAC - Standard"]; + RadioFormat *format3 = [[RadioFormat alloc] init]; + [format3 setFormat:@"Flash - MP3"]; + [radioFormatController addObjects:@[format1,format2,format3]]; + } + if ([[itvFormatController arrangedObjects] count] == 0) + { + TVFormat *format1 = [[TVFormat alloc] init]; + [format1 setFormat:@"Flash - High"]; + TVFormat *format2 = [[TVFormat alloc] init]; + [format2 setFormat:@"Flash - Standard"]; + TVFormat *format3 = [[TVFormat alloc] init]; + [format3 setFormat:@"Flash - Low"]; + TVFormat *format4 = [[TVFormat alloc] init]; + [format4 setFormat:@"Flash - Very Low"]; + [itvFormatController addObjects:@[format1,format2,format3,format4]]; + } + + //Growl Initialization + @try { + [GrowlApplicationBridge setGrowlDelegate:(id)@""]; + } + @catch (NSException *e) { + NSLog(@"ERROR: Growl initialisation failed: %@: %@", [e name], [e description]); + [logger addToLog:[NSString stringWithFormat:@"ERROR: Growl initialisation failed: %@: %@", [e name], [e description]]]; + } + + //Populate Live TV Channel List + LiveTVChannel *bbcOne = [[LiveTVChannel alloc] initWithChannelName:@"BBC One"]; + LiveTVChannel *bbcTwo = [[LiveTVChannel alloc] initWithChannelName:@"BBC Two"]; + LiveTVChannel *bbcNews24 = [[LiveTVChannel alloc] initWithChannelName:@"BBC News 24"]; + [liveTVChannelController setContent:@[bbcOne,bbcTwo,bbcNews24]]; + [liveTVTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO]; + + //Remove SWFinfo + NSString *infoPath = @"~/.swfinfo"; + infoPath = [infoPath stringByExpandingTildeInPath]; + if ([fileManager fileExistsAtPath:infoPath]) [fileManager removeItemAtPath:infoPath error:nil]; + + if (hasCached4oD) + [self updateCache:nil]; + else + [self updateCache:@""]; } - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)application { - return YES; + return YES; } - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { - if (runDownloads) - { - NSAlert *downloadAlert = [NSAlert alertWithMessageText:@"Are you sure you wish to quit?" + if (runDownloads) + { + NSAlert *downloadAlert = [NSAlert alertWithMessageText:@"Are you sure you wish to quit?" + defaultButton:@"No" + alternateButton:@"Yes" + otherButton:nil + informativeTextWithFormat:@"You are currently downloading shows. If you quit, they will be cancelled."]; + NSInteger response = [downloadAlert runModal]; + if (response == NSAlertDefaultReturn) return NSTerminateCancel; + } + else if (runUpdate && ![[[NSUserDefaults standardUserDefaults] objectForKey:@"QuickCache"] boolValue]) + { + NSAlert *updateAlert = [NSAlert alertWithMessageText:@"Are you sure?" defaultButton:@"No" alternateButton:@"Yes" otherButton:nil - informativeTextWithFormat:@"You are currently downloading shows. If you quit, they will be cancelled."]; - NSInteger response = [downloadAlert runModal]; - if (response == NSAlertDefaultReturn) return NSTerminateCancel; - } - else if (runUpdate && ![[[NSUserDefaults standardUserDefaults] objectForKey:@"QuickCache"] boolValue]) - { - NSAlert *updateAlert = [NSAlert alertWithMessageText:@"Are you sure?" - defaultButton:@"No" - alternateButton:@"Yes" - otherButton:nil - informativeTextWithFormat:@"Get iPlayer Automator is currently updating the cache." - @"If you proceed with quiting, some series-link information will be lost." - @"It is not reccommended to quit during an update. Are you sure you wish to quit?"]; - NSInteger response = [updateAlert runModal]; - if (response == NSAlertDefaultReturn) return NSTerminateCancel; - } - - return NSTerminateNow; + informativeTextWithFormat:@"Get iPlayer Automator is currently updating the cache." + @"If you proceed with quiting, some series-link information will be lost." + @"It is not reccommended to quit during an update. Are you sure you wish to quit?"]; + NSInteger response = [updateAlert runModal]; + if (response == NSAlertDefaultReturn) return NSTerminateCancel; + } + + return NSTerminateNow; } - (BOOL)windowShouldClose:(id)sender { - if ([sender isEqualTo:mainWindow]) - { - if (runUpdate && ![[[NSUserDefaults standardUserDefaults] objectForKey:@"QuickCache"] boolValue]) - { - NSAlert *updateAlert = [NSAlert alertWithMessageText:@"Are you sure?" - defaultButton:@"No" - alternateButton:@"Yes" - otherButton:nil - informativeTextWithFormat:@"Get iPlayer Automator is currently updating the cache." - @"If you proceed with quiting, some series-link information will be lost." - @"It is not reccommended to quit during an update. Are you sure you wish to quit?"]; - NSInteger response = [updateAlert runModal]; - if (response == NSAlertDefaultReturn) return NO; - else if (response == NSAlertAlternateReturn) return YES; - } - else if (runDownloads) - { - NSAlert *downloadAlert = [NSAlert alertWithMessageText:@"Are you sure you wish to quit?" - defaultButton:@"No" - alternateButton:@"Yes" - otherButton:nil - informativeTextWithFormat:@"You are currently downloading shows. If you quit, they will be cancelled."]; - NSInteger response = [downloadAlert runModal]; - if (response == NSAlertDefaultReturn) return NO; - else return YES; - - } - return YES; - } - else return YES; + if ([sender isEqualTo:mainWindow]) + { + if (runUpdate && ![[[NSUserDefaults standardUserDefaults] objectForKey:@"QuickCache"] boolValue]) + { + NSAlert *updateAlert = [NSAlert alertWithMessageText:@"Are you sure?" + defaultButton:@"No" + alternateButton:@"Yes" + otherButton:nil + informativeTextWithFormat:@"Get iPlayer Automator is currently updating the cache." + @"If you proceed with quiting, some series-link information will be lost." + @"It is not reccommended to quit during an update. Are you sure you wish to quit?"]; + NSInteger response = [updateAlert runModal]; + if (response == NSAlertDefaultReturn) return NO; + else if (response == NSAlertAlternateReturn) return YES; + } + else if (runDownloads) + { + NSAlert *downloadAlert = [NSAlert alertWithMessageText:@"Are you sure you wish to quit?" + defaultButton:@"No" + alternateButton:@"Yes" + otherButton:nil + informativeTextWithFormat:@"You are currently downloading shows. If you quit, they will be cancelled."]; + NSInteger response = [downloadAlert runModal]; + if (response == NSAlertDefaultReturn) return NO; + else return YES; + + } + return YES; + } + else return YES; } - (void)windowWillClose:(NSNotification *)note { - if ([[note object] isEqualTo:mainWindow]) [application terminate:self]; + if ([[note object] isEqualTo:mainWindow]) [application terminate:self]; } - (void)applicationWillTerminate:(NSNotification *)aNotification { - //End Downloads if Running - if (runDownloads) - [currentDownload cancelDownload:nil]; - - [self saveAppData]; + //End Downloads if Running + if (runDownloads) + [currentDownload cancelDownload:nil]; + + [self saveAppData]; } - (void)updater:(SUUpdater *)updater didFindValidUpdate:(SUAppcastItem *)update { - @try - { - - [GrowlApplicationBridge notifyWithTitle:@"Update Available!" - description:[NSString stringWithFormat:@"Get iPlayer Automator %@ is available.",[update displayVersionString]] - notificationName:@"New Version Available" - iconData:nil - priority:0 - isSticky:NO - clickContext:nil]; - } - @catch (NSException *e) { - NSLog(@"ERROR: Growl notification failed (updater): %@: %@", [e name], [e description]); - [logger addToLog:[NSString stringWithFormat:@"ERROR: Growl notification failed (updater): %@: %@", [e name], [e description]]]; - } + @try + { + + [GrowlApplicationBridge notifyWithTitle:@"Update Available!" + description:[NSString stringWithFormat:@"Get iPlayer Automator %@ is available.",[update displayVersionString]] + notificationName:@"New Version Available" + iconData:nil + priority:0 + isSticky:NO + clickContext:nil]; + } + @catch (NSException *e) { + NSLog(@"ERROR: Growl notification failed (updater): %@: %@", [e name], [e description]); + [logger addToLog:[NSString stringWithFormat:@"ERROR: Growl notification failed (updater): %@: %@", [e name], [e description]]]; + } } #pragma mark Cache Update - (IBAction)updateCache:(id)sender { - @try - { - [searchField setEnabled:NO]; - [stopButton setEnabled:NO]; - [startButton setEnabled:NO]; - [pvrSearchField setEnabled:NO]; - } - @catch (NSException *e) { - NSLog(@"NO UI: updateCache:"); - } - if ((![[[NSUserDefaults standardUserDefaults] objectForKey:@"QuickCache"] boolValue] || quickUpdateFailed) && [[[NSUserDefaults standardUserDefaults] valueForKey:@"AlwaysUseProxy"] boolValue]) - { - getiPlayerProxy = [[GetiPlayerProxy alloc] initWithLogger:logger]; - [getiPlayerProxy loadProxyInBackgroundForSelector:@selector(updateCache:proxyDict:) withObject:sender onTarget:self silently:runScheduled]; - } - else - { - [self updateCache:sender proxyDict:nil]; - } + @try + { + [searchField setEnabled:NO]; + [stopButton setEnabled:NO]; + [startButton setEnabled:NO]; + [pvrSearchField setEnabled:NO]; + } + @catch (NSException *e) { + NSLog(@"NO UI: updateCache:"); + } + if ((![[[NSUserDefaults standardUserDefaults] objectForKey:@"QuickCache"] boolValue] || quickUpdateFailed) && [[[NSUserDefaults standardUserDefaults] valueForKey:@"AlwaysUseProxy"] boolValue]) + { + getiPlayerProxy = [[GetiPlayerProxy alloc] initWithLogger:logger]; + [getiPlayerProxy loadProxyInBackgroundForSelector:@selector(updateCache:proxyDict:) withObject:sender onTarget:self silently:runScheduled]; + } + else + { + [self updateCache:sender proxyDict:nil]; + } } - (void)updateCache:(id)sender proxyDict:(NSDictionary *)proxyDict { - getiPlayerProxy = nil; - // reset after proxy load - @try - { - [searchField setEnabled:YES]; - [stopButton setEnabled:YES]; - [startButton setEnabled:YES]; - [pvrSearchField setEnabled:YES]; - } - @catch (NSException *e) { - NSLog(@"NO UI: updateCache:proxyError:"); - } + getiPlayerProxy = nil; + // reset after proxy load + @try + { + [searchField setEnabled:YES]; + [stopButton setEnabled:YES]; + [startButton setEnabled:YES]; + [pvrSearchField setEnabled:YES]; + } + @catch (NSException *e) { + NSLog(@"NO UI: updateCache:proxyError:"); + } if (proxyDict && [proxyDict[@"error"] code] == kProxyLoadCancelled) { [stopButton setEnabled:NO]; return; } - runSinceChange=YES; - runUpdate=YES; - didUpdate=NO; - [mainWindow setDocumentEdited:YES]; - - NSArray *tempQueue = [queueController arrangedObjects]; - for (Programme *show in tempQueue) - { - if (show.successful.boolValue) - { - [queueController removeObject:show]; - } - } - - //UI might not be loaded yet - @try - { - //Update Should Be Running: - [currentIndicator setIndeterminate:YES]; - [currentIndicator startAnimation:nil]; - [currentProgress setStringValue:@"Updating Program Indexes..."]; - //Shouldn't search until update is done. - [searchField setEnabled:NO]; - [stopButton setEnabled:NO]; - [startButton setEnabled:NO]; - [pvrSearchField setEnabled:NO]; - } - @catch (NSException *e) { - NSLog(@"NO UI"); - } - - HTTPProxy *proxy; - if (proxyDict) { - proxy = proxyDict[@"proxy"]; - } - - if (![[[NSUserDefaults standardUserDefaults] objectForKey:@"QuickCache"] boolValue] || quickUpdateFailed) - { - quickUpdateFailed=NO; - - NSString *cacheExpiryArg; - if ([[sender class] isEqualTo:[@"" class]]) - { - cacheExpiryArg = @"-e1"; - } - else - { - cacheExpiryArg = [[NSString alloc] initWithFormat:@"-e%d", ([[[NSUserDefaults standardUserDefaults] objectForKey:@"CacheExpiryTime"] intValue]*3600)]; - } - - NSString *typeArgument = [[GetiPlayerArguments sharedController] typeArgumentForCacheUpdate:YES]; - - getiPlayerUpdateArgs = @[getiPlayerPath,cacheExpiryArg,typeArgument,@"--nopurge",[GetiPlayerArguments sharedController].profileDirArg]; - - if (proxy && [[[NSUserDefaults standardUserDefaults] valueForKey:@"AlwaysUseProxy"] boolValue]) - { - getiPlayerUpdateArgs = [getiPlayerUpdateArgs arrayByAddingObject:[[NSString alloc] initWithFormat:@"-p%@", [proxy url]]]; - } - - [logger addToLog:@"Updating Program Index Feeds...\r" :self]; - - - getiPlayerUpdateTask = [[NSTask alloc] init]; - [getiPlayerUpdateTask setLaunchPath:@"/usr/bin/perl"]; - [getiPlayerUpdateTask setArguments:getiPlayerUpdateArgs]; - getiPlayerUpdatePipe = [[NSPipe alloc] init]; - [getiPlayerUpdateTask setStandardOutput:getiPlayerUpdatePipe]; - [getiPlayerUpdateTask setStandardError:getiPlayerUpdatePipe]; - - NSFileHandle *fh = [getiPlayerUpdatePipe fileHandleForReading]; - NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; - - [nc addObserver:self - selector:@selector(dataReady:) - name:NSFileHandleReadCompletionNotification - object:fh]; - NSMutableDictionary *envVariableDictionary = [NSMutableDictionary dictionaryWithDictionary:[getiPlayerUpdateTask environment]]; - envVariableDictionary[@"HOME"] = [@"~" stringByExpandingTildeInPath]; - envVariableDictionary[@"PERL_UNICODE"] = @"AS"; - [getiPlayerUpdateTask setEnvironment:envVariableDictionary]; - [getiPlayerUpdateTask launch]; - - [fh readInBackgroundAndNotify]; - } - else - { - [logger addToLog:@"Updating Program Index Feeds from Server..." :nil]; - - NSLog(@"DEBUG: Last cache update: %@",lastUpdate); - - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - if (!lastUpdate || ([[NSDate date] timeIntervalSinceDate:lastUpdate] > ([[defaults objectForKey:@"CacheExpiryTime"] intValue]*3600)) || [[sender class] isEqualTo:[@"" class]]) - { - typesToCache = [[NSMutableArray alloc] initWithCapacity:5]; - if ([[defaults objectForKey:@"CacheBBC_TV"] boolValue]) [typesToCache addObject:@"tv"]; - if ([[defaults objectForKey:@"CacheITV_TV"] boolValue]) [typesToCache addObject:@"itv"]; - if ([[defaults objectForKey:@"CacheBBC_Radio"] boolValue]) [typesToCache addObject:@"radio"]; - if ([[defaults objectForKey:@"CacheBBC_Podcasts"] boolValue]) [typesToCache addObject:@"podcast"]; - // TODO: Remove 4oD - if ([[defaults objectForKey:@"Cache4oD_TV"] boolValue]) [typesToCache addObject:@"ch4"]; - - NSArray *urlKeys = @[@"tv",@"itv",@"radio",@"podcast",@"ch4"]; - NSArray *urlObjects = @[@"http://tom-tech.com/get_iplayer/cache/tv.cache", - @"http://tom-tech.com/get_iplayer/cache/itv.cache", - @"http://tom-tech.com/get_iplayer/cache/radio.cache", - @"http://tom-tech.com/get_iplayer/cache/podcast.cache", - @"http://tom-tech.com/get_iplayer/cache/ch4.cache"]; - updateURLDic = [[NSDictionary alloc] initWithObjects:urlObjects forKeys:urlKeys]; - - nextToCache=0; - if ([typesToCache count] > 0) - [self updateCacheForType:typesToCache[0]]; - } - else [self getiPlayerUpdateFinished]; - - } + runSinceChange=YES; + runUpdate=YES; + didUpdate=NO; + [mainWindow setDocumentEdited:YES]; + + NSArray *tempQueue = [queueController arrangedObjects]; + for (Programme *show in tempQueue) + { + if (show.successful.boolValue) + { + [queueController removeObject:show]; + } + } + + //UI might not be loaded yet + @try + { + //Update Should Be Running: + [currentIndicator setIndeterminate:YES]; + [currentIndicator startAnimation:nil]; + [currentProgress setStringValue:@"Updating Program Indexes..."]; + //Shouldn't search until update is done. + [searchField setEnabled:NO]; + [stopButton setEnabled:NO]; + [startButton setEnabled:NO]; + [pvrSearchField setEnabled:NO]; + } + @catch (NSException *e) { + NSLog(@"NO UI"); + } + + HTTPProxy *proxy; + if (proxyDict) { + proxy = proxyDict[@"proxy"]; + } + + if (![[[NSUserDefaults standardUserDefaults] objectForKey:@"QuickCache"] boolValue] || quickUpdateFailed) + { + quickUpdateFailed=NO; + + NSString *cacheExpiryArg; + if ([[sender class] isEqualTo:[@"" class]]) + { + cacheExpiryArg = @"-e1"; + } + else + { + cacheExpiryArg = [[NSString alloc] initWithFormat:@"-e%d", ([[[NSUserDefaults standardUserDefaults] objectForKey:@"CacheExpiryTime"] intValue]*3600)]; + } + + NSString *typeArgument = [[GetiPlayerArguments sharedController] typeArgumentForCacheUpdate:YES]; + + getiPlayerUpdateArgs = @[getiPlayerPath,cacheExpiryArg,typeArgument,@"--nopurge",[GetiPlayerArguments sharedController].profileDirArg]; + + if (proxy && [[[NSUserDefaults standardUserDefaults] valueForKey:@"AlwaysUseProxy"] boolValue]) + { + getiPlayerUpdateArgs = [getiPlayerUpdateArgs arrayByAddingObject:[[NSString alloc] initWithFormat:@"-p%@", [proxy url]]]; + } + + [logger addToLog:@"Updating Program Index Feeds...\r" :self]; + + + getiPlayerUpdateTask = [[NSTask alloc] init]; + [getiPlayerUpdateTask setLaunchPath:@"/usr/bin/perl"]; + [getiPlayerUpdateTask setArguments:getiPlayerUpdateArgs]; + getiPlayerUpdatePipe = [[NSPipe alloc] init]; + [getiPlayerUpdateTask setStandardOutput:getiPlayerUpdatePipe]; + [getiPlayerUpdateTask setStandardError:getiPlayerUpdatePipe]; + + NSFileHandle *fh = [getiPlayerUpdatePipe fileHandleForReading]; + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + + [nc addObserver:self + selector:@selector(dataReady:) + name:NSFileHandleReadCompletionNotification + object:fh]; + NSMutableDictionary *envVariableDictionary = [NSMutableDictionary dictionaryWithDictionary:[getiPlayerUpdateTask environment]]; + envVariableDictionary[@"HOME"] = [@"~" stringByExpandingTildeInPath]; + envVariableDictionary[@"PERL_UNICODE"] = @"AS"; + [getiPlayerUpdateTask setEnvironment:envVariableDictionary]; + [getiPlayerUpdateTask launch]; + + [fh readInBackgroundAndNotify]; + } + else + { + [logger addToLog:@"Updating Program Index Feeds from Server..." :nil]; + + NSLog(@"DEBUG: Last cache update: %@",lastUpdate); + + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + if (!lastUpdate || ([[NSDate date] timeIntervalSinceDate:lastUpdate] > ([[defaults objectForKey:@"CacheExpiryTime"] intValue]*3600)) || [[sender class] isEqualTo:[@"" class]]) + { + typesToCache = [[NSMutableArray alloc] initWithCapacity:5]; + if ([[defaults objectForKey:@"CacheBBC_TV"] boolValue]) [typesToCache addObject:@"tv"]; + if ([[defaults objectForKey:@"CacheITV_TV"] boolValue]) [typesToCache addObject:@"itv"]; + if ([[defaults objectForKey:@"CacheBBC_Radio"] boolValue]) [typesToCache addObject:@"radio"]; + if ([[defaults objectForKey:@"CacheBBC_Podcasts"] boolValue]) [typesToCache addObject:@"podcast"]; + // TODO: Remove 4oD + if ([[defaults objectForKey:@"Cache4oD_TV"] boolValue]) [typesToCache addObject:@"ch4"]; + + NSArray *urlKeys = @[@"tv",@"itv",@"radio",@"podcast",@"ch4"]; + NSArray *urlObjects = @[@"http://tom-tech.com/get_iplayer/cache/tv.cache", + @"http://tom-tech.com/get_iplayer/cache/itv.cache", + @"http://tom-tech.com/get_iplayer/cache/radio.cache", + @"http://tom-tech.com/get_iplayer/cache/podcast.cache", + @"http://tom-tech.com/get_iplayer/cache/ch4.cache"]; + updateURLDic = [[NSDictionary alloc] initWithObjects:urlObjects forKeys:urlKeys]; + + nextToCache=0; + if ([typesToCache count] > 0) + [self updateCacheForType:typesToCache[0]]; + } + else [self getiPlayerUpdateFinished]; + + } } - (void)updateCacheForType:(NSString *)type { - [logger addToLog:[NSString stringWithFormat:@" Retrieving %@ index feeds.",type] :nil]; - [currentProgress setStringValue:[NSString stringWithFormat:@"Updating Program Indexes: Getting %@ index feeds from server...",type]]; - - ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:updateURLDic[type]]]; - [request setDelegate:self]; - [request setDidFinishSelector:@selector(indexRequestFinished:)]; - [request setDidFailSelector:@selector(indexRequestFinished:)]; - [request setTimeOutSeconds:10]; - [request setNumberOfTimesToRetryOnTimeout:2]; - [request setDownloadDestinationPath:[[@"~/Library/Application Support/Get iPlayer Automator" stringByExpandingTildeInPath] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.cache",type]]]; - [request startAsynchronous]; + [logger addToLog:[NSString stringWithFormat:@" Retrieving %@ index feeds.",type] :nil]; + [currentProgress setStringValue:[NSString stringWithFormat:@"Updating Program Indexes: Getting %@ index feeds from server...",type]]; + + ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:updateURLDic[type]]]; + [request setDelegate:self]; + [request setDidFinishSelector:@selector(indexRequestFinished:)]; + [request setDidFailSelector:@selector(indexRequestFinished:)]; + [request setTimeOutSeconds:10]; + [request setNumberOfTimesToRetryOnTimeout:2]; + [request setDownloadDestinationPath:[[@"~/Library/Application Support/Get iPlayer Automator" stringByExpandingTildeInPath] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.cache",type]]]; + [request startAsynchronous]; } - (void)indexRequestFinished:(ASIHTTPRequest *)request { - if ([request responseStatusCode] != 200) - { - quickUpdateFailed=YES; - [self updateCache:@""]; - } - else - { - didUpdate=YES; - nextToCache++; - if (nextToCache < [typesToCache count]) - [self updateCacheForType:typesToCache[nextToCache]]; - else - { - [self getiPlayerUpdateFinished]; - } - } + if ([request responseStatusCode] != 200) + { + quickUpdateFailed=YES; + [self updateCache:@""]; + } + else + { + didUpdate=YES; + nextToCache++; + if (nextToCache < [typesToCache count]) + [self updateCacheForType:typesToCache[nextToCache]]; + else + { + [self getiPlayerUpdateFinished]; + } + } } - (void)dataReady:(NSNotification *)n { - NSData *d; - d = [[n userInfo] valueForKey:NSFileHandleNotificationDataItem]; - BOOL matches=NO; - if ([d length] > 0) { - NSString *s = [[NSString alloc] initWithData:d - encoding:NSUTF8StringEncoding]; - if ([s hasPrefix:@"INFO:"]) - { - [logger addToLog:[NSString stringWithString:s] :nil]; - NSScanner *scanner = [NSScanner scannerWithString:s]; - NSString *r; - [scanner scanUpToCharactersFromSet:[NSCharacterSet newlineCharacterSet] intoString:&r]; - NSString *infoMessage = [[NSString alloc] initWithFormat:@"Updating Program Indexes: %@", r]; - [currentProgress setStringValue:infoMessage]; - infoMessage = nil; - scanner = nil; - } - else if ([s hasPrefix:@"WARNING:"] || [s hasPrefix:@"ERROR:"]) - { - [logger addToLog:s :nil]; - } - else if ([s isEqualToString:@"."]) - { - NSMutableString *infomessage = [[NSMutableString alloc] initWithFormat:@"%@.", [currentProgress stringValue]]; - if ([infomessage hasSuffix:@".........."]) [infomessage deleteCharactersInRange:NSMakeRange([infomessage length]-9, 9)]; - [currentProgress setStringValue:infomessage]; - infomessage = nil; - didUpdate = YES; - } - else if ([s hasPrefix:@"Matches:"]) - { - matches=YES; - getiPlayerUpdateTask=nil; - [self getiPlayerUpdateFinished]; - } - } - else - { - getiPlayerUpdateTask = nil; - [self getiPlayerUpdateFinished]; - } - - // If the task is running, start reading again - if (getiPlayerUpdateTask && !matches) - [[getiPlayerUpdatePipe fileHandleForReading] readInBackgroundAndNotify]; + NSData *d; + d = [[n userInfo] valueForKey:NSFileHandleNotificationDataItem]; + BOOL matches=NO; + if ([d length] > 0) { + NSString *s = [[NSString alloc] initWithData:d + encoding:NSUTF8StringEncoding]; + if ([s hasPrefix:@"INFO:"]) + { + [logger addToLog:[NSString stringWithString:s] :nil]; + NSScanner *scanner = [NSScanner scannerWithString:s]; + NSString *r; + [scanner scanUpToCharactersFromSet:[NSCharacterSet newlineCharacterSet] intoString:&r]; + NSString *infoMessage = [[NSString alloc] initWithFormat:@"Updating Program Indexes: %@", r]; + [currentProgress setStringValue:infoMessage]; + infoMessage = nil; + scanner = nil; + } + else if ([s hasPrefix:@"WARNING:"] || [s hasPrefix:@"ERROR:"]) + { + [logger addToLog:s :nil]; + } + else if ([s isEqualToString:@"."]) + { + NSMutableString *infomessage = [[NSMutableString alloc] initWithFormat:@"%@.", [currentProgress stringValue]]; + if ([infomessage hasSuffix:@".........."]) [infomessage deleteCharactersInRange:NSMakeRange([infomessage length]-9, 9)]; + [currentProgress setStringValue:infomessage]; + infomessage = nil; + didUpdate = YES; + } + else if ([s hasPrefix:@"Matches:"]) + { + matches=YES; + getiPlayerUpdateTask=nil; + [self getiPlayerUpdateFinished]; + } + } + else + { + getiPlayerUpdateTask = nil; + [self getiPlayerUpdateFinished]; + } + + // If the task is running, start reading again + if (getiPlayerUpdateTask && !matches) + [[getiPlayerUpdatePipe fileHandleForReading] readInBackgroundAndNotify]; } - (void)getiPlayerUpdateFinished { - runUpdate=NO; - [mainWindow setDocumentEdited:NO]; - - [currentProgress setStringValue:@""]; - [currentIndicator setIndeterminate:NO]; - [currentIndicator stopAnimation:nil]; - [searchField setEnabled:YES]; - getiPlayerUpdatePipe = nil; - getiPlayerUpdateTask = nil; - [startButton setEnabled:YES]; - [pvrSearchField setEnabled:YES]; - - - if (didUpdate) - { - @try - { - [GrowlApplicationBridge notifyWithTitle:@"Index Updated" - description:@"The program index was updated." - notificationName:@"Index Updating Completed" - iconData:nil - priority:0 - isSticky:NO - clickContext:nil]; - } - @catch (NSException *e) { - NSLog(@"ERROR: Growl notification failed (getiPlayerUpdateFinished): %@: %@", [e name], [e description]); - [logger addToLog:[NSString stringWithFormat:@"ERROR: Growl notification failed (getiPlayerUpdateFinished): %@: %@", [e name], [e description]]]; - } - [logger addToLog:@"Index Updated." :self]; - lastUpdate=[NSDate date]; - } - else - { - runSinceChange=NO; - [logger addToLog:@"Index was Up-To-Date." :self]; - } - - - //Long, Complicated Bit of Code that updates the index number. - //This is neccessary because if the cache is updated, the index number will almost certainly change. - NSArray *tempQueue = [queueController arrangedObjects]; - for (Programme *show in tempQueue) - { - BOOL foundMatch=NO; - if ([[show showName] length] > 0) - { - NSTask *pipeTask = [[NSTask alloc] init]; - NSPipe *newPipe = [[NSPipe alloc] init]; - NSFileHandle *readHandle2 = [newPipe fileHandleForReading]; - NSData *someData; - - NSString *name = [[show showName] copy]; - NSScanner *scanner = [NSScanner scannerWithString:name]; - NSString *searchArgument; - [scanner scanUpToString:@" - " intoString:&searchArgument]; - // write handle is closed to this process - [pipeTask setStandardOutput:newPipe]; - [pipeTask setStandardError:newPipe]; - [pipeTask setLaunchPath:@"/usr/bin/perl"]; - [pipeTask setArguments:@[getiPlayerPath,[GetiPlayerArguments sharedController].profileDirArg,@"--nopurge",[GetiPlayerArguments sharedController].noWarningArg,[[GetiPlayerArguments sharedController] typeArgumentForCacheUpdate:NO],[[GetiPlayerArguments sharedController] cacheExpiryArgument:nil],[GetiPlayerArguments sharedController].standardListFormat, - searchArgument]]; - NSMutableString *taskData = [[NSMutableString alloc] initWithString:@""]; - NSMutableDictionary *envVariableDictionary = [NSMutableDictionary dictionaryWithDictionary:[pipeTask environment]]; - envVariableDictionary[@"HOME"] = [@"~" stringByExpandingTildeInPath]; - envVariableDictionary[@"PERL_UNICODE"] = @"AS"; - [pipeTask setEnvironment:envVariableDictionary]; - [pipeTask launch]; - while ((someData = [readHandle2 availableData]) && [someData length]) { - [taskData appendString:[[NSString alloc] initWithData:someData - encoding:NSUTF8StringEncoding]]; - } - NSString *string = [NSString stringWithString:taskData]; - NSArray *array = [string componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]; - for (NSString *string in array) - { - if (![string isEqualToString:@"Matches:"] && ![string hasPrefix:@"INFO:"] && ![string hasPrefix:@"WARNING:"] && [string length]>0) + runUpdate=NO; + [mainWindow setDocumentEdited:NO]; + + [currentProgress setStringValue:@""]; + [currentIndicator setIndeterminate:NO]; + [currentIndicator stopAnimation:nil]; + [searchField setEnabled:YES]; + getiPlayerUpdatePipe = nil; + getiPlayerUpdateTask = nil; + [startButton setEnabled:YES]; + [pvrSearchField setEnabled:YES]; + + + if (didUpdate) + { + @try + { + [GrowlApplicationBridge notifyWithTitle:@"Index Updated" + description:@"The program index was updated." + notificationName:@"Index Updating Completed" + iconData:nil + priority:0 + isSticky:NO + clickContext:nil]; + } + @catch (NSException *e) { + NSLog(@"ERROR: Growl notification failed (getiPlayerUpdateFinished): %@: %@", [e name], [e description]); + [logger addToLog:[NSString stringWithFormat:@"ERROR: Growl notification failed (getiPlayerUpdateFinished): %@: %@", [e name], [e description]]]; + } + [logger addToLog:@"Index Updated." :self]; + lastUpdate=[NSDate date]; + } + else + { + runSinceChange=NO; + [logger addToLog:@"Index was Up-To-Date." :self]; + } + + + //Long, Complicated Bit of Code that updates the index number. + //This is neccessary because if the cache is updated, the index number will almost certainly change. + NSArray *tempQueue = [queueController arrangedObjects]; + for (Programme *show in tempQueue) + { + BOOL foundMatch=NO; + if ([[show showName] length] > 0) + { + NSTask *pipeTask = [[NSTask alloc] init]; + NSPipe *newPipe = [[NSPipe alloc] init]; + NSFileHandle *readHandle2 = [newPipe fileHandleForReading]; + NSData *someData; + + NSString *name = [[show showName] copy]; + NSScanner *scanner = [NSScanner scannerWithString:name]; + NSString *searchArgument; + [scanner scanUpToString:@" - " intoString:&searchArgument]; + // write handle is closed to this process + [pipeTask setStandardOutput:newPipe]; + [pipeTask setStandardError:newPipe]; + [pipeTask setLaunchPath:@"/usr/bin/perl"]; + [pipeTask setArguments:@[getiPlayerPath,[GetiPlayerArguments sharedController].profileDirArg,@"--nopurge",[GetiPlayerArguments sharedController].noWarningArg,[[GetiPlayerArguments sharedController] typeArgumentForCacheUpdate:NO],[[GetiPlayerArguments sharedController] cacheExpiryArgument:nil],[GetiPlayerArguments sharedController].standardListFormat, + searchArgument]]; + NSMutableString *taskData = [[NSMutableString alloc] initWithString:@""]; + NSMutableDictionary *envVariableDictionary = [NSMutableDictionary dictionaryWithDictionary:[pipeTask environment]]; + envVariableDictionary[@"HOME"] = [@"~" stringByExpandingTildeInPath]; + envVariableDictionary[@"PERL_UNICODE"] = @"AS"; + [pipeTask setEnvironment:envVariableDictionary]; + [pipeTask launch]; + while ((someData = [readHandle2 availableData]) && [someData length]) { + [taskData appendString:[[NSString alloc] initWithData:someData + encoding:NSUTF8StringEncoding]]; + } + NSString *string = [NSString stringWithString:taskData]; + NSArray *array = [string componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]; + for (NSString *string in array) { - @try - { - NSScanner *myScanner = [NSScanner scannerWithString:string]; - Programme *p = [[Programme alloc] init]; - NSString *temp_pid, *temp_showName, *temp_tvNetwork, *temp_type, *url; - [myScanner scanUpToString:@":" intoString:&temp_pid]; - [myScanner scanUpToString:@"," intoString:&temp_type]; - [myScanner scanString:@", ~" intoString:NULL]; - [myScanner scanUpToString:@"~," intoString:&temp_showName]; - [myScanner scanString:@"~," intoString:NULL]; - [myScanner scanUpToString:@"," intoString:&temp_tvNetwork]; - [myScanner scanString:@"," intoString:nil]; - [myScanner scanUpToString:@"kljkjkj" intoString:&url]; - - if ([temp_showName hasSuffix:@" - -"]) - { - NSString *temp_showName2; - NSScanner *dashScanner = [NSScanner scannerWithString:temp_showName]; - [dashScanner scanUpToString:@" - -" intoString:&temp_showName2]; - temp_showName = temp_showName2; - temp_showName = [temp_showName stringByAppendingFormat:@" - %@", temp_showName2]; - } - [p setValue:temp_pid forKey:@"pid"]; - [p setValue:temp_showName forKey:@"showName"]; - [p setValue:temp_tvNetwork forKey:@"tvNetwork"]; - [p setUrl:url]; - if ([temp_type isEqualToString:@"radio"]) [p setValue:@YES forKey:@"radio"]; - if ([[p showName] isEqualToString:[show showName]] || ([[p url] isEqualToString:[show url]] && [show url])) - { - [show setValue:[p pid] forKey:@"pid"]; - foundMatch=YES; - break; - } - } - @catch (NSException *e) { - NSAlert *searchException = [[NSAlert alloc] init]; - [searchException addButtonWithTitle:@"OK"]; - [searchException setMessageText:[NSString stringWithFormat:@"Invalid Output!"]]; - [searchException setInformativeText:@"Please check your query. Your query must not alter the output format of Get_iPlayer. (getiPlayerUpdateFinished)"]; - [searchException setAlertStyle:NSWarningAlertStyle]; - [searchException runModal]; - searchException = nil; - } + if (![string isEqualToString:@"Matches:"] && ![string hasPrefix:@"INFO:"] && ![string hasPrefix:@"WARNING:"] && [string length]>0) + { + @try + { + NSScanner *myScanner = [NSScanner scannerWithString:string]; + Programme *p = [[Programme alloc] init]; + NSString *temp_pid, *temp_showName, *temp_tvNetwork, *temp_type, *url; + [myScanner scanUpToString:@":" intoString:&temp_pid]; + [myScanner scanUpToString:@"," intoString:&temp_type]; + [myScanner scanString:@", ~" intoString:NULL]; + [myScanner scanUpToString:@"~," intoString:&temp_showName]; + [myScanner scanString:@"~," intoString:NULL]; + [myScanner scanUpToString:@"," intoString:&temp_tvNetwork]; + [myScanner scanString:@"," intoString:nil]; + [myScanner scanUpToString:@"kljkjkj" intoString:&url]; + + if ([temp_showName hasSuffix:@" - -"]) + { + NSString *temp_showName2; + NSScanner *dashScanner = [NSScanner scannerWithString:temp_showName]; + [dashScanner scanUpToString:@" - -" intoString:&temp_showName2]; + temp_showName = temp_showName2; + temp_showName = [temp_showName stringByAppendingFormat:@" - %@", temp_showName2]; + } + [p setValue:temp_pid forKey:@"pid"]; + [p setValue:temp_showName forKey:@"showName"]; + [p setValue:temp_tvNetwork forKey:@"tvNetwork"]; + [p setUrl:url]; + if ([temp_type isEqualToString:@"radio"]) [p setValue:@YES forKey:@"radio"]; + if ([[p showName] isEqualToString:[show showName]] || ([[p url] isEqualToString:[show url]] && [show url])) + { + [show setValue:[p pid] forKey:@"pid"]; + show.status = @"Available"; + foundMatch=YES; + break; + } + } + @catch (NSException *e) { + NSAlert *searchException = [[NSAlert alloc] init]; + [searchException addButtonWithTitle:@"OK"]; + [searchException setMessageText:[NSString stringWithFormat:@"Invalid Output!"]]; + [searchException setInformativeText:@"Please check your query. Your query must not alter the output format of Get_iPlayer. (getiPlayerUpdateFinished)"]; + [searchException setAlertStyle:NSWarningAlertStyle]; + [searchException runModal]; + searchException = nil; + } + } + else + { + if ([string hasPrefix:@"Unknown option:"] || [string hasPrefix:@"Option"] || [string hasPrefix:@"Usage"]) + { + NSLog(@"Unknown Option"); + } + } } - else + if (!foundMatch) { - if ([string hasPrefix:@"Unknown option:"] || [string hasPrefix:@"Option"] || [string hasPrefix:@"Usage"]) - { - NSLog(@"Unknown Option"); - } + show.status = @"Processing..."; + [show getName]; } - } - if (!foundMatch) - { - [show setValue:@"Not Found In Cache" forKey:@"status"]; - [show setValue:@YES forKey:@"complete"]; - [show setValue:@NO forKey:@"successful"]; - } - } - - } - - //Don't want to add these until the cache is up-to-date! - if ([[[NSUserDefaults standardUserDefaults] valueForKey:@"SeriesLinkStartup"] boolValue]) - { - NSLog(@"Checking series link"); - [self addSeriesLinkToQueue:self]; - } - else - { - if (runScheduled) - { - [self performSelectorOnMainThread:@selector(startDownloads:) withObject:self waitUntilDone:NO]; - } - } - - //Check for Updates - Don't want to prompt the user when updates are running. - SUUpdater *updater = [SUUpdater sharedUpdater]; - [updater checkForUpdatesInBackground]; - - if (runDownloads) - { - [logger addToLog:@"Download(s) are still running." :self]; - } + } + + } + + //Don't want to add these until the cache is up-to-date! + if ([[[NSUserDefaults standardUserDefaults] valueForKey:@"SeriesLinkStartup"] boolValue]) + { + NSLog(@"Checking series link"); + [self addSeriesLinkToQueue:self]; + } + else + { + if (runScheduled) + { + [self performSelectorOnMainThread:@selector(startDownloads:) withObject:self waitUntilDone:NO]; + } + } + + //Check for Updates - Don't want to prompt the user when updates are running. + SUUpdater *updater = [SUUpdater sharedUpdater]; + [updater checkForUpdatesInBackground]; + + if (runDownloads) + { + [logger addToLog:@"Download(s) are still running." :self]; + } } - (IBAction)forceUpdate:(id)sender { - [self updateCache:@"force"]; + [self updateCache:@"force"]; } #pragma mark Search - (IBAction)goToSearch:(id)sender { - [mainWindow makeKeyAndOrderFront:self]; - [mainWindow makeFirstResponder:searchField]; + [mainWindow makeKeyAndOrderFront:self]; + [mainWindow makeFirstResponder:searchField]; } - (IBAction)mainSearch:(id)sender { - if([searchField.stringValue length] > 0) - { - [searchField setEnabled:NO]; - [searchIndicator startAnimation:nil]; - [resultsController removeObjectsAtArrangedObjectIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [resultsController.arrangedObjects count])]]; - currentSearch = [[GiASearch alloc] initWithSearchTerms:searchField.stringValue - allowHidingOfDownloadedItems:YES - logController:logger - selector:@selector(searchFinished:) - withTarget:self]; - } + if([searchField.stringValue length] > 0) + { + [searchField setEnabled:NO]; + [searchIndicator startAnimation:nil]; + [resultsController removeObjectsAtArrangedObjectIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [resultsController.arrangedObjects count])]]; + currentSearch = [[GiASearch alloc] initWithSearchTerms:searchField.stringValue + allowHidingOfDownloadedItems:YES + logController:logger + selector:@selector(searchFinished:) + withTarget:self]; + } } - (void)searchFinished:(NSArray *)results { - [searchField setEnabled:YES]; - [resultsController addObjects:results]; - [resultsController setSelectionIndexes:[NSIndexSet indexSet]]; - [searchIndicator stopAnimation:nil]; - if (![results count]) - { - NSAlert *noneFound = [NSAlert alertWithMessageText:@"No Shows Found" - defaultButton:@"OK" - alternateButton:nil - otherButton:nil - informativeTextWithFormat:@"0 shows were found for your search terms. Please check your spelling!"]; - [noneFound runModal]; - } - currentSearch = nil; + [searchField setEnabled:YES]; + [resultsController addObjects:results]; + [resultsController setSelectionIndexes:[NSIndexSet indexSet]]; + [searchIndicator stopAnimation:nil]; + if (![results count]) + { + NSAlert *noneFound = [NSAlert alertWithMessageText:@"No Shows Found" + defaultButton:@"OK" + alternateButton:nil + otherButton:nil + informativeTextWithFormat:@"0 shows were found for your search terms. Please check your spelling!"]; + [noneFound runModal]; + } + currentSearch = nil; } #pragma mark Queue - (NSArray *)queueArray { - return [NSArray arrayWithArray:queueArray]; + return [NSArray arrayWithArray:queueArray]; } - (void)setQueueArray:(NSArray *)queue { - queueArray = [NSMutableArray arrayWithArray:queue]; + queueArray = [NSMutableArray arrayWithArray:queue]; } - (IBAction)addToQueue:(id)sender { - for (Programme *show in resultsController.selectedObjects) - { - if (![queueController.arrangedObjects containsObject:show]) - { - if (runDownloads) show.status = @"Waiting..."; - [queueController addObject:show]; - } - } + for (Programme *show in resultsController.selectedObjects) + { + if (![queueController.arrangedObjects containsObject:show]) + { + if (runDownloads) show.status = @"Waiting..."; + else show.status = @"Available"; + [queueController addObject:show]; + } + } } - (IBAction)getName:(id)sender { - for (Programme *p in queueController.selectedObjects) - { + for (Programme *p in queueController.selectedObjects) + { p.status = @"Processing..."; - [p performSelectorInBackground:@selector(getName) withObject:nil]; - } + [p performSelectorInBackground:@selector(getName) withObject:nil]; + } } - (IBAction)getCurrentWebpage:(id)sender { - Programme *p = [GetCurrentWebpage getCurrentWebpage:logger]; - if (p) [queueController addObject:p]; + Programme *p = [GetCurrentWebpage getCurrentWebpage:logger]; + if (p) [queueController addObject:p]; } - (IBAction)removeFromQueue:(id)sender { - //Check to make sure one of the shows isn't currently downloading. - if (runDownloads) - { - BOOL downloading=NO; - NSArray *selected = [queueController selectedObjects]; - for (Programme *show in selected) - { - if (![[show status] isEqualToString:@"Waiting..."] && ![[show complete] isEqualToNumber:@YES]) - { - downloading = YES; - } - } - if (downloading) - { - NSAlert *cantRemove = [NSAlert alertWithMessageText:@"A Selected Show is Currently Downloading." - defaultButton:@"OK" - alternateButton:nil - otherButton:nil - informativeTextWithFormat:@"You can not remove a show that is currently downloading. " - @"Please stop the downloads then remove the download if you wish to cancel it."]; - [cantRemove runModal]; - } - else - { - [queueController remove:self]; - } - } - else - { - [queueController remove:self]; - } + //Check to make sure one of the shows isn't currently downloading. + if (runDownloads) + { + BOOL downloading=NO; + NSArray *selected = [queueController selectedObjects]; + for (Programme *show in selected) + { + if (![[show status] isEqualToString:@"Waiting..."] && ![[show complete] isEqualToNumber:@YES]) + { + downloading = YES; + } + } + if (downloading) + { + NSAlert *cantRemove = [NSAlert alertWithMessageText:@"A Selected Show is Currently Downloading." + defaultButton:@"OK" + alternateButton:nil + otherButton:nil + informativeTextWithFormat:@"You can not remove a show that is currently downloading. " + @"Please stop the downloads then remove the download if you wish to cancel it."]; + [cantRemove runModal]; + } + else + { + [queueController remove:self]; + } + } + else + { + [queueController remove:self]; + } } - (IBAction)hidePvrShow:(id)sender { - NSArray *temp_queue = [queueController selectedObjects]; - for (Programme *show in temp_queue) - { - if ([show realPID] && [[show status] isEqualToString:@"Added by Series-Link"]) - { - NSDictionary *info = @{@"Programme": show}; - [[NSNotificationCenter defaultCenter] postNotificationName:@"AddProgToHistory" object:self userInfo:info]; - [queueController removeObject:show]; - } - } + NSArray *temp_queue = [queueController selectedObjects]; + for (Programme *show in temp_queue) + { + if ([show realPID] && [[show status] isEqualToString:@"Added by Series-Link"]) + { + NSDictionary *info = @{@"Programme": show}; + [[NSNotificationCenter defaultCenter] postNotificationName:@"AddProgToHistory" object:self userInfo:info]; + [queueController removeObject:show]; + } + } } #pragma mark Download Controller - (IBAction)startDownloads:(id)sender { - @try - { - [stopButton setEnabled:NO]; - [startButton setEnabled:NO]; - } - @catch (NSException *e) { - NSLog(@"NO UI: startDownloads:"); - } - [self saveAppData]; //Save data in case of crash. - getiPlayerProxy = [[GetiPlayerProxy alloc] initWithLogger:logger]; - [getiPlayerProxy loadProxyInBackgroundForSelector:@selector(startDownloads:proxyDict:) withObject:sender onTarget:self silently:runScheduled]; + @try + { + [stopButton setEnabled:NO]; + [startButton setEnabled:NO]; + } + @catch (NSException *e) { + NSLog(@"NO UI: startDownloads:"); + } + [self saveAppData]; //Save data in case of crash. + getiPlayerProxy = [[GetiPlayerProxy alloc] initWithLogger:logger]; + [getiPlayerProxy loadProxyInBackgroundForSelector:@selector(startDownloads:proxyDict:) withObject:sender onTarget:self silently:runScheduled]; } - (void)startDownloads:(id)sender proxyDict:(NSDictionary *)proxyDict { - getiPlayerProxy = nil; - // reset after proxy load - @try - { - [stopButton setEnabled:YES]; - } - @catch (NSException *e) { - NSLog(@"NO UI: startDownloads:proxyError:"); - } + getiPlayerProxy = nil; + // reset after proxy load + @try + { + [stopButton setEnabled:YES]; + } + @catch (NSException *e) { + NSLog(@"NO UI: startDownloads:proxyError:"); + } if (proxyDict && [proxyDict[@"error"] code] == kProxyLoadCancelled) { [startButton setEnabled:YES]; [stopButton setEnabled:NO]; return; } - - if (proxyDict) { - proxy = proxyDict[@"proxy"]; - } - - NSAlert *whatAnIdiot = [NSAlert alertWithMessageText:@"No Shows in Queue!" - defaultButton:nil - alternateButton:nil - otherButton:nil - informativeTextWithFormat:@"Try adding shows to the queue before clicking start; " - @"Get iPlayer Automator needs to know what to download."]; - if ([[queueController arrangedObjects] count] > 0) - { - NSLog(@"Initialising Failure Dictionary"); - if (!solutionsDictionary) - solutionsDictionary = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"ReasonsForFailure" ofType:@"plist"]]; - NSLog(@"Failure Dictionary Ready"); - - BOOL foundOne=NO; - runDownloads=YES; - runScheduled=NO; - [mainWindow setDocumentEdited:YES]; - [logger addToLog:@"\rAppController: Starting Downloads" :nil]; - - //Clean-Up Queue - NSArray *tempQueue = [queueController arrangedObjects]; - for (Programme *show in tempQueue) - { - if ([[show successful] isEqualToNumber:@NO]) - { - if ([[show processedPID] boolValue]) - { - [show setComplete:@NO]; - [show setStatus:@"Waiting..."]; - foundOne=YES; - } - else - { - [show getName]; - if ([[show showName] isEqualToString:@"Unknown - Not in Cache"]) - { - [show setComplete:@YES]; - [show setSuccessful:@NO]; - [show setStatus:@"Failed: Please set the show name"]; - [logger addToLog:@"Could not download. Please set a show name first." :self]; - } - else - { - [show setComplete:@NO]; - [show setStatus:@"Waiting..."]; - foundOne=YES; - } - } - } - else - { - [queueController removeObject:show]; - } - } - if (foundOne) - { - //Start First Download - IOPMAssertionCreateWithDescription(kIOPMAssertionTypePreventUserIdleSystemSleep, (CFStringRef)@"Downloading Show", (CFStringRef)@"GiA is downloading shows.", NULL, NULL, (double)0, NULL, &powerAssertionID); - - NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; - [nc addObserver:self selector:@selector(setPercentage:) name:@"setPercentage" object:nil]; - [nc addObserver:self selector:@selector(setProgress:) name:@"setCurrentProgress" object:nil]; - [nc addObserver:self selector:@selector(nextDownload:) name:@"DownloadFinished" object:nil]; - - tempQueue = [queueController arrangedObjects]; - [logger addToLog:[NSString stringWithFormat:@"\rDownloading Show %lu/%lu:\r", - (unsigned long)1, - (unsigned long)[tempQueue count]] - :nil]; - for (Programme *show in tempQueue) - { - if ([[show complete] isEqualToNumber:@NO]) - { - if ([[show tvNetwork] hasPrefix:@"ITV"]) - currentDownload = [[ITVDownload alloc] initWithProgramme:show itvFormats:[itvFormatController arrangedObjects] proxy:proxy logController:logger]; - /*else if ([[show tvNetwork] hasPrefix:@"4oD"]) - currentDownload = [[FourODDownload alloc] initWithProgramme:show proxy:proxy];*/ - else - currentDownload = [[BBCDownload alloc] initWithProgramme:show - tvFormats:[tvFormatController arrangedObjects] - radioFormats:[radioFormatController arrangedObjects] - proxy:proxy - logController:logger]; - break; - } - } - [startButton setEnabled:NO]; - [stopButton setEnabled:YES]; - - } - else - { - [whatAnIdiot runModal]; - runDownloads=NO; - [mainWindow setDocumentEdited:NO]; - } - } - else - { - runDownloads=NO; - [mainWindow setDocumentEdited:NO]; - if (!runScheduled) - [whatAnIdiot runModal]; - else if ([[[NSUserDefaults standardUserDefaults] valueForKey:@"AutoRetryFailed"] boolValue]) - { - NSDate *scheduledDate = [NSDate dateWithTimeIntervalSinceNow:60*[[[NSUserDefaults standardUserDefaults] valueForKey:@"AutoRetryTime"] doubleValue]]; - [datePicker setDateValue:scheduledDate]; - [self scheduleStart:self]; - } - else if (runScheduled) - runScheduled=NO; - } + + if (proxyDict) { + proxy = proxyDict[@"proxy"]; + } + + NSAlert *whatAnIdiot = [NSAlert alertWithMessageText:@"No Shows in Queue!" + defaultButton:nil + alternateButton:nil + otherButton:nil + informativeTextWithFormat:@"Try adding shows to the queue before clicking start; " + @"Get iPlayer Automator needs to know what to download."]; + if ([[queueController arrangedObjects] count] > 0) + { + NSLog(@"Initialising Failure Dictionary"); + if (!solutionsDictionary) + solutionsDictionary = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"ReasonsForFailure" ofType:@"plist"]]; + NSLog(@"Failure Dictionary Ready"); + + BOOL foundOne=NO; + runDownloads=YES; + runScheduled=NO; + [mainWindow setDocumentEdited:YES]; + [logger addToLog:@"\rAppController: Starting Downloads" :nil]; + + //Clean-Up Queue + NSArray *tempQueue = [queueController arrangedObjects]; + for (Programme *show in tempQueue) + { + if ([[show successful] isEqualToNumber:@NO]) + { + if ([[show processedPID] boolValue]) + { + [show setComplete:@NO]; + [show setStatus:@"Waiting..."]; + foundOne=YES; + } + else + { + [show getNameSynchronous]; + if ([[show showName] isEqualToString:@"Unknown - Not in Cache"]) + { + [show setComplete:@YES]; + [show setSuccessful:@NO]; + [show setStatus:@"Failed: Please set the show name"]; + [logger addToLog:@"Could not download. Please set a show name first." :self]; + } + else + { + [show setComplete:@NO]; + [show setStatus:@"Waiting..."]; + foundOne=YES; + } + } + } + else + { + [queueController removeObject:show]; + } + } + if (foundOne) + { + //Start First Download + IOPMAssertionCreateWithDescription(kIOPMAssertionTypePreventUserIdleSystemSleep, (CFStringRef)@"Downloading Show", (CFStringRef)@"GiA is downloading shows.", NULL, NULL, (double)0, NULL, &powerAssertionID); + + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc addObserver:self selector:@selector(setPercentage:) name:@"setPercentage" object:nil]; + [nc addObserver:self selector:@selector(setProgress:) name:@"setCurrentProgress" object:nil]; + [nc addObserver:self selector:@selector(nextDownload:) name:@"DownloadFinished" object:nil]; + + tempQueue = [queueController arrangedObjects]; + [logger addToLog:[NSString stringWithFormat:@"\rDownloading Show %lu/%lu:\r", + (unsigned long)1, + (unsigned long)[tempQueue count]] + :nil]; + for (Programme *show in tempQueue) + { + if ([[show complete] isEqualToNumber:@NO]) + { + if ([[show tvNetwork] hasPrefix:@"ITV"]) + currentDownload = [[ITVDownload alloc] initWithProgramme:show itvFormats:[itvFormatController arrangedObjects] proxy:proxy logController:logger]; + /*else if ([[show tvNetwork] hasPrefix:@"4oD"]) + currentDownload = [[FourODDownload alloc] initWithProgramme:show proxy:proxy];*/ + else + currentDownload = [[BBCDownload alloc] initWithProgramme:show + tvFormats:[tvFormatController arrangedObjects] + radioFormats:[radioFormatController arrangedObjects] + proxy:proxy + logController:logger]; + break; + } + } + [startButton setEnabled:NO]; + [stopButton setEnabled:YES]; + + } + else + { + [whatAnIdiot runModal]; + runDownloads=NO; + [mainWindow setDocumentEdited:NO]; + } + } + else + { + runDownloads=NO; + [mainWindow setDocumentEdited:NO]; + if (!runScheduled) + [whatAnIdiot runModal]; + else if ([[[NSUserDefaults standardUserDefaults] valueForKey:@"AutoRetryFailed"] boolValue]) + { + NSDate *scheduledDate = [NSDate dateWithTimeIntervalSinceNow:60*[[[NSUserDefaults standardUserDefaults] valueForKey:@"AutoRetryTime"] doubleValue]]; + [datePicker setDateValue:scheduledDate]; + [self scheduleStart:self]; + } + else if (runScheduled) + runScheduled=NO; + } } - (IBAction)stopDownloads:(id)sender { - IOPMAssertionRelease(powerAssertionID); - - runDownloads=NO; - runScheduled=NO; - [currentDownload cancelDownload:self]; - [[currentDownload show] setStatus:@"Cancelled"]; - if (!runUpdate) - [startButton setEnabled:YES]; - [stopButton setEnabled:NO]; - [currentIndicator stopAnimation:nil]; - [currentIndicator setDoubleValue:0]; - if (!runUpdate) - { - [currentProgress setStringValue:@""]; - [mainWindow setDocumentEdited:NO]; - } - - NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; - [nc removeObserver:self name:@"setPercentage" object:nil]; - [nc removeObserver:self name:@"setCurrentProgress" object:nil]; - [nc removeObserver:self name:@"DownloadFinished" object:nil]; - - NSArray *tempQueue = [queueController arrangedObjects]; - for (Programme *show in tempQueue) - if ([[show status] isEqualToString:@"Waiting..."]) [show setStatus:@""]; - - [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(fixDownloadStatus:) userInfo:currentDownload repeats:NO]; + IOPMAssertionRelease(powerAssertionID); + + runDownloads=NO; + runScheduled=NO; + [currentDownload cancelDownload:self]; + [[currentDownload show] setStatus:@"Cancelled"]; + if (!runUpdate) + [startButton setEnabled:YES]; + [stopButton setEnabled:NO]; + [currentIndicator stopAnimation:nil]; + [currentIndicator setDoubleValue:0]; + if (!runUpdate) + { + [currentProgress setStringValue:@""]; + [mainWindow setDocumentEdited:NO]; + } + + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc removeObserver:self name:@"setPercentage" object:nil]; + [nc removeObserver:self name:@"setCurrentProgress" object:nil]; + [nc removeObserver:self name:@"DownloadFinished" object:nil]; + + NSArray *tempQueue = [queueController arrangedObjects]; + for (Programme *show in tempQueue) + if ([[show status] isEqualToString:@"Waiting..."]) [show setStatus:@""]; + + [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(fixDownloadStatus:) userInfo:currentDownload repeats:NO]; } - (void)fixDownloadStatus:(NSNotification *)note { - if (!runDownloads) - { - [[(Download*)[note userInfo] show] setValue:@"Cancelled" forKey:@"status"]; - currentDownload=nil; - NSLog(@"Download should read cancelled"); - } - else - NSLog(@"fixDownloadStatus handler did not run because downloads appear to be running again"); + if (!runDownloads) + { + [[(Download*)[note userInfo] show] setValue:@"Cancelled" forKey:@"status"]; + currentDownload=nil; + NSLog(@"Download should read cancelled"); + } + else + NSLog(@"fixDownloadStatus handler did not run because downloads appear to be running again"); } - (void)setPercentage:(NSNotification *)note { - if ([note userInfo]) - { - if (note.userInfo[@"indeterminate"]) { - [currentIndicator setIndeterminate:[note.userInfo[@"indeterminate"] boolValue]]; - } - if (note.userInfo[@"animated"]) { - if ([note.userInfo[@"animated"] boolValue]) { + if ([note userInfo]) + { + if (note.userInfo[@"indeterminate"]) { + [currentIndicator setIndeterminate:[note.userInfo[@"indeterminate"] boolValue]]; + } + if (note.userInfo[@"animated"]) { + if ([note.userInfo[@"animated"] boolValue]) { + [currentIndicator startAnimation:nil]; + } + else { + [currentIndicator stopAnimation:nil]; + } + } + if (note.userInfo[@"nsDouble"]) { + NSDictionary *userInfo = [note userInfo]; + [currentIndicator setIndeterminate:NO]; [currentIndicator startAnimation:nil]; - } - else { - [currentIndicator stopAnimation:nil]; - } - } - if (note.userInfo[@"nsDouble"]) { - NSDictionary *userInfo = [note userInfo]; - [currentIndicator setIndeterminate:NO]; - [currentIndicator startAnimation:nil]; - [currentIndicator setMinValue:0]; - [currentIndicator setMaxValue:100]; - [currentIndicator setDoubleValue:[[userInfo valueForKey:@"nsDouble"] doubleValue]]; - } - } - else - { - [currentIndicator setIndeterminate:YES]; - [currentIndicator startAnimation:nil]; - } + [currentIndicator setMinValue:0]; + [currentIndicator setMaxValue:100]; + [currentIndicator setDoubleValue:[[userInfo valueForKey:@"nsDouble"] doubleValue]]; + } + } + else + { + [currentIndicator setIndeterminate:YES]; + [currentIndicator startAnimation:nil]; + } } - (void)setProgress:(NSNotification *)note { - if (!runUpdate) - [currentProgress setStringValue:[[note userInfo] valueForKey:@"string"]]; - if (runDownloads) - { - [startButton setEnabled:NO]; - [stopButton setEnabled:YES]; - [mainWindow setDocumentEdited:YES]; - } + if (!runUpdate) + [currentProgress setStringValue:[[note userInfo] valueForKey:@"string"]]; + if (runDownloads) + { + [startButton setEnabled:NO]; + [stopButton setEnabled:YES]; + [mainWindow setDocumentEdited:YES]; + } } - (void)nextDownload:(NSNotification *)note { - if (runDownloads) - { - Programme *finishedShow = [note object]; - if ([[finishedShow successful] boolValue]) - { - [finishedShow setValue:@"Processing..." forKey:@"status"]; - if ([[[finishedShow path] pathExtension] isEqualToString:@"mov"]) - { - [self cleanUpPath:finishedShow]; - [self seasonEpisodeInfo:finishedShow]; - } - if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"AddCompletedToiTunes"] isEqualTo:@YES]) - [NSThread detachNewThreadSelector:@selector(addToiTunesThread:) toTarget:self withObject:finishedShow]; - else - [finishedShow setValue:@"Download Complete" forKey:@"status"]; - - @try - { - [GrowlApplicationBridge notifyWithTitle:@"Download Finished" - description:[NSString stringWithFormat:@"%@ Completed Successfully",[finishedShow showName]] - notificationName:@"Download Finished" - iconData:nil - priority:0 - isSticky:NO - clickContext:nil]; - } - @catch (NSException *e) { - NSLog(@"ERROR: Growl notification failed (nextDownload - finished): %@: %@", [e name], [e description]); - [logger addToLog:[NSString stringWithFormat:@"ERROR: Growl notification failed (nextDownload - finished): %@: %@", [e name], [e description]]]; - } - } - else - { - @try - { - [GrowlApplicationBridge notifyWithTitle:@"Download Failed" - description:[NSString stringWithFormat:@"%@ failed. See log for details.",[finishedShow showName]] - notificationName:@"Download Failed" - iconData:nil - priority:0 - isSticky:NO - clickContext:nil]; - } - @catch (NSException *e) { - NSLog(@"ERROR: Growl notification failed (nextDownload - failed): %@: %@", [e name], [e description]); - [logger addToLog:[NSString stringWithFormat:@"ERROR: Growl notification failed (nextDownload - failed): %@: %@", [e name], [e description]]]; - } - - ReasonForFailure *showSolution = [[ReasonForFailure alloc] init]; - [showSolution setShowName:[finishedShow showName]]; - [showSolution setSolution:solutionsDictionary[finishedShow.reasonForFailure]]; - if (![showSolution solution]) - [showSolution setSolution:@"Problem Unknown.\nPlease submit a bug report from the application menu."]; - NSLog(@"Reason for Failure: %@", [finishedShow reasonForFailure]); - NSLog(@"Dictionary Lookup: %@", [solutionsDictionary valueForKey:[finishedShow reasonForFailure]]); - NSLog(@"Solution: %@", [showSolution solution]); - [solutionsArrayController addObject:showSolution]; - NSLog(@"Added Solution"); - [solutionsTableView setRowHeight:68]; - } - - [self saveAppData]; //Save app data in case of crash. - - NSArray *tempQueue = [queueController arrangedObjects]; - Programme *nextShow=nil; - NSUInteger showNum=0; - @try - { - for (Programme *show in tempQueue) - { - showNum++; - if (![[show complete] boolValue]) - { - nextShow = show; - break; - } - } - if (nextShow==nil) - { - NSException *noneLeft = [NSException exceptionWithName:@"EndOfDownloads" reason:@"Done" userInfo:nil]; - [noneLeft raise]; - } - [logger addToLog:[NSString stringWithFormat:@"\rDownloading Show %lu/%lu:\r", - (unsigned long)([tempQueue indexOfObject:nextShow]+1), - (unsigned long)[tempQueue count]] - :nil]; - if ([[nextShow complete] isEqualToNumber:@NO]) - { - if ([[nextShow tvNetwork] hasPrefix:@"ITV"]) - currentDownload = [[ITVDownload alloc] initWithProgramme:nextShow itvFormats:[itvFormatController arrangedObjects] proxy:proxy logController:logger]; - /*else if ([[nextShow tvNetwork] hasPrefix:@"4oD"]) - currentDownload = [[FourODDownload alloc] initWithProgramme:nextShow proxy:proxy];*/ + if (runDownloads) + { + Programme *finishedShow = [note object]; + if ([[finishedShow successful] boolValue]) + { + [finishedShow setValue:@"Processing..." forKey:@"status"]; + if ([[[finishedShow path] pathExtension] isEqualToString:@"mov"]) + { + [self cleanUpPath:finishedShow]; + [self seasonEpisodeInfo:finishedShow]; + } + if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"AddCompletedToiTunes"] isEqualTo:@YES]) + [NSThread detachNewThreadSelector:@selector(addToiTunesThread:) toTarget:self withObject:finishedShow]; else - currentDownload = [[BBCDownload alloc] initWithProgramme:nextShow - tvFormats:[tvFormatController arrangedObjects] - radioFormats:[radioFormatController arrangedObjects] - proxy:proxy - logController:logger]; - } - } - @catch (NSException *e) - { - //Downloads must be finished. - IOPMAssertionRelease(powerAssertionID); - - [stopButton setEnabled:NO]; - [startButton setEnabled:YES]; - [currentProgress setStringValue:@""]; - [currentIndicator setDoubleValue:0]; - @try {[currentIndicator stopAnimation:nil];} - @catch (NSException *exception) {NSLog(@"Unable to stop Animation.");} - [currentIndicator setIndeterminate:NO]; - [logger addToLog:@"\rAppController: Downloads Finished" :nil]; - NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; - [nc removeObserver:self name:@"setPercentage" object:nil]; - [nc removeObserver:self name:@"setCurrentProgress" object:nil]; - [nc removeObserver:self name:@"DownloadFinished" object:nil]; - - runDownloads=NO; - [mainWindow setDocumentEdited:NO]; - - //Growl Notification - NSUInteger downloadsSuccessful=0, downloadsFailed=0; - for (Programme *show in tempQueue) - { - if ([[show successful] boolValue]) - { - downloadsSuccessful++; - } - else - { - downloadsFailed++; - } - } - tempQueue=nil; - @try - { - [GrowlApplicationBridge notifyWithTitle:@"Downloads Finished" - description:[NSString stringWithFormat:@"Downloads Successful = %lu\nDownload Failed = %lu", - (unsigned long)downloadsSuccessful,(unsigned long)downloadsFailed] - notificationName:@"Downloads Finished" - iconData:nil - priority:0 - isSticky:NO - clickContext:nil]; - } - @catch (NSException *e) { - NSLog(@"ERROR: Growl notification failed (nextDownload - complete): %@: %@", [e name], [e description]); - [logger addToLog:[NSString stringWithFormat:@"ERROR: Growl notification failed (nextDownload - complete): %@: %@", [e name], [e description]]]; - } - [[SUUpdater sharedUpdater] checkForUpdatesInBackground]; - - if (downloadsFailed>0) - [solutionsWindow makeKeyAndOrderFront:self]; - if ([[[NSUserDefaults standardUserDefaults] valueForKey:@"AutoRetryFailed"] boolValue] && downloadsFailed>0) - { - NSDate *scheduledDate = [NSDate dateWithTimeIntervalSinceNow:60*[[[NSUserDefaults standardUserDefaults] valueForKey:@"AutoRetryTime"] doubleValue]]; - [datePicker setDateValue:scheduledDate]; - [self scheduleStart:self]; - } - - return; - } - } - return; + [finishedShow setValue:@"Download Complete" forKey:@"status"]; + + @try + { + [GrowlApplicationBridge notifyWithTitle:@"Download Finished" + description:[NSString stringWithFormat:@"%@ Completed Successfully",[finishedShow showName]] + notificationName:@"Download Finished" + iconData:nil + priority:0 + isSticky:NO + clickContext:nil]; + } + @catch (NSException *e) { + NSLog(@"ERROR: Growl notification failed (nextDownload - finished): %@: %@", [e name], [e description]); + [logger addToLog:[NSString stringWithFormat:@"ERROR: Growl notification failed (nextDownload - finished): %@: %@", [e name], [e description]]]; + } + } + else + { + @try + { + [GrowlApplicationBridge notifyWithTitle:@"Download Failed" + description:[NSString stringWithFormat:@"%@ failed. See log for details.",[finishedShow showName]] + notificationName:@"Download Failed" + iconData:nil + priority:0 + isSticky:NO + clickContext:nil]; + } + @catch (NSException *e) { + NSLog(@"ERROR: Growl notification failed (nextDownload - failed): %@: %@", [e name], [e description]); + [logger addToLog:[NSString stringWithFormat:@"ERROR: Growl notification failed (nextDownload - failed): %@: %@", [e name], [e description]]]; + } + + ReasonForFailure *showSolution = [[ReasonForFailure alloc] init]; + [showSolution setShowName:[finishedShow showName]]; + [showSolution setSolution:solutionsDictionary[finishedShow.reasonForFailure]]; + if (![showSolution solution]) + [showSolution setSolution:@"Problem Unknown.\nPlease submit a bug report from the application menu."]; + NSLog(@"Reason for Failure: %@", [finishedShow reasonForFailure]); + NSLog(@"Dictionary Lookup: %@", [solutionsDictionary valueForKey:[finishedShow reasonForFailure]]); + NSLog(@"Solution: %@", [showSolution solution]); + [solutionsArrayController addObject:showSolution]; + NSLog(@"Added Solution"); + [solutionsTableView setRowHeight:68]; + } + + [self saveAppData]; //Save app data in case of crash. + + NSArray *tempQueue = [queueController arrangedObjects]; + Programme *nextShow=nil; + NSUInteger showNum=0; + @try + { + for (Programme *show in tempQueue) + { + showNum++; + if (![[show complete] boolValue]) + { + nextShow = show; + break; + } + } + if (nextShow==nil) + { + NSException *noneLeft = [NSException exceptionWithName:@"EndOfDownloads" reason:@"Done" userInfo:nil]; + [noneLeft raise]; + } + [logger addToLog:[NSString stringWithFormat:@"\rDownloading Show %lu/%lu:\r", + (unsigned long)([tempQueue indexOfObject:nextShow]+1), + (unsigned long)[tempQueue count]] + :nil]; + if ([[nextShow complete] isEqualToNumber:@NO]) + { + if ([[nextShow tvNetwork] hasPrefix:@"ITV"]) + currentDownload = [[ITVDownload alloc] initWithProgramme:nextShow itvFormats:[itvFormatController arrangedObjects] proxy:proxy logController:logger]; + /*else if ([[nextShow tvNetwork] hasPrefix:@"4oD"]) + currentDownload = [[FourODDownload alloc] initWithProgramme:nextShow proxy:proxy];*/ + else + currentDownload = [[BBCDownload alloc] initWithProgramme:nextShow + tvFormats:[tvFormatController arrangedObjects] + radioFormats:[radioFormatController arrangedObjects] + proxy:proxy + logController:logger]; + } + } + @catch (NSException *e) + { + //Downloads must be finished. + IOPMAssertionRelease(powerAssertionID); + + [stopButton setEnabled:NO]; + [startButton setEnabled:YES]; + [currentProgress setStringValue:@""]; + [currentIndicator setDoubleValue:0]; + @try {[currentIndicator stopAnimation:nil];} + @catch (NSException *exception) {NSLog(@"Unable to stop Animation.");} + [currentIndicator setIndeterminate:NO]; + [logger addToLog:@"\rAppController: Downloads Finished" :nil]; + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc removeObserver:self name:@"setPercentage" object:nil]; + [nc removeObserver:self name:@"setCurrentProgress" object:nil]; + [nc removeObserver:self name:@"DownloadFinished" object:nil]; + + runDownloads=NO; + [mainWindow setDocumentEdited:NO]; + + //Growl Notification + NSUInteger downloadsSuccessful=0, downloadsFailed=0; + for (Programme *show in tempQueue) + { + if ([[show successful] boolValue]) + { + downloadsSuccessful++; + } + else + { + downloadsFailed++; + } + } + tempQueue=nil; + @try + { + [GrowlApplicationBridge notifyWithTitle:@"Downloads Finished" + description:[NSString stringWithFormat:@"Downloads Successful = %lu\nDownload Failed = %lu", + (unsigned long)downloadsSuccessful,(unsigned long)downloadsFailed] + notificationName:@"Downloads Finished" + iconData:nil + priority:0 + isSticky:NO + clickContext:nil]; + } + @catch (NSException *e) { + NSLog(@"ERROR: Growl notification failed (nextDownload - complete): %@: %@", [e name], [e description]); + [logger addToLog:[NSString stringWithFormat:@"ERROR: Growl notification failed (nextDownload - complete): %@: %@", [e name], [e description]]]; + } + [[SUUpdater sharedUpdater] checkForUpdatesInBackground]; + + if (downloadsFailed>0) + [solutionsWindow makeKeyAndOrderFront:self]; + if ([[[NSUserDefaults standardUserDefaults] valueForKey:@"AutoRetryFailed"] boolValue] && downloadsFailed>0) + { + NSDate *scheduledDate = [NSDate dateWithTimeIntervalSinceNow:60*[[[NSUserDefaults standardUserDefaults] valueForKey:@"AutoRetryTime"] doubleValue]]; + [datePicker setDateValue:scheduledDate]; + [self scheduleStart:self]; + } + + return; + } + } + return; } #pragma mark PVR - (IBAction)pvrSearch:(id)sender { - if([pvrSearchField.stringValue length]) - { - [pvrSearchField setEnabled:NO]; - [pvrResultsController removeObjectsAtArrangedObjectIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [pvrResultsController.arrangedObjects count])]]; - currentPVRSearch = [[GiASearch alloc] initWithSearchTerms:pvrSearchField.stringValue - allowHidingOfDownloadedItems:NO logController:logger - selector:@selector(pvrSearchFinished:) - withTarget:self]; - [pvrSearchIndicator startAnimation:nil]; - } + if([pvrSearchField.stringValue length]) + { + [pvrSearchField setEnabled:NO]; + [pvrResultsController removeObjectsAtArrangedObjectIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [pvrResultsController.arrangedObjects count])]]; + currentPVRSearch = [[GiASearch alloc] initWithSearchTerms:pvrSearchField.stringValue + allowHidingOfDownloadedItems:NO logController:logger + selector:@selector(pvrSearchFinished:) + withTarget:self]; + [pvrSearchIndicator startAnimation:nil]; + } } - (void)pvrSearchFinished:(NSArray *)results { - [pvrResultsController addObjects:results]; - [pvrResultsController setSelectionIndexes:[NSIndexSet indexSet]]; - [pvrSearchIndicator stopAnimation:nil]; - [pvrSearchField setEnabled:YES]; - if (![results count]) - { - NSAlert *noneFound = [NSAlert alertWithMessageText:@"No Shows Found" - defaultButton:@"OK" - alternateButton:nil - otherButton:nil - informativeTextWithFormat:@"0 shows were found for your search terms. Please check your spelling!"]; - [noneFound runModal]; - } - currentPVRSearch = nil; + [pvrResultsController addObjects:results]; + [pvrResultsController setSelectionIndexes:[NSIndexSet indexSet]]; + [pvrSearchIndicator stopAnimation:nil]; + [pvrSearchField setEnabled:YES]; + if (![results count]) + { + NSAlert *noneFound = [NSAlert alertWithMessageText:@"No Shows Found" + defaultButton:@"OK" + alternateButton:nil + otherButton:nil + informativeTextWithFormat:@"0 shows were found for your search terms. Please check your spelling!"]; + [noneFound runModal]; + } + currentPVRSearch = nil; } - (IBAction)addToAutoRecord:(id)sender { - NSArray *selected = [[NSArray alloc] initWithArray:[pvrResultsController selectedObjects]]; - for (Programme *programme in selected) - { - NSString *episodeName = [[NSString alloc] initWithString:[programme showName]]; - NSScanner *scanner = [NSScanner scannerWithString:episodeName]; - NSString *tempName; - [scanner scanUpToString:@" - " intoString:&tempName]; - Series *show = [[Series alloc] initWithShowname:tempName]; - show.added = programme.timeadded; - show.tvNetwork = programme.tvNetwork; - show.lastFound = [NSDate date]; - - //Check to make sure the programme isn't already in the queue before adding it. - NSArray *queuedObjects = [pvrQueueController arrangedObjects]; - BOOL add=YES; - for (Programme *queuedShow in queuedObjects) - { - if ([[show showName] isEqualToString:[queuedShow showName]] && [show tvNetwork] == [queuedShow tvNetwork]) - add=NO; - } - if (add) - { - [pvrQueueController addObject:show]; - } - } + NSArray *selected = [[NSArray alloc] initWithArray:[pvrResultsController selectedObjects]]; + for (Programme *programme in selected) + { + NSString *episodeName = [[NSString alloc] initWithString:[programme showName]]; + NSScanner *scanner = [NSScanner scannerWithString:episodeName]; + NSString *tempName; + [scanner scanUpToString:@" - " intoString:&tempName]; + Series *show = [[Series alloc] initWithShowname:tempName]; + show.added = programme.timeadded; + show.tvNetwork = programme.tvNetwork; + show.lastFound = [NSDate date]; + + //Check to make sure the programme isn't already in the queue before adding it. + NSArray *queuedObjects = [pvrQueueController arrangedObjects]; + BOOL add=YES; + for (Programme *queuedShow in queuedObjects) + { + if ([[show showName] isEqualToString:[queuedShow showName]] && [show tvNetwork] == [queuedShow tvNetwork]) + add=NO; + } + if (add) + { + [pvrQueueController addObject:show]; + } + } } - (IBAction)addSeriesLinkToQueue:(id)sender { - if ([[pvrQueueController arrangedObjects] count] > 0 && !runUpdate) - { - if (!runDownloads) - { - [currentIndicator setIndeterminate:YES]; - [currentIndicator startAnimation:self]; - [startButton setEnabled:NO]; - } - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(seriesLinkFinished:) name:@"NSThreadWillExitNotification" object:nil]; - NSLog(@"About to launch Series-Link Thread"); - [NSThread detachNewThreadSelector:@selector(seriesLinkToQueueThread) toTarget:self withObject:nil]; - NSLog(@"Series-Link Thread Launched"); - } - else if (runScheduled && !scheduleTimer) - { - [self performSelectorOnMainThread:@selector(startDownloads:) withObject:self waitUntilDone:NO]; - } + if ([[pvrQueueController arrangedObjects] count] > 0 && !runUpdate) + { + if (!runDownloads) + { + [currentIndicator setIndeterminate:YES]; + [currentIndicator startAnimation:self]; + [startButton setEnabled:NO]; + } + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(seriesLinkFinished:) name:@"NSThreadWillExitNotification" object:nil]; + NSLog(@"About to launch Series-Link Thread"); + [NSThread detachNewThreadSelector:@selector(seriesLinkToQueueThread) toTarget:self withObject:nil]; + NSLog(@"Series-Link Thread Launched"); + } + else if (runScheduled && !scheduleTimer) + { + [self performSelectorOnMainThread:@selector(startDownloads:) withObject:self waitUntilDone:NO]; + } } - (void)seriesLinkToQueueThread { - @autoreleasepool { - NSArray *seriesLink = [pvrQueueController arrangedObjects]; - if (!runDownloads) - [currentProgress performSelectorOnMainThread:@selector(setStringValue:) withObject:@"Updating Series Link..." waitUntilDone:YES]; - NSMutableArray *seriesToBeRemoved = [[NSMutableArray alloc] init]; - for (Series *series in seriesLink) - { - if (!runDownloads) - [currentProgress performSelectorOnMainThread:@selector(setStringValue:) withObject:[NSString stringWithFormat:@"Updating Series Link - %lu/%lu - %@",(unsigned long)[seriesLink indexOfObject:series]+1,(unsigned long)[seriesLink count],[series showName]] waitUntilDone:YES]; - if ([[series showName] length] == 0) { - [seriesToBeRemoved addObject:series]; - continue; - } else if ([[series tvNetwork] length] == 0) { - [series setTvNetwork:@"*"]; - } - NSString *cacheExpiryArgument = [[GetiPlayerArguments sharedController] cacheExpiryArgument:nil]; - NSString *typeArgument = [[GetiPlayerArguments sharedController] typeArgumentForCacheUpdate:NO]; - - NSMutableArray *autoRecordArgs = [[NSMutableArray alloc] initWithObjects:getiPlayerPath, - [GetiPlayerArguments sharedController].noWarningArg,@"--nopurge", - @"--listformat=: , ~ - ~, , , ,", - cacheExpiryArgument, - typeArgument, - [GetiPlayerArguments sharedController].profileDirArg, - @"--hide", - [self escapeSpecialCharactersInString:[series showName]], - nil]; - - NSTask *autoRecordTask = [[NSTask alloc] init]; - NSPipe *autoRecordPipe = [[NSPipe alloc] init]; - NSMutableString *autoRecordData = [[NSMutableString alloc] initWithString:@""]; - NSFileHandle *readHandle = [autoRecordPipe fileHandleForReading]; - NSData *inData = nil; - - [autoRecordTask setLaunchPath:@"/usr/bin/perl"]; - [autoRecordTask setArguments:autoRecordArgs]; - [autoRecordTask setStandardOutput:autoRecordPipe]; - NSMutableDictionary *envVariableDictionary = [NSMutableDictionary dictionaryWithDictionary:[autoRecordTask environment]]; - envVariableDictionary[@"HOME"] = [@"~" stringByExpandingTildeInPath]; - envVariableDictionary[@"PERL_UNICODE"] = @"AS"; - [autoRecordTask setEnvironment:envVariableDictionary]; - [autoRecordTask launch]; - - while ((inData = [readHandle availableData]) && [inData length]) { - NSString *tempData = [[NSString alloc] initWithData:inData encoding:NSUTF8StringEncoding]; - [autoRecordData appendString:tempData]; - } - if (![self processAutoRecordData:[autoRecordData copy] forSeries:series]) - [seriesToBeRemoved addObject:series]; - } - [pvrQueueController performSelectorOnMainThread:@selector(removeObjects:) withObject:seriesToBeRemoved waitUntilDone:NO]; - } + @autoreleasepool { + NSArray *seriesLink = [pvrQueueController arrangedObjects]; + if (!runDownloads) + [currentProgress performSelectorOnMainThread:@selector(setStringValue:) withObject:@"Updating Series Link..." waitUntilDone:YES]; + NSMutableArray *seriesToBeRemoved = [[NSMutableArray alloc] init]; + for (Series *series in seriesLink) + { + if (!runDownloads) + [currentProgress performSelectorOnMainThread:@selector(setStringValue:) withObject:[NSString stringWithFormat:@"Updating Series Link - %lu/%lu - %@",(unsigned long)[seriesLink indexOfObject:series]+1,(unsigned long)[seriesLink count],[series showName]] waitUntilDone:YES]; + if ([[series showName] length] == 0) { + [seriesToBeRemoved addObject:series]; + continue; + } else if ([[series tvNetwork] length] == 0) { + [series setTvNetwork:@"*"]; + } + NSString *cacheExpiryArgument = [[GetiPlayerArguments sharedController] cacheExpiryArgument:nil]; + NSString *typeArgument = [[GetiPlayerArguments sharedController] typeArgumentForCacheUpdate:NO]; + + NSMutableArray *autoRecordArgs = [[NSMutableArray alloc] initWithObjects:getiPlayerPath, + [GetiPlayerArguments sharedController].noWarningArg,@"--nopurge", + @"--listformat=: , ~ - ~, , , ,", + cacheExpiryArgument, + typeArgument, + [GetiPlayerArguments sharedController].profileDirArg, + @"--hide", + [self escapeSpecialCharactersInString:[series showName]], + nil]; + + NSTask *autoRecordTask = [[NSTask alloc] init]; + NSPipe *autoRecordPipe = [[NSPipe alloc] init]; + NSMutableString *autoRecordData = [[NSMutableString alloc] initWithString:@""]; + NSFileHandle *readHandle = [autoRecordPipe fileHandleForReading]; + NSData *inData = nil; + + [autoRecordTask setLaunchPath:@"/usr/bin/perl"]; + [autoRecordTask setArguments:autoRecordArgs]; + [autoRecordTask setStandardOutput:autoRecordPipe]; + NSMutableDictionary *envVariableDictionary = [NSMutableDictionary dictionaryWithDictionary:[autoRecordTask environment]]; + envVariableDictionary[@"HOME"] = [@"~" stringByExpandingTildeInPath]; + envVariableDictionary[@"PERL_UNICODE"] = @"AS"; + [autoRecordTask setEnvironment:envVariableDictionary]; + [autoRecordTask launch]; + + while ((inData = [readHandle availableData]) && [inData length]) { + NSString *tempData = [[NSString alloc] initWithData:inData encoding:NSUTF8StringEncoding]; + [autoRecordData appendString:tempData]; + } + if (![self processAutoRecordData:[autoRecordData copy] forSeries:series]) + [seriesToBeRemoved addObject:series]; + } + [pvrQueueController performSelectorOnMainThread:@selector(removeObjects:) withObject:seriesToBeRemoved waitUntilDone:NO]; + } } - (void)seriesLinkFinished:(NSNotification *)note { - NSLog(@"Thread Finished Notification Received"); - if (!runDownloads) - { - [currentProgress setStringValue:@""]; - [currentIndicator setIndeterminate:NO]; - [currentIndicator stopAnimation:self]; - [startButton setEnabled:YES]; - } - [[NSNotificationCenter defaultCenter] removeObserver:self name:@"NSThreadWillExitNotification" object:nil]; - - //If this is an update initiated by the scheduler, run the downloads. - if (runScheduled && !scheduleTimer) - { - [self performSelectorOnMainThread:@selector(startDownloads:) withObject:self waitUntilDone:NO]; - } - [self performSelectorOnMainThread:@selector(scheduleTimerForFinished:) withObject:nil waitUntilDone:NO]; - NSLog(@"Series-Link Thread Finished"); + NSLog(@"Thread Finished Notification Received"); + if (!runDownloads) + { + [currentProgress setStringValue:@""]; + [currentIndicator setIndeterminate:NO]; + [currentIndicator stopAnimation:self]; + [startButton setEnabled:YES]; + } + [[NSNotificationCenter defaultCenter] removeObserver:self name:@"NSThreadWillExitNotification" object:nil]; + + //If this is an update initiated by the scheduler, run the downloads. + if (runScheduled && !scheduleTimer) + { + [self performSelectorOnMainThread:@selector(startDownloads:) withObject:self waitUntilDone:NO]; + } + [self performSelectorOnMainThread:@selector(scheduleTimerForFinished:) withObject:nil waitUntilDone:NO]; + NSLog(@"Series-Link Thread Finished"); } - (void)scheduleTimerForFinished:(id)sender { - [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(seriesLinkFinished2:) userInfo:currentProgress repeats:NO]; + [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(seriesLinkFinished2:) userInfo:currentProgress repeats:NO]; } - (void)seriesLinkFinished2:(NSNotification *)note { - NSLog(@"Second Check"); - if (!runDownloads) - { - [currentProgress setStringValue:@""]; - [currentIndicator setIndeterminate:NO]; - [currentIndicator stopAnimation:self]; - [startButton setEnabled:YES]; - } - NSLog(@"Definitely shouldn't show an updating series-link thing!"); + NSLog(@"Second Check"); + if (!runDownloads) + { + [currentProgress setStringValue:@""]; + [currentIndicator setIndeterminate:NO]; + [currentIndicator stopAnimation:self]; + [startButton setEnabled:YES]; + } + NSLog(@"Definitely shouldn't show an updating series-link thing!"); } - (BOOL)processAutoRecordData:(NSString *)autoRecordData2 forSeries:(Series *)series2 { - BOOL oneFound=NO; - NSArray *array = [autoRecordData2 componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]; - for (NSString *string in array) - { - if (![string isEqualToString:@"Matches:"] && ![string hasPrefix:@"INFO:"] && ![string hasPrefix:@"WARNING:"] && [string length]>0 && ![string hasPrefix:@"."] && ![string hasPrefix:@"Added:"]) - { - @try { - NSScanner *myScanner = [NSScanner scannerWithString:string]; - NSArray *currentQueue = [queueController arrangedObjects]; - NSString *temp_pid, *temp_showName, *temp_tvNetwork, *temp_type, *temp_realPID, *url; - NSInteger timeadded; - [myScanner scanUpToString:@":" intoString:&temp_pid]; - [myScanner scanUpToCharactersFromSet:[NSCharacterSet alphanumericCharacterSet] intoString:NULL]; - [myScanner scanUpToString:@", ~" intoString:&temp_type]; - [myScanner scanString:@", ~" intoString:nil]; - [myScanner scanUpToString:@"~," intoString:&temp_showName]; - [myScanner scanUpToCharactersFromSet:[NSCharacterSet alphanumericCharacterSet] intoString:NULL]; - [myScanner scanUpToString:@"," intoString:&temp_tvNetwork]; - [myScanner scanString:@"," intoString:nil]; - [myScanner scanInteger:&timeadded]; - [myScanner scanUpToString:@", " intoString:nil]; - [myScanner scanString:@", " intoString:nil]; - [myScanner scanUpToString:@"," intoString:&temp_realPID]; - [myScanner scanString:@"," intoString:nil]; - [myScanner scanUpToString:@"kjkjkj" intoString:&url]; - - NSScanner *seriesEpisodeScanner = [NSScanner scannerWithString:temp_showName]; - NSString *series_Name, *episode_Name; - [seriesEpisodeScanner scanUpToString:@" - " intoString:&series_Name]; - [seriesEpisodeScanner scanString:@"-" intoString:nil]; - [seriesEpisodeScanner scanUpToString:@"kjkljfdg" intoString:&episode_Name]; - if ([temp_showName hasSuffix:@" - -"]) - { - NSString *temp_showName2; - NSScanner *dashScanner = [NSScanner scannerWithString:temp_showName]; - [dashScanner scanUpToString:@" - -" intoString:&temp_showName2]; - temp_showName = temp_showName2; - temp_showName = [temp_showName stringByAppendingFormat:@" - %@", temp_showName2]; - } - if (([[series2 added] integerValue] > timeadded) && - ([temp_tvNetwork isEqualToString:[series2 tvNetwork]] || [[[series2 tvNetwork] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] isEqualToString:@"*"] || [[series2 tvNetwork] length] == 0)) + BOOL oneFound=NO; + NSArray *array = [autoRecordData2 componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]; + for (NSString *string in array) + { + if (![string isEqualToString:@"Matches:"] && ![string hasPrefix:@"INFO:"] && ![string hasPrefix:@"WARNING:"] && [string length]>0 && ![string hasPrefix:@"."] && ![string hasPrefix:@"Added:"]) + { + @try { + NSScanner *myScanner = [NSScanner scannerWithString:string]; + NSArray *currentQueue = [queueController arrangedObjects]; + NSString *temp_pid, *temp_showName, *temp_tvNetwork, *temp_type, *temp_realPID, *url; + NSInteger timeadded; + [myScanner scanUpToString:@":" intoString:&temp_pid]; + [myScanner scanUpToCharactersFromSet:[NSCharacterSet alphanumericCharacterSet] intoString:NULL]; + [myScanner scanUpToString:@", ~" intoString:&temp_type]; + [myScanner scanString:@", ~" intoString:nil]; + [myScanner scanUpToString:@"~," intoString:&temp_showName]; + [myScanner scanUpToCharactersFromSet:[NSCharacterSet alphanumericCharacterSet] intoString:NULL]; + [myScanner scanUpToString:@"," intoString:&temp_tvNetwork]; + [myScanner scanString:@"," intoString:nil]; + [myScanner scanInteger:&timeadded]; + [myScanner scanUpToString:@", " intoString:nil]; + [myScanner scanString:@", " intoString:nil]; + [myScanner scanUpToString:@"," intoString:&temp_realPID]; + [myScanner scanString:@"," intoString:nil]; + [myScanner scanUpToString:@"kjkjkj" intoString:&url]; + + NSScanner *seriesEpisodeScanner = [NSScanner scannerWithString:temp_showName]; + NSString *series_Name, *episode_Name; + [seriesEpisodeScanner scanUpToString:@" - " intoString:&series_Name]; + [seriesEpisodeScanner scanString:@"-" intoString:nil]; + [seriesEpisodeScanner scanUpToString:@"kjkljfdg" intoString:&episode_Name]; + if ([temp_showName hasSuffix:@" - -"]) + { + NSString *temp_showName2; + NSScanner *dashScanner = [NSScanner scannerWithString:temp_showName]; + [dashScanner scanUpToString:@" - -" intoString:&temp_showName2]; + temp_showName = temp_showName2; + temp_showName = [temp_showName stringByAppendingFormat:@" - %@", temp_showName2]; + } + if (([[series2 added] integerValue] > timeadded) && + ([temp_tvNetwork isEqualToString:[series2 tvNetwork]] || [[[series2 tvNetwork] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] isEqualToString:@"*"] || [[series2 tvNetwork] length] == 0)) + { + [series2 setAdded:@(timeadded)]; + } + if (([[series2 added] integerValue] <= timeadded) && + ([temp_tvNetwork isEqualToString:[series2 tvNetwork]] || [[[series2 tvNetwork] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] isEqualToString:@"*"] || [[series2 tvNetwork] length] == 0)) + { + @try { + oneFound=YES; + Programme *p = [[Programme alloc] initWithInfo:nil pid:temp_pid programmeName:temp_showName network:temp_tvNetwork logController:logger]; + [p setRealPID:temp_realPID]; + [p setSeriesName:series_Name]; + [p setEpisodeName:episode_Name]; + [p setUrl:url]; + if ([temp_type isEqualToString:@"radio"]) [p setValue:@YES forKey:@"radio"]; + else if ([temp_type isEqualToString:@"podcast"]) [p setPodcast:@YES]; + [p setValue:@"Added by Series-Link" forKey:@"status"]; + BOOL inQueue=NO; + for (Programme *show in currentQueue) + if ([[show showName] isEqualToString:[p showName]] && [[show pid] isEqualToString:[p pid]]) inQueue=YES; + if (!inQueue) + { + if (runDownloads) [p setValue:@"Waiting..." forKey:@"status"]; + else p.status = @"Available"; + [queueController performSelectorOnMainThread:@selector(addObject:) withObject:p waitUntilDone:NO]; + } + } + @catch (NSException *e) { + NSAlert *queueException = [[NSAlert alloc] init]; + [queueException addButtonWithTitle:@"OK"]; + [queueException setMessageText:[NSString stringWithFormat:@"Series-Link to Queue Transfer Failed"]]; + [queueException setInformativeText:@"The recording queue is in an unknown state. Please restart GiA and clear the recording queue."]; + [queueException setAlertStyle:NSWarningAlertStyle]; + [queueException runModal]; + queueException = nil; + } + } + } + @catch (NSException *e) { + NSAlert *searchException = [[NSAlert alloc] init]; + [searchException addButtonWithTitle:@"OK"]; + [searchException setMessageText:[NSString stringWithFormat:@"Invalid Output!"]]; + [searchException setInformativeText:@"Please check your query. Your query must not alter the output format of Get_iPlayer. (processAutoRecordData)"]; + [searchException setAlertStyle:NSWarningAlertStyle]; + [searchException runModal]; + searchException = nil; + } + } + else + { + if ([string hasPrefix:@"Unknown option:"] || [string hasPrefix:@"Option"] || [string hasPrefix:@"Usage"]) { - [series2 setAdded:@(timeadded)]; + return NO; } - if (([[series2 added] integerValue] <= timeadded) && - ([temp_tvNetwork isEqualToString:[series2 tvNetwork]] || [[[series2 tvNetwork] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] isEqualToString:@"*"] || [[series2 tvNetwork] length] == 0)) - { - @try { - oneFound=YES; - Programme *p = [[Programme alloc] initWithInfo:nil pid:temp_pid programmeName:temp_showName network:temp_tvNetwork logController:logger]; - [p setRealPID:temp_realPID]; - [p setSeriesName:series_Name]; - [p setEpisodeName:episode_Name]; - [p setUrl:url]; - if ([temp_type isEqualToString:@"radio"]) [p setValue:@YES forKey:@"radio"]; - else if ([temp_type isEqualToString:@"podcast"]) [p setPodcast:@YES]; - [p setValue:@"Added by Series-Link" forKey:@"status"]; - BOOL inQueue=NO; - for (Programme *show in currentQueue) - if ([[show showName] isEqualToString:[p showName]] && [[show pid] isEqualToString:[p pid]]) inQueue=YES; - if (!inQueue) - { - if (runDownloads) [p setValue:@"Waiting..." forKey:@"status"]; - [queueController performSelectorOnMainThread:@selector(addObject:) withObject:p waitUntilDone:NO]; - } - } - @catch (NSException *e) { - NSAlert *queueException = [[NSAlert alloc] init]; - [queueException addButtonWithTitle:@"OK"]; - [queueException setMessageText:[NSString stringWithFormat:@"Series-Link to Queue Transfer Failed"]]; - [queueException setInformativeText:@"The recording queue is in an unknown state. Please restart GiA and clear the recording queue."]; - [queueException setAlertStyle:NSWarningAlertStyle]; - [queueException runModal]; - queueException = nil; - } - } - } - @catch (NSException *e) { - NSAlert *searchException = [[NSAlert alloc] init]; - [searchException addButtonWithTitle:@"OK"]; - [searchException setMessageText:[NSString stringWithFormat:@"Invalid Output!"]]; - [searchException setInformativeText:@"Please check your query. Your query must not alter the output format of Get_iPlayer. (processAutoRecordData)"]; - [searchException setAlertStyle:NSWarningAlertStyle]; - [searchException runModal]; - searchException = nil; - } - } - else - { - if ([string hasPrefix:@"Unknown option:"] || [string hasPrefix:@"Option"] || [string hasPrefix:@"Usage"]) - { - return NO; - } - } - } - if (oneFound) - { - [series2 setLastFound:[NSDate date]]; - return YES; - } - else - { - if (!([[NSDate date] timeIntervalSinceDate:[series2 lastFound]] < ([[[NSUserDefaults standardUserDefaults] valueForKey:@"KeepSeriesFor"] intValue]*86400)) && [[[NSUserDefaults standardUserDefaults] valueForKey:@"RemoveOldSeries"] boolValue]) - { - return NO; - } - return YES; - } + } + } + if (oneFound) + { + [series2 setLastFound:[NSDate date]]; + return YES; + } + else + { + if (!([[NSDate date] timeIntervalSinceDate:[series2 lastFound]] < ([[[NSUserDefaults standardUserDefaults] valueForKey:@"KeepSeriesFor"] intValue]*86400)) && [[[NSUserDefaults standardUserDefaults] valueForKey:@"RemoveOldSeries"] boolValue]) + { + return NO; + } + return YES; + } } #pragma mark Misc. @@ -1600,453 +1602,453 @@ - (BOOL)processAutoRecordData:(NSString *)autoRecordData2 forSeries:(Series *)se - (void)saveAppData { - //Save Queue & Series-Link - NSMutableArray *tempQueue = [[NSMutableArray alloc] initWithArray:[queueController arrangedObjects]]; - NSMutableArray *tempSeries = [[NSMutableArray alloc] initWithArray:[pvrQueueController arrangedObjects]]; - NSMutableArray *temptempQueue = [[NSMutableArray alloc] initWithArray:tempQueue]; - for (Programme *show in temptempQueue) - { - if (([[show complete] isEqualToNumber:@YES] && [[show successful] isEqualToNumber:@YES]) - || [[show status] isEqualToString:@"Added by Series-Link"]) [tempQueue removeObject:show]; - } - NSMutableArray *temptempSeries = [[NSMutableArray alloc] initWithArray:tempSeries]; - for (Series *series in temptempSeries) - { - if ([[series showName] length] == 0) { - [tempSeries removeObject:series]; - } else if ([[series tvNetwork] length] == 0) { - [series setTvNetwork:@"*"]; - } - - } - NSFileManager *fileManager = [NSFileManager defaultManager]; - - NSString *folder = @"~/Library/Application Support/Get iPlayer Automator/"; - folder = [folder stringByExpandingTildeInPath]; - if ([fileManager fileExistsAtPath: folder] == NO) - { - [fileManager createDirectoryAtPath:folder withIntermediateDirectories:NO attributes:nil error:nil]; - } - NSString *filename = @"Queue.automatorqueue"; - NSString *filePath = [folder stringByAppendingPathComponent:filename]; - - NSMutableDictionary * rootObject; - rootObject = [NSMutableDictionary dictionary]; - - [rootObject setValue:tempQueue forKey:@"queue"]; - [rootObject setValue:tempSeries forKey:@"serieslink"]; - [rootObject setValue:lastUpdate forKey:@"lastUpdate"]; - [NSKeyedArchiver archiveRootObject: rootObject toFile: filePath]; - - filename = @"Formats.automatorqueue"; - filePath = [folder stringByAppendingPathComponent:filename]; - - rootObject = [NSMutableDictionary dictionary]; - - [rootObject setValue:[tvFormatController arrangedObjects] forKey:@"tvFormats"]; - [rootObject setValue:[radioFormatController arrangedObjects] forKey:@"radioFormats"]; - [rootObject setValue:@YES forKey:@"hasUpdatedCacheFor4oD"]; - [NSKeyedArchiver archiveRootObject:rootObject toFile:filePath]; - - filename = @"ITVFormats.automator"; - filePath = [folder stringByAppendingPathComponent:filename]; - rootObject = [NSMutableDictionary dictionary]; - [rootObject setValue:[itvFormatController arrangedObjects] forKey:@"itvFormats"]; - [NSKeyedArchiver archiveRootObject:rootObject toFile:filePath]; - - //Store Preferences in case of crash - [[NSUserDefaults standardUserDefaults] synchronize]; + //Save Queue & Series-Link + NSMutableArray *tempQueue = [[NSMutableArray alloc] initWithArray:[queueController arrangedObjects]]; + NSMutableArray *tempSeries = [[NSMutableArray alloc] initWithArray:[pvrQueueController arrangedObjects]]; + NSMutableArray *temptempQueue = [[NSMutableArray alloc] initWithArray:tempQueue]; + for (Programme *show in temptempQueue) + { + if (([[show complete] isEqualToNumber:@YES] && [[show successful] isEqualToNumber:@YES]) + || [[show status] isEqualToString:@"Added by Series-Link"]) [tempQueue removeObject:show]; + } + NSMutableArray *temptempSeries = [[NSMutableArray alloc] initWithArray:tempSeries]; + for (Series *series in temptempSeries) + { + if ([[series showName] length] == 0) { + [tempSeries removeObject:series]; + } else if ([[series tvNetwork] length] == 0) { + [series setTvNetwork:@"*"]; + } + + } + NSFileManager *fileManager = [NSFileManager defaultManager]; + + NSString *folder = @"~/Library/Application Support/Get iPlayer Automator/"; + folder = [folder stringByExpandingTildeInPath]; + if ([fileManager fileExistsAtPath: folder] == NO) + { + [fileManager createDirectoryAtPath:folder withIntermediateDirectories:NO attributes:nil error:nil]; + } + NSString *filename = @"Queue.automatorqueue"; + NSString *filePath = [folder stringByAppendingPathComponent:filename]; + + NSMutableDictionary * rootObject; + rootObject = [NSMutableDictionary dictionary]; + + [rootObject setValue:tempQueue forKey:@"queue"]; + [rootObject setValue:tempSeries forKey:@"serieslink"]; + [rootObject setValue:lastUpdate forKey:@"lastUpdate"]; + [NSKeyedArchiver archiveRootObject: rootObject toFile: filePath]; + + filename = @"Formats.automatorqueue"; + filePath = [folder stringByAppendingPathComponent:filename]; + + rootObject = [NSMutableDictionary dictionary]; + + [rootObject setValue:[tvFormatController arrangedObjects] forKey:@"tvFormats"]; + [rootObject setValue:[radioFormatController arrangedObjects] forKey:@"radioFormats"]; + [rootObject setValue:@YES forKey:@"hasUpdatedCacheFor4oD"]; + [NSKeyedArchiver archiveRootObject:rootObject toFile:filePath]; + + filename = @"ITVFormats.automator"; + filePath = [folder stringByAppendingPathComponent:filename]; + rootObject = [NSMutableDictionary dictionary]; + [rootObject setValue:[itvFormatController arrangedObjects] forKey:@"itvFormats"]; + [NSKeyedArchiver archiveRootObject:rootObject toFile:filePath]; + + //Store Preferences in case of crash + [[NSUserDefaults standardUserDefaults] synchronize]; } - (IBAction)closeWindow:(id)sender { - if ([logger.window isKeyWindow]) [logger.window performClose:self]; - else if ([historyWindow isKeyWindow]) [historyWindow performClose:self]; - else if ([pvrPanel isKeyWindow]) [pvrPanel performClose:self]; - else if ([prefsPanel isKeyWindow]) [prefsPanel performClose:self]; - else if ([mainWindow isKeyWindow]) - { - NSAlert *downloadAlert = [NSAlert alertWithMessageText:@"Are you sure you wish to quit?" - defaultButton:@"Yes" - alternateButton:@"No" - otherButton:nil - informativeTextWithFormat:nil]; - NSInteger response = [downloadAlert runModal]; - if (response == NSAlertDefaultReturn) [mainWindow performClose:self]; - } + if ([logger.window isKeyWindow]) [logger.window performClose:self]; + else if ([historyWindow isKeyWindow]) [historyWindow performClose:self]; + else if ([pvrPanel isKeyWindow]) [pvrPanel performClose:self]; + else if ([prefsPanel isKeyWindow]) [prefsPanel performClose:self]; + else if ([mainWindow isKeyWindow]) + { + NSAlert *downloadAlert = [NSAlert alertWithMessageText:@"Are you sure you wish to quit?" + defaultButton:@"Yes" + alternateButton:@"No" + otherButton:nil + informativeTextWithFormat:nil]; + NSInteger response = [downloadAlert runModal]; + if (response == NSAlertDefaultReturn) [mainWindow performClose:self]; + } } - (NSString *)escapeSpecialCharactersInString:(NSString *)string { - NSArray *characters = @[@"+", @"-", @"&", @"!", @"(", @")", @"{" ,@"}", - @"[", @"]", @"^", @"~", @"*", @"?", @":", @"\""]; - for (NSString *character in characters) - string = [string stringByReplacingOccurrencesOfString:character withString:[NSString stringWithFormat:@"\\%@",character]]; - - return string; + NSArray *characters = @[@"+", @"-", @"&", @"!", @"(", @")", @"{" ,@"}", + @"[", @"]", @"^", @"~", @"*", @"?", @":", @"\""]; + for (NSString *character in characters) + string = [string stringByReplacingOccurrencesOfString:character withString:[NSString stringWithFormat:@"\\%@",character]]; + + return string; } - (void)thirtyTwoBitModeAlert { - if ([[NSAlert alertWithMessageText:@"File could not be added to iTunes," defaultButton:@"Help Me!" alternateButton:@"Do nothing" otherButton:nil informativeTextWithFormat:@"This is usually fixed by running iTunes in 32-bit mode. Would you like instructions to do this?"] runModal] == NSAlertDefaultReturn) - [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://support.apple.com/kb/TS3771"]]; + if ([[NSAlert alertWithMessageText:@"File could not be added to iTunes," defaultButton:@"Help Me!" alternateButton:@"Do nothing" otherButton:nil informativeTextWithFormat:@"This is usually fixed by running iTunes in 32-bit mode. Would you like instructions to do this?"] runModal] == NSAlertDefaultReturn) + [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://support.apple.com/kb/TS3771"]]; } - (void)addToiTunesThread:(Programme *)show { - @autoreleasepool { - NSString *path = [[NSString alloc] initWithString:[show path]]; - NSString *ext = [path pathExtension]; - - [logger performSelectorOnMainThread:@selector(addToLog:) withObject:[NSString stringWithFormat:@"Adding %@ to iTunes",[show showName]] waitUntilDone:NO]; - - iTunesApplication *iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"]; - - NSArray *fileToAdd = @[[NSURL fileURLWithPath:path]]; - if (![iTunes isRunning]) [iTunes activate]; - @try - { - if ([ext isEqualToString:@"mov"] || [ext isEqualToString:@"mp4"] || [ext isEqualToString:@"mp3"] || [ext isEqualToString:@"m4a"]) - { - iTunesTrack *track = [iTunes add:fileToAdd to:nil]; - NSLog(@"Track exists = %@", ([track exists] ? @"YES" : @"NO")); - if ([track exists] && ([ext isEqualToString:@"mov"] || [ext isEqualToString:@"mp4"])) + @autoreleasepool { + NSString *path = [[NSString alloc] initWithString:[show path]]; + NSString *ext = [path pathExtension]; + + [logger performSelectorOnMainThread:@selector(addToLog:) withObject:[NSString stringWithFormat:@"Adding %@ to iTunes",[show showName]] waitUntilDone:NO]; + + iTunesApplication *iTunes = [SBApplication applicationWithBundleIdentifier:@"com.apple.iTunes"]; + + NSArray *fileToAdd = @[[NSURL fileURLWithPath:path]]; + if (![iTunes isRunning]) [iTunes activate]; + @try + { + if ([ext isEqualToString:@"mov"] || [ext isEqualToString:@"mp4"] || [ext isEqualToString:@"mp3"] || [ext isEqualToString:@"m4a"]) { - if ([ext isEqualToString:@"mov"]) - { - [track setName:[show episodeName]]; - [track setEpisodeID:[show episodeName]]; - [track setShow:[show seriesName]]; - [track setArtist:[show tvNetwork]]; - if ([show season]>0) [track setSeasonNumber:[show season]]; - if ([show episode]>0) [track setEpisodeNumber:[show episode]]; - } - [track setUnplayed:YES]; - [show setValue:@"Complete & in iTunes" forKey:@"status"]; - } - else if ([track exists] && ([ext isEqualToString:@"mp3"] || [ext isEqualToString:@"m4a"])) - { - [track setBookmarkable:YES]; - [track setUnplayed:YES]; - [show setValue:@"Complete & in iTunes" forKey:@"status"]; + iTunesTrack *track = [iTunes add:fileToAdd to:nil]; + NSLog(@"Track exists = %@", ([track exists] ? @"YES" : @"NO")); + if ([track exists] && ([ext isEqualToString:@"mov"] || [ext isEqualToString:@"mp4"])) + { + if ([ext isEqualToString:@"mov"]) + { + [track setName:[show episodeName]]; + [track setEpisodeID:[show episodeName]]; + [track setShow:[show seriesName]]; + [track setArtist:[show tvNetwork]]; + if ([show season]>0) [track setSeasonNumber:[show season]]; + if ([show episode]>0) [track setEpisodeNumber:[show episode]]; + } + [track setUnplayed:YES]; + [show setValue:@"Complete & in iTunes" forKey:@"status"]; + } + else if ([track exists] && ([ext isEqualToString:@"mp3"] || [ext isEqualToString:@"m4a"])) + { + [track setBookmarkable:YES]; + [track setUnplayed:YES]; + [show setValue:@"Complete & in iTunes" forKey:@"status"]; + } + else + { + [logger performSelectorOnMainThread:@selector(addToLog:) withObject:@"iTunes did not accept file." waitUntilDone:YES]; + if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_8) { //10.8 or older + [logger performSelectorOnMainThread:@selector(addToLog:) withObject:@"Try setting iTunes to open in 32-bit mode." waitUntilDone:YES]; + [self performSelectorOnMainThread:@selector(thirtyTwoBitModeAlert) withObject:nil waitUntilDone:NO]; + } + else { //Newer than 10.8. iTunes can no longer be run in 32-bit mode. + [logger performSelectorOnMainThread:@selector(addToLog:) withObject:@"Unfortunately new versions of iTunes cannot accept this file." waitUntilDone:YES]; + } + [show setValue:@"Complete: Not in iTunes" forKey:@"status"]; + } } else { - [logger performSelectorOnMainThread:@selector(addToLog:) withObject:@"iTunes did not accept file." waitUntilDone:YES]; - if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_8) { //10.8 or older - [logger performSelectorOnMainThread:@selector(addToLog:) withObject:@"Try setting iTunes to open in 32-bit mode." waitUntilDone:YES]; - [self performSelectorOnMainThread:@selector(thirtyTwoBitModeAlert) withObject:nil waitUntilDone:NO]; - } - else { //Newer than 10.8. iTunes can no longer be run in 32-bit mode. - [logger performSelectorOnMainThread:@selector(addToLog:) withObject:@"Unfortunately new versions of iTunes cannot accept this file." waitUntilDone:YES]; - } - [show setValue:@"Complete: Not in iTunes" forKey:@"status"]; + [logger performSelectorOnMainThread:@selector(addToLog:) withObject:@"Can't add to iTunes; incompatible format." waitUntilDone:YES]; + [logger performSelectorOnMainThread:@selector(addToLog:) withObject:@" iTunes Compatible Modes: Flash - High, Flash - Standard, Flash - HD, iPhone, Radio - MP3, Podcast" waitUntilDone:YES]; + [show setValue:@"Download Complete" forKey:@"status"]; } - } - else - { - [logger performSelectorOnMainThread:@selector(addToLog:) withObject:@"Can't add to iTunes; incompatible format." waitUntilDone:YES]; - [logger performSelectorOnMainThread:@selector(addToLog:) withObject:@" iTunes Compatible Modes: Flash - High, Flash - Standard, Flash - HD, iPhone, Radio - MP3, Podcast" waitUntilDone:YES]; - [show setValue:@"Download Complete" forKey:@"status"]; - } - } - @catch (NSException *e) - { - [logger performSelectorOnMainThread:@selector(addToLog:) withObject:@"Unable to Add to iTunes" waitUntilDone:YES]; - NSLog(@"Unable %@ to iTunes",show); - [show setValue:@"Complete, Could not add to iTunes." forKey:@"status"]; - } - } + } + @catch (NSException *e) + { + [logger performSelectorOnMainThread:@selector(addToLog:) withObject:@"Unable to Add to iTunes" waitUntilDone:YES]; + NSLog(@"Unable %@ to iTunes",show); + [show setValue:@"Complete, Could not add to iTunes." forKey:@"status"]; + } + } } - (void)cleanUpPath:(Programme *)show { - - //Process Show Name into Parts - NSString *originalShowName, *originalEpisodeName; - NSScanner *nameScanner = [NSScanner scannerWithString:[show showName]]; - [nameScanner scanUpToString:@" - " intoString:&originalShowName]; - [nameScanner scanString:@"-" intoString:nil]; - [nameScanner scanUpToString:@"Scan to End" intoString:&originalEpisodeName]; - - - //Replace :'s with -'s - NSString *showName = [originalShowName stringByReplacingOccurrencesOfString:@":" withString:@" -"]; - NSString *episodeName = [originalEpisodeName stringByReplacingOccurrencesOfString:@":" withString:@" -"]; - - //Replace /'s with _'s - showName = [showName stringByReplacingOccurrencesOfString:@"/" withString:@"-"]; - episodeName = [episodeName stringByReplacingOccurrencesOfString:@"/" withString:@"-"]; - - //Save Data to Programme for Later Use - [show setValue:showName forKey:@"seriesName"]; - [show setValue:episodeName forKey:@"episodeName"]; + + //Process Show Name into Parts + NSString *originalShowName, *originalEpisodeName; + NSScanner *nameScanner = [NSScanner scannerWithString:[show showName]]; + [nameScanner scanUpToString:@" - " intoString:&originalShowName]; + [nameScanner scanString:@"-" intoString:nil]; + [nameScanner scanUpToString:@"Scan to End" intoString:&originalEpisodeName]; + + + //Replace :'s with -'s + NSString *showName = [originalShowName stringByReplacingOccurrencesOfString:@":" withString:@" -"]; + NSString *episodeName = [originalEpisodeName stringByReplacingOccurrencesOfString:@":" withString:@" -"]; + + //Replace /'s with _'s + showName = [showName stringByReplacingOccurrencesOfString:@"/" withString:@"-"]; + episodeName = [episodeName stringByReplacingOccurrencesOfString:@"/" withString:@"-"]; + + //Save Data to Programme for Later Use + [show setValue:showName forKey:@"seriesName"]; + [show setValue:episodeName forKey:@"episodeName"]; } - (void)seasonEpisodeInfo:(Programme *)show { - NSInteger episode=0, season=0; - @try - { - NSString *episodeName = [show episodeName]; - NSString *seriesName = [show seriesName]; - - NSScanner *episodeScanner = [NSScanner scannerWithString:episodeName]; - NSScanner *seasonScanner = [NSScanner scannerWithString:seriesName]; - - [episodeScanner scanUpToString:@"Episode" intoString:nil]; - if ([episodeScanner scanString:@"Episode" intoString:nil]) - { - [episodeScanner scanUpToCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] intoString:nil]; - [episodeScanner scanInteger:&episode]; - } - - [seasonScanner scanUpToString:@"Series" intoString:nil]; - if ([seasonScanner scanString:@"Series" intoString:nil]) - { - [seasonScanner scanUpToCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] intoString:nil]; - [seasonScanner scanInteger:&season]; - } - - //Remove Series Number from Series Name - //Showname is now Top Gear instead of Top Gear - Series 12 - NSString *show2; - [seasonScanner setScanLocation:0]; - [seasonScanner scanUpToString:@" - " intoString:&show2]; - [show setSeriesName:show2]; - } - @catch (NSException *e) { - NSLog(@"Error occured while retrieving Season/Episode info"); - } - @finally - { - [show setEpisode:episode]; - [show setSeason:season]; - } + NSInteger episode=0, season=0; + @try + { + NSString *episodeName = [show episodeName]; + NSString *seriesName = [show seriesName]; + + NSScanner *episodeScanner = [NSScanner scannerWithString:episodeName]; + NSScanner *seasonScanner = [NSScanner scannerWithString:seriesName]; + + [episodeScanner scanUpToString:@"Episode" intoString:nil]; + if ([episodeScanner scanString:@"Episode" intoString:nil]) + { + [episodeScanner scanUpToCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] intoString:nil]; + [episodeScanner scanInteger:&episode]; + } + + [seasonScanner scanUpToString:@"Series" intoString:nil]; + if ([seasonScanner scanString:@"Series" intoString:nil]) + { + [seasonScanner scanUpToCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] intoString:nil]; + [seasonScanner scanInteger:&season]; + } + + //Remove Series Number from Series Name + //Showname is now Top Gear instead of Top Gear - Series 12 + NSString *show2; + [seasonScanner setScanLocation:0]; + [seasonScanner scanUpToString:@" - " intoString:&show2]; + [show setSeriesName:show2]; + } + @catch (NSException *e) { + NSLog(@"Error occured while retrieving Season/Episode info"); + } + @finally + { + [show setEpisode:episode]; + [show setSeason:season]; + } } - (IBAction)chooseDownloadPath:(id)sender { - NSOpenPanel *openPanel = [[NSOpenPanel alloc] init]; - [openPanel setCanChooseFiles:NO]; - [openPanel setCanChooseDirectories:YES]; - [openPanel setAllowsMultipleSelection:NO]; - [openPanel setCanCreateDirectories:YES]; - [openPanel runModal]; - NSArray *urls = [openPanel URLs]; - [[NSUserDefaults standardUserDefaults] setValue:[urls[0] path] forKey:@"DownloadPath"]; + NSOpenPanel *openPanel = [[NSOpenPanel alloc] init]; + [openPanel setCanChooseFiles:NO]; + [openPanel setCanChooseDirectories:YES]; + [openPanel setAllowsMultipleSelection:NO]; + [openPanel setCanCreateDirectories:YES]; + [openPanel runModal]; + NSArray *urls = [openPanel URLs]; + [[NSUserDefaults standardUserDefaults] setValue:[urls[0] path] forKey:@"DownloadPath"]; } - (IBAction)showFeedback:(id)sender { - [JRFeedbackController showFeedback]; + [JRFeedbackController showFeedback]; } - (IBAction)restoreDefaults:(id)sender { - NSUserDefaults *sharedDefaults = [NSUserDefaults standardUserDefaults]; - [sharedDefaults removeObjectForKey:@"DownloadPath"]; - [sharedDefaults removeObjectForKey:@"Proxy"]; - [sharedDefaults removeObjectForKey:@"CustomProxy"]; - [sharedDefaults removeObjectForKey:@"AutoRetryFailed"]; - [sharedDefaults removeObjectForKey:@"AutoRetryTime"]; - [sharedDefaults removeObjectForKey:@"AddCompletedToiTunes"]; - [sharedDefaults removeObjectForKey:@"DefaultBrowser"]; - [sharedDefaults removeObjectForKey:@"DefaultFormat"]; - [sharedDefaults removeObjectForKey:@"AlternateFormat"]; - [sharedDefaults removeObjectForKey:@"CacheBBC_TV"]; - [sharedDefaults removeObjectForKey:@"CacheITV_TV"]; - [sharedDefaults removeObjectForKey:@"CacheBBC_Radio"]; - [sharedDefaults removeObjectForKey:@"CacheBBC_Podcasts"]; - [sharedDefaults removeObjectForKey:@"Cache4oD_TV"]; - [sharedDefaults removeObjectForKey:@"CacheExpiryTime"]; - [sharedDefaults removeObjectForKey:@"Verbose"]; - [sharedDefaults removeObjectForKey:@"SeriesLinkStartup"]; - [sharedDefaults removeObjectForKey:@"DownloadSubtitles"]; - [sharedDefaults removeObjectForKey:@"AlwaysUseProxy"]; - [sharedDefaults removeObjectForKey:@"XBMC_naming"]; + NSUserDefaults *sharedDefaults = [NSUserDefaults standardUserDefaults]; + [sharedDefaults removeObjectForKey:@"DownloadPath"]; + [sharedDefaults removeObjectForKey:@"Proxy"]; + [sharedDefaults removeObjectForKey:@"CustomProxy"]; + [sharedDefaults removeObjectForKey:@"AutoRetryFailed"]; + [sharedDefaults removeObjectForKey:@"AutoRetryTime"]; + [sharedDefaults removeObjectForKey:@"AddCompletedToiTunes"]; + [sharedDefaults removeObjectForKey:@"DefaultBrowser"]; + [sharedDefaults removeObjectForKey:@"DefaultFormat"]; + [sharedDefaults removeObjectForKey:@"AlternateFormat"]; + [sharedDefaults removeObjectForKey:@"CacheBBC_TV"]; + [sharedDefaults removeObjectForKey:@"CacheITV_TV"]; + [sharedDefaults removeObjectForKey:@"CacheBBC_Radio"]; + [sharedDefaults removeObjectForKey:@"CacheBBC_Podcasts"]; + [sharedDefaults removeObjectForKey:@"Cache4oD_TV"]; + [sharedDefaults removeObjectForKey:@"CacheExpiryTime"]; + [sharedDefaults removeObjectForKey:@"Verbose"]; + [sharedDefaults removeObjectForKey:@"SeriesLinkStartup"]; + [sharedDefaults removeObjectForKey:@"DownloadSubtitles"]; + [sharedDefaults removeObjectForKey:@"AlwaysUseProxy"]; + [sharedDefaults removeObjectForKey:@"XBMC_naming"]; } - (void)applescriptStartDownloads { - runScheduled=YES; - [self forceUpdate:self]; + runScheduled=YES; + [self forceUpdate:self]; } + (AppController *)sharedController { - return sharedController; + return sharedController; } #pragma mark Scheduler - (IBAction)showScheduleWindow:(id)sender { - if (!runDownloads) - { - [scheduleWindow makeKeyAndOrderFront:self]; - [datePicker setDateValue:[NSDate date]]; - } - else - { - NSAlert *alert = [NSAlert alertWithMessageText:@"Downloads are already running." - defaultButton:@"OK" - alternateButton:nil - otherButton:nil - informativeTextWithFormat:@"You cannot schedule downloads to start if they are already running."]; - [alert runModal]; - } + if (!runDownloads) + { + [scheduleWindow makeKeyAndOrderFront:self]; + [datePicker setDateValue:[NSDate date]]; + } + else + { + NSAlert *alert = [NSAlert alertWithMessageText:@"Downloads are already running." + defaultButton:@"OK" + alternateButton:nil + otherButton:nil + informativeTextWithFormat:@"You cannot schedule downloads to start if they are already running."]; + [alert runModal]; + } } - (IBAction)cancelSchedule:(id)sender { - [scheduleWindow close]; + [scheduleWindow close]; } - (IBAction)scheduleStart:(id)sender { - NSDate *startTime = [datePicker dateValue]; - scheduleTimer = [[NSTimer alloc] initWithFireDate:startTime - interval:1 - target:self - selector:@selector(runScheduledDownloads:) - userInfo:nil - repeats:NO]; - interfaceTimer = [NSTimer scheduledTimerWithTimeInterval:1 - target:self - selector:@selector(updateScheduleStatus:) - userInfo:nil - repeats:YES]; - if ([scheduleWindow isVisible]) - [scheduleWindow close]; - [startButton setEnabled:NO]; - [stopButton setLabel:@"Cancel Timer"]; - [stopButton setAction:@selector(stopTimer:)]; - [stopButton setEnabled:YES]; - NSRunLoop *runLoop = [NSRunLoop mainRunLoop]; - [runLoop addTimer:scheduleTimer forMode:NSDefaultRunLoopMode]; - runScheduled=YES; - [mainWindow setDocumentEdited:YES]; + NSDate *startTime = [datePicker dateValue]; + scheduleTimer = [[NSTimer alloc] initWithFireDate:startTime + interval:1 + target:self + selector:@selector(runScheduledDownloads:) + userInfo:nil + repeats:NO]; + interfaceTimer = [NSTimer scheduledTimerWithTimeInterval:1 + target:self + selector:@selector(updateScheduleStatus:) + userInfo:nil + repeats:YES]; + if ([scheduleWindow isVisible]) + [scheduleWindow close]; + [startButton setEnabled:NO]; + [stopButton setLabel:@"Cancel Timer"]; + [stopButton setAction:@selector(stopTimer:)]; + [stopButton setEnabled:YES]; + NSRunLoop *runLoop = [NSRunLoop mainRunLoop]; + [runLoop addTimer:scheduleTimer forMode:NSDefaultRunLoopMode]; + runScheduled=YES; + [mainWindow setDocumentEdited:YES]; } - (void)runScheduledDownloads:(NSTimer *)theTimer { - [interfaceTimer invalidate]; - [mainWindow setDocumentEdited:NO]; - [startButton setEnabled:YES]; - [stopButton setEnabled:NO]; - [stopButton setLabel:@"Stop"]; - [stopButton setAction:@selector(stopDownloads:)]; - scheduleTimer=nil; - [self forceUpdate:self]; + [interfaceTimer invalidate]; + [mainWindow setDocumentEdited:NO]; + [startButton setEnabled:YES]; + [stopButton setEnabled:NO]; + [stopButton setLabel:@"Stop"]; + [stopButton setAction:@selector(stopDownloads:)]; + scheduleTimer=nil; + [self forceUpdate:self]; } - (void)updateScheduleStatus:(NSTimer *)theTimer { - NSDate *startTime = [scheduleTimer fireDate]; - NSDate *currentTime = [NSDate date]; - - unsigned int unitFlags = NSHourCalendarUnit | NSMinuteCalendarUnit | NSDayCalendarUnit | NSSecondCalendarUnit; - NSDateComponents *conversionInfo = [[NSCalendar currentCalendar] components:unitFlags fromDate:currentTime toDate:startTime options:0]; - - NSString *status = [NSString stringWithFormat:@"Time until Start (DD:HH:MM:SS): %02ld:%02ld:%02ld:%02ld", - (long)[conversionInfo day], (long)[conversionInfo hour], - (long)[conversionInfo minute],(long)[conversionInfo second]]; - if (!runUpdate) - [currentProgress setStringValue:status]; - [currentIndicator setIndeterminate:YES]; - [currentIndicator startAnimation:self]; + NSDate *startTime = [scheduleTimer fireDate]; + NSDate *currentTime = [NSDate date]; + + unsigned int unitFlags = NSHourCalendarUnit | NSMinuteCalendarUnit | NSDayCalendarUnit | NSSecondCalendarUnit; + NSDateComponents *conversionInfo = [[NSCalendar currentCalendar] components:unitFlags fromDate:currentTime toDate:startTime options:0]; + + NSString *status = [NSString stringWithFormat:@"Time until Start (DD:HH:MM:SS): %02ld:%02ld:%02ld:%02ld", + (long)[conversionInfo day], (long)[conversionInfo hour], + (long)[conversionInfo minute],(long)[conversionInfo second]]; + if (!runUpdate) + [currentProgress setStringValue:status]; + [currentIndicator setIndeterminate:YES]; + [currentIndicator startAnimation:self]; } - (void)stopTimer:(id)sender { - [interfaceTimer invalidate]; - [scheduleTimer invalidate]; - [startButton setEnabled:YES]; - [stopButton setEnabled:NO]; - [stopButton setLabel:@"Stop"]; - [stopButton setAction:@selector(stopDownloads:)]; - [currentProgress setStringValue:@""]; - [currentIndicator setIndeterminate:NO]; - [currentIndicator stopAnimation:self]; - [mainWindow setDocumentEdited:NO]; - runScheduled=NO; + [interfaceTimer invalidate]; + [scheduleTimer invalidate]; + [startButton setEnabled:YES]; + [stopButton setEnabled:NO]; + [stopButton setLabel:@"Stop"]; + [stopButton setAction:@selector(stopDownloads:)]; + [currentProgress setStringValue:@""]; + [currentIndicator setIndeterminate:NO]; + [currentIndicator stopAnimation:self]; + [mainWindow setDocumentEdited:NO]; + runScheduled=NO; } #pragma mark Live TV - (IBAction)showLiveTVWindow:(id)sender { - if (!runDownloads) - { - [liveTVWindow makeKeyAndOrderFront:self]; - } - else - { - NSAlert *downloadRunning = [NSAlert alertWithMessageText:@"Downloads are Running!" - defaultButton:@"Continue" - alternateButton:@"Cancel" - otherButton:nil - informativeTextWithFormat:@"You may experience choppy playback while downloads are running."]; - NSInteger response = [downloadRunning runModal]; - if (response == NSAlertDefaultReturn) - { - [liveTVWindow makeKeyAndOrderFront:self]; - } - } + if (!runDownloads) + { + [liveTVWindow makeKeyAndOrderFront:self]; + } + else + { + NSAlert *downloadRunning = [NSAlert alertWithMessageText:@"Downloads are Running!" + defaultButton:@"Continue" + alternateButton:@"Cancel" + otherButton:nil + informativeTextWithFormat:@"You may experience choppy playback while downloads are running."]; + NSInteger response = [downloadRunning runModal]; + if (response == NSAlertDefaultReturn) + { + [liveTVWindow makeKeyAndOrderFront:self]; + } + } } - (IBAction)startLiveTV:(id)sender { - getiPlayerProxy = [[GetiPlayerProxy alloc] initWithLogger:logger]; - [getiPlayerProxy loadProxyInBackgroundForSelector:@selector(startLiveTV:proxyDict:) withObject:sender onTarget:self silently:NO]; + getiPlayerProxy = [[GetiPlayerProxy alloc] initWithLogger:logger]; + [getiPlayerProxy loadProxyInBackgroundForSelector:@selector(startLiveTV:proxyDict:) withObject:sender onTarget:self silently:NO]; } - (IBAction)startLiveTV:(id)sender proxyDict:(NSDictionary *)proxyDict { - getiPlayerProxy = nil; - if ([proxyDict[@"proxy"] code] == kProxyLoadCancelled) - return; - getiPlayerStreamer = [[NSTask alloc] init]; - mplayerStreamer = [[NSTask alloc] init]; - liveTVPipe = [[NSPipe alloc] init]; - liveTVError = [[NSPipe alloc] init]; - - [getiPlayerStreamer setLaunchPath:@"/usr/bin/perl"]; - [getiPlayerStreamer setStandardOutput:liveTVPipe]; - [getiPlayerStreamer setStandardError:liveTVPipe]; - [mplayerStreamer setStandardInput:liveTVPipe]; - [mplayerStreamer setLaunchPath:[[NSBundle mainBundle] pathForResource:@"mplayer" ofType:nil]]; - [mplayerStreamer setStandardError:liveTVError]; - [mplayerStreamer setStandardOutput:liveTVError]; - - //Get selected channel - LiveTVChannel *selectedChannel = [liveTVChannelController arrangedObjects][[liveTVChannelController selectionIndex]]; - - //Set Proxy Arguments - NSString *proxyArg = NULL; - NSString *partialProxyArg = NULL; - if (proxy) - { - proxyArg = [[NSString alloc] initWithFormat:@"-p%@", [proxy url]]; - if (![[[NSUserDefaults standardUserDefaults] valueForKey:@"AlwaysUseProxy"] boolValue]) - { - partialProxyArg = @"--partial-proxy"; - } - } - - //Prepare Arguments - NSArray *args = @[[[NSBundle mainBundle] pathForResource:@"get_iplayer" ofType:@"pl"], - [GetiPlayerArguments sharedController].profileDirArg, - @"--stream", - @"--modes=flashnormal", - @"--type=livetv", - [selectedChannel channel], - //@"--player=mplayer -cache 3072 -", - // [NSString stringWithFormat:@"--player=\"%@\" -cache 3072 -", [[NSBundle mainBundle] pathForResource:@"mplayer" ofType:nil]], - proxyArg, - partialProxyArg]; - [getiPlayerStreamer setArguments:args]; - - [mplayerStreamer setArguments:@[@"-cache",@"3072",@"-"]]; - - - [getiPlayerStreamer launch]; - [mplayerStreamer launch]; - [liveStart setEnabled:NO]; - [liveStop setEnabled:YES]; + getiPlayerProxy = nil; + if ([proxyDict[@"proxy"] code] == kProxyLoadCancelled) + return; + getiPlayerStreamer = [[NSTask alloc] init]; + mplayerStreamer = [[NSTask alloc] init]; + liveTVPipe = [[NSPipe alloc] init]; + liveTVError = [[NSPipe alloc] init]; + + [getiPlayerStreamer setLaunchPath:@"/usr/bin/perl"]; + [getiPlayerStreamer setStandardOutput:liveTVPipe]; + [getiPlayerStreamer setStandardError:liveTVPipe]; + [mplayerStreamer setStandardInput:liveTVPipe]; + [mplayerStreamer setLaunchPath:[[NSBundle mainBundle] pathForResource:@"mplayer" ofType:nil]]; + [mplayerStreamer setStandardError:liveTVError]; + [mplayerStreamer setStandardOutput:liveTVError]; + + //Get selected channel + LiveTVChannel *selectedChannel = [liveTVChannelController arrangedObjects][[liveTVChannelController selectionIndex]]; + + //Set Proxy Arguments + NSString *proxyArg = NULL; + NSString *partialProxyArg = NULL; + if (proxy) + { + proxyArg = [[NSString alloc] initWithFormat:@"-p%@", [proxy url]]; + if (![[[NSUserDefaults standardUserDefaults] valueForKey:@"AlwaysUseProxy"] boolValue]) + { + partialProxyArg = @"--partial-proxy"; + } + } + + //Prepare Arguments + NSArray *args = @[[[NSBundle mainBundle] pathForResource:@"get_iplayer" ofType:@"pl"], + [GetiPlayerArguments sharedController].profileDirArg, + @"--stream", + @"--modes=flashnormal", + @"--type=livetv", + [selectedChannel channel], + //@"--player=mplayer -cache 3072 -", + // [NSString stringWithFormat:@"--player=\"%@\" -cache 3072 -", [[NSBundle mainBundle] pathForResource:@"mplayer" ofType:nil]], + proxyArg, + partialProxyArg]; + [getiPlayerStreamer setArguments:args]; + + [mplayerStreamer setArguments:@[@"-cache",@"3072",@"-"]]; + + + [getiPlayerStreamer launch]; + [mplayerStreamer launch]; + [liveStart setEnabled:NO]; + [liveStop setEnabled:YES]; } - (IBAction)stopLiveTV:(id)sender { - [getiPlayerStreamer interrupt]; - [mplayerStreamer interrupt]; - [liveStart setEnabled:YES]; - [liveStop setEnabled:NO]; + [getiPlayerStreamer interrupt]; + [mplayerStreamer interrupt]; + [liveStart setEnabled:YES]; + [liveStop setEnabled:NO]; } #pragma mark Proxy diff --git a/Programme.h b/Programme.h index 0750ba0a..4e792583 100644 --- a/Programme.h +++ b/Programme.h @@ -72,6 +72,7 @@ typedef NS_ENUM(NSInteger, GIA_ProgrammeType) { - (NSString *)typeDescription; - (void)getName; - (void)processGetNameData:(NSString *)getNameData; +- (void)getNameSynchronous; @property (readwrite) NSString *showName; @property (readwrite) NSString *tvNetwork; diff --git a/Programme.m b/Programme.m index 65aed944..a22d270b 100644 --- a/Programme.m +++ b/Programme.m @@ -14,137 +14,143 @@ //extern bool runDownloads; -@implementation Programme +@implementation Programme { + bool getNameRunning; +} + - (id)initWithLogController:(LogController *)logger { - if (![self init]) return nil; - self->logger = logger; - return self; + if (![self init]) return nil; + self->logger = logger; + return self; } - (id)initWithInfo:(id)sender pid:(NSString *)PID programmeName:(NSString *)SHOWNAME network:(NSString *)TVNETWORK logController:(LogController *)logger { - if (!(self = [super init])) return nil; - self->logger = logger; - pid = [PID stringByReplacingOccurrencesOfString:@";amp" withString:@""]; - showName = [[[NSString alloc] initWithString:SHOWNAME] stringByDecodingHTMLEntities]; - tvNetwork = [[NSString alloc] initWithString:TVNETWORK]; - status = [[NSString alloc] init]; - complete = @NO; - successful = @NO; - path = @"Unknown"; - seriesName = [[NSString alloc] init]; - episodeName = [[NSString alloc] init]; - timeadded = [[NSNumber alloc] init]; - processedPID = @YES; - radio = @NO; - subtitlePath=[[NSString alloc] init]; - realPID=[[NSString alloc] init]; - reasonForFailure=[[NSString alloc] init]; - availableModes=[[NSString alloc] init]; - desc=[[NSString alloc] init]; - podcast=@NO; - extendedMetadataRetrieved=@NO; - return self; + if (!(self = [super init])) return nil; + self->logger = logger; + pid = [PID stringByReplacingOccurrencesOfString:@";amp" withString:@""]; + showName = [[[NSString alloc] initWithString:SHOWNAME] stringByDecodingHTMLEntities]; + tvNetwork = [[NSString alloc] initWithString:TVNETWORK]; + status = [[NSString alloc] init]; + complete = @NO; + successful = @NO; + path = @"Unknown"; + seriesName = [[NSString alloc] init]; + episodeName = [[NSString alloc] init]; + timeadded = [[NSNumber alloc] init]; + processedPID = @YES; + radio = @NO; + subtitlePath=[[NSString alloc] init]; + realPID=[[NSString alloc] init]; + reasonForFailure=[[NSString alloc] init]; + availableModes=[[NSString alloc] init]; + desc=[[NSString alloc] init]; + podcast=@NO; + extendedMetadataRetrieved=@NO; + getNameRunning = false; + return self; } - (id)initWithShow:(Programme *)show { - pid = [[NSString alloc] initWithString:[show pid]]; - showName = [[[NSString alloc] initWithString:[show showName]] stringByDecodingHTMLEntities]; - tvNetwork = [[NSString alloc] initWithString:[show tvNetwork]]; - status = [[NSString alloc] initWithString:[show status]]; - complete = @NO; - successful = @NO; - path = [[NSString alloc] initWithString:[show path]]; - seriesName = [[NSString alloc] init]; - episodeName = [[NSString alloc] init]; - timeadded = [[NSNumber alloc] init]; - processedPID = @YES; - radio = [show radio]; - realPID = [show realPID]; - subtitlePath = [show subtitlePath]; - reasonForFailure=[show reasonForFailure]; - availableModes=[[NSString alloc] init]; - desc=[[NSString alloc] init]; - podcast = [show podcast]; - extendedMetadataRetrieved=@NO; - return self; + pid = [[NSString alloc] initWithString:[show pid]]; + showName = [[[NSString alloc] initWithString:[show showName]] stringByDecodingHTMLEntities]; + tvNetwork = [[NSString alloc] initWithString:[show tvNetwork]]; + status = [[NSString alloc] initWithString:[show status]]; + complete = @NO; + successful = @NO; + path = [[NSString alloc] initWithString:[show path]]; + seriesName = [[NSString alloc] init]; + episodeName = [[NSString alloc] init]; + timeadded = [[NSNumber alloc] init]; + processedPID = @YES; + radio = [show radio]; + realPID = [show realPID]; + subtitlePath = [show subtitlePath]; + reasonForFailure=[show reasonForFailure]; + availableModes=[[NSString alloc] init]; + desc=[[NSString alloc] init]; + podcast = [show podcast]; + extendedMetadataRetrieved=@NO; + getNameRunning = false; + return self; } - (id)init { - if (!(self = [super init])) return nil; - pid = [[NSString alloc] init]; - showName = [[NSString alloc] init]; - tvNetwork = [[NSString alloc] init]; - if (runDownloads) - { - status = @"Waiting..."; - } - else - { - status = [[NSString alloc] init]; - } - seriesName = [[NSString alloc] init]; - episodeName = [[NSString alloc] init]; - complete = @NO; - successful = @NO; - timeadded = [[NSNumber alloc] init]; - path = @"Unknown"; - processedPID = @NO; - radio = @NO; - url = [[NSString alloc] init]; - realPID=[[NSString alloc] init]; - subtitlePath=[[NSString alloc] init]; - reasonForFailure=[[NSString alloc] init]; - availableModes=[[NSString alloc] init]; - desc=[[NSString alloc] init]; - podcast=@NO; - extendedMetadataRetrieved=@NO; - return self; + if (!(self = [super init])) return nil; + pid = [[NSString alloc] init]; + showName = [[NSString alloc] init]; + tvNetwork = [[NSString alloc] init]; + if (runDownloads) + { + status = @"Waiting..."; + } + else + { + status = [[NSString alloc] init]; + } + seriesName = [[NSString alloc] init]; + episodeName = [[NSString alloc] init]; + complete = @NO; + successful = @NO; + timeadded = [[NSNumber alloc] init]; + path = @"Unknown"; + processedPID = @NO; + radio = @NO; + url = [[NSString alloc] init]; + realPID=[[NSString alloc] init]; + subtitlePath=[[NSString alloc] init]; + reasonForFailure=[[NSString alloc] init]; + availableModes=[[NSString alloc] init]; + desc=[[NSString alloc] init]; + podcast=@NO; + extendedMetadataRetrieved=@NO; + getNameRunning = false; + return self; } - (id)description { - return [NSString stringWithFormat:@"%@: %@",pid,showName]; + return [NSString stringWithFormat:@"%@: %@",pid,showName]; } - (void) encodeWithCoder: (NSCoder *)coder { - [coder encodeObject: showName forKey:@"showName"]; - [coder encodeObject: pid forKey:@"pid"]; - [coder encodeObject:tvNetwork forKey:@"tvNetwork"]; - [coder encodeObject:status forKey:@"status"]; - [coder encodeObject:path forKey:@"path"]; - [coder encodeObject:seriesName forKey:@"seriesName"]; - [coder encodeObject:episodeName forKey:@"episodeName"]; - [coder encodeObject:timeadded forKey:@"timeadded"]; - [coder encodeObject:processedPID forKey:@"processedPID"]; - [coder encodeObject:radio forKey:@"radio"]; - [coder encodeObject:realPID forKey:@"realPID"]; - [coder encodeObject:url forKey:@"url"]; - [coder encodeObject:podcast forKey:@"podcast"]; + [coder encodeObject: showName forKey:@"showName"]; + [coder encodeObject: pid forKey:@"pid"]; + [coder encodeObject:tvNetwork forKey:@"tvNetwork"]; + [coder encodeObject:status forKey:@"status"]; + [coder encodeObject:path forKey:@"path"]; + [coder encodeObject:seriesName forKey:@"seriesName"]; + [coder encodeObject:episodeName forKey:@"episodeName"]; + [coder encodeObject:timeadded forKey:@"timeadded"]; + [coder encodeObject:processedPID forKey:@"processedPID"]; + [coder encodeObject:radio forKey:@"radio"]; + [coder encodeObject:realPID forKey:@"realPID"]; + [coder encodeObject:url forKey:@"url"]; + [coder encodeObject:podcast forKey:@"podcast"]; } - (id) initWithCoder: (NSCoder *)coder { - if (!(self = [super init])) return nil; - pid = [[NSString alloc] initWithString:[coder decodeObjectForKey:@"pid"]]; - showName = [[NSString alloc] initWithString:[coder decodeObjectForKey:@"showName"]]; - tvNetwork = [[NSString alloc] initWithString:[coder decodeObjectForKey:@"tvNetwork"]]; - status = @""; - complete = @NO; - successful = @NO; - path = [[NSString alloc] initWithString:[coder decodeObjectForKey:@"path"]]; - seriesName = [[NSString alloc] initWithString:[coder decodeObjectForKey:@"seriesName"]]; - episodeName = [[NSString alloc] initWithString:[coder decodeObjectForKey:@"episodeName"]]; - timeadded = [coder decodeObjectForKey:@"timeadded"]; - processedPID = [coder decodeObjectForKey:@"processedPID"]; - radio = [coder decodeObjectForKey:@"radio"]; - realPID = [coder decodeObjectForKey:@"realPID"]; - url = [coder decodeObjectForKey:@"url"]; - subtitlePath=[[NSString alloc] init]; - reasonForFailure=[[NSString alloc] init]; - availableModes=[[NSString alloc] init]; - desc=[[NSString alloc] init]; - podcast = [coder decodeObjectForKey:@"podcast"]; - extendedMetadataRetrieved=@NO; - return self; + if (!(self = [super init])) return nil; + pid = [[NSString alloc] initWithString:[coder decodeObjectForKey:@"pid"]]; + showName = [[NSString alloc] initWithString:[coder decodeObjectForKey:@"showName"]]; + tvNetwork = [[NSString alloc] initWithString:[coder decodeObjectForKey:@"tvNetwork"]]; + status = @""; + complete = @NO; + successful = @NO; + path = [[NSString alloc] initWithString:[coder decodeObjectForKey:@"path"]]; + seriesName = [[NSString alloc] initWithString:[coder decodeObjectForKey:@"seriesName"]]; + episodeName = [[NSString alloc] initWithString:[coder decodeObjectForKey:@"episodeName"]]; + timeadded = [coder decodeObjectForKey:@"timeadded"]; + processedPID = [coder decodeObjectForKey:@"processedPID"]; + radio = [coder decodeObjectForKey:@"radio"]; + realPID = [coder decodeObjectForKey:@"realPID"]; + url = [coder decodeObjectForKey:@"url"]; + subtitlePath=[[NSString alloc] init]; + reasonForFailure=[[NSString alloc] init]; + availableModes=[[NSString alloc] init]; + desc=[[NSString alloc] init]; + podcast = [coder decodeObjectForKey:@"podcast"]; + extendedMetadataRetrieved=@NO; + return self; } /* - (id)pasteboardPropertyListForType:(NSString *)type @@ -161,252 +167,262 @@ - (NSArray *)writableTypesForPasteboard:(NSPasteboard *)pasteboard */ -(void)setPid:(NSString *)newPID { - self->pid = [newPID stringByReplacingOccurrencesOfString:@"amp;" withString:@""]; + self->pid = [newPID stringByReplacingOccurrencesOfString:@"amp;" withString:@""]; } -(NSString *)pid { - return pid; + return pid; } -(void)printLongDescription { - NSLog(@"%@:\n TV Network: %@\n Processed PID: %@\n Real PID: %@\n Available Modes: %@\n URL: %@\n", - showName,tvNetwork,processedPID,realPID,availableModes,url); + NSLog(@"%@:\n TV Network: %@\n Processed PID: %@\n Real PID: %@\n Available Modes: %@\n URL: %@\n", + showName,tvNetwork,processedPID,realPID,availableModes,url); } -(void)retrieveExtendedMetadata { - [logger addToLog:@"Retrieving Extended Metadata" :self]; - getiPlayerProxy = [[GetiPlayerProxy alloc] initWithLogger:logger]; - [getiPlayerProxy loadProxyInBackgroundForSelector:@selector(proxyRetrievalFinished:proxyDict:) withObject:nil onTarget:self silently:NO]; + [logger addToLog:@"Retrieving Extended Metadata" :self]; + getiPlayerProxy = [[GetiPlayerProxy alloc] initWithLogger:logger]; + [getiPlayerProxy loadProxyInBackgroundForSelector:@selector(proxyRetrievalFinished:proxyDict:) withObject:nil onTarget:self silently:NO]; } -(void)proxyRetrievalFinished:(id)sender proxyDict:(NSDictionary *)proxyDict { - getiPlayerProxy = nil; + getiPlayerProxy = nil; if (proxyDict && [proxyDict[@"error"] code] == kProxyLoadCancelled) return; - - taskOutput = [[NSMutableString alloc] init]; - metadataTask = [[NSTask alloc] init]; - pipe = [[NSPipe alloc] init]; - - [metadataTask setLaunchPath:@"/usr/bin/perl"]; - NSMutableArray *args = [NSMutableArray arrayWithArray:@[[[NSBundle mainBundle] pathForResource:@"get_iplayer" ofType:@"pl"], - @"--nopurge", - @"--nocopyright", - @"-e60480000000000000", - @"-i", - [NSString stringWithFormat:@"--profile-dir=%@",[@"~/Library/Application Support/Get iPlayer Automator/" stringByExpandingTildeInPath]],pid]]; - if (proxyDict[@"proxy"]) { - [args addObject:[NSString stringWithFormat:@"-p%@",[proxyDict[@"proxy"] url]]]; - - if (![[[NSUserDefaults standardUserDefaults] valueForKey:@"AlwaysUseProxy"] boolValue]) - { - [args addObject:@"--partial-proxy"]; - } - - } - - [metadataTask setArguments:args]; - - [metadataTask setStandardOutput:pipe]; - NSFileHandle *fh = [pipe fileHandleForReading]; - - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(metadataRetrievalDataReady:) name:NSFileHandleReadCompletionNotification object:fh]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(metadataRetrievalFinished:) name:NSTaskDidTerminateNotification object:metadataTask]; - - NSMutableDictionary *envVariableDictionary = [NSMutableDictionary dictionaryWithDictionary:[metadataTask environment]]; - envVariableDictionary[@"HOME"] = [@"~" stringByExpandingTildeInPath]; - envVariableDictionary[@"PERL_UNICODE"] = @"AS"; - [metadataTask setEnvironment:envVariableDictionary]; - [metadataTask launch]; - [fh readInBackgroundAndNotify]; + + taskOutput = [[NSMutableString alloc] init]; + metadataTask = [[NSTask alloc] init]; + pipe = [[NSPipe alloc] init]; + + [metadataTask setLaunchPath:@"/usr/bin/perl"]; + NSMutableArray *args = [NSMutableArray arrayWithArray:@[[[NSBundle mainBundle] pathForResource:@"get_iplayer" ofType:@"pl"], + @"--nopurge", + @"--nocopyright", + @"-e60480000000000000", + @"-i", + [NSString stringWithFormat:@"--profile-dir=%@",[@"~/Library/Application Support/Get iPlayer Automator/" stringByExpandingTildeInPath]],pid]]; + if (proxyDict[@"proxy"]) { + [args addObject:[NSString stringWithFormat:@"-p%@",[proxyDict[@"proxy"] url]]]; + + if (![[[NSUserDefaults standardUserDefaults] valueForKey:@"AlwaysUseProxy"] boolValue]) + { + [args addObject:@"--partial-proxy"]; + } + + } + + [metadataTask setArguments:args]; + + [metadataTask setStandardOutput:pipe]; + NSFileHandle *fh = [pipe fileHandleForReading]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(metadataRetrievalDataReady:) name:NSFileHandleReadCompletionNotification object:fh]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(metadataRetrievalFinished:) name:NSTaskDidTerminateNotification object:metadataTask]; + + NSMutableDictionary *envVariableDictionary = [NSMutableDictionary dictionaryWithDictionary:[metadataTask environment]]; + envVariableDictionary[@"HOME"] = [@"~" stringByExpandingTildeInPath]; + envVariableDictionary[@"PERL_UNICODE"] = @"AS"; + [metadataTask setEnvironment:envVariableDictionary]; + [metadataTask launch]; + [fh readInBackgroundAndNotify]; } -(void)metadataRetrievalDataReady:(NSNotification *)n { - NSData *d = [[n userInfo] valueForKey:NSFileHandleNotificationDataItem]; - - if ([d length] > 0) { - NSString *s = [[NSString alloc] initWithData:d - encoding:NSUTF8StringEncoding]; - - [taskOutput appendString:s]; - [logger addToLog:s :self]; - [[pipe fileHandleForReading] readInBackgroundAndNotify]; - } - else { - [self metadataRetrievalFinished:nil]; - } + NSData *d = [[n userInfo] valueForKey:NSFileHandleNotificationDataItem]; + + if ([d length] > 0) { + NSString *s = [[NSString alloc] initWithData:d + encoding:NSUTF8StringEncoding]; + + [taskOutput appendString:s]; + [logger addToLog:s :self]; + [[pipe fileHandleForReading] readInBackgroundAndNotify]; + } + else { + [self metadataRetrievalFinished:nil]; + } } -(void)metadataRetrievalFinished:(NSNotification *)n { - taskRunning=NO; - categories = [self scanField:@"categories" fromList:taskOutput]; - - NSString *descTemp = [self scanField:@"desc" fromList:taskOutput]; - if (descTemp) { - desc = descTemp; - } - - NSString *durationTemp = [self scanField:@"duration" fromList:taskOutput]; - if (durationTemp) { - if ([durationTemp hasSuffix:@"min"]) - duration = [NSNumber numberWithInteger:[durationTemp integerValue]]; - else - duration = [NSNumber numberWithInteger:[durationTemp integerValue]/60]; - } - - firstBroadcast = [self processDate:[self scanField:@"firstbcast" fromList:taskOutput]]; - lastBroadcast = [self processDate:[self scanField:@"lastbcast" fromList:taskOutput]]; - - seriesName = [self scanField:@"longname" fromList:taskOutput]; - - episodeName = [self scanField:@"episode" fromList:taskOutput]; - - NSString *seasonNumber = [self scanField:@"seriesnum" fromList:taskOutput]; - if (seasonNumber) { - season = [seasonNumber integerValue]; - } - - NSString *episodeNumber = [self scanField:@"episodenum" fromList:taskOutput]; - if (episodeNumber) { - episode = [episodeNumber integerValue]; - } - NSString *modeSizesString = [self scanField:@"modesizes" fromList:taskOutput]; - if (modeSizesString) { - NSScanner *sizeScanner = [NSScanner scannerWithString:modeSizesString]; - [sizeScanner scanString:@"default:" intoString:nil]; - NSString *newSizesString; - [sizeScanner scanUpToString:@":" intoString:&newSizesString]; - - NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[a-z]*[0-2]=[0-9]*MB" options:0 error:nil]; - NSArray *matches = [regex matchesInString:newSizesString options:0 range:NSMakeRange(0, [newSizesString length])]; - if ([matches count] > 0) { - NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; - for (NSTextCheckingResult *modesizeResult in matches) { - NSString *modesize = [newSizesString substringWithRange:modesizeResult.range]; - if ([modesize hasPrefix:@"rtsp"] || [modesize hasPrefix:@"wma"]) { - continue; - } - NSArray *comps = [modesize componentsSeparatedByString:@"="]; - if ([comps count] == 2) { - [dictionary setObject:comps[1] forKey:comps[0]]; + taskRunning=NO; + categories = [self scanField:@"categories" fromList:taskOutput]; + + NSString *descTemp = [self scanField:@"desc" fromList:taskOutput]; + if (descTemp) { + desc = descTemp; + } + + NSString *durationTemp = [self scanField:@"duration" fromList:taskOutput]; + if (durationTemp) { + if ([durationTemp hasSuffix:@"min"]) + duration = [NSNumber numberWithInteger:[durationTemp integerValue]]; + else + duration = [NSNumber numberWithInteger:[durationTemp integerValue]/60]; + } + + firstBroadcast = [self processDate:[self scanField:@"firstbcast" fromList:taskOutput]]; + lastBroadcast = [self processDate:[self scanField:@"lastbcast" fromList:taskOutput]]; + + seriesName = [self scanField:@"longname" fromList:taskOutput]; + + episodeName = [self scanField:@"episode" fromList:taskOutput]; + + NSString *seasonNumber = [self scanField:@"seriesnum" fromList:taskOutput]; + if (seasonNumber) { + season = [seasonNumber integerValue]; + } + + NSString *episodeNumber = [self scanField:@"episodenum" fromList:taskOutput]; + if (episodeNumber) { + episode = [episodeNumber integerValue]; + } + NSString *modeSizesString = [self scanField:@"modesizes" fromList:taskOutput]; + if (modeSizesString) { + NSScanner *sizeScanner = [NSScanner scannerWithString:modeSizesString]; + [sizeScanner scanString:@"default:" intoString:nil]; + NSString *newSizesString; + [sizeScanner scanUpToString:@":" intoString:&newSizesString]; + + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[a-z]*[0-2]=[0-9]*MB" options:0 error:nil]; + NSArray *matches = [regex matchesInString:newSizesString options:0 range:NSMakeRange(0, [newSizesString length])]; + if ([matches count] > 0) { + NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; + for (NSTextCheckingResult *modesizeResult in matches) { + NSString *modesize = [newSizesString substringWithRange:modesizeResult.range]; + if ([modesize hasPrefix:@"rtsp"] || [modesize hasPrefix:@"wma"]) { + continue; + } + NSArray *comps = [modesize componentsSeparatedByString:@"="]; + if ([comps count] == 2) { + [dictionary setObject:comps[1] forKey:comps[0]]; + } } - } - modeSizes = dictionary; - } - } - NSString *thumbURL = [self scanField:@"thumbnail4" fromList:taskOutput]; - if (!thumbURL) { - thumbURL = [self scanField:@"thumbnail" fromList:taskOutput]; - } - if (thumbURL) { - NSLog(@"URL: %@", thumbURL); - ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:thumbURL]]; - [request setDelegate:self]; - [request setDidFinishSelector:@selector(thumbnailRequestFinished:)]; - [request setDidFailSelector:@selector(thumbnailRequestFinished:)]; - [request setTimeOutSeconds:3]; - [request setNumberOfTimesToRetryOnTimeout:3]; - [request startAsynchronous]; - } + modeSizes = dictionary; + } + } + NSString *thumbURL = [self scanField:@"thumbnail4" fromList:taskOutput]; + if (!thumbURL) { + thumbURL = [self scanField:@"thumbnail" fromList:taskOutput]; + } + if (thumbURL) { + NSLog(@"URL: %@", thumbURL); + ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:thumbURL]]; + [request setDelegate:self]; + [request setDidFinishSelector:@selector(thumbnailRequestFinished:)]; + [request setDidFailSelector:@selector(thumbnailRequestFinished:)]; + [request setTimeOutSeconds:3]; + [request setNumberOfTimesToRetryOnTimeout:3]; + [request startAsynchronous]; + } } - (void)thumbnailRequestFinished:(ASIHTTPRequest *)request { - if (request.responseStatusCode == 200) { - thumbnail = [[NSImage alloc] initWithData:request.responseData]; - } - successfulRetrieval = @YES; - extendedMetadataRetrieved = @YES; - [[NSNotificationCenter defaultCenter] postNotificationName:@"ExtendedInfoRetrieved" object:self]; - + if (request.responseStatusCode == 200) { + thumbnail = [[NSImage alloc] initWithData:request.responseData]; + } + successfulRetrieval = @YES; + extendedMetadataRetrieved = @YES; + [[NSNotificationCenter defaultCenter] postNotificationName:@"ExtendedInfoRetrieved" object:self]; + } -(NSString *)scanField:(NSString *)field fromList:(NSString *)list { - NSString __autoreleasing *buffer; - - NSScanner *scanner = [NSScanner scannerWithString:list]; - [scanner scanUpToString:[NSString stringWithFormat:@"%@:",field] intoString:nil]; - [scanner scanString:[NSString stringWithFormat:@"%@:",field] intoString:nil]; - [scanner scanCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] intoString:nil]; - [scanner scanUpToCharactersFromSet:[NSCharacterSet newlineCharacterSet] intoString:&buffer]; - - return [buffer copy]; + NSString __autoreleasing *buffer; + + NSScanner *scanner = [NSScanner scannerWithString:list]; + [scanner scanUpToString:[NSString stringWithFormat:@"%@:",field] intoString:nil]; + [scanner scanString:[NSString stringWithFormat:@"%@:",field] intoString:nil]; + [scanner scanCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] intoString:nil]; + [scanner scanUpToCharactersFromSet:[NSCharacterSet newlineCharacterSet] intoString:&buffer]; + + return [buffer copy]; } -(NSDate *)processDate:(NSString *)date { - NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; - if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_8) //10.8, 10.9 - [dateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ssZZZZZ"]; - else //10.7 - [dateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ssZZ"]; - - if (date) { - date = [self scanField:@"default" fromList:date]; - if (date) { - if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_8) { //Before 10.9 doesn't recognize the Z - if ([date hasSuffix:@"Z"]) { - date = [date stringByReplacingOccurrencesOfString:@"Z" withString:@"+00:00"]; + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_8) //10.8, 10.9 + [dateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ssZZZZZ"]; + else //10.7 + [dateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ssZZ"]; + + if (date) { + date = [self scanField:@"default" fromList:date]; + if (date) { + if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_8) { //Before 10.9 doesn't recognize the Z + if ([date hasSuffix:@"Z"]) { + date = [date stringByReplacingOccurrencesOfString:@"Z" withString:@"+00:00"]; + } + } + if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_7) { + date = [date stringByReplacingCharactersInRange:NSMakeRange(date.length - 3, 1) withString:@""]; } - } - if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_7) { - date = [date stringByReplacingCharactersInRange:NSMakeRange(date.length - 3, 1) withString:@""]; - } - return [dateFormatter dateFromString:date]; - } - } - return nil; + return [dateFormatter dateFromString:date]; + } + } + return nil; } -(void)cancelMetadataRetrieval { - if ([metadataTask isRunning]) { - [metadataTask interrupt]; - } - [logger addToLog:@"Metadata Retrieval Cancelled" :self]; + if ([metadataTask isRunning]) { + [metadataTask interrupt]; + } + [logger addToLog:@"Metadata Retrieval Cancelled" :self]; } - (GIA_ProgrammeType)type { - if (radio.boolValue) - return GiA_ProgrammeTypeBBC_Radio; - else if (podcast.boolValue) - return GiA_ProgrammeTypeBBC_Podcast; - else if ([tvNetwork hasPrefix:@"ITV"]) - return GIA_ProgrammeTypeITV; - else - return GiA_ProgrammeTypeBBC_TV; + if (radio.boolValue) + return GiA_ProgrammeTypeBBC_Radio; + else if (podcast.boolValue) + return GiA_ProgrammeTypeBBC_Podcast; + else if ([tvNetwork hasPrefix:@"ITV"]) + return GIA_ProgrammeTypeITV; + else + return GiA_ProgrammeTypeBBC_TV; } - (NSString *)typeDescription { - NSDictionary *dic = @{@(GiA_ProgrammeTypeBBC_TV): @"BBC TV", - @(GiA_ProgrammeTypeBBC_Radio): @"BBC Radio", - @(GiA_ProgrammeTypeBBC_Podcast): @"BBC Podcast", - @(GIA_ProgrammeTypeITV): @"ITV"}; - - return [dic objectForKey:@([self type])]; + NSDictionary *dic = @{@(GiA_ProgrammeTypeBBC_TV): @"BBC TV", + @(GiA_ProgrammeTypeBBC_Radio): @"BBC Radio", + @(GiA_ProgrammeTypeBBC_Podcast): @"BBC Podcast", + @(GIA_ProgrammeTypeITV): @"ITV"}; + + return [dic objectForKey:@([self type])]; } - (BOOL)isEqual:(id)object { - if ([object isKindOfClass:[self class]]) { - Programme *otherP = (Programme *)object; - return [otherP.showName isEqual:showName] && [otherP.pid isEqual:pid]; - } - else { - return false; - } + if ([object isKindOfClass:[self class]]) { + Programme *otherP = (Programme *)object; + return [otherP.showName isEqual:showName] && [otherP.pid isEqual:pid]; + } + else { + return false; + } +} + +- (void)getNameSynchronous +{ + [self getName]; + while (getNameRunning) { + [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow: 0.1]]; + } } - (void)getName { @autoreleasepool { + getNameRunning = true; + NSTask *getNameTask = [[NSTask alloc] init]; NSPipe *getNamePipe = [[NSPipe alloc] init]; NSMutableString *getNameData = [[NSMutableString alloc] initWithString:@""]; @@ -480,6 +496,7 @@ - (void)processGetNameData:(NSString *)getNameData [p setValue:index forKey:@"pid"]; [p setValue:tvNetwork forKey:@"tvNetwork"]; [p setUrl:url]; + p.status = @"Available"; if ([type isEqualToString:@"radio"]) [p setValue:@YES forKey:@"radio"]; else if ([type isEqualToString:@"podcast"]) [p setPodcast:@YES]; } @@ -503,7 +520,10 @@ - (void)processGetNameData:(NSString *)getNameData [p getNameFromPID]; } else + { [p setProcessedPID:@YES]; + getNameRunning = false; + } } @@ -630,6 +650,7 @@ - (void)processGetNameDataFromPID:(NSString *)getNameData [p setValue:@"Unknown: PID Not Found" forKey:@"showName"]; } [p setProcessedPID:@NO]; + getNameRunning = false; } @synthesize showName;