Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Audiobook play time #2551

Open
wants to merge 26 commits into
base: main
Choose a base branch
from

Conversation

joachimesque
Copy link
Contributor

@joachimesque joachimesque commented Dec 26, 2022

Closes #2536
Closes #2941

This PR adds an audiobook duration field whenever the "Audiobook" choice is selected as a format

  • I opted for a permissive field, allowing both hh:mm and minutes formats.
  • I saw no use for the seconds in the duration. There is no reason IMO to complicate the feature further.
  • The localization/translation of the duration is made through humanize. Considering that django.contrib.humanize doesn't provide the support for durations, I chose to add it to the requirements, to avoid relying on a lot of localization code and translation keys.
  • The JS helps toggle betwen the "pages" field and the "play time" field whenever the Format select changes.

Happy holidays!

Copy link
Contributor

@cincodenada cincodenada left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great overall, and is an excellent addition. I left some comments, most importantly that I think we should avoid storing loosely-formatted dates directly in the database, and interpret those at input time instead. I also had a minor observation around breakage for users without Javascript. The remaining feedback is mostly style preferences and is not crucial.

Thanks for making this happen!

@@ -59,6 +59,7 @@ class Edition(Book):
isbn13: str = ""
oclcNumber: str = ""
pages: int = None
audiobookPlayTime: str = ""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of encoding audiobookPlayTime as an integer (seconds or minutes), or even better a time interval and interpreting it accordingly on the frontend? As a general principle, I find it's best if the data stored in the database is as unambiguous and as close to "ground truth" as possible, with any interpretation being done clientside.

More briefly: I find it leads to less headaches if you are permissive on input, and strict on what you store.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One big question is: how will it federate? My transform (* 60 to the value at clean() time) would multiply an already correct value, coming from another server, and so on. Do you know how I can prevent that? Is it by making an activitypub-aware field with field_to_activity and field_from_activity transforms? That's a part I really don't know in the codebase.

bookwyrm/models/fields.py Outdated Show resolved Hide resolved
bookwyrm/templatetags/book_display_tags.py Outdated Show resolved Hide resolved
bookwyrm/templates/book/publisher_info.html Outdated Show resolved Hide resolved
@joachimesque
Copy link
Contributor Author

Thank you for the review @cincodenada :)

I agree with you about storing badly formatted data in the database, and had first tried with an ArrayField, which didn’t work too well. And somehow I had overlooked the time interval field type, made exactly for this type of data 🤦

As for the JS: you’re right, I forgot about non-JS users! What would you think of a CSS utility that’s like .is-hidden, but works only when there’s JS in the page? Or maybe it exists and I forgot about it? Your solution fits well, too (and saves up on somewhat unreadable Django template code)

bookwyrm/models/book.py Show resolved Hide resolved
bookwyrm/static/js/forms.js Show resolved Hide resolved
bookwyrm/templates/book/format_info.html Show resolved Hide resolved
@mouse-reeve
Copy link
Member

Does this need anything besides an update from main and a merge migration to be ready to go? I don't think either of my comments above need to be blockers

@jaschaurbach
Copy link
Member

@joachimesque Are you still able and willing to work on this? Please let us know - thank you!

@joachimesque
Copy link
Contributor Author

@mouse-reeve @jaschaurbach I updated from main and fixed the negative timedelta problem.

From what I can remember, my question about federation/ActivityPub serialization has not been tested. As I don't know this part of the logic very well, I'll ask for your help :)
#2551 (comment)

{% if format_property %}
<meta itemprop="bookFormat" content="{{ format_property }}">
{% if book.physical_format == "AudiobookFormat" and book.audiobook_play_time %}
<meta itemprop="timeRequired" content="{{ book.audiobook_play_time|iso_duration }}">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I tested this, it looks like this line was passing in a string-ified version of the duration (for the arbitrary numbers I tried, 85 days, 17:36:00), which was throwing an error in the filter. I think that this is because I entered a big enough number that it went over hours and into days

@@ -299,6 +299,10 @@ class Edition(Book):
max_length=255, choices=FormatChoices, null=True, blank=True
)
physical_format_detail = fields.CharField(max_length=255, blank=True, null=True)
audiobook_play_time = models.DurationField(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this is calling a standard Django model field, rather than a custom BookWyrm activitypub model field, it's not going to be serialized in ActivityPub. To fix this, there needs to be a subclass of DurationField in https://github.com/bookwyrm-social/bookwyrm/blob/main/bookwyrm/models/fields.py#L528 -- that code will handle parsing the string version of the play time into a DurationField.

I know this is kind of murky depths of how the activitypub implementation works --is that something you want to do, and if so does that give you enough of an idea of how to proceed? If you'd rather not, I can go ahead and make that change.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joachimesque Have you seen this?

@mouse-reeve
Copy link
Member

I believe the tests are just failing because this needs a merge migration

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Switching input data when physical type is changed Playtime for audio books
4 participants