浏览代码

[books] Calc stats and dont die when title not found

Colin Powell 4 周之前
父节点
当前提交
782f5c15d6
共有 2 个文件被更改,包括 43 次插入2 次删除
  1. 1 1
      vrobbler/apps/books/models.py
  2. 42 1
      vrobbler/apps/scrobbles/models.py

+ 1 - 1
vrobbler/apps/books/models.py

@@ -290,7 +290,7 @@ class Book(LongPlayScrobblableMixin):
         return book
 
     def save_image_from_url(self, url: str, force_update: bool = False):
-        if not self.cover or (force_update and url):
+        if url and (not self.cover or force_update):
             r = requests.get(url)
             if r.status_code == 200:
                 fname = f"{self.title}_{self.uuid}.jpg"

+ 42 - 1
vrobbler/apps/scrobbles/models.py

@@ -1181,6 +1181,7 @@ class Scrobble(TimeStampedModel):
                         for page in page_list:
                             if not page.get("end_ts", None):
                                 page["end_ts"] = int(timezone.now().timestamp())
+                                page["duration"] = page["end_ts"] - page.get("start_ts")
 
                     page_list.append(
                         BookPageLogData(
@@ -1198,7 +1199,7 @@ class Scrobble(TimeStampedModel):
             scrobble_data.pop("playback_status")
 
         if read_log_page:
-            scrobble_data["log"] = BookLogData(page_data=BookPageLogData(page_number=read_log_page, start_ts=int(timezone.now().timestamp())))
+            scrobble_data["log"] = BookLogData(page_data=[BookPageLogData(page_number=read_log_page, start_ts=int(timezone.now().timestamp()))])
 
         logger.info(
             f"[scrobbling] creating new scrobble",
@@ -1392,6 +1393,9 @@ class Scrobble(TimeStampedModel):
         if class_name in LONG_PLAY_MEDIA.values():
             self.finish_long_play()
 
+        if class_name == "Book":
+            self.calculate_reading_stats()
+
         logger.info(
             f"[scrobbling] stopped",
             extra={
@@ -1487,3 +1491,40 @@ class Scrobble(TimeStampedModel):
             beyond_completion = False
 
         return beyond_completion
+
+    def calculate_reading_stats(self, commit=True):
+        # --- Sort safely by numeric page_number ---
+        def safe_page_number(entry):
+            try:
+                return int(entry.get("page_number", 0))
+            except (ValueError, TypeError):
+                return float("inf")  # push invalid entries to the end
+
+        page_data = self.log.get("page_data")
+
+        if not page_data:
+            logger.warning("No page data found to calculate")
+            return
+
+        if isinstance(page_data, dict):
+            logger.warning("Page data is dict, migrate koreader data")
+            return
+
+        page_data.sort(key=safe_page_number)
+
+        # --- Extract valid numeric page numbers ---
+        valid_pages = []
+        for page in page_data:
+            try:
+                valid_pages.append(int(page["page_number"]))
+            except (ValueError, TypeError):
+                continue
+
+        # --- Compute stats ---
+        if valid_pages:
+            self.log["page_start"] = min(valid_pages)
+            self.log["page_end"] = max(valid_pages)
+            self.log["pages_read"] = len(set(valid_pages))
+
+            if commit:
+                self.save(update_fields=["log"])