| 1 | // |
|---|
| 2 | // SapphirePopulateDataMenu.m |
|---|
| 3 | // Sapphire |
|---|
| 4 | // |
|---|
| 5 | // Created by pnmerrill on 6/24/07. |
|---|
| 6 | // Copyright 2007 __www.nanopi.net__. All rights reserved. |
|---|
| 7 | // |
|---|
| 8 | |
|---|
| 9 | #import "SapphirePopulateDataMenu.h" |
|---|
| 10 | #import "SapphireMetaData.h" |
|---|
| 11 | #include <sys/types.h> |
|---|
| 12 | #include <sys/stat.h> |
|---|
| 13 | |
|---|
| 14 | //Single Attributes |
|---|
| 15 | #define MEDIA_TVSHOW_XML_QUERY @"/media[@type='TV Show']/text()" |
|---|
| 16 | #define MEDIA_MOVIE_XML_QUERY @"/media[@type='Movie']/text()" |
|---|
| 17 | #define SUMMARY_XML_QUERY @"/media/summary/text()" |
|---|
| 18 | #define DESCRIPTION_XML_QUERY @"/media/description/text()" |
|---|
| 19 | #define PUBLISHER_XML_QUERY @"/media/publisher/text()" |
|---|
| 20 | #define COPYRIGHT_XML_QUERY @"/media/copyright/text()" |
|---|
| 21 | #define USER_RATING_XML_QUERY @"/media/userStarRating/text()" |
|---|
| 22 | #define RATING_XML_QUERY @"/media/rating/text()" |
|---|
| 23 | #define SERIES_NAME_XML_QUERY @"/media/seriesName/text()" |
|---|
| 24 | #define BROADCASTER_XML_QUERY @"/media/broadcaster/text()" |
|---|
| 25 | #define EPISODE_NUMBER_XML_QUERY @"/media/episodeNumber/text()" |
|---|
| 26 | #define EPISODE_XML_QUERY @"/media/episode/text()" |
|---|
| 27 | #define SEASON_XML_QUERY @"/media/season/text()" |
|---|
| 28 | #define PUBLISHED_XML_QUERY @"/media/published/text()" |
|---|
| 29 | //Multi Attributes |
|---|
| 30 | #define TITLE_XML_QUERY @"/media/title/text()" |
|---|
| 31 | #define GENRES_XML_QUERY @"/media/genres/genre/text()" |
|---|
| 32 | #define CAST_XML_QUERY @"/media/cast/name/text()" |
|---|
| 33 | #define DIRECTORS_XML_QUERY @"/media/directors/name/text()" |
|---|
| 34 | #define PRODUCERS_XML_QUERY @"/media/producers/name/text()" |
|---|
| 35 | |
|---|
| 36 | @implementation SapphirePopulateDataMenu |
|---|
| 37 | |
|---|
| 38 | /*Information to make the XML import easier*/ |
|---|
| 39 | static NSDictionary *xmlSingleAttributes = nil; |
|---|
| 40 | static NSDictionary *xmlMultiAttributes = nil; |
|---|
| 41 | |
|---|
| 42 | +(void) initialize |
|---|
| 43 | { |
|---|
| 44 | xmlSingleAttributes = [[NSDictionary alloc] initWithObjectsAndKeys: |
|---|
| 45 | META_TITLE_KEY, TITLE_XML_QUERY, |
|---|
| 46 | META_SUMMARY_KEY, SUMMARY_XML_QUERY, |
|---|
| 47 | META_DESCRIPTION_KEY, DESCRIPTION_XML_QUERY, |
|---|
| 48 | @"Publisher", PUBLISHER_XML_QUERY, |
|---|
| 49 | META_COPYRIGHT_KEY, COPYRIGHT_XML_QUERY, |
|---|
| 50 | META_SHOW_FAVORITE_RATING_KEY, USER_RATING_XML_QUERY, |
|---|
| 51 | META_SHOW_RATING_KEY, RATING_XML_QUERY, |
|---|
| 52 | META_SHOW_NAME_KEY, SERIES_NAME_XML_QUERY, |
|---|
| 53 | META_SHOW_BROADCASTER_KEY, BROADCASTER_XML_QUERY, |
|---|
| 54 | META_ABSOLUTE_EP_NUMBER_KEY, EPISODE_NUMBER_XML_QUERY, |
|---|
| 55 | META_EPISODE_NUMBER_KEY, EPISODE_XML_QUERY, |
|---|
| 56 | META_SEASON_NUMBER_KEY, SEASON_XML_QUERY, |
|---|
| 57 | META_SHOW_PUBLISHED_DATE_KEY, PUBLISHED_XML_QUERY,nil] ; |
|---|
| 58 | xmlMultiAttributes = [[NSDictionary alloc] initWithObjectsAndKeys: |
|---|
| 59 | @"Genres", GENRES_XML_QUERY, |
|---|
| 60 | @"Cast", CAST_XML_QUERY, |
|---|
| 61 | @"Producers" , PRODUCERS_XML_QUERY, |
|---|
| 62 | @"Directors", DIRECTORS_XML_QUERY,nil]; |
|---|
| 63 | } |
|---|
| 64 | |
|---|
| 65 | /*See super documentation*/ |
|---|
| 66 | - (void)getItems |
|---|
| 67 | { |
|---|
| 68 | [super getItems]; |
|---|
| 69 | xmlFileCount=0 ; |
|---|
| 70 | } |
|---|
| 71 | |
|---|
| 72 | /*See super documentation*/ |
|---|
| 73 | - (BOOL)doImport |
|---|
| 74 | { |
|---|
| 75 | /*Initialization*/ |
|---|
| 76 | BOOL ret = NO; |
|---|
| 77 | NSFileManager *fm = [NSFileManager defaultManager]; |
|---|
| 78 | /*Get the file*/ |
|---|
| 79 | SapphireFileMetaData *fileMeta = [importItems objectAtIndex:0]; |
|---|
| 80 | /*Check for XML file*/ |
|---|
| 81 | NSString * xmlFilePath=[fileMeta path] ; |
|---|
| 82 | xmlPathIsDir = NO; |
|---|
| 83 | xmlFilePath=[[xmlFilePath stringByDeletingPathExtension] stringByAppendingPathExtension:@"xml"]; |
|---|
| 84 | if([fm fileExistsAtPath:xmlFilePath isDirectory:&xmlPathIsDir] && !xmlPathIsDir) |
|---|
| 85 | { |
|---|
| 86 | /*Check modification date on XML file*/ |
|---|
| 87 | struct stat sb; |
|---|
| 88 | memset(&sb, 0, sizeof(struct stat)); |
|---|
| 89 | stat([xmlFilePath fileSystemRepresentation], &sb); |
|---|
| 90 | long modTime = sb.st_mtimespec.tv_sec; |
|---|
| 91 | long oldTime = [fileMeta importedTimeFromSource:META_XML_IMPORT_KEY]; |
|---|
| 92 | if(oldTime < modTime) |
|---|
| 93 | { |
|---|
| 94 | /*Import the XML file and update counts*/ |
|---|
| 95 | [self importXMLFile:xmlFilePath forMeta:fileMeta] ; |
|---|
| 96 | xmlFileCount++ ; |
|---|
| 97 | ret = YES; |
|---|
| 98 | } |
|---|
| 99 | } |
|---|
| 100 | /*Import file if necessary*/ |
|---|
| 101 | if ([fileMeta updateMetaData]) |
|---|
| 102 | ret = YES; |
|---|
| 103 | /*Return whether we imported or not*/ |
|---|
| 104 | return ret; |
|---|
| 105 | } |
|---|
| 106 | |
|---|
| 107 | /*See super documentation*/ |
|---|
| 108 | - (void)setCompletionText |
|---|
| 109 | { |
|---|
| 110 | [self setText:BRLocalizedString(@"Sapphire will continue to import new files as it encounters them. You may initiate this import again at any time, and any new or changed files will be imported", @"End text after import of files is complete")]; |
|---|
| 111 | [self setCurrentFile:[NSString stringWithFormat:@"Imported %d XML file(s)",xmlFileCount]]; |
|---|
| 112 | } |
|---|
| 113 | |
|---|
| 114 | /*! |
|---|
| 115 | * @brief Import and XML file into meta data |
|---|
| 116 | * |
|---|
| 117 | * @param xmlFileName The path of the xml file |
|---|
| 118 | * @param fileMeta The file's meta data |
|---|
| 119 | */ |
|---|
| 120 | - (void)importXMLFile:(NSString *)xmlFileName forMeta: (SapphireFileMetaData *) fileMeta |
|---|
| 121 | { |
|---|
| 122 | /*Read the XML document*/ |
|---|
| 123 | NSURL *url = [NSURL fileURLWithPath:xmlFileName]; |
|---|
| 124 | NSError *error = nil; |
|---|
| 125 | NSMutableDictionary * metaData=[NSMutableDictionary dictionary]; |
|---|
| 126 | NSXMLDocument *document = [[NSXMLDocument alloc] initWithContentsOfURL:url options:NSXMLDocumentTidyXML error:&error]; |
|---|
| 127 | NSXMLElement *root = [document rootElement]; |
|---|
| 128 | if(!root) |
|---|
| 129 | return; |
|---|
| 130 | /* |
|---|
| 131 | NSString *type = [[root attributeForName:@"type"] stringValue]; |
|---|
| 132 | //Need to catch the media type {"TV Show" , "Movie"} |
|---|
| 133 | if(type!=nil)metaData |
|---|
| 134 | */ |
|---|
| 135 | /*Import single attribute items*/ |
|---|
| 136 | NSEnumerator *keyEnum = [xmlSingleAttributes keyEnumerator]; |
|---|
| 137 | NSString *key = nil; |
|---|
| 138 | |
|---|
| 139 | while((key = [keyEnum nextObject]) != nil) |
|---|
| 140 | { |
|---|
| 141 | /*Search for the attribute*/ |
|---|
| 142 | NSArray *objects = [root objectsForXQuery:key error:&error]; |
|---|
| 143 | if([objects count]) |
|---|
| 144 | { |
|---|
| 145 | /*Import the attribute*/ |
|---|
| 146 | [metaData setObject:[[objects objectAtIndex:0] stringValue] forKey:[xmlSingleAttributes objectForKey:key]] ; |
|---|
| 147 | } |
|---|
| 148 | } |
|---|
| 149 | /*Search for multi attribute items*/ |
|---|
| 150 | keyEnum = [xmlMultiAttributes keyEnumerator]; |
|---|
| 151 | while((key = [keyEnum nextObject]) != nil) |
|---|
| 152 | { |
|---|
| 153 | /*Search for the attribute*/ |
|---|
| 154 | NSArray *objects = [root objectsForXQuery:key error:&error]; |
|---|
| 155 | int count = [objects count]; |
|---|
| 156 | NSMutableArray *newData= nil; |
|---|
| 157 | if(!count) |
|---|
| 158 | continue; |
|---|
| 159 | /*Itterate through the attribute's values*/ |
|---|
| 160 | newData = [NSMutableArray arrayWithCapacity:count]; |
|---|
| 161 | NSEnumerator *objectsEnum = [objects objectEnumerator]; |
|---|
| 162 | NSXMLNode *node = nil; |
|---|
| 163 | while((node = [objectsEnum nextObject]) != nil) |
|---|
| 164 | { |
|---|
| 165 | /*Add each value*/ |
|---|
| 166 | [newData addObject:[node stringValue]]; |
|---|
| 167 | } |
|---|
| 168 | /*Import the attribute*/ |
|---|
| 169 | [metaData setObject:newData forKey:[xmlMultiAttributes objectForKey:key]] ; |
|---|
| 170 | } |
|---|
| 171 | /*Special cases*/ |
|---|
| 172 | /*The air date*/ |
|---|
| 173 | NSString *value = [metaData objectForKey:META_SHOW_AIR_DATE]; |
|---|
| 174 | if(value != nil) |
|---|
| 175 | { |
|---|
| 176 | /*Change date string to a number*/ |
|---|
| 177 | [metaData removeObjectForKey:META_SHOW_AIR_DATE]; |
|---|
| 178 | NSDate *newValue = [NSDate dateWithNaturalLanguageString:value]; |
|---|
| 179 | if([newValue timeIntervalSince1970]) |
|---|
| 180 | [metaData setObject:newValue forKey:META_SHOW_AIR_DATE]; |
|---|
| 181 | } |
|---|
| 182 | /*The aquired date*/ |
|---|
| 183 | value = [metaData objectForKey:META_SHOW_AQUIRED_DATE]; |
|---|
| 184 | if(value != nil) |
|---|
| 185 | { |
|---|
| 186 | /*Change date sttring to a number*/ |
|---|
| 187 | [metaData removeObjectForKey:META_SHOW_AQUIRED_DATE]; |
|---|
| 188 | NSDate *newValue = [NSDate dateWithNaturalLanguageString:value]; |
|---|
| 189 | if([newValue timeIntervalSince1970]) |
|---|
| 190 | [metaData setObject:newValue forKey:META_SHOW_AQUIRED_DATE]; |
|---|
| 191 | } |
|---|
| 192 | /*Values which need to be converted to numbers*/ |
|---|
| 193 | NSArray *convertToNumbers = [NSArray arrayWithObjects:META_SHOW_FAVORITE_RATING_KEY, META_ABSOLUTE_EP_NUMBER_KEY, META_SEASON_NUMBER_KEY, META_EPISODE_NUMBER_KEY, nil]; |
|---|
| 194 | NSEnumerator *numEnum = [convertToNumbers objectEnumerator]; |
|---|
| 195 | while((key = [numEnum nextObject]) != nil) |
|---|
| 196 | { |
|---|
| 197 | /*Check for presence of value*/ |
|---|
| 198 | NSString *value = [metaData objectForKey:key]; |
|---|
| 199 | if(value != nil) |
|---|
| 200 | { |
|---|
| 201 | /*Convert to a number, either a double or int, depending on value*/ |
|---|
| 202 | double newValue = [value doubleValue]; |
|---|
| 203 | NSNumber *newNum = [NSNumber numberWithInt:[value intValue]]; |
|---|
| 204 | if(newValue != round(newValue)) |
|---|
| 205 | newNum = [NSNumber numberWithDouble:newValue]; |
|---|
| 206 | [metaData setObject:newNum forKey:key]; |
|---|
| 207 | } |
|---|
| 208 | } |
|---|
| 209 | /*Update modification date*/ |
|---|
| 210 | struct stat sb; |
|---|
| 211 | memset(&sb, 0, sizeof(struct stat)); |
|---|
| 212 | stat([xmlFileName fileSystemRepresentation], &sb); |
|---|
| 213 | long modTime = sb.st_mtimespec.tv_sec; |
|---|
| 214 | /*Import into meta data*/ |
|---|
| 215 | [fileMeta importInfo: metaData fromSource:META_XML_IMPORT_KEY withTime:modTime]; |
|---|
| 216 | } |
|---|
| 217 | |
|---|
| 218 | /*See super documentation*/ |
|---|
| 219 | - (void)importNextItem:(NSTimer *)timer |
|---|
| 220 | { |
|---|
| 221 | /*Set the current file in the progress*/ |
|---|
| 222 | SapphireFileMetaData *fileMeta = [importItems objectAtIndex:0]; |
|---|
| 223 | NSString * fileName=[[fileMeta path] lastPathComponent] ; |
|---|
| 224 | [self setCurrentFile:[NSString stringWithFormat:BRLocalizedString(@"Current File: %@", @"Current file processes in import format"),fileName]]; |
|---|
| 225 | [super importNextItem:timer]; |
|---|
| 226 | } |
|---|
| 227 | |
|---|
| 228 | /*See super documentation*/ |
|---|
| 229 | - (void)resetUIElements |
|---|
| 230 | { |
|---|
| 231 | [super resetUIElements]; |
|---|
| 232 | [title setTitle: BRLocalizedString(@"Import File Data", @"Title")]; |
|---|
| 233 | [self setText:BRLocalizedString(@"This will populate Sapphire's File data. This proceedure may take a while, but you may cancel at any time", @"Description of the import processes")]; |
|---|
| 234 | [button setTitle: BRLocalizedString(@"Import File Data", @"Button")]; |
|---|
| 235 | } |
|---|
| 236 | @end |
|---|