[books] Move book metadata into the log field
This commit is contained in:
@ -293,6 +293,11 @@ def build_scrobbles_from_book_map(
|
|||||||
logger.info(
|
logger.info(
|
||||||
f"Queueing scrobble for {book_id}, page {cur_page_number}"
|
f"Queueing scrobble for {book_id}, page {cur_page_number}"
|
||||||
)
|
)
|
||||||
|
log_data = {
|
||||||
|
"koreader_hash": book_dict.get("hash"),
|
||||||
|
"page_data": scrobble_page_data,
|
||||||
|
"pages_read": cur_page_number,
|
||||||
|
}
|
||||||
scrobbles_to_create.append(
|
scrobbles_to_create.append(
|
||||||
Scrobble(
|
Scrobble(
|
||||||
book_id=book_id,
|
book_id=book_id,
|
||||||
@ -300,11 +305,9 @@ def build_scrobbles_from_book_map(
|
|||||||
source="KOReader",
|
source="KOReader",
|
||||||
media_type=Scrobble.MediaType.BOOK,
|
media_type=Scrobble.MediaType.BOOK,
|
||||||
timestamp=timestamp,
|
timestamp=timestamp,
|
||||||
|
log=log_data,
|
||||||
stop_timestamp=stop_timestamp,
|
stop_timestamp=stop_timestamp,
|
||||||
playback_position_seconds=playback_position_seconds,
|
playback_position_seconds=playback_position_seconds,
|
||||||
book_koreader_hash=book_dict.get("hash"),
|
|
||||||
book_page_data=scrobble_page_data,
|
|
||||||
book_pages_read=cur_page_number,
|
|
||||||
in_progress=False,
|
in_progress=False,
|
||||||
played_to_completion=True,
|
played_to_completion=True,
|
||||||
long_play_complete=False,
|
long_play_complete=False,
|
||||||
@ -338,9 +341,9 @@ def fix_long_play_stats_for_scrobbles(scrobbles: list) -> None:
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
scrobble.long_play_seconds = scrobble.playback_position_seconds
|
scrobble.long_play_seconds = scrobble.playback_position_seconds
|
||||||
scrobble.book_pages_read = scrobble.calc_pages_read()
|
scrobble.log["book_pages_read"] = scrobble.calc_pages_read()
|
||||||
|
|
||||||
scrobble.save(update_fields=["book_pages_read", "long_play_seconds"])
|
scrobble.save(update_fields=["log", "long_play_seconds"])
|
||||||
|
|
||||||
|
|
||||||
def process_koreader_sqlite_file(file_path, user_id) -> list:
|
def process_koreader_sqlite_file(file_path, user_id) -> list:
|
||||||
|
|||||||
@ -0,0 +1,29 @@
|
|||||||
|
import logging
|
||||||
|
import pytz
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from books.models import Book
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from scrobbles.models import Scrobble
|
||||||
|
from vrobbler.apps.books.koreader import fix_long_play_stats_for_scrobbles
|
||||||
|
from vrobbler.apps.scrobbles.utils import timestamp_user_tz_to_utc
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
total_books = Book.objects.all().count()
|
||||||
|
processed_books = 0
|
||||||
|
|
||||||
|
for book in Book.objects.all():
|
||||||
|
for scrobble in book.scrobble_set.all():
|
||||||
|
log_data = {
|
||||||
|
"koreader_hash": scrobble.book_koreader_hash,
|
||||||
|
"page_data": scrobble.book_page_data,
|
||||||
|
"pages_read": scrobble.book_pages_read,
|
||||||
|
}
|
||||||
|
scrobble.log = log_data
|
||||||
|
scrobble.save(update_fields=["log"])
|
||||||
|
processed_books += 1
|
||||||
|
logger.info(f"Processed book {processed_books} of {total_books}")
|
||||||
@ -30,9 +30,6 @@ class ScrobbleInline(admin.TabularInline):
|
|||||||
exclude = (
|
exclude = (
|
||||||
"scrobble_log",
|
"scrobble_log",
|
||||||
"timezone",
|
"timezone",
|
||||||
"book_koreader_hash",
|
|
||||||
"book_page_data",
|
|
||||||
"book_pages_read",
|
|
||||||
"videogame_save_data",
|
"videogame_save_data",
|
||||||
"videogame_screenshot",
|
"videogame_screenshot",
|
||||||
)
|
)
|
||||||
|
|||||||
@ -85,7 +85,7 @@ class LifeEventMetadata(JSONMetadata):
|
|||||||
participant_names: Optional[list[str]] = None
|
participant_names: Optional[list[str]] = None
|
||||||
location: Optional[str] = None
|
location: Optional[str] = None
|
||||||
geo_location_id: Optional[int] = None
|
geo_location_id: Optional[int] = None
|
||||||
details: Optional[str]
|
details: Optional[str] = None
|
||||||
|
|
||||||
def participants(self) -> list[str]:
|
def participants(self) -> list[str]:
|
||||||
participants = []
|
participants = []
|
||||||
|
|||||||
@ -0,0 +1,24 @@
|
|||||||
|
# Generated by Django 4.2.13 on 2024-08-06 15:27
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import scrobbles.dataclasses
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("scrobbles", "0056_scrobble_life_event_alter_scrobble_media_type"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="scrobble",
|
||||||
|
name="log",
|
||||||
|
field=models.JSONField(
|
||||||
|
blank=True,
|
||||||
|
decoder=scrobbles.dataclasses.ScrobbleMetadataDecoder,
|
||||||
|
encoder=scrobbles.dataclasses.ScrobbleMetadataEncoder,
|
||||||
|
null=True,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -40,6 +40,7 @@ from videogames.models import VideoGame
|
|||||||
from videos.models import Series, Video
|
from videos.models import Series, Video
|
||||||
from scrobbles.dataclasses import (
|
from scrobbles.dataclasses import (
|
||||||
BoardGameMetadata,
|
BoardGameMetadata,
|
||||||
|
BookMetadata,
|
||||||
JSONMetadata,
|
JSONMetadata,
|
||||||
LifeEventMetadata,
|
LifeEventMetadata,
|
||||||
ScrobbleMetadataDecoder,
|
ScrobbleMetadataDecoder,
|
||||||
@ -541,7 +542,7 @@ class Scrobble(TimeStampedModel):
|
|||||||
)
|
)
|
||||||
timezone = models.CharField(max_length=50, **BNULL)
|
timezone = models.CharField(max_length=50, **BNULL)
|
||||||
|
|
||||||
# Fields for keeping track of book data
|
# Fields for keeping track of book data DEPRECATED, remove after migration
|
||||||
book_koreader_hash = models.CharField(max_length=50, **BNULL)
|
book_koreader_hash = models.CharField(max_length=50, **BNULL)
|
||||||
book_pages_read = models.IntegerField(**BNULL)
|
book_pages_read = models.IntegerField(**BNULL)
|
||||||
book_page_data = models.JSONField(**BNULL)
|
book_page_data = models.JSONField(**BNULL)
|
||||||
@ -615,6 +616,8 @@ class Scrobble(TimeStampedModel):
|
|||||||
metadata_cls = BoardGameMetadata
|
metadata_cls = BoardGameMetadata
|
||||||
if self.media_type == self.MediaType.VIDEO:
|
if self.media_type == self.MediaType.VIDEO:
|
||||||
metadata_cls = VideoMetadata
|
metadata_cls = VideoMetadata
|
||||||
|
if self.media_type == self.MediaType.BOOK:
|
||||||
|
metadata_cls = BookMetadata
|
||||||
|
|
||||||
if not metadata_cls:
|
if not metadata_cls:
|
||||||
logger.warn(
|
logger.warn(
|
||||||
@ -725,9 +728,9 @@ class Scrobble(TimeStampedModel):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def session_pages_read(self) -> Optional[int]:
|
def session_pages_read(self) -> Optional[int]:
|
||||||
if not self.book_pages_read:
|
if not self.log.get("pages_read"):
|
||||||
return 0
|
return 0
|
||||||
return self.book_pages_read
|
return self.log.get("pages_read")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_long_play(self) -> bool:
|
def is_long_play(self) -> bool:
|
||||||
|
|||||||
Reference in New Issue
Block a user