[format] Blacken everything
All checks were successful
build & deploy / test (push) Successful in 1m53s
build & deploy / deploy (push) Successful in 1m12s

This commit is contained in:
2026-03-11 23:54:24 -04:00
parent 1e11679419
commit 5934dcdf8e
49 changed files with 480 additions and 201 deletions

View File

@ -58,7 +58,9 @@ logger = logging.getLogger(__name__)
User = get_user_model()
BNULL = {"blank": True, "null": True}
POINTS_FOR_MOVEMENT_HISTORY = int(getattr(settings, "POINTS_FOR_MOVEMENT_HISTORY", 3))
POINTS_FOR_MOVEMENT_HISTORY = int(
getattr(settings, "POINTS_FOR_MOVEMENT_HISTORY", 3)
)
class BaseFileImportMixin(TimeStampedModel):
@ -101,7 +103,9 @@ class BaseFileImportMixin(TimeStampedModel):
scrobble_id = line.split("\t")[0]
scrobble = Scrobble.objects.filter(id=scrobble_id).first()
if not scrobble:
logger.warning(f"Could not find scrobble {scrobble_id} to undo")
logger.warning(
f"Could not find scrobble {scrobble_id} to undo"
)
continue
logger.info(f"Removing scrobble {scrobble_id}")
if not dryrun:
@ -144,7 +148,9 @@ class BaseFileImportMixin(TimeStampedModel):
return
for count, scrobble in enumerate(scrobbles):
scrobble_str = f"{scrobble.id}\t{scrobble.timestamp}\t{scrobble.media_obj}"
scrobble_str = (
f"{scrobble.id}\t{scrobble.timestamp}\t{scrobble.media_obj}"
)
log_line = f"{scrobble_str}"
if count > 0:
log_line = "\n" + log_line
@ -166,7 +172,9 @@ class KoReaderImport(BaseFileImportMixin):
return "KOReader"
def get_absolute_url(self):
return reverse("scrobbles:koreader-import-detail", kwargs={"slug": self.uuid})
return reverse(
"scrobbles:koreader-import-detail", kwargs={"slug": self.uuid}
)
def get_path(instance, filename):
extension = filename.split(".")[-1]
@ -202,11 +210,15 @@ class KoReaderImport(BaseFileImportMixin):
fix_profile_historic_timezones(self.user.profile)
if self.processed_finished and not force:
logger.info(f"{self} already processed on {self.processed_finished}")
logger.info(
f"{self} already processed on {self.processed_finished}"
)
return
self.mark_started()
scrobbles = process_koreader_sqlite_file(self.upload_file_path, self.user.id)
scrobbles = process_koreader_sqlite_file(
self.upload_file_path, self.user.id
)
self.record_log(scrobbles)
self.mark_finished()
@ -220,7 +232,9 @@ class AudioScrobblerTSVImport(BaseFileImportMixin):
return "AudiosScrobbler"
def get_absolute_url(self):
return reverse("scrobbles:tsv-import-detail", kwargs={"slug": self.uuid})
return reverse(
"scrobbles:tsv-import-detail", kwargs={"slug": self.uuid}
)
def get_path(instance, filename):
extension = filename.split(".")[-1]
@ -244,12 +258,16 @@ class AudioScrobblerTSVImport(BaseFileImportMixin):
fix_profile_historic_timezones(self.user.profile)
if self.processed_finished and not force:
logger.info(f"{self} already processed on {self.processed_finished}")
logger.info(
f"{self} already processed on {self.processed_finished}"
)
return
self.mark_started()
scrobbles = import_audioscrobbler_tsv_file(self.upload_file_path, self.user.id)
scrobbles = import_audioscrobbler_tsv_file(
self.upload_file_path, self.user.id
)
self.record_log(scrobbles)
self.mark_finished()
@ -263,7 +281,9 @@ class LastFmImport(BaseFileImportMixin):
return "LastFM"
def get_absolute_url(self):
return reverse("scrobbles:lastfm-import-detail", kwargs={"slug": self.uuid})
return reverse(
"scrobbles:lastfm-import-detail", kwargs={"slug": self.uuid}
)
def process(self, import_all=False):
"""Import scrobbles found on LastFM"""
@ -272,7 +292,9 @@ class LastFmImport(BaseFileImportMixin):
fix_profile_historic_timezones(self.user.profile)
if self.processed_finished:
logger.info(f"{self} already processed on {self.processed_finished}")
logger.info(
f"{self} already processed on {self.processed_finished}"
)
return
last_import = None
@ -310,7 +332,9 @@ class RetroarchImport(BaseFileImportMixin):
return "Retroarch"
def get_absolute_url(self):
return reverse("scrobbles:retroarch-import-detail", kwargs={"slug": self.uuid})
return reverse(
"scrobbles:retroarch-import-detail", kwargs={"slug": self.uuid}
)
def process(self, import_all=False, force=False):
"""Import scrobbles found on Retroarch"""
@ -318,7 +342,9 @@ class RetroarchImport(BaseFileImportMixin):
fix_profile_historic_timezones(self.user.profile)
if self.processed_finished and not force:
logger.info(f"{self} already processed on {self.processed_finished}")
logger.info(
f"{self} already processed on {self.processed_finished}"
)
return
if force:
@ -509,25 +535,39 @@ class Scrobble(TimeStampedModel):
podcast_episode = models.ForeignKey(
PodcastEpisode, on_delete=models.DO_NOTHING, **BNULL
)
sport_event = models.ForeignKey(SportEvent, on_delete=models.DO_NOTHING, **BNULL)
sport_event = models.ForeignKey(
SportEvent, on_delete=models.DO_NOTHING, **BNULL
)
book = models.ForeignKey(Book, on_delete=models.DO_NOTHING, **BNULL)
paper = models.ForeignKey(Paper, on_delete=models.DO_NOTHING, **BNULL)
video_game = models.ForeignKey(VideoGame, on_delete=models.DO_NOTHING, **BNULL)
board_game = models.ForeignKey(BoardGame, on_delete=models.DO_NOTHING, **BNULL)
geo_location = models.ForeignKey(GeoLocation, on_delete=models.DO_NOTHING, **BNULL)
video_game = models.ForeignKey(
VideoGame, on_delete=models.DO_NOTHING, **BNULL
)
board_game = models.ForeignKey(
BoardGame, on_delete=models.DO_NOTHING, **BNULL
)
geo_location = models.ForeignKey(
GeoLocation, on_delete=models.DO_NOTHING, **BNULL
)
beer = models.ForeignKey(Beer, on_delete=models.DO_NOTHING, **BNULL)
puzzle = models.ForeignKey(Puzzle, on_delete=models.DO_NOTHING, **BNULL)
food = models.ForeignKey(Food, on_delete=models.DO_NOTHING, **BNULL)
trail = models.ForeignKey(Trail, on_delete=models.DO_NOTHING, **BNULL)
task = models.ForeignKey(Task, on_delete=models.DO_NOTHING, **BNULL)
web_page = models.ForeignKey(WebPage, on_delete=models.DO_NOTHING, **BNULL)
life_event = models.ForeignKey(LifeEvent, on_delete=models.DO_NOTHING, **BNULL)
life_event = models.ForeignKey(
LifeEvent, on_delete=models.DO_NOTHING, **BNULL
)
mood = models.ForeignKey(Mood, on_delete=models.DO_NOTHING, **BNULL)
brick_set = models.ForeignKey(BrickSet, on_delete=models.DO_NOTHING, **BNULL)
brick_set = models.ForeignKey(
BrickSet, on_delete=models.DO_NOTHING, **BNULL
)
media_type = models.CharField(
max_length=14, choices=MediaType.choices, default=MediaType.VIDEO
)
user = models.ForeignKey(User, blank=True, null=True, on_delete=models.DO_NOTHING)
user = models.ForeignKey(
User, blank=True, null=True, on_delete=models.DO_NOTHING
)
# Time keeping
timestamp = models.DateTimeField(**BNULL)
@ -555,7 +595,9 @@ class Scrobble(TimeStampedModel):
upload_to="scrobbles/videogame_save_data/", **BNULL
)
gpx_file = models.FileField(upload_to="scrobbles/gpx_file/", **BNULL)
screenshot = models.ImageField(upload_to="scrobbles/videogame_screenshot/", **BNULL)
screenshot = models.ImageField(
upload_to="scrobbles/videogame_screenshot/", **BNULL
)
screenshot_small = ImageSpecField(
source="screenshot",
processors=[ResizeToFit(100, 100)],
@ -577,7 +619,12 @@ class Scrobble(TimeStampedModel):
models.Index(fields=["media_type"]),
models.Index(fields=["source_id"]),
models.Index(
fields=["user", "in_progress", "played_to_completion", "is_paused"]
fields=[
"user",
"in_progress",
"played_to_completion",
"is_paused",
]
),
]
@ -646,7 +693,9 @@ class Scrobble(TimeStampedModel):
from scrobbles.models import Scrobble
if self.logdata and self.logdata.serial_scrobble_id:
return Scrobble.objects.filter(id=self.logdata.serial_scrobble_id).first()
return Scrobble.objects.filter(
id=self.logdata.serial_scrobble_id
).first()
@property
def finish_url(self) -> str:
@ -669,7 +718,8 @@ class Scrobble(TimeStampedModel):
self.media_type = self.MediaType(self.media_obj.__class__.__name__)
if (self.timestamp and self.stop_timestamp) and (
not self.playback_position_seconds or self.playback_position_seconds <= 0
not self.playback_position_seconds
or self.playback_position_seconds <= 0
):
self.playback_position_seconds = (
self.stop_timestamp - self.timestamp
@ -684,9 +734,9 @@ class Scrobble(TimeStampedModel):
return reverse("scrobbles:detail", kwargs={"uuid": self.uuid})
def push_to_archivebox(self):
pushable_media = hasattr(self.media_obj, "push_to_archivebox") and callable(
self.media_obj.push_to_archivebox
)
pushable_media = hasattr(
self.media_obj, "push_to_archivebox"
) and callable(self.media_obj.push_to_archivebox)
if pushable_media and self.user.profile.archivebox_url:
try:
@ -750,7 +800,10 @@ class Scrobble(TimeStampedModel):
logger.info(f"Redirecting to {self.media_obj.url}")
redirect_url = self.media_obj.url
if self.media_type == self.MediaType.VIDEO and self.media_obj.youtube_id:
if (
self.media_type == self.MediaType.VIDEO
and self.media_obj.youtube_id
):
redirect_url = self.media_obj.youtube_link
return redirect_url
@ -766,7 +819,9 @@ class Scrobble(TimeStampedModel):
@property
def local_stop_timestamp(self):
if self.stop_timestamp:
return timezone.localtime(self.stop_timestamp, timezone=self.tzinfo)
return timezone.localtime(
self.stop_timestamp, timezone=self.tzinfo
)
@property
def scrobble_media_key(self) -> str:
@ -894,7 +949,9 @@ class Scrobble(TimeStampedModel):
long_play_secs = 0
if self.previous and not self.previous.long_play_complete:
long_play_secs = self.previous.long_play_seconds or 0
percent = int(((playback_seconds + long_play_secs) / run_time_secs) * 100)
percent = int(
((playback_seconds + long_play_secs) / run_time_secs) * 100
)
return percent
@ -939,7 +996,9 @@ class Scrobble(TimeStampedModel):
expected_end = self.timestamp + datetime.timedelta(
seconds=self.media_obj.run_time_seconds
)
expected_end_padded = expected_end + datetime.timedelta(seconds=padding_seconds)
expected_end_padded = expected_end + datetime.timedelta(
seconds=padding_seconds
)
# Take our start time, add our media length and an extra 30 min (1800s) is it still in the future? keep going
is_in_progress = expected_end_padded > pendulum.now()
logger.info(
@ -1002,9 +1061,11 @@ class Scrobble(TimeStampedModel):
@classmethod
def by_date(cls, media_type: str = "Track"):
cls.objects.filter(media_type=media_type).values("timestamp__date").annotate(
count=models.Count("id")
).values("timestamp__date", "count").order_by(
cls.objects.filter(media_type=media_type).values(
"timestamp__date"
).annotate(count=models.Count("id")).values(
"timestamp__date", "count"
).order_by(
"-count",
)
@ -1116,7 +1177,9 @@ class Scrobble(TimeStampedModel):
"source_id": source_id,
},
)
scrobble_data["playback_status"] = scrobble_data.pop("status", None)
scrobble_data["playback_status"] = scrobble_data.pop(
"status", None
)
return existing_by_source_id.update(scrobble_data)
# Find our last scrobble of this media item (track, video, etc)
@ -1136,7 +1199,9 @@ class Scrobble(TimeStampedModel):
logger.warning(
f"[create_or_update] geoloc requires create_or_update_location"
)
scrobble = cls.create_or_update_location(media, scrobble_data, user_id)
scrobble = cls.create_or_update_location(
media, scrobble_data, user_id
)
return scrobble
if not skip_in_progress_check or read_log_page:
@ -1149,7 +1214,9 @@ class Scrobble(TimeStampedModel):
"scrobble_data": scrobble_data,
},
)
scrobble_data["playback_status"] = scrobble_data.pop("status", None)
scrobble_data["playback_status"] = scrobble_data.pop(
"status", None
)
# If it's marked as stopped, send it through our update mechanism, which will complete it
if scrobble and (
scrobble.can_be_updated
@ -1161,8 +1228,12 @@ class Scrobble(TimeStampedModel):
if page_list:
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["end_ts"] = int(
timezone.now().timestamp()
)
page["duration"] = page["end_ts"] - page.get(
"start_ts"
)
page_list.append(
BookPageLogData(
@ -1198,9 +1269,9 @@ class Scrobble(TimeStampedModel):
"source": source,
},
)
if mtype == cls.MediaType.FOOD and not scrobble_data.get("log", {}).get(
"calories", None
):
if mtype == cls.MediaType.FOOD and not scrobble_data.get(
"log", {}
).get("calories", None):
if media.calories:
scrobble_data["log"] = FoodLogData(calories=media.calories)
@ -1287,7 +1358,9 @@ class Scrobble(TimeStampedModel):
if existing_locations := location.in_proximity(named=True):
existing_location = existing_locations.first()
ts = int(pendulum.now().timestamp())
scrobble.log[ts] = f"Location {location.id} too close to this scrobble"
scrobble.log[
ts
] = f"Location {location.id} too close to this scrobble"
scrobble.save(update_fields=["log"])
logger.info(
f"[scrobbling] finished - found existing named location",
@ -1466,7 +1539,9 @@ class Scrobble(TimeStampedModel):
"""Returns true if our media is beyond our completion percent, unless
our type is geolocation in which case we always return false
"""
beyond_completion = self.percent_played >= self.media_obj.COMPLETION_PERCENT
beyond_completion = (
self.percent_played >= self.media_obj.COMPLETION_PERCENT
)
if self.media_type == "GeoLocation":
logger.info(