root/branches/CoreData/SapphireFrappliance/MetaData/SapphireMObjects/SapphireEpisode.m @ 836

Revision 836, 10.8 KB (checked in by gbooker, 17 months ago)

Better place to handle files added and removed from episodes and movies

Line 
1#import "SapphireEpisode.h"
2#import "SapphireSeason.h"
3#import "SapphireSubEpisode.h"
4#import "SapphireMediaPreview.h"
5#import "SapphireFileMetaData.h"
6#import "SapphireMetaDataSupport.h"
7#import "SapphireXMLData.h"
8#import "SapphireApplianceController.h"
9#import "CoreDataSupportFunctions.h"
10
11@implementation SapphireEpisode
12
13+ (SapphireEpisode *)episode:(int)ep inSeason:(int)season forShow:(NSString *)show withPath:(NSString *)showPath inContext:(NSManagedObjectContext *)moc
14{
15        SapphireSeason *tvseason = [SapphireSeason season:season forShow:show withPath:showPath inContext:moc];
16        NSEnumerator *epEnum = [tvseason.episodesSet objectEnumerator];
17        SapphireEpisode *tvep;
18        while((tvep = [epEnum nextObject]) != nil)
19        {
20                if([SapphireSubEpisode subEpisode:ep inEpisode:tvep] != nil)
21                        return tvep;
22        }
23       
24        SapphireEpisode *ret = [NSEntityDescription insertNewObjectForEntityForName:SapphireEpisodeName inManagedObjectContext:moc];
25        ret.season = tvseason;
26        ret.tvShow = tvseason.tvShow;
27        [ret addSubEpisodesObject:[SapphireSubEpisode createSubEpisode:ep inEpisode:ret]];
28        return ret;
29}
30
31+ (SapphireEpisode *)episodeTitle:(NSString *)title inSeason:(int)season forShow:(NSString *)show withPath:(NSString *)showPath inContext:(NSManagedObjectContext *)moc
32{
33        SapphireSeason *tvseason = [SapphireSeason season:season forShow:show withPath:showPath inContext:moc];
34        NSEnumerator *epEnum = [tvseason.episodesSet objectEnumerator];
35        SapphireEpisode *tvep;
36        while((tvep = [epEnum nextObject]) != nil)
37        {
38                if([SapphireSubEpisode subEpisodeTitle:title inEpisode:tvep] != nil)
39                        return tvep;
40        }
41       
42        SapphireEpisode *ret = [NSEntityDescription insertNewObjectForEntityForName:SapphireEpisodeName inManagedObjectContext:moc];
43        ret.season = tvseason;
44        ret.tvShow = tvseason.tvShow;
45        [ret addSubEpisodesObject:[SapphireSubEpisode createSubEpisodeTitle:title inEpisode:ret]];
46        return ret;
47}
48
49+ (void)upgradeV1EpisodesFromContext:(NSManagedObjectContext *)oldMoc toContext:(NSManagedObjectContext *)newMoc file:(NSDictionary *)fileLookup
50{
51        NSArray *eps = doFetchRequest(SapphireEpisodeName, oldMoc, nil);
52        NSEnumerator *epEnum = [eps objectEnumerator];
53        NSManagedObject *oldEp;
54        while((oldEp = [epEnum nextObject]) != nil)
55        {
56                NSArray *oldFilePaths = [oldEp valueForKeyPath:@"files.path"];
57                NSEnumerator *pathEnum = [oldFilePaths objectEnumerator];
58                NSString *path;
59                NSMutableSet *newFiles = [NSMutableSet set];
60                while((path = [pathEnum nextObject]) != nil)
61                {
62                        SapphireFileMetaData *newFile = [fileLookup objectForKey:path];
63                        if(newFile != nil)
64                                [newFiles addObject:newFile];
65                }
66                if([newFiles count] == 0)
67                        continue;
68               
69                NSNumber *seasonNum = [oldEp valueForKeyPath:@"season.seasonNumber"];
70                NSString *showName = [oldEp valueForKeyPath:@"tvShow.name"];
71                NSString *showPath = [oldEp valueForKeyPath:@"tvShow.showPath"];
72               
73                SapphireSeason *season = [SapphireSeason season:[seasonNum intValue] forShow:showName withPath:showPath inContext:newMoc];
74                if(season == nil)
75                        continue;
76               
77                SapphireEpisode *newEp = [NSEntityDescription insertNewObjectForEntityForName:SapphireEpisodeName inManagedObjectContext:newMoc];
78                newEp.season = season;
79                newEp.tvShow = season.tvShow;
80                [newEp.filesSet setSet:newFiles];
81               
82                NSEnumerator *subEpEnum = [[oldEp valueForKey:@"subEpisodes"] objectEnumerator];
83                NSManagedObject *subEp;
84                while((subEp = [subEpEnum nextObject]) != nil)
85                        [SapphireSubEpisode upgradeV1SubEpisode:subEp toContext:newMoc inEpisode:newEp];
86        }
87}
88
89- (void) dealloc
90{
91        [sortedSubEpisodes release];
92        [super dealloc];
93}
94
95- (void)createSortedEpisodes
96{
97        if(sortedSubEpisodes != nil)
98                return;
99       
100        NSArray *unsorted = [self.subEpisodesSet allObjects];
101        sortedSubEpisodes = [[unsorted sortedArrayUsingSelector:@selector(compare:)] retain];
102}
103
104- (void)insertDictionary:(NSDictionary *)dict
105{
106        SapphireSubEpisode *sub = [self.subEpisodesSet anyObject];
107        int secondEp = [[dict objectForKey:META_EPISODE_2_NUMBER_KEY] intValue];
108        int setIndex = -1;
109        if(secondEp != 0)
110                setIndex = 0;
111        [sub insertDictionary:dict epIndex:setIndex];
112        if(secondEp != 0)
113        {
114                SapphireSubEpisode *sub = [SapphireSubEpisode createSubEpisode:secondEp inEpisode:self];
115                [sub insertDictionary:dict epIndex:1];
116                [self addSubEpisodesObject:sub];
117        }
118        else
119                [self.subEpisodesSet setSet:[NSSet setWithObject:sub]];
120}
121
122+ (SapphireEpisode *)episodeWithDictionary:(NSDictionary *)dict inContext:(NSManagedObjectContext *)moc
123{
124        NSString *show = [dict objectForKey:META_SHOW_NAME_KEY];
125        int season = [[dict objectForKey:META_SEASON_NUMBER_KEY] intValue];
126        int ep = [[dict objectForKey:META_EPISODE_NUMBER_KEY] intValue];
127       
128        if(show == nil || season == 0)
129                return nil;
130       
131        NSString *showPath = [dict objectForKey:META_SHOW_IDENTIFIER_KEY];
132        SapphireEpisode *ret;
133        if(ep == 0)
134        {
135                NSString *title = [dict objectForKey:META_TITLE_KEY];
136                ret = [SapphireEpisode episodeTitle:title inSeason:season forShow:show withPath:showPath inContext:moc];
137        }
138        else
139                ret = [SapphireEpisode episode:ep inSeason:season forShow:show withPath:showPath inContext:moc];
140        [ret insertDictionary:dict];
141        return ret;
142}
143
144- (NSNumber *)episodeNumber
145{
146        overrideWithXMLForKey(NSNumber, episodeNumber);
147        [self createSortedEpisodes];
148        return ((SapphireSubEpisode *)[sortedSubEpisodes objectAtIndex:0]).episodeNumber;
149}
150
151- (int)episodeNumberValue
152{
153        return [[self episodeNumber] intValue];
154}
155
156- (NSNumber *)lastEpisodeNumber
157{
158        overrideWithXMLForKey(NSNumber, lastEpisodeNumber);
159        if([self.subEpisodesSet count] == 1)
160                //Special case, only one episode here and XML didn't override last ep number
161                return [self episodeNumber];
162        [self createSortedEpisodes];
163        return ((SapphireSubEpisode *)[sortedSubEpisodes objectAtIndex:sortedSubEpisodes.count - 1]).episodeNumber;
164}
165
166- (int)lastEpisodeNumberValue
167{
168        return [[self lastEpisodeNumber] intValue];
169}
170
171- (NSNumber *)absoluteEpisodeNumber
172{
173        overrideWithXMLForKey(NSNumber, absoluteEpisodeNumber);
174        [self createSortedEpisodes];
175        return ((SapphireSubEpisode *)[sortedSubEpisodes objectAtIndex:0]).absoluteEpisodeNumber;
176}
177
178- (int)absoluteEpisodeNumberValue
179{
180        return [[self absoluteEpisodeNumber] intValue];
181}
182
183- (NSString *)episodeTitle
184{
185        overrideWithXMLForKey(NSString, title);
186        [self createSortedEpisodes];
187        NSMutableArray *subs = [[sortedSubEpisodes valueForKey:@"episodeTitle"] mutableCopy];
188        [subs removeObject:[NSNull null]];
189        NSString *ret = [subs componentsJoinedByString:@" / "];
190        [subs release];
191        return ret;
192}
193
194- (NSString *)episodeDescription
195{
196        overrideWithXMLForKey(NSString, contentDescription);
197        [self createSortedEpisodes];
198        NSMutableArray *subs = [[sortedSubEpisodes valueForKey:@"episodeDescription"] mutableCopy];
199        [subs removeObject:[NSNull null]];
200        NSString *ret = [subs componentsJoinedByString:@" / "];
201        [subs release];
202        return ret;
203}
204
205- (NSComparisonResult)compare:(SapphireEpisode *)other
206{
207        NSComparisonResult result = [self.season compare:other.season];
208        if(result != NSOrderedSame)
209                return result;
210       
211        NSNumber *myNumber = [self episodeNumber];
212        NSNumber *theirNumber = [other episodeNumber];
213        if([myNumber intValue] == 0 || [theirNumber intValue] == 0)
214                return [self airDateCompare:other];
215
216        return [myNumber compare:theirNumber];
217}
218
219- (NSDate *)airDate
220{
221        [self createSortedEpisodes];
222        return ((SapphireSubEpisode *)[sortedSubEpisodes objectAtIndex:0]).airDate;
223}
224
225- (NSComparisonResult)airDateCompare:(SapphireEpisode *)other
226{
227        return [[self airDate] compare:[other airDate]];
228}
229
230- (void)insertDisplayMetaData:(NSMutableDictionary *)dict
231{
232        id value = [self episodeTitle];
233        if(value != nil)
234                [dict setObject:value forKey:META_TITLE_KEY];
235        value = [self episodeDescription];
236        if(value != nil)
237                [dict setObject:value forKey:META_DESCRIPTION_KEY];
238        value = [[sortedSubEpisodes objectAtIndex:0] airDate];
239        if(value != nil)
240                [dict setObject:value forKey:META_SHOW_AIR_DATE];
241        int season = [[self season] seasonNumberValue];
242        int ep = [self episodeNumberValue];
243        if(season != 0)
244                [dict setObject:[[self season] seasonNumber] forKey:BRLocalizedString(META_SEASON_NUMBER_KEY, @"Season in metadata display")];
245        if(ep != 0)
246                [dict setObject:[NSNumber numberWithInt:ep] forKey:BRLocalizedString(META_EPISODE_NUMBER_KEY, @"Episode in metadata display")];
247        if(ep != 0 && season != 0)
248        {
249                int lastEp = [self lastEpisodeNumberValue];
250                NSString *key = BRLocalizedString(META_EPISODE_AND_SEASON_KEY, @"Season / Episode in metadata display");
251                if(lastEp != nil && lastEp != ep)
252                        [dict setObject:[NSString stringWithFormat:@"%@ - %d / %d-%d", [[self tvShow] name], season, ep, lastEp] forKey:key];
253                else
254                        [dict setObject:[NSString stringWithFormat:@"%@ - %d / %d", [[self tvShow] name], season, lastEp] forKey:key];         
255        }
256}
257
258- (void)insertAdditionalEpisode:(NSDictionary *)dict
259{
260        SapphireSubEpisode *sub = [SapphireSubEpisode createSubEpisode:[[dict objectForKey:META_EPISODE_NUMBER_KEY] intValue] inEpisode:self];
261        [sub insertDictionary:dict epIndex:-1];
262        [self addSubEpisodesObject:sub];
263}
264
265- (NSString *)path
266{
267        [self createSortedEpisodes];
268        return [[sortedSubEpisodes objectAtIndex:0] path];
269}
270
271- (NSString *)coverArtPath
272{
273        NSString *ret = [[SapphireMetaDataSupport collectionArtPath] stringByAppendingPathComponent:[self path]];
274        NSString *file = searchCoverArtExtForPath(ret);
275        if(file == nil)
276                return [self.season coverArtPath];
277        return ret;
278}
279
280- (NSNumber *)watched
281{
282        NSSet *files = self.filesSet;
283        if([files count] < 2)
284                return [[files anyObject] watched];
285       
286        NSArray *remain = [[files allObjects] filteredArrayUsingPredicate:[SapphireApplianceController unwatchedPredicate]];
287        if([remain count])
288                return [NSNumber numberWithBool:YES];
289        return [NSNumber numberWithBool:NO];
290}
291
292- (NSNumber *)favorite
293{
294        NSSet *files = self.filesSet;
295        if([files count] < 2)
296                return [[files anyObject] favorite];
297       
298        NSArray *remain = [[files allObjects] filteredArrayUsingPredicate:[SapphireApplianceController favoritePredicate]];
299        if([remain count])
300                return [NSNumber numberWithBool:YES];
301        return [NSNumber numberWithBool:NO];
302}
303
304/*Overrides*/
305- (void)addSubEpisodes:(NSSet*)value_
306{
307        [sortedSubEpisodes release];
308        sortedSubEpisodes = nil;
309        [super addSubEpisodes:value_];
310}
311
312- (void)removeSubEpisodes:(NSSet*)value_
313{
314        [sortedSubEpisodes release];
315        sortedSubEpisodes = nil;
316        [super removeSubEpisodes:value_];
317}
318
319- (void)addSubEpisodesObject:(SapphireSubEpisode*)value_
320{
321        [sortedSubEpisodes release];
322        sortedSubEpisodes = nil;
323        [super addSubEpisodesObject:value_];
324}
325
326- (void)removeSubEpisodesObject:(SapphireSubEpisode*)value_
327{
328        [sortedSubEpisodes release];
329        sortedSubEpisodes = nil;
330        [super removeSubEpisodesObject:value_]; 
331}
332
333- (void)clearPredicateCache
334{
335        [self.season clearPredicateCache];
336}
337
338- (void)addFiles:(NSSet*)addedFiles
339{
340        [super addFiles:addedFiles];
341        [self clearPredicateCache];
342}
343
344-(void)removeFiles:(NSSet*)removeFiles
345{
346        [super removeFiles:removeFiles];
347        [self clearPredicateCache];
348}
349
350- (void)addFilesObject:(SapphireFileMetaData *)addedFile
351{
352        [super addFilesObject:addedFile];
353        [self clearPredicateCache];
354}
355
356- (void)removeFilesObject:(SapphireFileMetaData *)removeFile
357{
358        [super removeFilesObject:removeFile];
359        [self clearPredicateCache];
360}
361
362@end
Note: See TracBrowser for help on using the browser.