| 1 | /* |
|---|
| 2 | * SapphireTVShowImporter.m |
|---|
| 3 | * Sapphire |
|---|
| 4 | * |
|---|
| 5 | * Created by Graham Booker on Jun. 30, 2007. |
|---|
| 6 | * Copyright 2007 Sapphire Development Team and/or www.nanopi.net |
|---|
| 7 | * All rights reserved. |
|---|
| 8 | * |
|---|
| 9 | * This program is free software; you can redistribute it and/or modify it under the terms of the GNU |
|---|
| 10 | * General Public License as published by the Free Software Foundation; either version 3 of the License, |
|---|
| 11 | * or (at your option) any later version. |
|---|
| 12 | * |
|---|
| 13 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even |
|---|
| 14 | * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
|---|
| 15 | * Public License for more details. |
|---|
| 16 | * |
|---|
| 17 | * You should have received a copy of the GNU General Public License along with this program; if not, |
|---|
| 18 | * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|---|
| 19 | */ |
|---|
| 20 | |
|---|
| 21 | #import <SapphireCompatClasses/SapphireFrontRowCompat.h> |
|---|
| 22 | #import "SapphireTVShowImporter.h" |
|---|
| 23 | #import "SapphireFileMetaData.h" |
|---|
| 24 | #import "NSString-Extensions.h" |
|---|
| 25 | #import "NSFileManager-Extensions.h" |
|---|
| 26 | #import "SapphireShowChooser.h" |
|---|
| 27 | #import "SapphireMetaDataSupport.h" |
|---|
| 28 | #import "SapphireTVTranslation.h" |
|---|
| 29 | #import "SapphireEpisode.h" |
|---|
| 30 | #import "SapphireSettings.h" |
|---|
| 31 | #import "NSImage-Extensions.h" |
|---|
| 32 | #import "SapphireTVShow.h" |
|---|
| 33 | #import "NSXMLDocument-Extensions.h" |
|---|
| 34 | #import "SapphireScraper.h" |
|---|
| 35 | #import "SapphireApplianceController.h" |
|---|
| 36 | #import "SapphireURLLoader.h" |
|---|
| 37 | |
|---|
| 38 | /* TVRage XPATHS */ |
|---|
| 39 | #define TVRAGE_SHOWNAME_XPATH @".//font[@size=2][@color=\"white\"]/b/text()" |
|---|
| 40 | #define TVRAGE_EPLIST_XPATH @"//*[@class='b']" |
|---|
| 41 | #define TVRAGE_EP_INFO @".//*[@class='b2']/*" |
|---|
| 42 | #define TVRAGE_EP_TEXT @".//*[@class='b2']/text()" |
|---|
| 43 | #define TVRAGE_SCREEN_CAP_XPATH @".//img[contains(@src, 'screencap')]" |
|---|
| 44 | #define TVRAGE_SEARCH_XPATH @"//*[@class='b1']/a" |
|---|
| 45 | #define TVRAGE_UNKNOWN_XPATH @"//*[contains(text(), 'Unknown Page')]" |
|---|
| 46 | #define TVRAGE_SHOW_FULL_DESC_XPATH @"//div[@id='sft_1']//text()" |
|---|
| 47 | #define TVRAGE_SHOW_RAW_DESC_XPATH @"//tr[@id='iconn1']/td/table/tr/td//text()" |
|---|
| 48 | #define TVRAGE_SHOW_IMG_XPATH @"//img[contains(@src, 'shows')]" |
|---|
| 49 | |
|---|
| 50 | #define LINK_KEY @"Link" |
|---|
| 51 | #define IMG_URL @"imgURL" |
|---|
| 52 | |
|---|
| 53 | @interface SapphireTVShowImportStateData : SapphireImportStateData |
|---|
| 54 | { |
|---|
| 55 | @public |
|---|
| 56 | SapphireSiteTVShowScraper *siteScraper; |
|---|
| 57 | SapphireTVTranslation *translation; |
|---|
| 58 | NSString *showName; |
|---|
| 59 | NSString *episodeListURL; |
|---|
| 60 | SapphireTVShow *show; |
|---|
| 61 | int episode; |
|---|
| 62 | int secondEp; |
|---|
| 63 | int season; |
|---|
| 64 | NSString *episodeTitle; |
|---|
| 65 | NSMutableArray *episodeInfoArray; |
|---|
| 66 | int episodesCompleted; |
|---|
| 67 | } |
|---|
| 68 | - (id)initWithFile:(SapphireFileMetaData *)aFile atPath:(NSString *)aPath scraper:(SapphireSiteTVShowScraper *)siteScaper; |
|---|
| 69 | - (void)setTranslation:(SapphireTVTranslation *)translation; |
|---|
| 70 | - (void)setShowName:(NSString *)showName; |
|---|
| 71 | - (void)setEpisodeListURL:(NSString *)episodeListURL; |
|---|
| 72 | - (void)setShow:(SapphireTVShow *)show; |
|---|
| 73 | - (void)setEpisodeTitle:(NSString *)episodeTitle; |
|---|
| 74 | - (void)setEpisodeInfoArray:(NSMutableArray *)episodeInfoArray; |
|---|
| 75 | @end |
|---|
| 76 | |
|---|
| 77 | @implementation SapphireTVShowImportStateData |
|---|
| 78 | |
|---|
| 79 | - (id)initWithFile:(SapphireFileMetaData *)aFile atPath:(NSString *)aPath scraper:(SapphireSiteTVShowScraper *)aSiteScaper |
|---|
| 80 | { |
|---|
| 81 | self = [super initWithFile:aFile atPath:aPath]; |
|---|
| 82 | if(!self) |
|---|
| 83 | return self; |
|---|
| 84 | |
|---|
| 85 | siteScraper = [aSiteScaper retain]; |
|---|
| 86 | |
|---|
| 87 | return self; |
|---|
| 88 | } |
|---|
| 89 | |
|---|
| 90 | - (void)dealloc |
|---|
| 91 | { |
|---|
| 92 | [siteScraper release]; |
|---|
| 93 | [translation release]; |
|---|
| 94 | [showName release]; |
|---|
| 95 | [episodeListURL release]; |
|---|
| 96 | [show release]; |
|---|
| 97 | [episodeTitle release]; |
|---|
| 98 | [episodeInfoArray release]; |
|---|
| 99 | [super dealloc]; |
|---|
| 100 | } |
|---|
| 101 | |
|---|
| 102 | - (void)setTranslation:(SapphireTVTranslation *)aTranslation |
|---|
| 103 | { |
|---|
| 104 | [translation autorelease]; |
|---|
| 105 | translation = [aTranslation retain]; |
|---|
| 106 | NSString *epListURL = translation.episodeListURL; |
|---|
| 107 | if([epListURL length]) |
|---|
| 108 | [self setEpisodeListURL:epListURL]; |
|---|
| 109 | } |
|---|
| 110 | |
|---|
| 111 | - (void)setShowName:(NSString *)aShowName |
|---|
| 112 | { |
|---|
| 113 | [showName autorelease]; |
|---|
| 114 | showName = [aShowName retain]; |
|---|
| 115 | } |
|---|
| 116 | |
|---|
| 117 | - (void)setEpisodeListURL:(NSString *)aEpisodeListURL |
|---|
| 118 | { |
|---|
| 119 | [episodeListURL autorelease]; |
|---|
| 120 | episodeListURL = [aEpisodeListURL retain]; |
|---|
| 121 | } |
|---|
| 122 | |
|---|
| 123 | - (void)setShow:(SapphireTVShow *)aShow |
|---|
| 124 | { |
|---|
| 125 | [show autorelease]; |
|---|
| 126 | show = [aShow retain]; |
|---|
| 127 | NSString *aShowName = aShow.name; |
|---|
| 128 | if([aShowName length]) |
|---|
| 129 | [self setShowName:aShowName]; |
|---|
| 130 | } |
|---|
| 131 | |
|---|
| 132 | - (void)setEpisodeTitle:(NSString *)anEpisodeTitle |
|---|
| 133 | { |
|---|
| 134 | [episodeTitle autorelease]; |
|---|
| 135 | episodeTitle = [anEpisodeTitle retain]; |
|---|
| 136 | } |
|---|
| 137 | |
|---|
| 138 | - (void)setEpisodeInfoArray:(NSMutableArray *)anEpisodeInfoArray |
|---|
| 139 | { |
|---|
| 140 | [episodeInfoArray release]; |
|---|
| 141 | episodeInfoArray = [anEpisodeInfoArray retain]; |
|---|
| 142 | } |
|---|
| 143 | |
|---|
| 144 | @end |
|---|
| 145 | |
|---|
| 146 | @interface SapphireSingleTVShowEpisodeImportStateData : NSObject |
|---|
| 147 | { |
|---|
| 148 | @public |
|---|
| 149 | SapphireTVShowImportStateData *state; |
|---|
| 150 | int index; |
|---|
| 151 | SapphireSiteTVShowScraper *siteScraper; |
|---|
| 152 | int absEpisode; |
|---|
| 153 | NSString *epID; |
|---|
| 154 | } |
|---|
| 155 | |
|---|
| 156 | - (id)initWithState:(SapphireTVShowImportStateData *)state index:(int)index episodeID:(NSString *)epID; |
|---|
| 157 | @end |
|---|
| 158 | |
|---|
| 159 | @implementation SapphireSingleTVShowEpisodeImportStateData |
|---|
| 160 | |
|---|
| 161 | - (id)initWithState:(SapphireTVShowImportStateData *)aState index:(int)anIndex episodeID:(NSString *)anEpID; |
|---|
| 162 | { |
|---|
| 163 | self = [super init]; |
|---|
| 164 | if(!self) |
|---|
| 165 | return self; |
|---|
| 166 | |
|---|
| 167 | state = [aState retain]; |
|---|
| 168 | index = anIndex; |
|---|
| 169 | if(anIndex == 0) |
|---|
| 170 | siteScraper = [aState->siteScraper retain]; |
|---|
| 171 | else |
|---|
| 172 | siteScraper = [aState->siteScraper copy]; |
|---|
| 173 | epID = [anEpID retain]; |
|---|
| 174 | |
|---|
| 175 | return self; |
|---|
| 176 | } |
|---|
| 177 | |
|---|
| 178 | - (void)dealloc |
|---|
| 179 | { |
|---|
| 180 | [state release]; |
|---|
| 181 | [siteScraper release]; |
|---|
| 182 | [epID release]; |
|---|
| 183 | [super dealloc]; |
|---|
| 184 | } |
|---|
| 185 | |
|---|
| 186 | |
|---|
| 187 | @end |
|---|
| 188 | |
|---|
| 189 | @interface SapphireTVShowImporter () |
|---|
| 190 | - (void)getTVShowResultsForState:(SapphireTVShowImportStateData *)state; |
|---|
| 191 | - (void)getTVShowEpisodeListForState:(SapphireTVShowImportStateData *)state; |
|---|
| 192 | - (void)getTVShowEpisodesForState:(SapphireSingleTVShowEpisodeImportStateData *)state atURL:(NSString *)url; |
|---|
| 193 | - (void)completeWithState:(SapphireTVShowImportStateData *)state withStatus:(ImportState)status importComplete:(BOOL)importComplete; |
|---|
| 194 | - (void)completedEpisode:(NSDictionary *)dict forState:(SapphireTVShowImportStateData *)state atIndex:(int)index; |
|---|
| 195 | @end |
|---|
| 196 | |
|---|
| 197 | @implementation SapphireTVShowImporter |
|---|
| 198 | |
|---|
| 199 | - (id)init |
|---|
| 200 | { |
|---|
| 201 | self = [super init]; |
|---|
| 202 | if(!self) |
|---|
| 203 | return nil; |
|---|
| 204 | |
|---|
| 205 | scraper = [[SapphireScraper scrapperWithName:@"TV Rage"] retain]; |
|---|
| 206 | |
|---|
| 207 | /*Initialize the regexes*/ |
|---|
| 208 | regcomp(&letterMarking, "[\\. -]?S[0-9]+E[S0-9]+([-E]+[0-9]+)?", REG_EXTENDED | REG_ICASE); |
|---|
| 209 | regcomp(&seasonByEpisode, "[\\. -]?[0-9]+x[S0-9]+(-[0-9]+)?", REG_EXTENDED | REG_ICASE); |
|---|
| 210 | regcomp(&seasonEpisodeTriple, "[\\. -][0-9]{1,3}[S0-9]{2}[\\. -]", REG_EXTENDED | REG_ICASE); |
|---|
| 211 | return self; |
|---|
| 212 | } |
|---|
| 213 | |
|---|
| 214 | - (void)dealloc |
|---|
| 215 | { |
|---|
| 216 | [scraper release]; |
|---|
| 217 | regfree(&letterMarking); |
|---|
| 218 | regfree(&seasonByEpisode); |
|---|
| 219 | regfree(&seasonEpisodeTriple); |
|---|
| 220 | [super dealloc]; |
|---|
| 221 | } |
|---|
| 222 | |
|---|
| 223 | - (void)setDelegate:(id <SapphireImporterDelegate>)aDelegate |
|---|
| 224 | { |
|---|
| 225 | delegate = aDelegate; |
|---|
| 226 | } |
|---|
| 227 | |
|---|
| 228 | - (void)cancelImports |
|---|
| 229 | { |
|---|
| 230 | cancelled = YES; |
|---|
| 231 | } |
|---|
| 232 | |
|---|
| 233 | - (void)retrievedSearchResuls:(NSXMLDocument *)results forObject:(id)stateObj |
|---|
| 234 | { |
|---|
| 235 | SapphireTVShowImportStateData *state = (SapphireTVShowImportStateData *)stateObj; |
|---|
| 236 | [state->siteScraper setObject:nil]; //Avoid retain loop |
|---|
| 237 | if(cancelled) |
|---|
| 238 | return; |
|---|
| 239 | |
|---|
| 240 | if(results == nil) |
|---|
| 241 | { |
|---|
| 242 | /*Failed to get data, network likely, don't mark this as imported*/ |
|---|
| 243 | [self completeWithState:state withStatus:ImportStateNotUpdated importComplete:NO]; |
|---|
| 244 | return; |
|---|
| 245 | } |
|---|
| 246 | NSXMLElement *root = [results rootElement]; |
|---|
| 247 | NSArray *entities = [root elementsForName:@"entity"]; |
|---|
| 248 | NSMutableArray *shows = [[NSMutableArray alloc] initWithCapacity:[entities count]]; |
|---|
| 249 | NSEnumerator *entityEnum = [entities objectEnumerator]; |
|---|
| 250 | NSXMLElement *entity; |
|---|
| 251 | while((entity = [entityEnum nextObject]) != nil) |
|---|
| 252 | { |
|---|
| 253 | NSString *title = stringValueOfChild(entity, @"title"); |
|---|
| 254 | NSString *url = stringValueOfChild(entity, @"url"); |
|---|
| 255 | NSString *itemID = stringValueOfChild(entity, @"id"); |
|---|
| 256 | if([title length] && [url length]) |
|---|
| 257 | [shows addObject:[NSDictionary dictionaryWithObjectsAndKeys: |
|---|
| 258 | title, tvShowTranslationNameKey, |
|---|
| 259 | url, tvShowTranslationLinkKey, |
|---|
| 260 | itemID, tvShowTranslationItemIDKey, |
|---|
| 261 | nil]]; |
|---|
| 262 | } |
|---|
| 263 | |
|---|
| 264 | SapphireLog(SapphireLogTypeImport, SapphireLogLevelDetail, @"Found shows: %@", shows); |
|---|
| 265 | |
|---|
| 266 | /* No need to prompt the user for an empty set */ |
|---|
| 267 | if(![shows count]) |
|---|
| 268 | { |
|---|
| 269 | /* We tried to import but found nothing - mark this file to be skipped on future imports */ |
|---|
| 270 | [self completeWithState:state withStatus:ImportStateNotUpdated importComplete:YES]; |
|---|
| 271 | } |
|---|
| 272 | if([[SapphireSettings sharedSettings] autoSelection]) |
|---|
| 273 | { |
|---|
| 274 | SapphireFileMetaData *metaData = state->file; |
|---|
| 275 | NSManagedObjectContext *moc = [metaData managedObjectContext]; |
|---|
| 276 | NSString *showURL = [[shows objectAtIndex:0] objectForKey:tvShowTranslationLinkKey]; |
|---|
| 277 | NSString *showID = [[shows objectAtIndex:0] objectForKey:tvShowTranslationItemIDKey]; |
|---|
| 278 | SapphireTVTranslation *tran = [SapphireTVTranslation createTVTranslationForName:state->lookupName withURL:showURL itemID:showID importer:[[state->siteScraper scraper] name] inContext:moc]; |
|---|
| 279 | [state setTranslation:tran]; |
|---|
| 280 | [self getTVShowResultsForState:state]; |
|---|
| 281 | } |
|---|
| 282 | else |
|---|
| 283 | { |
|---|
| 284 | /*Bring up the prompt*/ |
|---|
| 285 | SapphireShowChooser *chooser = [[SapphireShowChooser alloc] initWithScene:[delegate chooserScene]]; |
|---|
| 286 | [chooser setShows:shows]; |
|---|
| 287 | [chooser setFileName:[NSString stringByCroppingDirectoryPath:state->path toLength:3]]; |
|---|
| 288 | [chooser setListTitle:BRLocalizedString(@"Select Show Title", @"Prompt the user for showname with a file")]; |
|---|
| 289 | /*And display prompt*/ |
|---|
| 290 | [delegate displayChooser:chooser forImporter:self withContext:state]; |
|---|
| 291 | [chooser release]; |
|---|
| 292 | } |
|---|
| 293 | [shows release]; |
|---|
| 294 | } |
|---|
| 295 | |
|---|
| 296 | - (void)getTVShowResultsForState:(SapphireTVShowImportStateData *)state |
|---|
| 297 | { |
|---|
| 298 | SapphireTVShow *show = [state->translation tvShow]; |
|---|
| 299 | BOOL fetchShowData = NO; |
|---|
| 300 | if(show == nil) |
|---|
| 301 | fetchShowData = YES; |
|---|
| 302 | else if(![[show showDescription] length]) |
|---|
| 303 | fetchShowData = YES; |
|---|
| 304 | else if(![state->episodeListURL length]) |
|---|
| 305 | fetchShowData = YES; |
|---|
| 306 | |
|---|
| 307 | if(!fetchShowData) |
|---|
| 308 | { |
|---|
| 309 | NSString *coverArtPath = [[SapphireMetaDataSupport collectionArtPath] stringByAppendingPathComponent:[NSString stringWithFormat:@"@TV/%@/cover.jpg", [show name]]]; |
|---|
| 310 | if(![[NSFileManager defaultManager] fileExistsAtPath:coverArtPath]) |
|---|
| 311 | fetchShowData = YES; |
|---|
| 312 | } |
|---|
| 313 | if(fetchShowData) |
|---|
| 314 | { |
|---|
| 315 | SapphireSiteTVShowScraper *siteScraper = state->siteScraper; |
|---|
| 316 | [siteScraper setObject:state]; |
|---|
| 317 | NSString *fullURL = state->translation.url; |
|---|
| 318 | [siteScraper getShowDetailsAtURL:fullURL forShowID:state->translation.itemID]; |
|---|
| 319 | } |
|---|
| 320 | else |
|---|
| 321 | { |
|---|
| 322 | [state setShow:show]; |
|---|
| 323 | [self getTVShowEpisodeListForState:state]; |
|---|
| 324 | } |
|---|
| 325 | } |
|---|
| 326 | |
|---|
| 327 | - (void)retrievedShowDetails:(NSXMLDocument *)details forObject:(id)stateObj |
|---|
| 328 | { |
|---|
| 329 | SapphireTVShowImportStateData *state = (SapphireTVShowImportStateData *)stateObj; |
|---|
| 330 | [state->siteScraper setObject:nil]; //Avoid retain loop |
|---|
| 331 | if(cancelled) |
|---|
| 332 | return; |
|---|
| 333 | |
|---|
| 334 | if(details == nil) |
|---|
| 335 | { |
|---|
| 336 | /*Failed to get data, network likely, don't mark this as imported*/ |
|---|
| 337 | [self completeWithState:state withStatus:ImportStateNotUpdated importComplete:NO]; |
|---|
| 338 | return; |
|---|
| 339 | } |
|---|
| 340 | NSXMLElement *root = [details rootElement]; |
|---|
| 341 | NSString *plot = stringValueOfChild(root, @"plot"); |
|---|
| 342 | NSString *thumb = stringValueOfChild(root, @"thumb"); |
|---|
| 343 | |
|---|
| 344 | /*Check for series info*/ |
|---|
| 345 | NSManagedObjectContext *moc = [state->file managedObjectContext]; |
|---|
| 346 | SapphireTVShow *show = state->show; |
|---|
| 347 | if(!show) |
|---|
| 348 | { |
|---|
| 349 | SapphireTVTranslation *tran = state->translation; |
|---|
| 350 | show = tran.tvShow; |
|---|
| 351 | if(!show) |
|---|
| 352 | { |
|---|
| 353 | NSString *title = stringValueOfChild(root, @"title"); |
|---|
| 354 | if(![title length]) |
|---|
| 355 | { |
|---|
| 356 | //We can't import anymore. Importer or site broken; abort. |
|---|
| 357 | [self completeWithState:state withStatus:ImportStateNotUpdated importComplete:NO]; |
|---|
| 358 | return; |
|---|
| 359 | } |
|---|
| 360 | show = [SapphireTVShow show:title inContext:moc]; |
|---|
| 361 | tran.tvShow = show; |
|---|
| 362 | } |
|---|
| 363 | [state setShow:show]; |
|---|
| 364 | } |
|---|
| 365 | if([thumb length]) |
|---|
| 366 | { |
|---|
| 367 | NSString *coverArtPath = [[SapphireMetaDataSupport collectionArtPath] stringByAppendingPathComponent:[NSString stringWithFormat:@"@TV/%@/cover.jpg", [show name]]]; |
|---|
| 368 | [[SapphireApplianceController urlLoader] saveDataAtURL:thumb toFile:coverArtPath]; |
|---|
| 369 | } |
|---|
| 370 | if([plot length]) |
|---|
| 371 | show.showDescription = plot; |
|---|
| 372 | |
|---|
| 373 | if(![state->episodeListURL length]) |
|---|
| 374 | { |
|---|
| 375 | NSArray *episodeListURLs = arrayStringValueOfXPath(root, @"episodeguide/url"); |
|---|
| 376 | if([episodeListURLs count]) |
|---|
| 377 | { |
|---|
| 378 | NSString *episodeListURL = [episodeListURLs objectAtIndex:0]; |
|---|
| 379 | [state setEpisodeListURL:episodeListURL]; |
|---|
| 380 | [state->translation setEpisodeListURL:episodeListURL]; |
|---|
| 381 | } |
|---|
| 382 | } |
|---|
| 383 | |
|---|
| 384 | [self getTVShowEpisodeListForState:state]; |
|---|
| 385 | } |
|---|
| 386 | |
|---|
| 387 | - (void)getTVShowEpisodeListForState:(SapphireTVShowImportStateData *)state |
|---|
| 388 | { |
|---|
| 389 | SapphireSiteTVShowScraper *siteScraper = state->siteScraper; |
|---|
| 390 | [siteScraper setObject:state]; |
|---|
| 391 | NSString *fullURL = state->episodeListURL; |
|---|
| 392 | [siteScraper getEpisodeListAtURL:fullURL]; |
|---|
| 393 | } |
|---|
| 394 | |
|---|
| 395 | - (void)getEpisode:(int)episode withSeason:(int)season title:(NSString *)episodeTitle state:(SapphireTVShowImportStateData *)state inList:(NSXMLDocument *)episodeList index:(int)index |
|---|
| 396 | { |
|---|
| 397 | NSString *xquery; |
|---|
| 398 | if(episode) |
|---|
| 399 | xquery = [NSString stringWithFormat:@"//episode[number(season)=%d and number(epnum)=%d]/url", season, episode]; |
|---|
| 400 | else |
|---|
| 401 | { |
|---|
| 402 | NSString *escapedTitle = [[episodeTitle lowercaseString] stringByReplacingAllOccurancesOf:@"'" withString:@"\\'"]; |
|---|
| 403 | xquery = [NSString stringWithFormat:@"//episode[number(season)=%d and lower-case(title)='%@']/url", season, escapedTitle]; |
|---|
| 404 | } |
|---|
| 405 | NSArray *epElements = [episodeList objectsForXQuery:xquery error:nil]; |
|---|
| 406 | if([epElements count]) |
|---|
| 407 | { |
|---|
| 408 | NSXMLElement *epURLElement = [epElements objectAtIndex:0]; |
|---|
| 409 | NSXMLElement *episodeElement = (NSXMLElement *)[epURLElement parent]; |
|---|
| 410 | NSNumber *absoluteNumber = intValueOfChild(episodeElement, @"absoluteEp"); |
|---|
| 411 | NSString *epID = stringValueOfChild(episodeElement, @"id"); |
|---|
| 412 | int absNumber = [absoluteNumber intValue]; |
|---|
| 413 | SapphireSingleTVShowEpisodeImportStateData *epState = [[SapphireSingleTVShowEpisodeImportStateData alloc] initWithState:state index:index episodeID:epID]; |
|---|
| 414 | epState->absEpisode = absNumber; |
|---|
| 415 | [self getTVShowEpisodesForState:epState atURL:[epURLElement stringValue]]; |
|---|
| 416 | [epState release]; |
|---|
| 417 | } |
|---|
| 418 | else |
|---|
| 419 | [self completedEpisode:nil forState:state atIndex:index]; |
|---|
| 420 | } |
|---|
| 421 | |
|---|
| 422 | - (void)retrievedEpisodeList:(NSXMLDocument *)episodeList forObject:(id)stateObj |
|---|
| 423 | { |
|---|
| 424 | SapphireTVShowImportStateData *state = (SapphireTVShowImportStateData *)stateObj; |
|---|
| 425 | [state->siteScraper setObject:nil]; //Avoid retain loop |
|---|
| 426 | if(cancelled) |
|---|
| 427 | return; |
|---|
| 428 | |
|---|
| 429 | if(episodeList == nil) |
|---|
| 430 | { |
|---|
| 431 | /*Failed to get data, network likely, don't mark this as imported*/ |
|---|
| 432 | [self completeWithState:state withStatus:ImportStateNotUpdated importComplete:NO]; |
|---|
| 433 | return; |
|---|
| 434 | } |
|---|
| 435 | NSMutableArray *infoArray; |
|---|
| 436 | int secondEp = state->secondEp; |
|---|
| 437 | if(secondEp) |
|---|
| 438 | infoArray = [[NSMutableArray alloc] initWithObjects:[NSNull null], [NSNull null], nil]; |
|---|
| 439 | else |
|---|
| 440 | infoArray = [[NSMutableArray alloc] initWithObjects:[NSNull null], nil]; |
|---|
| 441 | [state setEpisodeInfoArray:infoArray]; |
|---|
| 442 | [infoArray release]; |
|---|
| 443 | |
|---|
| 444 | [self getEpisode:state->episode withSeason:state->season title:state->episodeTitle state:state inList:episodeList index:0]; |
|---|
| 445 | if(secondEp) |
|---|
| 446 | [self getEpisode:secondEp withSeason:state->season title:nil state:state inList:episodeList index:1]; |
|---|
| 447 | } |
|---|
| 448 | |
|---|
| 449 | - (void)getTVShowEpisodesForState:(SapphireSingleTVShowEpisodeImportStateData *)epState atURL:(NSString *)url |
|---|
| 450 | { |
|---|
| 451 | SapphireSiteTVShowScraper *siteScraper = epState->siteScraper; |
|---|
| 452 | [siteScraper setObject:epState]; |
|---|
| 453 | [siteScraper getEpisodeDetailsAtURL:url forEpisodeID:epState->epID]; |
|---|
| 454 | } |
|---|
| 455 | |
|---|
| 456 | - (void)retrievedEpisodeDetails:(NSXMLDocument *)details forObject:(id)stateObj |
|---|
| 457 | { |
|---|
| 458 | SapphireSingleTVShowEpisodeImportStateData *state = (SapphireSingleTVShowEpisodeImportStateData *)stateObj; |
|---|
| 459 | SapphireTVShowImportStateData *tvState = state->state; |
|---|
| 460 | [state->siteScraper setObject:nil]; //Avoid retain loop |
|---|
| 461 | if(cancelled) |
|---|
| 462 | return; |
|---|
| 463 | |
|---|
| 464 | if(details == nil) |
|---|
| 465 | { |
|---|
| 466 | /*Failed to get data, network likely, don't mark this as imported*/ |
|---|
| 467 | [self completeWithState:tvState withStatus:ImportStateNotUpdated importComplete:NO]; |
|---|
| 468 | return; |
|---|
| 469 | } |
|---|
| 470 | int index = state->index; |
|---|
| 471 | NSXMLElement *root = [details rootElement]; |
|---|
| 472 | NSString *epTitle = stringValueOfChild(root, @"title"); |
|---|
| 473 | int ep = tvState->episode; |
|---|
| 474 | if(index != 0) |
|---|
| 475 | ep = tvState->secondEp; |
|---|
| 476 | if(ep == 0 && ![epTitle length]) |
|---|
| 477 | { |
|---|
| 478 | //No episode number or title; something is seriously wrong here |
|---|
| 479 | [self completedEpisode:nil forState:tvState atIndex:state->index]; |
|---|
| 480 | return; |
|---|
| 481 | } |
|---|
| 482 | |
|---|
| 483 | NSMutableDictionary *epDict = [NSMutableDictionary dictionary]; |
|---|
| 484 | /*Add info*/ |
|---|
| 485 | [epDict setObject:tvState->show.name forKey:META_SHOW_NAME_KEY]; |
|---|
| 486 | if(ep != 0) |
|---|
| 487 | [epDict setObject:[NSNumber numberWithInt:ep] forKey:META_EPISODE_NUMBER_KEY]; |
|---|
| 488 | [epDict setObject:[NSNumber numberWithInt:tvState->season] forKey:META_SEASON_NUMBER_KEY]; |
|---|
| 489 | |
|---|
| 490 | if(epTitle != nil) |
|---|
| 491 | [epDict setObject:epTitle forKey:META_TITLE_KEY]; |
|---|
| 492 | NSString *summary = stringValueOfChild(root, @"plot"); |
|---|
| 493 | if(summary != nil) |
|---|
| 494 | [epDict setObject:summary forKey:META_DESCRIPTION_KEY]; |
|---|
| 495 | if(state->absEpisode) |
|---|
| 496 | [epDict setObject:[NSNumber numberWithInt:state->absEpisode] forKey:META_ABSOLUTE_EP_NUMBER_KEY]; |
|---|
| 497 | NSDate *airDate = dateValueOfChild(root, @"aired"); |
|---|
| 498 | if(airDate != nil) |
|---|
| 499 | [epDict setObject:airDate forKey:META_SHOW_AIR_DATE]; |
|---|
| 500 | NSString *imgURL = stringValueOfChild(root, @"thumb"); |
|---|
| 501 | if([imgURL length]) |
|---|
| 502 | { |
|---|
| 503 | NSString *previewArtPath = [NSFileManager previewArtPathForTV:tvState->show.name season:tvState->season]; |
|---|
| 504 | NSString *newPath = nil; |
|---|
| 505 | if(ep != 0) |
|---|
| 506 | newPath = [previewArtPath stringByAppendingFormat:@"/Episode %d", ep]; |
|---|
| 507 | else |
|---|
| 508 | newPath = [previewArtPath stringByAppendingPathComponent:epTitle]; |
|---|
| 509 | NSString *imageDestination = [newPath stringByAppendingPathExtension:@"jpg"]; |
|---|
| 510 | BOOL isDir = NO; |
|---|
| 511 | BOOL imageExists = [[NSFileManager defaultManager] fileExistsAtPath:imageDestination isDirectory:&isDir] && !isDir; |
|---|
| 512 | if(imgURL && !imageExists) |
|---|
| 513 | { |
|---|
| 514 | /*Download the screen cap*/ |
|---|
| 515 | [[SapphireApplianceController urlLoader] saveDataAtURL:imgURL toFile:imageDestination]; |
|---|
| 516 | } |
|---|
| 517 | else if(!imageExists) |
|---|
| 518 | { |
|---|
| 519 | //QTMovie is broken on ATV, don't fetch images there |
|---|
| 520 | SapphireFileMetaData *metaData = tvState->file; |
|---|
| 521 | if ([SapphireFrontRowCompat usingLeopard] && [metaData fileContainerTypeValue] == FILE_CONTAINER_TYPE_QT_MOVIE) |
|---|
| 522 | { |
|---|
| 523 | // NSImage-Extensions |
|---|
| 524 | [[NSImage imageFromMovie:tvState->path] writeToFile:imageDestination atomically:YES]; |
|---|
| 525 | } |
|---|
| 526 | } |
|---|
| 527 | } |
|---|
| 528 | [self completedEpisode:epDict forState:tvState atIndex:index]; |
|---|
| 529 | } |
|---|
| 530 | |
|---|
| 531 | - (void)completedEpisode:(NSDictionary *)dict forState:(SapphireTVShowImportStateData *)state atIndex:(int)index |
|---|
| 532 | { |
|---|
| 533 | state->episodesCompleted++; |
|---|
| 534 | NSMutableArray *infoArray = state->episodeInfoArray; |
|---|
| 535 | if(dict == nil) |
|---|
| 536 | dict = [NSMutableDictionary dictionary]; |
|---|
| 537 | [infoArray replaceObjectAtIndex:index withObject:dict]; |
|---|
| 538 | if(state->episodesCompleted == [infoArray count]) |
|---|
| 539 | { |
|---|
| 540 | int i; |
|---|
| 541 | for(i=0; i<[infoArray count]; i++) |
|---|
| 542 | { |
|---|
| 543 | if(![[infoArray objectAtIndex:i] count]) |
|---|
| 544 | { |
|---|
| 545 | [infoArray removeObjectAtIndex:i]; |
|---|
| 546 | i--; |
|---|
| 547 | } |
|---|
| 548 | } |
|---|
| 549 | if([infoArray count]) |
|---|
| 550 | { |
|---|
| 551 | SapphireFileMetaData *file = state->file; |
|---|
| 552 | SapphireEpisode *ep = [SapphireEpisode episodeWithDictionaries:infoArray inContext:[file managedObjectContext]]; |
|---|
| 553 | file.tvEpisode = ep; |
|---|
| 554 | [self completeWithState:state withStatus:ImportStateUpdated importComplete:YES]; |
|---|
| 555 | } |
|---|
| 556 | else |
|---|
| 557 | [self completeWithState:state withStatus:ImportStateNotUpdated importComplete:YES]; |
|---|
| 558 | } |
|---|
| 559 | } |
|---|
| 560 | |
|---|
| 561 | - (void)completeWithState:(SapphireTVShowImportStateData *)state withStatus:(ImportState)status importComplete:(BOOL)importComplete; |
|---|
| 562 | { |
|---|
| 563 | SapphireFileMetaData *currentData = state->file; |
|---|
| 564 | if(importComplete) |
|---|
| 565 | { |
|---|
| 566 | [currentData didImportType:ImportTypeMaskTVShow]; |
|---|
| 567 | if (status == ImportStateNotUpdated && [currentData fileClassValue] != FILE_CLASS_MOVIE) |
|---|
| 568 | [currentData setFileClassValue:FILE_CLASS_UNKNOWN]; |
|---|
| 569 | } |
|---|
| 570 | [delegate backgroundImporter:self completedImportOnPath:state->path withState:status]; |
|---|
| 571 | } |
|---|
| 572 | |
|---|
| 573 | - (NSString *)showURLFromNfoFilePath:(NSString *)filepath withID:(NSString * *)showID; |
|---|
| 574 | { |
|---|
| 575 | NSString *nfoContent = [NSString stringWithContentsOfFile:filepath]; |
|---|
| 576 | |
|---|
| 577 | if(![nfoContent length]) |
|---|
| 578 | return nil; |
|---|
| 579 | |
|---|
| 580 | NSString *results = [scraper searchResultsForNfoContent:nfoContent]; |
|---|
| 581 | if(![results length]) |
|---|
| 582 | return nil; |
|---|
| 583 | |
|---|
| 584 | NSString *fullResults = [NSString stringWithFormat:@"<results>%@</results>", results]; |
|---|
| 585 | NSError *error = nil; |
|---|
| 586 | NSXMLDocument *doc = [[[NSXMLDocument alloc] initWithXMLString:fullResults options:0 error:&error] autorelease]; |
|---|
| 587 | if(!doc) |
|---|
| 588 | return nil; |
|---|
| 589 | |
|---|
| 590 | NSXMLElement *root = [doc rootElement]; |
|---|
| 591 | NSString *urlStr = stringValueOfChild(root, @"url"); |
|---|
| 592 | if(![urlStr length]) |
|---|
| 593 | return nil; |
|---|
| 594 | |
|---|
| 595 | *showID = stringValueOfChild(root, @"id"); |
|---|
| 596 | return urlStr; |
|---|
| 597 | } |
|---|
| 598 | |
|---|
| 599 | - (ImportState)importMetaData:(SapphireFileMetaData *)metaData path:(NSString *)path |
|---|
| 600 | { |
|---|
| 601 | cancelled = NO; |
|---|
| 602 | /*Check to see if it is already imported*/ |
|---|
| 603 | if([metaData importTypeValue] & ImportTypeMaskTVShow) |
|---|
| 604 | return ImportStateNotUpdated; |
|---|
| 605 | // NSArray *pathComponents = [path pathComponents]; |
|---|
| 606 | NSString *extLessPath = path; |
|---|
| 607 | if([metaData fileContainerTypeValue] != FILE_CONTAINER_TYPE_VIDEO_TS) |
|---|
| 608 | extLessPath = [extLessPath stringByDeletingPathExtension]; |
|---|
| 609 | |
|---|
| 610 | NSString *fileName = [path lastPathComponent]; |
|---|
| 611 | |
|---|
| 612 | /*Check regexes to see if this is a tv show*/ |
|---|
| 613 | int index = NSNotFound; |
|---|
| 614 | int secondEp = -1; |
|---|
| 615 | regmatch_t matches[3]; |
|---|
| 616 | const char *theFileName = [fileName fileSystemRepresentation]; |
|---|
| 617 | NSString *scanString = nil; |
|---|
| 618 | if(!regexec(&letterMarking, theFileName, 3, matches, 0)) |
|---|
| 619 | { |
|---|
| 620 | index = matches[0].rm_so; |
|---|
| 621 | scanString = [fileName substringFromIndex:index]; |
|---|
| 622 | secondEp = matches[1].rm_so; |
|---|
| 623 | } |
|---|
| 624 | else if(!regexec(&seasonByEpisode, theFileName, 3, matches, 0)) |
|---|
| 625 | { |
|---|
| 626 | index = matches[0].rm_so; |
|---|
| 627 | scanString = [fileName substringFromIndex:index]; |
|---|
| 628 | secondEp = matches[1].rm_so; |
|---|
| 629 | } |
|---|
| 630 | else if(!regexec(&seasonEpisodeTriple, theFileName, 3, matches, 0)) |
|---|
| 631 | { |
|---|
| 632 | index = matches[0].rm_so; |
|---|
| 633 | /*Insert an artificial season/ep seperator so things are easier later*/ |
|---|
| 634 | NSMutableString *tempStr = [fileName mutableCopy]; |
|---|
| 635 | // if(index > [tempStr length] || index <= 0 )return NO; |
|---|
| 636 | [tempStr deleteCharactersInRange:NSMakeRange(0, index+1)]; |
|---|
| 637 | [tempStr insertString:@"x" atIndex:matches[0].rm_eo - index - 4]; |
|---|
| 638 | scanString = [tempStr autorelease]; |
|---|
| 639 | } |
|---|
| 640 | |
|---|
| 641 | /*See if we found a match*/ |
|---|
| 642 | if(index == NSNotFound) |
|---|
| 643 | { |
|---|
| 644 | [metaData didImportType:ImportTypeMaskTVShow]; |
|---|
| 645 | return ImportStateNotUpdated; |
|---|
| 646 | } |
|---|
| 647 | |
|---|
| 648 | int season = 0; |
|---|
| 649 | int ep = 0; |
|---|
| 650 | /*Get the season*/ |
|---|
| 651 | NSScanner *scanner = [NSScanner scannerWithString:scanString]; |
|---|
| 652 | NSCharacterSet *digits = [NSCharacterSet decimalDigitCharacterSet]; |
|---|
| 653 | [scanner scanUpToCharactersFromSet:digits intoString:nil]; |
|---|
| 654 | [scanner scanInt:&season]; |
|---|
| 655 | /*Get the episode number*/ |
|---|
| 656 | NSString *skipped = nil; |
|---|
| 657 | [scanner scanUpToCharactersFromSet:digits intoString:&skipped]; |
|---|
| 658 | [scanner scanInt:&ep]; |
|---|
| 659 | /*Was there an S before the episode number?*/ |
|---|
| 660 | if([skipped hasSuffix:@"S"] || [skipped hasSuffix:@"s"]) |
|---|
| 661 | ep = 0; |
|---|
| 662 | |
|---|
| 663 | int overriddenSeason = [metaData searchSeasonNumber]; |
|---|
| 664 | if(overriddenSeason != -1) |
|---|
| 665 | season = overriddenSeason; |
|---|
| 666 | |
|---|
| 667 | int overriddenEpisode = [metaData searchEpisodeNumber]; |
|---|
| 668 | if(overriddenEpisode != -1) |
|---|
| 669 | ep = overriddenEpisode; |
|---|
| 670 | |
|---|
| 671 | /*No season, no info*/ |
|---|
| 672 | if(season == 0) |
|---|
| 673 | { |
|---|
| 674 | [metaData didImportType:ImportTypeMaskTVShow]; |
|---|
| 675 | return ImportStateNotUpdated; |
|---|
| 676 | } |
|---|
| 677 | |
|---|
| 678 | int otherEp = 0; |
|---|
| 679 | if(secondEp != -1) |
|---|
| 680 | { |
|---|
| 681 | [scanner setScanLocation:secondEp - index]; |
|---|
| 682 | [scanner scanUpToCharactersFromSet:digits intoString:nil]; |
|---|
| 683 | [scanner scanInt:&otherEp]; |
|---|
| 684 | } |
|---|
| 685 | |
|---|
| 686 | overriddenEpisode = [metaData searchLastEpisodeNumber]; |
|---|
| 687 | if(overriddenEpisode != -1) |
|---|
| 688 | otherEp = overriddenEpisode; |
|---|
| 689 | |
|---|
| 690 | /*Get the show title*/ |
|---|
| 691 | NSString *searchStr = [fileName substringToIndex:index]; |
|---|
| 692 | NSString *searchShowName = [metaData searchShowName]; |
|---|
| 693 | if(searchShowName != nil) |
|---|
| 694 | searchStr = searchShowName; |
|---|
| 695 | searchStr = [searchStr lowercaseString]; |
|---|
| 696 | SapphireLog(SapphireLogTypeImport, SapphireLogLevelDebug, @"%@ matched regex; checking show name %@", fileName, searchStr); |
|---|
| 697 | /*Check to see if we know this title*/ |
|---|
| 698 | NSManagedObjectContext *moc = [metaData managedObjectContext]; |
|---|
| 699 | SapphireTVTranslation *tran = [SapphireTVTranslation tvTranslationForName:searchStr inContext:moc]; |
|---|
| 700 | SapphireSiteTVShowScraper *siteScraper = [[SapphireSiteTVShowScraper alloc] initWithTVShowScraper:scraper delegate:self loader:[SapphireApplianceController urlLoader]]; |
|---|
| 701 | SapphireTVShowImportStateData *state = [[[SapphireTVShowImportStateData alloc] initWithFile:metaData atPath:path scraper:siteScraper] autorelease]; |
|---|
| 702 | [siteScraper release]; |
|---|
| 703 | |
|---|
| 704 | [state setLookupName:searchStr]; |
|---|
| 705 | [state setTranslation:tran]; |
|---|
| 706 | SapphireTVShow *show = tran.tvShow; |
|---|
| 707 | [state setShow:show]; |
|---|
| 708 | state->episode = ep; |
|---|
| 709 | state->season = season; |
|---|
| 710 | state->secondEp = otherEp; |
|---|
| 711 | if(ep == 0) |
|---|
| 712 | { |
|---|
| 713 | NSString *epTitle = nil; |
|---|
| 714 | [scanner scanUpToCharactersFromSet:[NSCharacterSet alphanumericCharacterSet] intoString:nil]; |
|---|
| 715 | if([scanner scanUpToString:@"." intoString:&epTitle]) |
|---|
| 716 | [state setEpisodeTitle:epTitle]; |
|---|
| 717 | } |
|---|
| 718 | if([tran itemID] == nil) |
|---|
| 719 | { |
|---|
| 720 | BOOL nfoPathIsDir = NO; |
|---|
| 721 | NSString *nfoFilePath=[extLessPath stringByAppendingPathExtension:@"nfo"]; |
|---|
| 722 | NSString *showURL = nil; |
|---|
| 723 | NSString *showID = nil; |
|---|
| 724 | if([[NSFileManager defaultManager] fileExistsAtPath:nfoFilePath isDirectory:&nfoPathIsDir] && !nfoPathIsDir) |
|---|
| 725 | showURL = [self showURLFromNfoFilePath:nfoFilePath withID:&showID]; |
|---|
| 726 | |
|---|
| 727 | if([showURL length]) |
|---|
| 728 | { |
|---|
| 729 | [tran setUrl:showURL]; |
|---|
| 730 | if([showID length]) |
|---|
| 731 | [tran setItemID:showID]; |
|---|
| 732 | } |
|---|
| 733 | else |
|---|
| 734 | { |
|---|
| 735 | SapphireLog(SapphireLogTypeImport, SapphireLogLevelDebug, @"Conducting search"); |
|---|
| 736 | if(![delegate canDisplayChooser]) |
|---|
| 737 | /*There is no data menu, background import. So we can't ask user, skip*/ |
|---|
| 738 | return ImportStateNotUpdated; |
|---|
| 739 | /*Ask the user what show this is*/ |
|---|
| 740 | [siteScraper setObject:state]; |
|---|
| 741 | [siteScraper searchForShowNamed:searchStr]; |
|---|
| 742 | return ImportStateMultipleSuspend; |
|---|
| 743 | } |
|---|
| 744 | } |
|---|
| 745 | |
|---|
| 746 | [self getTVShowResultsForState:state]; |
|---|
| 747 | return ImportStateMultipleSuspend; |
|---|
| 748 | } |
|---|
| 749 | |
|---|
| 750 | /*! |
|---|
| 751 | * @brief Write our setings out |
|---|
| 752 | */ |
|---|
| 753 | - (void)writeSettingsForContext:(NSManagedObjectContext *)moc |
|---|
| 754 | { |
|---|
| 755 | [SapphireMetaDataSupport save:moc]; |
|---|
| 756 | } |
|---|
| 757 | |
|---|
| 758 | /*- (ImportState)importMetaData:(SapphireFileMetaData *)metaData path:(NSString *)path |
|---|
| 759 | { |
|---|
| 760 | [showInfoClearTimer invalidate]; |
|---|
| 761 | showInfoClearTimer = nil; |
|---|
| 762 | ImportState ret = [self doRealImportMetaData:metaData path:path]; |
|---|
| 763 | showInfoClearTimer = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:@selector(clearCache) userInfo:nil repeats:NO]; |
|---|
| 764 | return ret; |
|---|
| 765 | }*/ |
|---|
| 766 | |
|---|
| 767 | - (NSString *)completionText |
|---|
| 768 | { |
|---|
| 769 | return BRLocalizedString(@"All available TV Show data has been imported", @"The TV Show import complete"); |
|---|
| 770 | } |
|---|
| 771 | |
|---|
| 772 | - (NSString *)initialText |
|---|
| 773 | { |
|---|
| 774 | return BRLocalizedString(@"Fetch TV Show Data", @"Title"); |
|---|
| 775 | } |
|---|
| 776 | |
|---|
| 777 | - (NSString *)informativeText |
|---|
| 778 | { |
|---|
| 779 | return BRLocalizedString(@"This tool will attempt to fetch information about your TV shows files from the Internet (TVRage). This procedure may take quite some time and could ask you questions. You may cancel at any time.", @"Description of the movie import"); |
|---|
| 780 | } |
|---|
| 781 | |
|---|
| 782 | - (NSString *)buttonTitle |
|---|
| 783 | { |
|---|
| 784 | return BRLocalizedString(@"Start Fetching Data", @"Button"); |
|---|
| 785 | } |
|---|
| 786 | |
|---|
| 787 | - (BOOL)stillNeedsDisplayOfChooser:(BRLayerController <SapphireChooser> *)chooser withContext:(id)context |
|---|
| 788 | { |
|---|
| 789 | SapphireTVShowImportStateData *state = (SapphireTVShowImportStateData *)context; |
|---|
| 790 | /*Check for a match done earlier*/ |
|---|
| 791 | NSManagedObjectContext *moc = [state->file managedObjectContext]; |
|---|
| 792 | SapphireTVTranslation *tran = [SapphireTVTranslation tvTranslationForName:state->lookupName inContext:moc]; |
|---|
| 793 | if([tran itemID]) |
|---|
| 794 | { |
|---|
| 795 | [state setTranslation:tran]; |
|---|
| 796 | [self getTVShowResultsForState:state]; |
|---|
| 797 | return NO; |
|---|
| 798 | } |
|---|
| 799 | return YES; |
|---|
| 800 | } |
|---|
| 801 | |
|---|
| 802 | - (void)exhumedChooser:(BRLayerController <SapphireChooser> *)aChooser withContext:(id)context |
|---|
| 803 | { |
|---|
| 804 | SapphireTVShowImportStateData *state = (SapphireTVShowImportStateData *)context; |
|---|
| 805 | if(![aChooser isKindOfClass:[SapphireShowChooser class]]) |
|---|
| 806 | return; |
|---|
| 807 | SapphireShowChooser *chooser = (SapphireShowChooser *)aChooser; |
|---|
| 808 | SapphireFileMetaData *currentData = state->file; |
|---|
| 809 | |
|---|
| 810 | /*Get the user's selection*/ |
|---|
| 811 | int selection = [chooser selection]; |
|---|
| 812 | if(selection == SapphireChooserChoiceCancel) |
|---|
| 813 | /*They aborted, skip*/ |
|---|
| 814 | [self completeWithState:state withStatus:ImportStateUserSkipped importComplete:NO]; |
|---|
| 815 | else if(selection == SapphireChooserChoiceNotType) |
|---|
| 816 | /*They said it is not a show, so put in empty data so they are not asked again*/ |
|---|
| 817 | [self completeWithState:state withStatus:ImportStateNotUpdated importComplete:YES]; |
|---|
| 818 | else |
|---|
| 819 | { |
|---|
| 820 | /*They selected a show, save the translation and write it*/ |
|---|
| 821 | NSDictionary *show = [[chooser shows] objectAtIndex:selection]; |
|---|
| 822 | NSManagedObjectContext *moc = [currentData managedObjectContext]; |
|---|
| 823 | NSString *showURL = [show objectForKey:tvShowTranslationLinkKey]; |
|---|
| 824 | NSString *showID = [show objectForKey:tvShowTranslationItemIDKey]; |
|---|
| 825 | SapphireTVTranslation *tran = [SapphireTVTranslation createTVTranslationForName:state->lookupName withURL:showURL itemID:showID importer:[[state->siteScraper scraper] name] inContext:moc]; |
|---|
| 826 | [state setTranslation:tran]; |
|---|
| 827 | [self writeSettingsForContext:moc]; |
|---|
| 828 | [self getTVShowResultsForState:state]; |
|---|
| 829 | } |
|---|
| 830 | } |
|---|
| 831 | |
|---|
| 832 | @end |
|---|