def detailed_author(cls, contributor): """Turn a Contributor into a detailed <author> tag.""" children = [] children.append(AtomFeed.name(contributor.display_name or "")) sort_name = AtomFeed.makeelement("{%s}sort_name" % AtomFeed.SIMPLIFIED_NS) sort_name.text = contributor.sort_name children.append(sort_name) if contributor.family_name: family_name = AtomFeed.makeelement(AtomFeed.schema_("family_name")) family_name.text = contributor.family_name children.append(family_name) if contributor.wikipedia_name: wikipedia_name = AtomFeed.makeelement( "{%s}wikipedia_name" % AtomFeed.SIMPLIFIED_NS) wikipedia_name.text = contributor.wikipedia_name children.append(wikipedia_name) if contributor.viaf: viaf_tag = AtomFeed.makeelement(AtomFeed.schema_("sameas")) viaf_tag.text = "http://viaf.org/viaf/%s" % contributor.viaf children.append(viaf_tag) if contributor.lc: lc_tag = AtomFeed.makeelement(AtomFeed.schema_("sameas")) lc_tag.text = "http://id.loc.gov/authorities/names/%s" % contributor.lc children.append(lc_tag) return AtomFeed.author(*children)
def rating_tag(cls, type_uri, value): """Generate a schema:Rating tag for the given type and value.""" rating_tag = AtomFeed.makeelement(AtomFeed.schema_("Rating")) value_key = AtomFeed.schema_('ratingValue') rating_tag.set(value_key, "%.4f" % value) if type_uri: type_key = AtomFeed.schema_('additionalType') rating_tag.set(type_key, type_uri) return rating_tag
def series(cls, series_name, series_position): """Generate a schema:Series tag for the given name and position.""" if not series_name: return None series_details = dict() series_details['name'] = series_name if series_position: series_details[AtomFeed.schema_('position')] = unicode(series_position) series_tag = AtomFeed.makeelement(AtomFeed.schema_("Series"), **series_details) return series_tag
def categories(cls, work): """Send out _all_ categories for the work. (So long as the category type has a URI associated with it in Subject.uri_lookup.) """ _db = Session.object_session(work) by_scheme_and_term = dict() identifier_ids = work.all_identifier_ids() classifications = Identifier.classifications_for_identifier_ids( _db, identifier_ids) for c in classifications: subject = c.subject if subject.type in Subject.uri_lookup: scheme = Subject.uri_lookup[subject.type] term = subject.identifier weight_field = AtomFeed.schema_("ratingValue") key = (scheme, term) if not key in by_scheme_and_term: value = dict(term=subject.identifier) if subject.name: value['label'] = subject.name value[weight_field] = 0 by_scheme_and_term[key] = value by_scheme_and_term[key][weight_field] += c.weight # Collapse by_scheme_and_term to by_scheme by_scheme = defaultdict(list) for (scheme, term), value in by_scheme_and_term.items(): by_scheme[scheme].append(value) by_scheme.update(super(VerboseAnnotator, cls).categories(work)) return by_scheme
def _make_entry_xml(self, work, license_pool, edition, identifier, lane_link): # Find the .epub link epub_href = None p = None links = [] cover_quality = 0 qualities = [] if work: qualities.append(("Work quality", work.quality)) full_url = None thumbnail_urls, full_urls = self.annotator.cover_links(work) for rel, urls in ( (Hyperlink.IMAGE, full_urls), (Hyperlink.THUMBNAIL_IMAGE, thumbnail_urls)): for url in urls: image_type = "image/png" if url.endswith(".jpeg") or url.endswith(".jpg"): image_type = "image/jpeg" elif url.endswith(".gif"): image_type = "image/gif" links.append(AtomFeed.link(rel=rel, href=url, type=image_type)) permalink = self.annotator.permalink_for(work, license_pool, identifier) content = self.annotator.content(work) if isinstance(content, str): content = content.decode("utf8") content_type = 'html' kw = {} if edition.medium: additional_type = Edition.medium_to_additional_type.get( edition.medium) if not additional_type: logging.warn("No additionalType for medium %s", edition.medium) additional_type_field = AtomFeed.schema_("additionalType") kw[additional_type_field] = additional_type entry = AtomFeed.entry( AtomFeed.id(permalink), AtomFeed.title(edition.title or OPDSFeed.NO_TITLE), **kw ) if edition.subtitle: subtitle_tag = AtomFeed.makeelement(AtomFeed.schema_("alternativeHeadline")) subtitle_tag.text = edition.subtitle entry.append(subtitle_tag) if license_pool: provider_name_attr = "{%s}ProviderName" % AtomFeed.BIBFRAME_NS kwargs = {provider_name_attr : license_pool.data_source.name} data_source_tag = AtomFeed.makeelement( "{%s}distribution" % AtomFeed.BIBFRAME_NS, **kwargs ) entry.extend([data_source_tag]) author_tags = self.annotator.authors(work, license_pool, edition, identifier) entry.extend(author_tags) if edition.series: entry.extend([self.annotator.series(edition.series, edition.series_position)]) if content: entry.extend([AtomFeed.summary(content, type=content_type)]) entry.extend([ AtomFeed.updated(AtomFeed._strftime(datetime.datetime.utcnow())), ]) permanent_work_id_tag = AtomFeed.makeelement("{%s}pwid" % AtomFeed.SIMPLIFIED_NS) permanent_work_id_tag.text = edition.permanent_work_id entry.append(permanent_work_id_tag) entry.extend(links) categories_by_scheme = self.annotator.categories(work) category_tags = [] for scheme, categories in categories_by_scheme.items(): for category in categories: if isinstance(category, basestring): category = dict(term=category) category = dict(map(unicode, (k, v)) for k, v in category.items()) category_tag = AtomFeed.category(scheme=scheme, **category) category_tags.append(category_tag) entry.extend(category_tags) # print " ID %s TITLE %s AUTHORS %s" % (tag, work.title, work.authors) language = edition.language_code if language: language_tag = AtomFeed.makeelement("{%s}language" % AtomFeed.DCTERMS_NS) language_tag.text = language entry.append(language_tag) if edition.publisher: publisher_tag = AtomFeed.makeelement("{%s}publisher" % AtomFeed.DCTERMS_NS) publisher_tag.text = edition.publisher entry.extend([publisher_tag]) # We use Atom 'published' for the date the book first became # available to people using this application. now = datetime.datetime.utcnow() today = datetime.date.today() if license_pool and license_pool.availability_time: avail = license_pool.availability_time if isinstance(avail, datetime.datetime): avail = avail.date() if avail <= today: availability_tag = AtomFeed.makeelement("published") # TODO: convert to local timezone. availability_tag.text = AtomFeed._strftime(license_pool.availability_time) entry.extend([availability_tag]) # Entry.issued is the date the ebook came out, as distinct # from Entry.published (which may refer to the print edition # or some original edition way back when). # # For Dublin Core 'created' we use Entry.issued if we have it # and Entry.published if not. In general this means we use # issued date for Gutenberg and published date for other # sources. # # We use dc:created instead of dc:issued because dc:issued is # commonly conflated with atom:published. # # For the date the book was added to our collection we use # atom:published. issued = edition.issued or edition.published if (isinstance(issued, datetime.datetime) or isinstance(issued, datetime.date)): issued_already = False if isinstance(issued, datetime.datetime): issued_already = (issued <= now) elif isinstance(issued, datetime.date): issued_already = (issued <= today) if issued_already: issued_tag = AtomFeed.makeelement("{%s}created" % AtomFeed.DCTERMS_NS) # TODO: convert to local timezone, not that it matters much. issued_tag.text = issued.strftime("%Y-%m-%d") entry.extend([issued_tag]) return entry
def categories(cls, work): """Return all relevant classifications of this work. :return: A dictionary mapping 'scheme' URLs to dictionaries of attribute-value pairs. Notable attributes: 'term', 'label', 'http://schema.org/ratingValue' """ if not work: return {} categories = {} fiction_term = None if work.fiction == True: fiction_term = 'Fiction' elif work.fiction == False: fiction_term = 'Nonfiction' if fiction_term: fiction_scheme = Subject.SIMPLIFIED_FICTION_STATUS categories[fiction_scheme] = [ dict(term=fiction_scheme + fiction_term, label=fiction_term) ] simplified_genres = [] for wg in work.work_genres: simplified_genres.append(wg.genre.name) if simplified_genres: categories[Subject.SIMPLIFIED_GENRE] = [ dict(term=Subject.SIMPLIFIED_GENRE + urllib.quote(x), label=x) for x in simplified_genres ] # Add the appeals as a category of schema # http://librarysimplified.org/terms/appeal schema_url = AtomFeed.SIMPLIFIED_NS + "appeals/" appeals = [] categories[schema_url] = appeals for name, value in ( (Work.CHARACTER_APPEAL, work.appeal_character), (Work.LANGUAGE_APPEAL, work.appeal_language), (Work.SETTING_APPEAL, work.appeal_setting), (Work.STORY_APPEAL, work.appeal_story), ): if value: appeal = dict(term=schema_url + name, label=name) weight_field = AtomFeed.schema_("ratingValue") appeal[weight_field] = value appeals.append(appeal) # Add the audience as a category of schema # http://schema.org/audience if work.audience: audience_uri = AtomFeed.SCHEMA_NS + "audience" categories[audience_uri] = [ dict(term=work.audience, label=work.audience) ] if work.target_age: uri = Subject.uri_lookup[Subject.AGE_RANGE] target_age = work.target_age_string if target_age: categories[uri] = [dict(term=target_age, label=target_age)] return categories