forked from agno/TVShows
/
PresetTorrentsController.m
807 lines (653 loc) · 32 KB
/
PresetTorrentsController.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
/*
* This file is part of the TVShows 2 ("Phoenix") source code.
* http://github.com/victorpimentel/TVShows/
*
* TVShows is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* You should have received a copy of the GNU General Public License
* along with TVShows. If not, see <http://www.gnu.org/licenses/>.
*
*/
#import "AppInfoConstants.h"
#import "PresetTorrentsController.h"
#import "TabController.h"
#import "TSUserDefaults.h"
#import "TSParseXMLFeeds.h"
#import "TSRegexFun.h"
#import "TSTorrentFunctions.h"
#import "WebsiteFunctions.h"
#import "RegexKitLite.h"
#import "TheTVDB.h"
#import "TorrentzParser.h"
#import "NSXMLNode-utils.h"
#pragma mark Define Macros
#define AddRSSInstructionsURL @"http://blog.tvshowsapp.com/post/6487546781/how-to-add-a-custom-rss-to-tvshows"
#define AddRSSInstructionsURLES @"http://blog.tvshowsapp.com/post/6488183421/como-anadir-un-rss-personalizado-a-tvshows"
#define TVDBURL @"http://thetvdb.com/?tab=series&id=%@"
#define ShowListURL @"https://github.com/victorpimentel/tvshowsapp.com/raw/master/showlist/showlist.xml"
#define ShowListMirror @"http://tvshowsapp.com/showlist/showlist.xml"
#define SelectTagsRegex @"<select name=\"show\">(.+?)</select>"
#define OptionTagsRegex @"(?!<option value=\")([[:digit:]]+)(.*?)(?=</option>)"
#define RSSIDRegex @"([[:digit:]]+)(?![[:alnum:]]|[[:space:]])"
#define DisplayNameRegex @"\">(.+)"
#define SeparatorBetweenNameAndID @"\">"
#pragma mark -
#pragma mark Preset Torrents Window
@implementation PresetTorrentsController
@synthesize subscriptionsDelegate, presetsDelegate, PTArrayController, SBArrayController;
- init
{
if((self = [super init])) {
hasDownloadedList = NO;
isTranslated = NO;
}
return self;
}
- (void) localizeWindow
{
// Localize the buttons
[showQuality setTitle: TSLocalizeString(@"Download in HD")];
[cancelButton setTitle: TSLocalizeString(@"Cancel")];
[subscribeButton setTitle: TSLocalizeString(@"Subscribe")];
[moreInfoButton setTitle: [NSString stringWithFormat:@"%@...", TSLocalizeString(@"More Info")]];
[startFromText setStringValue: TSLocalizeString(@"Start subscription with:")];
[nextAiredButton setTitle: TSLocalizeString(@"Next aired episode")];
[otherEpisodeButton setTitle: TSLocalizeString(@"This episode:")];
// Localize the headings of the table columns
[[colHD headerCell] setStringValue: TSLocalizeString(@"HD")];
[[colName headerCell] setStringValue: TSLocalizeString(@"Episode Name")];
[[colSeason headerCell] setStringValue: TSLocalizeString(@"Season")];
[[colEpisode headerCell] setStringValue: TSLocalizeString(@"Episode")];
[[colDate headerCell] setStringValue: TSLocalizeString(@"Published Date")];
// Search field and Loading text
[[PTSearchField cell] setPlaceholderString: TSLocalizeString(@"Search")];
[moreShowsButton setTitle:[NSString stringWithFormat:@"%@...", TSLocalizeString(@"More Shows")]];
[loadingText setStringValue: TSLocalizeString(@"Updating Show Information…")];
// Sort the preloaded list
[self sortTorrentShowList];
// Reset the selection and search bar
[PTArrayController setSelectionIndex:-1];
[[PTSearchField cell] cancelButtonCell];
// Disable any control
[PTSearchField setEnabled:NO];
[PTTableView setEnabled:NO];
[cancelButton setEnabled:NO];
[subscribeButton setEnabled:NO];
[subscribeButton setTitle: TSLocalizeString(@"Subscribe")];
[showQuality setEnabled:NO];
[moreInfoButton setEnabled:NO];
[nextAiredButton setEnabled:NO];
[otherEpisodeButton setEnabled:NO];
// And start the loading throbber
[loading startAnimation:nil];
[loadingText setHidden:NO];
[descriptionView setHidden:YES];
isTranslated = YES;
}
- (IBAction) displayPresetTorrentsWindow:(id)sender
{
errorHasOccurred = NO;
// Localize things and prepare the window (only needed the first time)
if (!isTranslated) {
[self localizeWindow];
}
// Always remember the user preference
[showQuality setState:[TSUserDefaults getBoolFromKey:@"AutoSelectHDVersion" withDefault:NO]];
// Grab the list of episodes
[episodeArrayController removeObjects:[episodeArrayController content]];
[self tableViewSelectionDidChange:nil];
[NSApp beginSheet:PTWindow
modalForWindow:[[NSApplication sharedApplication] mainWindow]
modalDelegate:nil
didEndSelector:nil
contextInfo:nil];
// Only download the show list once per session
if (!hasDownloadedList) {
[self downloadTorrentShowList];
// Close the window
if(errorHasOccurred == YES) {
[NSApp endSheet:PTWindow];
[self closePresetTorrentsWindow:nil];
return;
}
// Enable the controls
[PTSearchField setEnabled:YES];
[PTTableView setEnabled:YES];
[cancelButton setEnabled:YES];
[showQuality setEnabled:YES];
[moreInfoButton setEnabled:YES];
[nextAiredButton setEnabled:YES];
// Reset the selection
[PTArrayController setSelectionIndex:0];
[PTTableView scrollRowToVisible:0];
}
// Focus the search field
[PTSearchField becomeFirstResponder];
[NSApp endSheet: PTWindow];
[NSApp runModalForWindow: PTWindow];
}
- (IBAction) closePresetTorrentsWindow:(id)sender
{
[NSApp stopModal];
[PTWindow orderOut:self];
}
- (IBAction) showQualityDidChange:(id)sender
{
if ([showQuality state]) {
// Is HD and HD is enabled.
[episodeArrayController setFilterPredicate:[NSPredicate predicateWithFormat:@"isHD == '1'"]];
} else if (![showQuality state]) {
// Is not HD and HD is not enabled.
[episodeArrayController setFilterPredicate:[NSPredicate predicateWithFormat:@"isHD == '0'"]];
}
// Select the first result
if ([[episodeArrayController arrangedObjects] count] > 0) {
[episodeTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO];
[otherEpisodeButton setEnabled:YES];
} else {
[nextAiredButton setState:YES];
[otherEpisodeButton setEnabled:NO];
[otherEpisodeButton setState:NO];
}
}
- (void) sortTorrentShowList
{
// Sort the shows alphabetically
NSSortDescriptor *PTSortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"sortName"
ascending:YES
selector:@selector(caseInsensitiveCompare:)];
[PTArrayController setSortDescriptors:[NSArray arrayWithObject:PTSortDescriptor]];
[PTSortDescriptor release];
}
- (IBAction) reloadShowList:(id)sender {
// Start the loading throbber
[loading startAnimation:nil];
[loadingText setHidden:NO];
// Grab the list of episodes (again)
[episodeArrayController removeObjects:[episodeArrayController content]];
[TSUserDefaults setKey:@"LastDownloadedShowList" fromDate:nil];
[self downloadTorrentShowList];
// Reset the selection
[PTArrayController setSelectionIndex:0];
[PTTableView scrollRowToVisible:0];
// Focus the search field
[PTSearchField becomeFirstResponder];
}
- (IBAction)visitInstructionsButton:(id)sender {
// Choose between the english version and the spanish one
NSString *locale = [[[NSLocale currentLocale] localeIdentifier] substringToIndex:2];
if ([locale isEqualToString:@"es"] ||
[locale isEqualToString:@"ca"] ||
[locale isEqualToString:@"eu"] ||
[locale isEqualToString:@"gl"]) {
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:AddRSSInstructionsURLES]];
} else {
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:AddRSSInstructionsURL]];
}
}
- (void) updateSubscriptions
{
// Update all subscriptions
for (NSManagedObject *show in [SBArrayController arrangedObjects]) {
// Only update the default tv shows
if ([show valueForKey:@"filters"] == nil) {
// Let's assume it is cancelled
BOOL cancelled = YES;
// Search in every known show
for (NSMutableDictionary *showDict in [PTArrayController arrangedObjects]) {
NSString *name = [show valueForKey:@"name"];
// Fix some shows that changed their names
if ([name isEqualToString:@"30 Seconds AU"]) name = @"30 Seconds";
if ([name isEqualToString:@"Archer"]) name = @"Archer (2009)";
if ([name isEqualToString:@"Being Human"]) name = @"Being Human (US)";
if ([name isEqualToString:@"Big Brother US"]) name = @"Big Brother";
if ([name isEqualToString:@"Bob's Burger"]) name = @"Bob's Burgers";
if ([name isEqualToString:@"Castle"]) name = @"Castle (2009)";
if ([name isEqualToString:@"Conan"]) name = @"Conan (2010)";
if ([name isEqualToString:@"Doctor Who"]) name = @"Doctor Who (2005)";
if ([name isEqualToString:@"David Letterman"]) name = @"Late Show with David Letterman";
if ([name isEqualToString:@"Hells Kitchen"]) name = @"Hells Kitchen (US)";
if ([name isEqualToString:@"MonsterQuest"]) name = @"Monster Quest";
if ([name isEqualToString:@"Parenthood"]) name = @"Parenthood (2010)";
if ([name isEqualToString:@"The Big C "]) name = @"The Big C";
if ([name isEqualToString:@"Shameless US"]) name = @"Shameless (US)";
if ([name isEqualToString:@"The Office"]) name = @"The Office (US)";
if ([name isEqualToString:@"The Daily Show"]) name = @"The Daily Show with Jon Stewart";
if ([name isEqualToString:@"The Killing"]) name = @"The Killing (2011)";
if ([name isEqualToString:@"Undercover Boss"]) name = @"Undercover Boss (US)";
if ([name isEqualToString:@"Who Do You Think You Are"]) name = @"Who Do You Think You Are (US)";
// And finally update all the info!
if ([name isEqualToString:[showDict valueForKey:@"displayName"]] ||
[[show valueForKey:@"tvdbID"] isEqualTo:[showDict valueForKey:@"tvdbID"]]) {
// Refresh the show from the subscriptions (it may have changed)
[[subscriptionsDelegate managedObjectContext] refreshObject:show mergeChanges:YES];
bool cleanSortName = YES;
NSArray *lastEpisode = [TSRegexFun parseSeasonAndEpisode:[show valueForKey:@"sortName"]];
// In the past the app could have downloaded some movies instead of the episodes, fix that
if (lastEpisode != nil &&
([lastEpisode count] == 4 ||
([lastEpisode count] == 3 && [[lastEpisode objectAtIndex:1] integerValue] != 20))) {
cleanSortName = NO;
}
[show setValue:[showDict valueForKey:@"displayName"] forKey:@"name"];
if (cleanSortName) [show setValue:[showDict valueForKey:@"sortName"] forKey:@"sortName"];
[show setValue:[showDict valueForKey:@"tvdbID"] forKey:@"tvdbID"];
if ([showDict valueForKey:@"name"]) [show setValue:[showDict valueForKey:@"name"] forKey:@"url"];
// Great, so it is not cancelled
cancelled = NO;
// Be sure to process pending changes before saving or it won't save correctly.
[[subscriptionsDelegate managedObjectContext] processPendingChanges];
[subscriptionsDelegate saveAction];
break;
}
}
// Oh, oh, the show has been cancelled, warn the user!
if (cancelled) {
// By disabling the sortName, the user interface gets updated
[show setValue:@"" forKey:@"sortName"];
}
}
}
}
- (void) downloadTorrentShowList
{
// First check if we need to update the show list
NSDate *lastChecked = [TSUserDefaults getDateFromKey:@"LastDownloadedShowList"];
// If seven days did not pass since the last check, do not update the show list
if (lastChecked != nil && [[NSDate date] timeIntervalSinceDate:lastChecked] < 7*24*60*60) {
LogInfo(@"Using a cached show list (%@).", lastChecked);
hasDownloadedList = YES;
return;
}
LogInfo(@"Downloading an updated show list.");
// The rest of this method is extremely messy but it works for the time being
// Feel free to improve it if you find a way
// Download the page containing the show list
NSString *showListContents = [WebsiteFunctions downloadStringFrom:ShowListURL];
// Try the mirror if there was no luck
if (!showListContents || [showListContents length] < 1000) {
LogInfo(@"Downloading an updated show list from the mirror.");
showListContents = [WebsiteFunctions downloadStringFrom:ShowListMirror];
}
NSXMLDocument *doc = [[[NSXMLDocument alloc] initWithXMLString:showListContents
options:NSXMLDocumentTidyXML
error:nil] autorelease];
NSXMLNode *rootNode = nil;
if (doc != nil) {
rootNode = [doc rootElement];
}
// Check to make sure the website is loading and that the root node isn't nil
if (showListContents && [showListContents length] < 1000) {
#if PREFPANE
[self errorWindowWithStatusCode:102];
#endif
} else if (rootNode == nil) {
#if PREFPANE
[self errorWindowWithStatusCode:101];
#endif
} else {
// Reset the existing show list before continuing. In a perfect world we'd
// only be adding shows that didn't already exist, instead of deleting
// everything and starting from scratch.
[presetsDelegate resetPresetShows];
[[PTArrayController content] removeAllObjects];
// Extract the shows from the children nodes
NSArray *shows = [rootNode children];
for (NSXMLNode *show in shows) {
NSManagedObject *showObj = [NSEntityDescription insertNewObjectForEntityForName:@"Show"
inManagedObjectContext:[presetsDelegate managedObjectContext]];
NSString *displayName = [[show childNamed:@"name"] stringValue];
NSString *sortName = [displayName stringByReplacingOccurrencesOfRegex:@"^The[[:space:]]" withString:@""];
int tvdbID = [[[show childNamed:@"tvdbid"] stringValue] intValue];
// Now we get to the really tricky part. We are going to use the name to store
// all the feed urls for this tv show. WHY? Because we cannot change the
// CoreData store until we moved this preference pane to an app
NSArray *array = [[[show childNamed:@"mirrors"] childrenAsStrings]
arrayByAddingObjectsFromArray:[[show childNamed:@"mirrors2"] childrenAsStrings]];
[showObj setValue:displayName forKey:@"displayName"];
[showObj setValue:[array componentsJoinedByString:@"#"] forKey:@"name"];
[showObj setValue:sortName forKey:@"sortName"];
[showObj setValue:[NSDate date] forKey:@"dateAdded"];
[showObj setValue:[NSNumber numberWithInt:tvdbID] forKey:@"tvdbID"];
[showObj setValue:[NSNumber numberWithInt:tvdbID] forKey:@"showrssID"];
[PTArrayController addObject:showObj];
}
hasDownloadedList = YES;
[[presetsDelegate managedObjectContext] processPendingChanges];
[presetsDelegate saveAction];
LogInfo(@"Finished downloading the new show list.");
[TSUserDefaults setKey:@"LastDownloadedShowList" fromDate:[NSDate date]];
[self updateSubscriptions];
}
[self sortTorrentShowList];
}
- (void) tableViewSelectionDidChange:(NSNotification *)notification
{
// Don't prematurely download show information;
// tableViewSelectionDidChange is called when the app first starts
if (hasDownloadedList) {
// If the selectedRow is -1 (no selection) or null, try to set a selection.
if ([PTTableView selectedRow] == -1 || ![PTTableView selectedRow]) {
[PTArrayController setSelectionIndex:0];
}
// No matter what, reset the elements of the view
[self resetShowView];
// Make sure we were able to correctly set a selection before continuing,
// or else searching and the scrollbar will fail.
if ([PTTableView selectedRow] != -1 || ![PTTableView selectedRow]) {
NSString *showFeeds = nil;
NSArray *arguments = nil;
// First disable completely the subscribe button is the user is already subscribed
if ([[PTArrayController selectedObjects] count] != 0) {
if ([self userIsSubscribedToShow:[[[PTArrayController selectedObjects] objectAtIndex:0] valueForKey:@"displayName"]]) {
[subscribeButton setEnabled:NO];
[subscribeButton setTitle: TSLocalizeString(@"Subscribed")];
} else {
[subscribeButton setEnabled:YES];
[subscribeButton setTitle: TSLocalizeString(@"Subscribe")];
}
showFeeds = [[[PTArrayController selectedObjects] objectAtIndex:0] valueForKey:@"name"];
arguments = [NSArray arrayWithObjects:
[[[PTArrayController selectedObjects] objectAtIndex:0] valueForKey:@"displayName"],
[NSString stringWithFormat:@"%@",
[[[PTArrayController selectedObjects] objectAtIndex:0] valueForKey:@"tvdbID"]], nil];
[moreInfoButton setEnabled:YES];
}
// In the meantime show the loading throbber
[self showLoadingThrobber];
if (showFeeds != nil) {
// Grab the list of episodes
[self performSelectorInBackground:@selector(setEpisodesForShow:) withObject:showFeeds];
}
if (arguments != nil) {
// Grab the show poster
[self performSelectorInBackground:@selector(setPosterForShow:) withObject:arguments];
// Grab the show description
[self performSelectorInBackground:@selector(setDescriptionForShow:) withObject:arguments];
}
}
}
}
- (void) resetShowView {
[episodeArrayController removeObjects:[episodeArrayController content]];
[showDescription setString:@""];
[moreInfoButton setEnabled:NO];
[nextAiredButton setState:YES];
[otherEpisodeButton setEnabled:NO];
[otherEpisodeButton setState:NO];
[episodeTableView setEnabled:NO];
[subscribeButton setEnabled:NO];
[self setDefaultPoster];
[self setUserDefinedShowQuality];
}
- (void) setDefaultPoster {
NSImage *defaultPoster = [[[NSImage alloc] initByReferencingFile:
[[NSBundle bundleForClass:[self class]] pathForResource:@"posterArtPlaceholder"
ofType:@"jpg"]] autorelease];
[defaultPoster setSize:NSMakeSize(129, 187)];
[showPoster setImage:defaultPoster];
}
- (void) setUserDefinedShowQuality {
[showQuality setState:[TSUserDefaults getBoolFromKey:@"AutoSelectHDVersion" withDefault:NO]];
}
- (void) showLoadingThrobber {
[loading startAnimation:nil];
[loadingText setHidden:NO];
[descriptionView setHidden:YES];
}
- (void) hideLoadingThrobber {
[loading stopAnimation:nil];
[loadingText setHidden:YES];
[descriptionView setHidden:NO];
}
- (IBAction) openMoreInfoURL:(id)sender {
// Check if any show is selected
NSArray *selectedObjects = [PTArrayController selectedObjects];
if ([selectedObjects count] == 0) {
return;
}
// Extract the TVDB id
NSString *tvdbid = [[selectedObjects objectAtIndex:0] valueForKey:@"tvdbID"];
// Open the url
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:TVDBURL, tvdbid]]];
}
- (IBAction) selectNextAired:(id)sender {
[episodeTableView setEnabled:NO];
}
- (IBAction) selectOtherEpisode:(id)sender {
[episodeTableView setEnabled:YES];
}
#pragma mark -
#pragma mark Background workers
- (void) setEpisodesForShow:(NSString *)showFeeds
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *feeds = [NSMutableArray arrayWithArray:[showFeeds componentsSeparatedByString:@"#"]];
// Generate the full feeds for this suscription
for (int i = 0; i < [feeds count]; i++) {
NSString *feed = [TSRegexFun obtainFullFeed:[feeds objectAtIndex:i]];
[feeds replaceObjectAtIndex:i
withObject:feed];
}
// Now we can trigger the time-expensive task
NSArray *results = [NSArray arrayWithObjects:showFeeds,
[TSParseXMLFeeds parseEpisodesFromFeeds:feeds
beingCustomShow:NO], nil];
if ([results count] < 2) {
LogError(@"Could not download/parse feed(s) <%@>", showFeeds);
[pool drain];
return;
}
[self performSelectorOnMainThread:@selector(updateEpisodes:) withObject:results waitUntilDone:NO];
[pool drain];
}
- (void) setPosterForShow:(NSArray *)arguments
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Now we can trigger the time-expensive task
NSArray *results = [NSArray arrayWithObjects:[arguments objectAtIndex:0],
[[[TheTVDB getPosterForShow:[arguments objectAtIndex:0]
withShowID:[arguments objectAtIndex:1]
withHeight:187
withWidth:129] copy] autorelease], nil];
[self performSelectorOnMainThread:@selector(updatePoster:) withObject:results waitUntilDone:NO];
[pool drain];
}
- (void) setDescriptionForShow:(NSArray *)arguments
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Now we can trigger the time-expensive task
NSArray *results = [NSArray arrayWithObjects:[arguments objectAtIndex:0],
[TheTVDB getValueForKey:@"Overview"
withShowID:[arguments objectAtIndex:1]
andShowName:[arguments objectAtIndex:0]], nil];
[self performSelectorOnMainThread:@selector(updateDescription:) withObject:results waitUntilDone:NO];
[pool drain];
}
- (void) updateEpisodes:(NSArray *)data
{
// We are back after probably a lot of time, so check carefully if the user has changed the selection
NSArray *selectedObjects = [PTArrayController selectedObjects];
if ([selectedObjects count] == 0) {
return;
}
// Extract the data
NSString *showFeeds = [data objectAtIndex:0];
NSArray *results = [data objectAtIndex:1];
NSString *copy = [[selectedObjects objectAtIndex:0] valueForKey:@"name"];
// Continue only if the selected show is the same as before
if ([showFeeds isEqualToString:copy]) {
[episodeArrayController addObjects:results];
// Check if there are HD episodes, if so enable the "Download in HD" checkbox
// BOOL feedHasHDEpisodes = [TSParseXMLFeeds feedHasHDEpisodes:results];
// if (!feedHasHDEpisodes) {
// [showQuality setState:NO];
// }
// [showQuality setEnabled:feedHasHDEpisodes];
// Update the filter predicate to only display the correct quality.
[self showQualityDidChange:nil];
}
}
- (void) updatePoster:(NSArray *)data
{
// We are back after probably a lot of time, so check carefully if the user has changed the selection
NSArray *selectedObjects = [PTArrayController selectedObjects];
if ([selectedObjects count] == 0) {
return;
}
// Extract the data
NSString *showName = [data objectAtIndex:0];
NSImage *poster = [data objectAtIndex:1];
NSString *copy = [[selectedObjects objectAtIndex:0] valueForKey:@"displayName"];
// Continue only if the selected show is the same as before
if ([showName isEqualToString:copy]) {
[showPoster setImage:poster];
[showPoster display];
}
}
- (void) updateDescription:(NSArray *)data
{
// We are back after probably a lot of time, so check carefully if the user has changed the selection
NSArray *selectedObjects = [PTArrayController selectedObjects];
if ([selectedObjects count] == 0) {
return;
}
// Extract the data
NSString *showName = [data objectAtIndex:0];
NSString *description = [data objectAtIndex:1];
NSString *copy = [[selectedObjects objectAtIndex:0] valueForKey:@"displayName"];
// Continue only if the selected show is the same as before
if ([showName isEqualToString:copy]) {
// And finally we can set the description
if (description != NULL) {
[showDescription setString: [TSRegexFun replaceHTMLEntitiesInString:description]];
[showDescription moveToBeginningOfDocument:nil];
} else {
[showDescription setString: TSLocalizeString(@"No description was found for this show.")];
}
// And stop the loading throbber
[self hideLoadingThrobber];
}
}
#pragma mark -
#pragma mark Error Window Methods
- (void) errorWindowWithStatusCode:(int)code
{
NSString *message, *title;
// Add 100 to any error codes if an older show list was found
if([[PTArrayController content] count] >= 1)
code = code + 100;
// Switch between each error code:
// x01 = Website loaded but we couldn't parse a show list from it
// x02 = The website did not load or the user is having connection issues
switch(code) {
case 101:
title = TSLocalizeString(@"An Error Has Occurred");
message = TSLocalizeString(@"A show list cannot be found. Please try again later or check your internet connection.");
break;
case 201:
title = TSLocalizeString(@"Unable to Update the Show List");
message = TSLocalizeString(@"A newer show list cannot be found. Using an old show list temporarily.");
break;
case 102:
title = TSLocalizeString(@"An Error Has Occurred");
message = TSLocalizeString(@"Cannot connect. Please try again later or check your internet connection.");
break;
case 202:
title = TSLocalizeString(@"Unable to Update the Show List");
message = TSLocalizeString(@"Cannot connect. Using an old show list temporarily.");
break;
default:
title = TSLocalizeString(@"An Error Has Occurred");
message = TSLocalizeString(@"An unknown error has occurred. Please try again later.");
break;
}
if (code < 200)
errorHasOccurred = YES;
[PTErrorHeader setStringValue: title];
[PTErrorText setStringValue: message];
[okayButton setTitle: TSLocalizeString(@"Ok")];
[NSApp beginSheet: PTErrorWindow
modalForWindow: [[NSApplication sharedApplication] mainWindow]
modalDelegate: nil
didEndSelector: nil
contextInfo: nil];
LogWarning(@"%@",message);
[NSApp endSheet: PTErrorWindow];
[NSApp runModalForWindow: PTErrorWindow];
}
- (IBAction) closeErrorWindow:(id)sender
{
[NSApp stopModal];
[PTErrorWindow orderOut:self];
}
#pragma mark -
#pragma mark Subscription Methods
- (IBAction) subscribeToShow:(id)sender
{
// Close the modal dialog box
[self closePresetTorrentsWindow:(id)sender];
NSManagedObject *newSubscription = [NSEntityDescription insertNewObjectForEntityForName:@"Subscription"
inManagedObjectContext:[subscriptionsDelegate managedObjectContext]];
NSArray *selectedShow = [PTArrayController selectedObjects];
// Set the information about the new show
[newSubscription setValue:[[selectedShow valueForKey:@"displayName"] objectAtIndex:0] forKey:@"name"];
[newSubscription setValue:[[selectedShow valueForKey:@"sortName"] objectAtIndex:0] forKey:@"sortName"];
[newSubscription setValue:[[selectedShow valueForKey:@"tvdbID"] objectAtIndex:0] forKey:@"tvdbID"];
[newSubscription setValue:[[selectedShow valueForKey:@"name"] objectAtIndex:0] forKey:@"url"];
[newSubscription setValue:[NSDate date] forKey:@"lastDownloaded"];
[newSubscription setValue:[NSNumber numberWithInt:[showQuality state]] forKey:@"quality"];
[newSubscription setValue:[NSNumber numberWithBool:YES] forKey:@"isEnabled"];
NSDictionary *subscriptionDictionary = [newSubscription dictionaryWithValuesForKeys:
[NSArray arrayWithObjects:@"name", @"sortName", @"tvdbID",
@"url", @"lastDownloaded", @"quality", @"isEnabled", nil]];
// Be sure to process pending changes before saving or it won't save correctly
[[subscriptionsDelegate managedObjectContext] processPendingChanges];
[subscriptionsDelegate saveAction];
// If other episode is selected, start with it (spawn background process)
if ([otherEpisodeButton state]) {
NSMutableArray *arguments = [NSMutableArray arrayWithObject:subscriptionDictionary];
for (int i = 0; i <= [episodeTableView selectedRow]; i++) {
[arguments addObject:[[episodeArrayController arrangedObjects] objectAtIndex:i]];
}
[self performSelectorInBackground:@selector(downloadEpisodes:) withObject:arguments];
}
// Notify Miso to add this subscription :)
[[NSNotificationCenter defaultCenter] postNotificationName:@"TSAddSubscription"
object:nil
userInfo:subscriptionDictionary];
}
- (void) downloadEpisodes:(NSArray *)arguments
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
for (int i = 1; i < [arguments count]; i++) {
if (![TSTorrentFunctions downloadEpisode:[arguments objectAtIndex:i]
ofShow:[arguments objectAtIndex:0]]) {
// Display the error
NSRunCriticalAlertPanel([NSString stringWithFormat:TSLocalizeString(@"Unable to download %@"),
[[arguments objectAtIndex:i] valueForKey:@"episodeName"]],
TSLocalizeString(@"Cannot connect. Please try again later or check your internet connection"),
TSLocalizeString(@"Ok"),
nil,
nil);
}
}
[pool drain];
}
- (BOOL) userIsSubscribedToShow:(NSString*)showName
{
for (NSManagedObject *subscription in [SBArrayController arrangedObjects]) {
if ([[subscription valueForKey:@"name"] isEqualToString:showName]) {
return YES;
}
}
return NO;
}
- (void) dealloc
{
[super dealloc];
}
@end