Add script for building scrobbles from past pages
This commit is contained in:
@ -1,9 +1,22 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
import logging
|
||||
import pytz
|
||||
from datetime import datetime
|
||||
from books.models import Book
|
||||
from django.core.management.base import BaseCommand
|
||||
from scrobbles.models import Scrobble
|
||||
from vrobbler.apps.scrobbles.utils import timestamp_user_tz_to_utc
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Grace period between page reads for it to be a new scrobble
|
||||
SESSION_GAP_SECONDS = 1800 # a half hour
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
def handle(self, *args, **options):
|
||||
scrobbles_to_create = []
|
||||
|
||||
for book in Book.objects.all():
|
||||
koreader_data = book.koreader_data_by_hash or {}
|
||||
if book.koreader_md5:
|
||||
@ -15,3 +28,117 @@ class Command(BaseCommand):
|
||||
}
|
||||
book.koreader_data_by_hash = koreader_data
|
||||
book.save(update_fields=["koreader_data_by_hash"])
|
||||
|
||||
# Next parse all this book's pages into new scrobbles
|
||||
should_create_scrobble = False
|
||||
scrobble_page_data = {}
|
||||
playback_position_seconds = 0
|
||||
prev_page = None
|
||||
|
||||
pages_processed = 0
|
||||
total_pages = book.pages
|
||||
for page in book.page_set.order_by("number"):
|
||||
user = page.user
|
||||
book_id = page.book.id
|
||||
pages_processed += 1
|
||||
scrobble_page_data[page.number] = {
|
||||
"duration": page.duration_seconds,
|
||||
"start_ts": page.start_time.timestamp(),
|
||||
"end_ts": page.end_time.timestamp(),
|
||||
}
|
||||
seconds_from_last_page = 0
|
||||
if prev_page:
|
||||
seconds_from_last_page = (
|
||||
page.end_time.timestamp()
|
||||
- prev_page.start_ts.timestamp()
|
||||
)
|
||||
playback_position_seconds = (
|
||||
playback_position_seconds + page.duration_seconds
|
||||
)
|
||||
|
||||
end_of_reading = pages_processed == total_pages
|
||||
if (
|
||||
seconds_from_last_page > SESSION_GAP_SECONDS
|
||||
or end_of_reading
|
||||
):
|
||||
should_create_scrobble = True
|
||||
|
||||
if should_create_scrobble:
|
||||
first_page = scrobble_page_data.get(
|
||||
list(scrobble_page_data.keys())[0]
|
||||
)
|
||||
last_page = scrobble_page_data.get(
|
||||
list(scrobble_page_data.keys())[-1]
|
||||
)
|
||||
start_ts = int(first_page.get("start_ts"))
|
||||
end_ts = start_ts + playback_position_seconds
|
||||
|
||||
timestamp = datetime.fromtimestamp(start_ts).replace(
|
||||
tzinfo=user.profile.tzinfo
|
||||
)
|
||||
stop_timestamp = datetime.fromtimestamp(end_ts).replace(
|
||||
tzinfo=user.profile.tzinfo
|
||||
)
|
||||
# Add a shim here temporarily to fix imports while we were in France
|
||||
# if date is between 10/15 and 12/15, cast it to Europe/Central
|
||||
if (
|
||||
datetime(2023, 10, 15).replace(
|
||||
tzinfo=pytz.timezone("Europe/Paris")
|
||||
)
|
||||
<= timestamp
|
||||
<= datetime(2023, 12, 15).replace(
|
||||
tzinfo=pytz.timezone("Europe/Paris")
|
||||
)
|
||||
):
|
||||
timestamp.replace(tzinfo=pytz.timezone("Europe/Paris"))
|
||||
|
||||
scrobble = Scrobble.objects.filter(
|
||||
timestamp=timestamp,
|
||||
book_id=book_id,
|
||||
user_id=user.id,
|
||||
).first()
|
||||
if scrobble:
|
||||
logger.info(
|
||||
f"Found existing scrobble {scrobble}, updating"
|
||||
)
|
||||
scrobble.book_page_data = scrobble_page_data
|
||||
scrobble.playback_position_seconds = (
|
||||
scrobble.calc_reading_duration()
|
||||
)
|
||||
scrobble.save(
|
||||
update_fields=[
|
||||
"book_page_data",
|
||||
"playback_position_seconds",
|
||||
]
|
||||
)
|
||||
if not scrobble:
|
||||
logger.info(
|
||||
f"Queueing scrobble for {book_id}, page {page.number}"
|
||||
)
|
||||
scrobbles_to_create.append(
|
||||
Scrobble(
|
||||
book_id=book_id,
|
||||
user_id=user.id,
|
||||
source="KOReader",
|
||||
media_type=Scrobble.MediaType.BOOK,
|
||||
timestamp=timestamp,
|
||||
stop_timestamp=stop_timestamp,
|
||||
playback_position_seconds=playback_position_seconds,
|
||||
book_koreader_hash=book.koreader_data_by_hash.keys()[
|
||||
0
|
||||
],
|
||||
book_page_data=scrobble_page_data,
|
||||
book_pages_read=page.number,
|
||||
in_progress=False,
|
||||
played_to_completion=True,
|
||||
long_play_complete=False,
|
||||
)
|
||||
)
|
||||
# Then start over
|
||||
should_create_scrobble = False
|
||||
playback_position_seconds = 0
|
||||
scrobble_page_data = {}
|
||||
|
||||
prev_page = page
|
||||
|
||||
created = Scrobble.objects.bulk_create(scrobbles_to_create)
|
||||
|
||||
Reference in New Issue
Block a user