Merge branch 'main' into add-edit-book
This commit is contained in:
@ -54,6 +54,7 @@ class Edition(Book):
|
||||
asin: str = ""
|
||||
pages: int = None
|
||||
physicalFormat: str = ""
|
||||
physicalFormatDetail: str = ""
|
||||
publishers: List[str] = field(default_factory=lambda: [])
|
||||
editionRank: int = 0
|
||||
|
||||
|
@ -9,6 +9,7 @@ from requests.exceptions import RequestException
|
||||
|
||||
from bookwyrm import activitypub, models, settings
|
||||
from .connector_manager import load_more_data, ConnectorException
|
||||
from .format_mappings import format_mappings
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -312,3 +313,25 @@ class Mapping:
|
||||
return self.formatter(value)
|
||||
except: # pylint: disable=bare-except
|
||||
return None
|
||||
|
||||
|
||||
def infer_physical_format(format_text):
|
||||
"""try to figure out what the standardized format is from the free value"""
|
||||
format_text = format_text.lower()
|
||||
if format_text in format_mappings:
|
||||
# try a direct match
|
||||
return format_mappings[format_text]
|
||||
# failing that, try substring
|
||||
matches = [v for k, v in format_mappings.items() if k in format_text]
|
||||
if not matches:
|
||||
return None
|
||||
return matches[0]
|
||||
|
||||
|
||||
def unique_physical_format(format_text):
|
||||
"""only store the format if it isn't diretly in the format mappings"""
|
||||
format_text = format_text.lower()
|
||||
if format_text in format_mappings:
|
||||
# try a direct match, so saving this would be redundant
|
||||
return None
|
||||
return format_text
|
||||
|
43
bookwyrm/connectors/format_mappings.py
Normal file
43
bookwyrm/connectors/format_mappings.py
Normal file
@ -0,0 +1,43 @@
|
||||
""" comparing a free text format to the standardized one """
|
||||
format_mappings = {
|
||||
"paperback": "Paperback",
|
||||
"soft": "Paperback",
|
||||
"pamphlet": "Paperback",
|
||||
"peperback": "Paperback",
|
||||
"tapa blanda": "Paperback",
|
||||
"turtleback": "Paperback",
|
||||
"pocket": "Paperback",
|
||||
"spiral": "Paperback",
|
||||
"ring": "Paperback",
|
||||
"平装": "Paperback",
|
||||
"简装": "Paperback",
|
||||
"hardcover": "Hardcover",
|
||||
"hardcocer": "Hardcover",
|
||||
"hardover": "Hardcover",
|
||||
"hardback": "Hardcover",
|
||||
"library": "Hardcover",
|
||||
"tapa dura": "Hardcover",
|
||||
"leather": "Hardcover",
|
||||
"clothbound": "Hardcover",
|
||||
"精装": "Hardcover",
|
||||
"ebook": "EBook",
|
||||
"e-book": "EBook",
|
||||
"digital": "EBook",
|
||||
"computer file": "EBook",
|
||||
"epub": "EBook",
|
||||
"online": "EBook",
|
||||
"pdf": "EBook",
|
||||
"elektronische": "EBook",
|
||||
"electronic": "EBook",
|
||||
"audiobook": "AudiobookFormat",
|
||||
"audio": "AudiobookFormat",
|
||||
"cd": "AudiobookFormat",
|
||||
"dvd": "AudiobookFormat",
|
||||
"mp3": "AudiobookFormat",
|
||||
"cassette": "AudiobookFormat",
|
||||
"kindle": "AudiobookFormat",
|
||||
"talking": "AudiobookFormat",
|
||||
"sound": "AudiobookFormat",
|
||||
"comic": "GraphicNovel",
|
||||
"graphic": "GraphicNovel",
|
||||
}
|
@ -8,7 +8,7 @@ from .connector_manager import ConnectorException
|
||||
|
||||
|
||||
class Connector(AbstractConnector):
|
||||
"""instantiate a connector for OL"""
|
||||
"""instantiate a connector for inventaire"""
|
||||
|
||||
def __init__(self, identifier):
|
||||
super().__init__(identifier)
|
||||
|
@ -3,7 +3,7 @@ import re
|
||||
|
||||
from bookwyrm import models
|
||||
from .abstract_connector import AbstractConnector, SearchResult, Mapping
|
||||
from .abstract_connector import get_data
|
||||
from .abstract_connector import get_data, infer_physical_format, unique_physical_format
|
||||
from .connector_manager import ConnectorException
|
||||
from .openlibrary_languages import languages
|
||||
|
||||
@ -43,7 +43,16 @@ class Connector(AbstractConnector):
|
||||
),
|
||||
Mapping("publishedDate", remote_field="publish_date"),
|
||||
Mapping("pages", remote_field="number_of_pages"),
|
||||
Mapping("physicalFormat", remote_field="physical_format"),
|
||||
Mapping(
|
||||
"physicalFormat",
|
||||
remote_field="physical_format",
|
||||
formatter=infer_physical_format,
|
||||
),
|
||||
Mapping(
|
||||
"physicalFormatDetail",
|
||||
remote_field="physical_format",
|
||||
formatter=unique_physical_format,
|
||||
),
|
||||
Mapping("publishers"),
|
||||
]
|
||||
|
||||
|
56
bookwyrm/migrations/0101_auto_20210929_1847.py
Normal file
56
bookwyrm/migrations/0101_auto_20210929_1847.py
Normal file
@ -0,0 +1,56 @@
|
||||
# Generated by Django 3.2 on 2021-05-21 00:17
|
||||
|
||||
from django.db import migrations
|
||||
import bookwyrm
|
||||
from bookwyrm.connectors.abstract_connector import infer_physical_format
|
||||
|
||||
|
||||
def infer_format(app_registry, schema_editor):
|
||||
"""set the new phsyical format field based on existing format data"""
|
||||
db_alias = schema_editor.connection.alias
|
||||
|
||||
editions = (
|
||||
app_registry.get_model("bookwyrm", "Edition")
|
||||
.objects.using(db_alias)
|
||||
.filter(physical_format_detail__isnull=False)
|
||||
)
|
||||
for edition in editions:
|
||||
free_format = edition.physical_format_detail.lower()
|
||||
edition.physical_format = infer_physical_format(free_format)
|
||||
edition.save()
|
||||
|
||||
|
||||
def reverse(app_registry, schema_editor):
|
||||
"""doesn't need to do anything"""
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("bookwyrm", "0100_shelf_description"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name="edition",
|
||||
old_name="physical_format",
|
||||
new_name="physical_format_detail",
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="edition",
|
||||
name="physical_format",
|
||||
field=bookwyrm.models.fields.CharField(
|
||||
blank=True,
|
||||
choices=[
|
||||
("AudiobookFormat", "Audiobook"),
|
||||
("EBook", "eBook"),
|
||||
("GraphicNovel", "Graphic novel"),
|
||||
("Hardcover", "Hardcover"),
|
||||
("Paperback", "Paperback"),
|
||||
],
|
||||
max_length=255,
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
migrations.RunPython(infer_format, reverse),
|
||||
]
|
@ -6,6 +6,7 @@ from django.contrib.postgres.indexes import GinIndex
|
||||
from django.db import models, transaction
|
||||
from django.db.models import Prefetch
|
||||
from django.dispatch import receiver
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from model_utils import FieldTracker
|
||||
from model_utils.managers import InheritanceManager
|
||||
from imagekit.models import ImageSpecField
|
||||
@ -226,6 +227,16 @@ class Work(OrderedCollectionPageMixin, Book):
|
||||
deserialize_reverse_fields = [("editions", "editions")]
|
||||
|
||||
|
||||
# https://schema.org/BookFormatType
|
||||
FormatChoices = [
|
||||
("AudiobookFormat", _("Audiobook")),
|
||||
("EBook", _("eBook")),
|
||||
("GraphicNovel", _("Graphic novel")),
|
||||
("Hardcover", _("Hardcover")),
|
||||
("Paperback", _("Paperback")),
|
||||
]
|
||||
|
||||
|
||||
class Edition(Book):
|
||||
"""an edition of a book"""
|
||||
|
||||
@ -243,7 +254,10 @@ class Edition(Book):
|
||||
max_length=255, blank=True, null=True, deduplication_field=True
|
||||
)
|
||||
pages = fields.IntegerField(blank=True, null=True)
|
||||
physical_format = fields.CharField(max_length=255, blank=True, null=True)
|
||||
physical_format = fields.CharField(
|
||||
max_length=255, choices=FormatChoices, null=True, blank=True
|
||||
)
|
||||
physical_format_detail = fields.CharField(max_length=255, blank=True, null=True)
|
||||
publishers = fields.ArrayField(
|
||||
models.CharField(max_length=255), blank=True, default=list
|
||||
)
|
||||
|
@ -253,12 +253,27 @@
|
||||
|
||||
<div class="block">
|
||||
<h2 class="title is-4">{% trans "Physical Properties" %}</h2>
|
||||
<div class="field">
|
||||
<label class="label" for="id_physical_format">{% trans "Format:" %}</label>
|
||||
{{ form.physical_format }}
|
||||
{% for error in form.physical_format.errors %}
|
||||
<p class="help is-danger">{{ error | escape }}</p>
|
||||
{% endfor %}
|
||||
<div class="columns">
|
||||
<div class="column is-one-third">
|
||||
<div class="field">
|
||||
<label class="label" for="id_physical_format">{% trans "Format:" %}</label>
|
||||
<div class="select">
|
||||
{{ form.physical_format }}
|
||||
</div>
|
||||
{% for error in form.physical_format.errors %}
|
||||
<p class="help is-danger">{{ error | escape }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="field">
|
||||
<label class="label" for="id_physical_format_detail">{% trans "Format details:" %}</label>
|
||||
{{ form.physical_format_detail }}
|
||||
{% for error in form.physical_format_detail.errors %}
|
||||
<p class="help is-danger">{{ error | escape }}</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
|
@ -4,13 +4,15 @@
|
||||
{% load humanize %}
|
||||
|
||||
<p>
|
||||
{% with format=book.physical_format pages=book.pages %}
|
||||
{% firstof book.physical_format_detail book.physical_format as format %}
|
||||
{% firstof book.physical_format book.physical_format_detail as format_property %}
|
||||
{% with pages=book.pages %}
|
||||
{% if format %}
|
||||
{% comment %}
|
||||
@todo The bookFormat property is limited to a list of values whereas the book edition is free text.
|
||||
@see https://schema.org/bookFormat
|
||||
{% endcomment %}
|
||||
<meta itemprop="bookFormat" content="{{ format }}">
|
||||
<meta itemprop="bookFormat" content="{{ format_property }}">
|
||||
{% endif %}
|
||||
|
||||
{% if pages %}
|
||||
|
Reference in New Issue
Block a user