From 3435ab8d2a19ad387cfb396f8d7b320bca0ec9ea Mon Sep 17 00:00:00 2001 From: Maurice Carrier Date: Mon, 19 Aug 2024 12:11:51 -0400 Subject: [PATCH 1/2] Update TPPOPDSEntry.m --- Palace/OPDS/TPPOPDSEntry.m | 289 +++++++++++++++++++------------------ 1 file changed, 150 insertions(+), 139 deletions(-) diff --git a/Palace/OPDS/TPPOPDSEntry.m b/Palace/OPDS/TPPOPDSEntry.m index 1a515afd4..ee7bf64b3 100644 --- a/Palace/OPDS/TPPOPDSEntry.m +++ b/Palace/OPDS/TPPOPDSEntry.m @@ -41,179 +41,190 @@ @implementation TPPOPDSEntry - (instancetype)initWithXML:(TPPXML *const)entryXML { self = [super init]; - if(!self) return nil; - + if (!self) return nil; + self.alternativeHeadline = [entryXML firstChildWithName:@"alternativeHeadline"].value; - { - NSMutableArray *const authorStrings = [NSMutableArray array]; - NSMutableArray const *authorLinks = [NSMutableArray array]; - - if ([[entryXML childrenWithName:@"duration"] count] > 0) { - TPPXML *durationXML = [[entryXML childrenWithName:@"duration"] firstObject]; - self.duration = durationXML.value; + [self parseAuthorsFromXML:entryXML]; + [self parseContributorsFromXML:entryXML]; + [self parseCategoriesFromXML:entryXML]; + + if (![self parseIdentifierFromXML:entryXML]) return nil; + + [self parseLinksFromXML:entryXML]; + + self.providerName = [entryXML firstChildWithName:@"distribution"].attributes[@"bibframe:ProviderName"]; + + NSString *dateString = [entryXML firstChildWithName:@"issued"].value; + if (dateString) { + self.published = [NSDate dateWithISO8601DateString:dateString]; + } + + self.publisher = [entryXML firstChildWithName:@"publisher"].value; + self.summary = [entryXML firstChildWithName:@"summary"].value; + + if (![self parseTitleFromXML:entryXML]) return nil; + if (![self parseUpdatedDateFromXML:entryXML]) return nil; + [self parseSeriesFromXML:entryXML]; + + return self; +} + +- (void)parseAuthorsFromXML:(TPPXML *const)entryXML { + NSMutableArray *authorStrings = [NSMutableArray array]; + NSMutableArray *authorLinks = [NSMutableArray array]; + + TPPXML *durationXML = [[entryXML childrenWithName:@"duration"] firstObject]; + if (durationXML) { + self.duration = durationXML.value; + } + + for (TPPXML *authorXML in [entryXML childrenWithName:@"author"]) { + TPPXML *nameXML = [authorXML firstChildWithName:@"name"]; + if (!nameXML) { + TPPLOG(@"'author' element missing required 'name' element. Ignoring malformed 'author' element."); + continue; } + [authorStrings addObject:nameXML.value]; - for(TPPXML *const authorXML in [entryXML childrenWithName:@"author"]) { - TPPXML *const nameXML = [authorXML firstChildWithName:@"name"]; - if(!nameXML) { - TPPLOG(@"'author' element missing required 'name' element. Ignoring malformed 'author' element."); - continue; - } - [authorStrings addObject:nameXML.value]; - - TPPXML *const authorLinkXML = [authorXML firstChildWithName:@"link"]; - TPPOPDSLink *const link = [[TPPOPDSLink alloc] initWithXML:authorLinkXML]; - if(!link) { - TPPLOG(@"Ignoring malformed 'link' element for author."); - } else if ([link.rel isEqualToString:@"contributor"]) { - [authorLinks addObject:link]; - } + TPPXML *authorLinkXML = [authorXML firstChildWithName:@"link"]; + TPPOPDSLink *link = [[TPPOPDSLink alloc] initWithXML:authorLinkXML]; + if (!link) { + TPPLOG(@"Ignoring malformed 'link' element for author."); + } else if ([link.rel isEqualToString:@"contributor"]) { + [authorLinks addObject:link]; } - - self.authorStrings = authorStrings; - self.authorLinks = [authorLinks copy]; } - // Contributors and their roles - { - NSMutableDictionary*> *contributors = [NSMutableDictionary dictionary]; - for(TPPXML *contributorNode in [entryXML childrenWithName:@"contributor"]) { - NSString *contributorRole = contributorNode.attributes[@"opf:role"]; - NSString *contributorName = [[contributorNode firstChildWithName:@"name"].value stringByDecodingHTMLEntities]; - if (contributorName) { - if (!contributors[contributorRole]) { - contributors[contributorRole] = [NSMutableArray array]; - } - [contributors[contributorRole] addObject:contributorName]; + self.authorStrings = authorStrings; + self.authorLinks = [authorLinks copy]; +} + +- (void)parseContributorsFromXML:(TPPXML *const)entryXML { + NSMutableDictionary*> *contributors = [NSMutableDictionary dictionary]; + + for (TPPXML *contributorNode in [entryXML childrenWithName:@"contributor"]) { + NSString *contributorRole = contributorNode.attributes[@"opf:role"]; + NSString *contributorName = [[contributorNode firstChildWithName:@"name"].value stringByDecodingHTMLEntities]; + if (contributorName) { + if (!contributors[contributorRole]) { + contributors[contributorRole] = [NSMutableArray array]; } - } - if ([contributors count] > 0) { - self.contributors = contributors; + [contributors[contributorRole] addObject:contributorName]; } } - { - NSMutableArray const *categories = [NSMutableArray array]; - - for(TPPXML *const categoryXML in [entryXML childrenWithName:@"category"]) { - NSString *const term = categoryXML.attributes[@"term"]; - if(!term) { - TPPLOG(@"Category missing required 'term'."); - continue; - } - NSString *const schemeString = categoryXML.attributes[@"scheme"]; - NSURL *const scheme = schemeString ? [NSURL URLWithString:schemeString] : nil; - [categories addObject:[TPPOPDSCategory - categoryWithTerm:term - label:categoryXML.attributes[@"label"] - scheme:scheme]]; + if (contributors.count > 0) { + self.contributors = contributors; + } +} + +- (void)parseCategoriesFromXML:(TPPXML *const)entryXML { + NSMutableArray *categories = [NSMutableArray array]; + + for (TPPXML *categoryXML in [entryXML childrenWithName:@"category"]) { + NSString *term = categoryXML.attributes[@"term"]; + if (!term) { + TPPLOG(@"Category missing required 'term'."); + continue; } - - self.categories = [categories copy]; + NSString *schemeString = categoryXML.attributes[@"scheme"]; + NSURL *scheme = schemeString ? [NSURL URLWithString:schemeString] : nil; + TPPOPDSCategory *category = [TPPOPDSCategory categoryWithTerm:term label:categoryXML.attributes[@"label"] scheme:scheme]; + [categories addObject:category]; } - if(!((self.identifier = [entryXML firstChildWithName:@"id"].value))) { + self.categories = [categories copy]; +} + +- (BOOL)parseIdentifierFromXML:(TPPXML *const)entryXML { + self.identifier = [entryXML firstChildWithName:@"id"].value; + if (!self.identifier) { TPPLOG(@"Missing required 'id' element."); - return nil; + return NO; } + return YES; +} + +- (void)parseLinksFromXML:(TPPXML *const)entryXML { + NSMutableArray *mutableLinks = [NSMutableArray array]; + NSMutableArray *mutableAcquisitions = [NSMutableArray array]; - { - NSMutableArray *const mutableLinks = [NSMutableArray array]; - NSMutableArray *const mutableAcquisitions = [NSMutableArray array]; - - for (TPPXML *const linkXML in [entryXML childrenWithName:@"link"]) { - - // Try parsing the link as an acquisition first to avoid creating an NYPLOPDSLink - // for no reason. - if ([[linkXML attributes][@"rel"] containsString:TPPOPDSRelationAcquisition]) { - TPPOPDSAcquisition *const acquisition = [TPPOPDSAcquisition acquisitionWithLinkXML:linkXML]; - if (acquisition) { - [mutableAcquisitions addObject:acquisition]; - continue; - } - } else if ([[linkXML attributes][@"rel"] containsString: TPPOPDSRelationPreview]) { - // Try parsing the link as a preview - TPPOPDSAcquisition *const acquisition = [TPPOPDSAcquisition acquisitionWithLinkXML:linkXML]; + for (TPPXML *linkXML in [entryXML childrenWithName:@"link"]) { + if ([linkXML.attributes[@"rel"] containsString:TPPOPDSRelationAcquisition]) { + TPPOPDSAcquisition *acquisition = [TPPOPDSAcquisition acquisitionWithLinkXML:linkXML]; + if (acquisition) { + [mutableAcquisitions addObject:acquisition]; + continue; + } + } else if ([linkXML.attributes[@"rel"] containsString:TPPOPDSRelationPreview]) { + if (!self.previewLink) { + TPPOPDSAcquisition *acquisition = [TPPOPDSAcquisition acquisitionWithLinkXML:linkXML]; if (acquisition) { self.previewLink = acquisition; } } - - // It may sometimes bet the case that `!acquisition` if the acquisition used a - // non-standard relation. As such, we do not log an error here and let things - // continue so the link can be added to `self.links`. - - TPPOPDSLink *const link = [[TPPOPDSLink alloc] initWithXML:linkXML]; - if(!link) { - TPPLOG(@"Ignoring malformed 'link' element."); - continue; - } - - if ([link.rel isEqualToString:@"http://www.w3.org/ns/oa#annotationService"]){ - self.annotations = link; - } else if ([link.rel isEqualToString:@"alternate"]){ - self.alternate = link; - self.analytics = [NSURL URLWithString:[link.href.absoluteString stringByReplacingOccurrencesOfString:@"/works/" withString:@"/analytics/"]]; - } else if ([link.rel isEqualToString:@"related"]){ - self.relatedWorks = link; - } else if ([link.rel isEqualToString:TPPOPDSRelationTimeTrackingLink]) { - // The app should track and report audiobook playback time if this link is present - self.timeTrackingLink = link; - } else { - [mutableLinks addObject:link]; - } } - self.acquisitions = [mutableAcquisitions copy]; - self.links = [mutableLinks copy]; - } - - self.providerName = [entryXML firstChildWithName:@"distribution"].attributes[@"bibframe:ProviderName"]; - - { - NSString *const dateString = [entryXML firstChildWithName:@"issued"].value; - if(dateString) { - self.published = [NSDate dateWithISO8601DateString:dateString]; + TPPOPDSLink *link = [[TPPOPDSLink alloc] initWithXML:linkXML]; + if (!link) { + TPPLOG(@"Ignoring malformed 'link' element."); + continue; + } + + if ([link.rel isEqualToString:@"http://www.w3.org/ns/oa#annotationService"]) { + self.annotations = link; + } else if ([link.rel isEqualToString:@"alternate"]) { + self.alternate = link; + self.analytics = [NSURL URLWithString:[link.href.absoluteString stringByReplacingOccurrencesOfString:@"/works/" withString:@"/analytics/"]]; + } else if ([link.rel isEqualToString:@"related"]) { + self.relatedWorks = link; + } else if ([link.rel isEqualToString:TPPOPDSRelationTimeTrackingLink]) { + self.timeTrackingLink = link; + } else { + [mutableLinks addObject:link]; } } - self.publisher = [entryXML firstChildWithName:@"publisher"].value; - - self.summary = [entryXML firstChildWithName:@"summary"].value; - - if(!((self.title = [entryXML firstChildWithName:@"title"].value))) { + self.acquisitions = [mutableAcquisitions copy]; + self.links = [mutableLinks copy]; +} + +- (BOOL)parseTitleFromXML:(TPPXML *const)entryXML { + self.title = [entryXML firstChildWithName:@"title"].value; + if (!self.title) { TPPLOG(@"Missing required 'title' element."); - return nil; + return NO; + } + return YES; +} + +- (BOOL)parseUpdatedDateFromXML:(TPPXML *const)entryXML { + NSString *updatedString = [entryXML firstChildWithName:@"updated"].value; + if (!updatedString) { + TPPLOG(@"Missing required 'updated' element."); + return NO; } - { - NSString *const updatedString = [entryXML firstChildWithName:@"updated"].value; - if(!updatedString) { - TPPLOG(@"Missing required 'updated' element."); - return nil; - } - - self.updated = [NSDate dateWithRFC3339String:updatedString]; - if(!self.updated) { - TPPLOG(@"Element 'updated' does not contain an RFC 3339 date."); - return nil; - } + self.updated = [NSDate dateWithRFC3339String:updatedString]; + if (!self.updated) { + TPPLOG(@"Element 'updated' does not contain an RFC 3339 date."); + return NO; } + return YES; +} - { - TPPXML *const seriesXML = [entryXML firstChildWithName:@"Series"]; - TPPXML *const linkXML = [seriesXML firstChildWithName:@"link"]; - if (linkXML) { - self.seriesLink = [[TPPOPDSLink alloc] initWithXML:linkXML]; - if (!self.seriesLink) { - TPPLOG(@"Ignoring malformed 'link' element for schema:Series."); - } +- (void)parseSeriesFromXML:(TPPXML *const)entryXML { + TPPXML *seriesXML = [entryXML firstChildWithName:@"Series"]; + TPPXML *linkXML = [seriesXML firstChildWithName:@"link"]; + if (linkXML) { + self.seriesLink = [[TPPOPDSLink alloc] initWithXML:linkXML]; + if (!self.seriesLink) { + TPPLOG(@"Ignoring malformed 'link' element for schema:Series."); } } - - return self; } + - (TPPOPDSEntryGroupAttributes *)groupAttributes { for(TPPOPDSLink *const link in self.links) { From 6df885f84ff8e1aaa57fab3a2f90e38707adfb44 Mon Sep 17 00:00:00 2001 From: Maurice Carrier Date: Tue, 20 Aug 2024 15:18:36 -0400 Subject: [PATCH 2/2] Update project.pbxproj --- Palace.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Palace.xcodeproj/project.pbxproj b/Palace.xcodeproj/project.pbxproj index 89c4436c7..518cf4f5e 100644 --- a/Palace.xcodeproj/project.pbxproj +++ b/Palace.xcodeproj/project.pbxproj @@ -5663,7 +5663,7 @@ CODE_SIGN_IDENTITY = "Apple Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 283; + CURRENT_PROJECT_VERSION = 284; DEVELOPMENT_TEAM = 88CBA74T8K; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 88CBA74T8K; ENABLE_BITCODE = NO; @@ -5722,7 +5722,7 @@ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES_ERROR; CODE_SIGN_ENTITLEMENTS = Palace/SimplyE.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 283; + CURRENT_PROJECT_VERSION = 284; DEVELOPMENT_TEAM = 88CBA74T8K; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 88CBA74T8K; ENABLE_BITCODE = NO; @@ -5907,7 +5907,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 283; + CURRENT_PROJECT_VERSION = 284; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 88CBA74T8K; ENABLE_BITCODE = NO; @@ -5968,7 +5968,7 @@ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES_ERROR; CODE_SIGN_ENTITLEMENTS = Palace/SimplyE.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 283; + CURRENT_PROJECT_VERSION = 284; DEVELOPMENT_TEAM = 88CBA74T8K; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 88CBA74T8K; ENABLE_BITCODE = NO; @@ -6030,7 +6030,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 283; + CURRENT_PROJECT_VERSION = 284; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 88CBA74T8K; ENABLE_BITCODE = NO; @@ -6091,7 +6091,7 @@ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES_ERROR; CODE_SIGN_ENTITLEMENTS = Palace/SimplyE.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; - CURRENT_PROJECT_VERSION = 283; + CURRENT_PROJECT_VERSION = 284; DEVELOPMENT_TEAM = 88CBA74T8K; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 88CBA74T8K; ENABLE_BITCODE = NO;