Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion openlibrary/i18n/messages.pot
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@ msgstr ""
msgid "Failed to fetch carousel."
msgstr ""

#: RawQueryCarousel.html
#: RawQueryCarousel.html home/index.html
msgid "Retry?"
msgstr ""

Expand Down Expand Up @@ -1271,6 +1271,10 @@ msgstr ""
msgid "This work does not appear on any lists."
msgstr ""

#: openlibrary/plugins/openlibrary/partials.py
msgid "Continue Reading"
msgstr ""

#: openlibrary/plugins/openlibrary/pd.py
msgid "I don't have one yet"
msgstr ""
Expand Down Expand Up @@ -5606,6 +5610,14 @@ msgstr[1] ""
msgid "Welcome to Open Library"
msgstr ""

#: home/index.html
msgid "Loading your books..."
msgstr ""

#: home/index.html
msgid "Failed to load."
msgstr ""

#: home/index.html
msgid "Recently Returned"
msgstr ""
Expand Down
76 changes: 75 additions & 1 deletion openlibrary/plugins/openlibrary/partials.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from infogami.utils import delegate
from infogami.utils.view import render_template
from openlibrary.core.fulltext import fulltext_search
from openlibrary.core.lending import compose_ia_url, get_available
from openlibrary.core.lending import compose_ia_url, get_available, get_loans_of_user
from openlibrary.i18n import gettext as _
from openlibrary.plugins.openlibrary.lists import get_user_lists
from openlibrary.plugins.upstream.yearly_reading_goals import get_reading_goals
Expand Down Expand Up @@ -365,6 +365,79 @@ def generate(self) -> dict:
return {"partials": str(macro)}


class ContinueReadingPartial(PartialDataHandler):
"""Handler for the Continue Reading carousel on the homepage."""

def __init__(self):
self.i = web.input(limit=20)

def generate(self) -> dict:
from openlibrary import accounts

# Get the currently logged-in user
user = accounts.get_current_user()
if not user:
return {"partials": ""}

user_key = user.key

# Fetch active loans
loans = get_loans_of_user(user_key)

if not loans:
return {"partials": ""}

# Convert loans to book format for carousel
books = []
for loan in loans:
book_key = loan.get('book')
if book_key:
book = web.ctx.site.get(book_key)
if book:
books.append(self._format_book(book, loan))

if not books:
return {"partials": ""}

# Render the carousel using existing template
carousel_html = render_template(
"books/custom_carousel",
books=books,
title=_("Continue Reading"),
url="/account/loans",
key="continue_reading",
load_more=None,
compact_mode=False,
)

return {"partials": str(carousel_html)}

def _format_book(self, book, loan=None):
"""Convert a book document to the format expected by carousel."""
authors = []
for a in book.get_authors():
if a and hasattr(a, 'name'):
# Use web.storage so template can access author.name
authors.append(
web.storage(
{'name': a.name or 'Unknown', 'key': getattr(a, 'key', '')}
)
)

cover_id = book.get_cover_id() if hasattr(book, 'get_cover_id') else None

return web.storage(
{
'key': book.key,
'title': book.title or 'Untitled',
'authors': authors,
'cover_i': cover_id,
'ia': [loan.get('ocaid')] if loan and loan.get('ocaid') else [],
'availability': {'status': 'borrow_available'},
}
)


class PartialRequestResolver:
# Maps `_component` values to PartialDataHandler subclasses
component_mapping = { # noqa: RUF012
Expand All @@ -376,6 +449,7 @@ class PartialRequestResolver:
"LazyCarousel": LazyCarouselPartial,
"MyBooksDropperLists": MyBooksDropperListsPartial,
"ReadingGoalProgress": ReadingGoalProgressPartial,
"ContinueReading": ContinueReadingPartial,
}

@staticmethod
Expand Down
10 changes: 10 additions & 0 deletions openlibrary/templates/home/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@

$:render_template("home/welcome", test=test)

$# Continue Reading carousel - placeholder always rendered, partial checks if user is logged in
$if not test:
$ continue_reading_config = json_encode({"_component": "ContinueReading"})
<div class="lazy-carousel" data-config="$continue_reading_config">
$:macros.LoadingIndicator(_("Loading your books..."), hidden=False)
<div class="lazy-carousel-retry hidden">
$_("Failed to load.") <a href="#" class="retry-btn">$_("Retry?")</a>
</div>
</div>

$if not test:
$:macros.QueryCarousel(query='trending_score_hourly_sum:[1 TO *] -subject:"content_warning:cover"', title=_('Trending Books'), key="trending", sort='trending', has_fulltext_only=False, user_lang_only=True)
$:macros.QueryCarousel(query="ddc:8* first_publish_year:[* TO 1950] publish_year:[2000 TO *] NOT public_scan_b:false", title=_('Classic Books'), key="public_domain", sort='trending', user_lang_only=True)
Expand Down
Loading