[books] Fix resume reading link and page calc
This commit is contained in:
@ -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
|
||||||
|
|||||||
@ -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"])
|
||||||
|
|||||||
@ -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(
|
||||||
|
|||||||
@ -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">
|
||||||
|
|||||||
Reference in New Issue
Block a user