Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0a880a2f2f | |||
| 248d3f2d3e | |||
| e243fec679 |
57
PROJECT.org
57
PROJECT.org
@ -544,6 +544,63 @@ log a warning and move on.
|
||||
We should have a global view `/favorites/` that shows the logged in users's
|
||||
favorited media objects.
|
||||
|
||||
* Version 50.2 [2/2]
|
||||
** DONE [#B] Koreader imports only import single-page scrobbles the next day :bug:books:importers:
|
||||
:PROPERTIES:
|
||||
:ID: b50141fd-cda6-4a3a-afd3-cd8499e7523e
|
||||
:END:
|
||||
|
||||
*** Description
|
||||
|
||||
When you read a single page in a book in Koreader and try to import it, the scrobble is only
|
||||
created the day after, not on the day of the reading.
|
||||
|
||||
** DONE [#A] Fix bugs in celery tasks causing imports to fail :bug:celery:tasks:
|
||||
:PROPERTIES:
|
||||
:ID: d1171cb0-6413-44b8-a68a-019a4d2fb285
|
||||
:END:
|
||||
|
||||
*** Description
|
||||
|
||||
Seems like all celery tasks are failing for different reasons except the chart
|
||||
updates.
|
||||
|
||||
*** Errors
|
||||
**** scrobbles.tasks.send_notification_for_in_progress
|
||||
#+begin_src bash
|
||||
KeyError: 'track'
|
||||
|
||||
During handling of the above exception, another exception occurred:
|
||||
|
||||
Traceback (most recent call last):
|
||||
File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 89, in _execute
|
||||
return self.cursor.execute(sql, params)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
psycopg2.errors.UndefinedColumn: column music_track.artist_id does not exist
|
||||
LINE 1: ..."."title", "music_track"."base_run_time_seconds", "music_tra...
|
||||
^
|
||||
HINT: Perhaps you meant to reference the column "music_track.artist_fk_id".
|
||||
#+end_src
|
||||
|
||||
**** scrobbles.tasks.import_from_webdav_all_users
|
||||
#+begin_src bash
|
||||
File "/usr/local/lib/python3.11/site-packages/vrobbler/apps/scrobbles/importers/webdav.py", line 166, in scan_webdav_for_koreader
|
||||
if last_import and last_import.webdav_etag and remote_etag:
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
AttributeError: 'KoReaderImport' object has no attribute 'webdav_etag'
|
||||
#+end_src
|
||||
|
||||
**** scrobbles.tasks.process_bgstats_import
|
||||
#+begin_src bash
|
||||
|
||||
Traceback (most recent call last):
|
||||
File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 89, in _execute
|
||||
return self.cursor.execute(sql, params)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
psycopg2.errors.NotNullViolation: null value in column "visibility" of relation "scrobbles_scrobble" violates not-null constraint
|
||||
DETAIL: Failing row contains (374463, 2026-06-11 13:27:06.528319+00, 2026-06-11 13:27:06.52834+00, 2026-06-11 13:17:34+00, 180, f, f, BG Stats, 1, null, t, {"players": [{"new": false, "win": false, "rank": 0, "role": "",..., null, null, null, 8e73ceec-b731-4623-9637-712bbf9f76ce, null, null, null, null, , null, BoardGame, 324, null, null, America/New_York, null, null, , null, null, , null, null, null, null, null, null, null, null, null, null, null).
|
||||
#+end_src
|
||||
|
||||
* Version 50.1 [1/1]
|
||||
** DONE [#B] Fix bug in charts where only #1 is displayed :charts:templates:
|
||||
:PROPERTIES:
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "vrobbler"
|
||||
version = "50.1"
|
||||
version = "50.2"
|
||||
description = ""
|
||||
authors = ["Colin Powell <colin@unbl.ink>"]
|
||||
|
||||
|
||||
@ -187,18 +187,20 @@ def build_page_data(page_rows: list, book_map: dict, user_tz=None) -> dict:
|
||||
book_ids_not_found.append(koreader_book_id)
|
||||
continue
|
||||
|
||||
if "pages" not in book_map[koreader_book_id].keys():
|
||||
book_map[koreader_book_id]["pages"] = {}
|
||||
book_map[koreader_book_id].setdefault("pages", [])
|
||||
|
||||
page_number = page_row[KoReaderPageStatColumn.PAGE.value]
|
||||
duration = page_row[KoReaderPageStatColumn.DURATION.value]
|
||||
start_ts = page_row[KoReaderPageStatColumn.START_TIME.value]
|
||||
|
||||
book_map[koreader_book_id]["pages"][page_number] = {
|
||||
"duration": duration,
|
||||
"start_ts": start_ts,
|
||||
"end_ts": start_ts + duration,
|
||||
}
|
||||
book_map[koreader_book_id]["pages"].append(
|
||||
{
|
||||
"page_number": page_number,
|
||||
"duration": duration,
|
||||
"start_ts": start_ts,
|
||||
"end_ts": start_ts + duration,
|
||||
}
|
||||
)
|
||||
if book_ids_not_found:
|
||||
logger.info(f"Found pages for books not in file: {set(book_ids_not_found)}")
|
||||
return book_map
|
||||
@ -225,11 +227,12 @@ def build_scrobbles_from_book_map(book_map: dict, user: "User") -> list["Scrobbl
|
||||
pages_processed = 0
|
||||
total_pages_read = len(book_map[koreader_book_id]["pages"])
|
||||
ordered_pages = sorted(
|
||||
book_map[koreader_book_id]["pages"].items(),
|
||||
key=lambda x: x[1]["start_ts"],
|
||||
book_map[koreader_book_id]["pages"],
|
||||
key=lambda x: x["start_ts"],
|
||||
)
|
||||
|
||||
for cur_page_number, stats in ordered_pages:
|
||||
for stats in ordered_pages:
|
||||
page_number = stats["page_number"]
|
||||
pages_processed += 1
|
||||
|
||||
seconds_from_last_page = 0
|
||||
@ -243,12 +246,14 @@ def build_scrobbles_from_book_map(book_map: dict, user: "User") -> list["Scrobbl
|
||||
)
|
||||
|
||||
end_of_reading = pages_processed == total_pages_read
|
||||
big_jump_to_this_page = (cur_page_number - last_page_number) > 10
|
||||
big_jump_to_this_page = (page_number - last_page_number) > 10
|
||||
is_session_gap = seconds_from_last_page > SESSION_GAP_SECONDS
|
||||
if (is_session_gap and not big_jump_to_this_page) or end_of_reading:
|
||||
should_create_scrobble = True
|
||||
|
||||
if should_create_scrobble:
|
||||
if not scrobble_page_data:
|
||||
scrobble_page_data[page_number] = stats
|
||||
scrobble_page_data = dict(
|
||||
sorted(
|
||||
scrobble_page_data.items(),
|
||||
@ -276,13 +281,6 @@ def build_scrobbles_from_book_map(book_map: dict, user: "User") -> list["Scrobbl
|
||||
datetime.fromtimestamp(int(last_page.get("end_ts")))
|
||||
)
|
||||
|
||||
# Adjust for Daylight Saving Time
|
||||
# if timestamp.dst() == timedelta(
|
||||
# 0
|
||||
# ) or stop_timestamp.dst() == timedelta(0):
|
||||
# timestamp = timestamp - timedelta(hours=1)
|
||||
# stop_timestamp = stop_timestamp - timedelta(hours=1)
|
||||
|
||||
scrobble = Scrobble.objects.filter(
|
||||
timestamp=timestamp,
|
||||
book_id=book_id,
|
||||
@ -291,7 +289,7 @@ def build_scrobbles_from_book_map(book_map: dict, user: "User") -> list["Scrobbl
|
||||
|
||||
if not scrobble:
|
||||
logger.info(
|
||||
f"Queueing scrobble for {book_id}, page {cur_page_number}"
|
||||
f"Queueing scrobble for {book_id}, page {page_number}"
|
||||
)
|
||||
log_data = {
|
||||
"koreader_hash": book_dict.get("hash"),
|
||||
@ -324,9 +322,9 @@ def build_scrobbles_from_book_map(book_map: dict, user: "User") -> list["Scrobbl
|
||||
scrobble_page_data = {}
|
||||
|
||||
# We accumulate pages for the scrobble until we should create a new one
|
||||
scrobble_page_data[cur_page_number] = stats
|
||||
scrobble_page_data[page_number] = stats
|
||||
|
||||
last_page_number = cur_page_number
|
||||
last_page_number = page_number
|
||||
prev_page_stats = stats
|
||||
if pages_not_found:
|
||||
logger.info(f"Pages not found for books: {set(pages_not_found)}")
|
||||
|
||||
@ -32,8 +32,6 @@ class KoReaderBookRows:
|
||||
DEFAULT_STR = "N/A"
|
||||
DEFAULT_INT = 0
|
||||
DEFAULT_TIME = 1703800469
|
||||
BOOK_ROWS = []
|
||||
PAGE_STATS_ROWS = []
|
||||
|
||||
def _gen_random_row(self, i):
|
||||
wiggle = random.randrange(15)
|
||||
@ -110,6 +108,8 @@ class KoReaderBookRows:
|
||||
end_session = True
|
||||
|
||||
def __init__(self, book_count=0, **kwargs):
|
||||
self.BOOK_ROWS = []
|
||||
self.PAGE_STATS_ROWS = []
|
||||
self._generate_random_book_rows(book_count)
|
||||
self._generate_custom_book_row(**kwargs)
|
||||
self._generate_random_page_stats_rows()
|
||||
|
||||
@ -145,7 +145,7 @@ CELERY_BEAT_SCHEDULE = {
|
||||
},
|
||||
"import-from-webdav": {
|
||||
"task": "scrobbles.tasks.import_from_webdav_all_users",
|
||||
"schedule": crontab(minute="*/3"),
|
||||
"schedule": crontab(minute="*/2"),
|
||||
},
|
||||
# Deprecated: BG Stats files now picked up from WebDAV var/bgstats/
|
||||
# "import-from-imap": {
|
||||
|
||||
Reference in New Issue
Block a user