[books] Fix resume reading link and page calc
All checks were successful
build & deploy / test (push) Successful in 1m44s
build & deploy / build-and-deploy (push) Successful in 33s

This commit is contained in:
2026-05-19 21:03:42 -04:00
parent af8b1d4f8a
commit 217e2443e2
4 changed files with 63 additions and 34 deletions

View File

@ -208,6 +208,10 @@ class Book(LongPlayScrobblableMixin):
def get_absolute_url(self): def get_absolute_url(self):
return reverse("books:book_detail", kwargs={"slug": self.uuid}) return reverse("books:book_detail", kwargs={"slug": self.uuid})
@property
def resume_start_url(self):
return reverse("scrobbles:start", kwargs={"uuid": self.uuid}) + "?resume=1"
@classmethod @classmethod
def get_from_comicvine( def get_from_comicvine(
cls, title: str, overwrite: bool = False, force_new: bool = False cls, title: str, overwrite: bool = False, force_new: bool = False

View File

@ -593,6 +593,17 @@ class Scrobble(TimeStampedModel):
self.stop_timestamp - self.timestamp self.stop_timestamp - self.timestamp
).seconds ).seconds
if (
self.log
and isinstance(self.log, dict)
and self.log.get("page_start") is not None
and self.log.get("page_end") is not None
and "pages_read" not in self.log
):
self.log["pages_read"] = (
self.log["page_end"] - self.log["page_start"] + 1
)
return super(Scrobble, self).save(*args, **kwargs) return super(Scrobble, self).save(*args, **kwargs)
def get_absolute_url(self): def get_absolute_url(self):
@ -1452,38 +1463,38 @@ class Scrobble(TimeStampedModel):
return False return False
def calculate_reading_stats(self, commit=True): def calculate_reading_stats(self, commit=True):
# --- Sort safely by numeric page_number ---
def safe_page_number(entry):
try:
return int(getattr("page_number", entry), 0)
except (ValueError, TypeError):
return float("inf") # push invalid entries to the end
page_data = self.log.get("page_data") page_data = self.log.get("page_data")
if not page_data: if page_data:
logger.warning("No page data found to calculate") # --- Sort safely by numeric page_number ---
return def safe_page_number(entry):
try:
return int(getattr("page_number", entry), 0)
except (ValueError, TypeError):
return float("inf")
if isinstance(page_data, dict): if isinstance(page_data, dict):
logger.warning("Page data is dict, migrate koreader data") logger.warning("Page data is dict, migrate koreader data")
return return
page_data.sort(key=safe_page_number) page_data.sort(key=safe_page_number)
# --- Extract valid numeric page numbers --- valid_pages = []
valid_pages = [] for page in page_data:
for page in page_data: try:
try: valid_pages.append(int(page["page_number"]))
valid_pages.append(int(page["page_number"])) except (ValueError, TypeError):
except (ValueError, TypeError): continue
continue
# --- Compute stats --- if valid_pages:
if valid_pages: self.log["page_start"] = min(valid_pages)
self.log["page_start"] = min(valid_pages) self.log["page_end"] = max(valid_pages)
self.log["page_end"] = max(valid_pages) self.log["pages_read"] = len(set(valid_pages))
self.log["pages_read"] = len(set(valid_pages)) else:
page_start = self.log.get("page_start")
page_end = self.log.get("page_end")
if page_start is not None and page_end is not None:
self.log["pages_read"] = page_end - page_start + 1
if commit: if commit and "pages_read" in self.log:
self.save(update_fields=["log"]) self.save(update_fields=["log"])

View File

@ -768,7 +768,25 @@ def scrobble_start(request, uuid):
scrobble = None scrobble = None
user_id = request.user.id user_id = request.user.id
if media_obj: if media_obj:
media_obj.scrobble_for_user(user_id) log_data = None
if (
request.GET.get("resume")
and media_obj.__class__.__name__ == Scrobble.MediaType.BOOK
):
last_scrobble = (
Scrobble.objects.filter(
book=media_obj,
user_id=user_id,
)
.filter(Q(long_play_complete=False) | Q(long_play_complete__isnull=True))
.filter(log__page_end__isnull=False)
.order_by("-timestamp")
.first()
)
if last_scrobble and last_scrobble.logdata:
next_page = last_scrobble.logdata.page_end + 1
log_data = {"page_start": next_page}
media_obj.scrobble_for_user(user_id, log=log_data)
if scrobble: if scrobble:
messages.add_message( messages.add_message(

View File

@ -35,11 +35,7 @@
<p>{{scrobbles.count}} scrobbles</p> <p>{{scrobbles.count}} scrobbles</p>
{% for s in scrobbles %} <p><a href="{{object.resume_start_url}}">Resume reading</a></p>
{% if forloop.first %}
<p><a href="{{s.logdata.resume_url}}">Resume reading</a></p>
{% endif %}
{% endfor %}
</div> </div>
{% if charts %} {% if charts %}
<div class="row"> <div class="row">