From dde28f4aff96085cac21b0201d5cc9e70b703a9f Mon Sep 17 00:00:00 2001 From: Colin Powell Date: Sat, 26 Jul 2025 10:18:43 -0400 Subject: [PATCH] [importers] Fix setting timezones before all imports --- PROJECT.org | 6 +++++- vrobbler/apps/books/koreader.py | 4 ---- vrobbler/apps/profiles/models.py | 22 ++++++++++++++++++++++ vrobbler/apps/profiles/utils.py | 10 ++++++---- vrobbler/apps/scrobbles/models.py | 14 ++++++++++++++ 5 files changed, 47 insertions(+), 9 deletions(-) diff --git a/PROJECT.org b/PROJECT.org index 942b93e..8442b6f 100644 --- a/PROJECT.org +++ b/PROJECT.org @@ -79,7 +79,7 @@ fetching and simple saving. :LOGBOOK: CLOCK: [2025-07-09 Wed 09:55]--[2025-07-09 Wed 10:15] => 0:20 :END: -* Backlog [7/28] +* Backlog [1/22] ** TODO [#A] Add classmethod for metadata fetching to tracks :vrobbler:feature:music:personal:project: :PROPERTIES: :ID: bc4b45e5-4c65-13c5-ab7b-1937d3fbf5c2 @@ -443,6 +443,10 @@ it's annoying. ** TODO [#C] Allow users to see tasks on calendar view :vrobbler:personal:project:templates:feature: https://codepen.io/oliviale/pen/QYqybo ** TODO [#C] Come up with a possible flow using WebDAV and super-productivity for tasks :personal:feature:project:vrobbler:tasks: +** DONE Use the timezone history log to fix old Scrobbles that fall into those timezone blocks :vrobbler:chore:scrobbles:project:personal: +:PROPERTIES: +:ID: 9d055ac1-584b-20c8-7ad9-9ce36b329dc7 +:END: * Version 18.4 ** DONE Track timezone changes for profiles :vrobbler:feature:profiles:personal:project: :PROPERTIES: diff --git a/vrobbler/apps/books/koreader.py b/vrobbler/apps/books/koreader.py index 31dcbd1..1d6d7d9 100644 --- a/vrobbler/apps/books/koreader.py +++ b/vrobbler/apps/books/koreader.py @@ -9,7 +9,6 @@ import requests from books.constants import BOOKS_TITLES_TO_IGNORE from django.apps import apps from django.contrib.auth import get_user_model -from profiles.utils import one_off_fix_colins_profile from scrobbles.notifications import NtfyNotification from stream_sqlite import stream_sqlite from webdav.client import get_webdav_client @@ -286,9 +285,6 @@ def build_scrobbles_from_book_map( datetime.fromtimestamp(int(last_page.get("end_ts"))) ) - if user.id == 1 and not user.profile.timezone_change_log: - one_off_fix_colins_profile(user.profile) - # Adjust for Daylight Saving Time if timestamp.dst() == timedelta( 0 diff --git a/vrobbler/apps/profiles/models.py b/vrobbler/apps/profiles/models.py index 18fa5ab..0d97998 100644 --- a/vrobbler/apps/profiles/models.py +++ b/vrobbler/apps/profiles/models.py @@ -115,6 +115,28 @@ class UserProfile(TimeStampedModel): return timestamp.replace(tzinfo=timezone) + def adjust_timezone_of_scrobbles(self, commit=False): + current_dt = None + scrobbles_to_change_qs_list = [] + for boundry_dt in self.historic_timezone_changes: + if current_dt and boundry_dt: + logger.info( + f"Checking for scrobbles between {current_dt} and {boundry_dt} to update to {current_dt.tzinfo.name}" + ) + scrobbles = self.user.scrobble_set.filter( + timestamp__gte=current_dt, + timestamp__lt=boundry_dt, + ).exclude(timezone=current_dt.tzinfo.name) + scrobbles_to_change_qs_list.append(scrobbles) + logger.info( + f"Updating {scrobbles.count()} scrobble timezones to {current_dt.tzinfo.name}" + ) + if commit: + scrobbles.update(timezone=current_dt.tzinfo.name) + + current_dt = boundry_dt + return scrobbles_to_change_qs_list + @cached_property def task_context_tags(self) -> list[str]: tag_list = [ diff --git a/vrobbler/apps/profiles/utils.py b/vrobbler/apps/profiles/utils.py index b933a6a..afe8256 100644 --- a/vrobbler/apps/profiles/utils.py +++ b/vrobbler/apps/profiles/utils.py @@ -59,15 +59,15 @@ def start_of_year(dt, profile) -> datetime: return start_of_day(dt, profile).replace(month=1, day=1) -def one_off_fix_colins_profile(profile): +def fix_profile_historic_timezones(profile): home_tz = "America/New_York" - europe = "2022-10-15 06:00:00" + europe = "2023-10-15 06:00:00" europe_end = "2023-12-16 12:00:00" europe_tz = "Europe/Paris" - washington = "2023-04-28 06:00:00" - washington_end = "2023-05-04 12:00:00" + washington = "2024-04-28 06:00:00" + washington_end = "2024-05-04 12:00:00" washington_tz = "America/Los_Angeles" camp = "2024-08-04 17:00:00" @@ -78,6 +78,8 @@ def one_off_fix_colins_profile(profile): summer_end = "2025-07-11 23:30:00" summer_tz = "America/Los_Angeles" + profile.timezone_change_log = None + profile.timezone_change_log = "" profile.timezone_change_log += f"{europe_tz} - {pendulum.parse(europe)}\n" profile.timezone_change_log += ( diff --git a/vrobbler/apps/scrobbles/models.py b/vrobbler/apps/scrobbles/models.py index ee5119f..d2b8cc3 100644 --- a/vrobbler/apps/scrobbles/models.py +++ b/vrobbler/apps/scrobbles/models.py @@ -33,6 +33,7 @@ from profiles.utils import ( end_of_day, end_of_month, end_of_week, + fix_profile_historic_timezones, start_of_day, start_of_month, start_of_week, @@ -205,6 +206,9 @@ class KoReaderImport(BaseFileImportMixin): def process(self, force=False): + if self.user.id == 1: + fix_profile_historic_timezones(self.user.profile) + if self.processed_finished and not force: logger.info( f"{self} already processed on {self.processed_finished}" @@ -250,6 +254,9 @@ class AudioScrobblerTSVImport(BaseFileImportMixin): def process(self, force=False): from scrobbles.importers.tsv import import_audioscrobbler_tsv_file + if self.user.id == 1: + fix_profile_historic_timezones(self.user.profile) + if self.processed_finished and not force: logger.info( f"{self} already processed on {self.processed_finished}" @@ -280,6 +287,10 @@ class LastFmImport(BaseFileImportMixin): def process(self, import_all=False): """Import scrobbles found on LastFM""" + + if self.user.id == 1: + fix_profile_historic_timezones(self.user.profile) + if self.processed_finished: logger.info( f"{self} already processed on {self.processed_finished}" @@ -327,6 +338,9 @@ class RetroarchImport(BaseFileImportMixin): def process(self, import_all=False, force=False): """Import scrobbles found on Retroarch""" + if self.user.id == 1: + fix_profile_historic_timezones(self.user.profile) + if self.processed_finished and not force: logger.info( f"{self} already processed on {self.processed_finished}"