[scrobbling] Fix scrobble overwriting bug and refactor location scrobbling
This commit is contained in:
@ -91,20 +91,19 @@ class GeoLocation(ScrobblableMixin):
|
|||||||
abs(Decimal(old_lat_lon[1]) - Decimal(self.lon)),
|
abs(Decimal(old_lat_lon[1]) - Decimal(self.lon)),
|
||||||
)
|
)
|
||||||
|
|
||||||
def has_moved(self, past_points) -> bool:
|
def has_moved(self, past_points: list["GeoLocation"]) -> bool:
|
||||||
has_moved = False
|
has_moved = False
|
||||||
|
|
||||||
all_moves = []
|
|
||||||
for point in past_points:
|
for point in past_points:
|
||||||
loc_diff = self.loc_diff((point.lat, point.lon))
|
loc_diff = self.loc_diff((point.lat, point.lon))
|
||||||
|
logger.info(f"[locations] {self} is {loc_diff} from {point}")
|
||||||
if (
|
if (
|
||||||
loc_diff[0] > GEOLOC_PROXIMITY
|
loc_diff[0] > GEOLOC_PROXIMITY
|
||||||
or loc_diff[1] > GEOLOC_PROXIMITY
|
or loc_diff[1] > GEOLOC_PROXIMITY
|
||||||
):
|
):
|
||||||
all_moves.append(True)
|
logger.info(
|
||||||
|
f"[locations] {loc_diff} is greater than proximity setting {GEOLOC_PROXIMITY}, moving"
|
||||||
if True in all_moves:
|
)
|
||||||
has_moved = True
|
has_moved = True
|
||||||
|
|
||||||
return has_moved
|
return has_moved
|
||||||
|
|
||||||
|
|||||||
@ -703,20 +703,6 @@ class Scrobble(TimeStampedModel):
|
|||||||
|
|
||||||
return updatable
|
return updatable
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def has_moved(cls, new_location: GeoLocation, user_id: int) -> bool:
|
|
||||||
"""Given a new location and a user, let us know if we've moved from there"""
|
|
||||||
# TODO This can be moved to a utility function, no reason it's a classmethod
|
|
||||||
has_moved = False
|
|
||||||
|
|
||||||
past_scrobbles = Scrobble.objects.filter(
|
|
||||||
media_type="GeoLocation",
|
|
||||||
user_id=user_id,
|
|
||||||
).order_by("-timestamp")[1:POINTS_FOR_MOVEMENT_HISTORY]
|
|
||||||
past_points = [s.media_obj for s in past_scrobbles]
|
|
||||||
|
|
||||||
return new_location.has_moved(past_points)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def media_obj(self):
|
def media_obj(self):
|
||||||
media_obj = None
|
media_obj = None
|
||||||
@ -767,6 +753,7 @@ class Scrobble(TimeStampedModel):
|
|||||||
media_query = models.Q(**{key: media})
|
media_query = models.Q(**{key: media})
|
||||||
scrobble_data[key + "_id"] = media.id
|
scrobble_data[key + "_id"] = media.id
|
||||||
|
|
||||||
|
# Find our last scrobble of this media item (track, video, etc)
|
||||||
scrobble = (
|
scrobble = (
|
||||||
cls.objects.filter(
|
cls.objects.filter(
|
||||||
media_query,
|
media_query,
|
||||||
@ -775,30 +762,28 @@ class Scrobble(TimeStampedModel):
|
|||||||
.order_by("-timestamp")
|
.order_by("-timestamp")
|
||||||
.first()
|
.first()
|
||||||
)
|
)
|
||||||
|
source = scrobble_data["source"]
|
||||||
|
mtype = media.__class__.__name__
|
||||||
|
|
||||||
moved_location = False
|
# Do some funny stuff if it's a geo location
|
||||||
if key == "geo_location":
|
if scrobble.media_type == cls.MediaType.GEO_LOCATION:
|
||||||
# For geo locations, we always only care about our last location
|
moved_location = cls.check_location_for_completion(media, user_id)
|
||||||
scrobble = (
|
if not moved_location:
|
||||||
cls.objects.filter(
|
logger.info(
|
||||||
media_type=cls.MediaType.GEO_LOCATION, user_id=user_id
|
f"[scrobbling] updating {scrobble.id} for {mtype} {media.id} from {source}",
|
||||||
|
{"scrobble_data": scrobble_data, "media": media},
|
||||||
)
|
)
|
||||||
.order_by("-timestamp")
|
scrobble.update(scrobble_data)
|
||||||
.first()
|
|
||||||
)
|
|
||||||
if scrobble and scrobble.media_obj == media:
|
|
||||||
# If scrobble loc and new loc are identical, we haven't moved
|
|
||||||
moved_location = False
|
|
||||||
else:
|
else:
|
||||||
# We have a new location, but have not moved from it,
|
logger.info(
|
||||||
# don't proceed with scrobbling, but update the last GeoLoc
|
f"[scrobbling] finishing {scrobble.id} for {mtype} {media.id} from {source}",
|
||||||
moved_location = cls.has_moved(media, user_id)
|
{"scrobble_data": scrobble_data, "media": media},
|
||||||
if scrobble and moved_location:
|
)
|
||||||
check_scrobble_for_finish(scrobble, force_finish=True)
|
scrobble.stop()
|
||||||
|
# Just blank our scrobble so we create a new one
|
||||||
|
scrobble = None
|
||||||
|
|
||||||
if scrobble and (scrobble.can_be_updated or not moved_location):
|
if scrobble and scrobble.can_be_updated:
|
||||||
source = scrobble_data["source"]
|
|
||||||
mtype = media.__class__.__name__
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"[scrobbling] updating {scrobble.id} for {mtype} {media.id} from {source}",
|
f"[scrobbling] updating {scrobble.id} for {mtype} {media.id} from {source}",
|
||||||
{"scrobble_data": scrobble_data, "media": media},
|
{"scrobble_data": scrobble_data, "media": media},
|
||||||
@ -808,13 +793,36 @@ class Scrobble(TimeStampedModel):
|
|||||||
# Discard status before creating
|
# Discard status before creating
|
||||||
scrobble_data.pop("mopidy_status", None)
|
scrobble_data.pop("mopidy_status", None)
|
||||||
scrobble_data.pop("jellyfin_status", None)
|
scrobble_data.pop("jellyfin_status", None)
|
||||||
source = scrobble_data["source"]
|
|
||||||
mtype = media.__class__.__name__
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"[scrobbling] creating for {mtype} {media.id} from {source}"
|
f"[scrobbling] creating for {mtype} {media.id} from {source}"
|
||||||
)
|
)
|
||||||
return cls.create(scrobble_data)
|
return cls.create(scrobble_data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def location_can_be_updated(
|
||||||
|
cls, location: GeoLocation, user_id: int
|
||||||
|
) -> bool:
|
||||||
|
scrobble = (
|
||||||
|
cls.objects.filter(
|
||||||
|
media_type=cls.MediaType.GEO_LOCATION, user_id=user_id
|
||||||
|
)
|
||||||
|
.order_by("-timestamp")
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
moved_location = True
|
||||||
|
if scrobble and scrobble.media_obj != location:
|
||||||
|
logger.info(
|
||||||
|
f"[scrobbling] New location {location} and last location {scrobble.media_obj} are different"
|
||||||
|
)
|
||||||
|
past_scrobbles = Scrobble.objects.filter(
|
||||||
|
media_type="GeoLocation",
|
||||||
|
user_id=user_id,
|
||||||
|
).order_by("-timestamp")[1:POINTS_FOR_MOVEMENT_HISTORY]
|
||||||
|
past_points = [s.media_obj for s in past_scrobbles]
|
||||||
|
|
||||||
|
moved_location = location.has_moved(past_points)
|
||||||
|
return moved_location
|
||||||
|
|
||||||
def update(self, scrobble_data: dict) -> "Scrobble":
|
def update(self, scrobble_data: dict) -> "Scrobble":
|
||||||
# Status is a field we get from Mopidy, which refuses to poll us
|
# Status is a field we get from Mopidy, which refuses to poll us
|
||||||
scrobble_status = scrobble_data.pop("mopidy_status", None)
|
scrobble_status = scrobble_data.pop("mopidy_status", None)
|
||||||
|
|||||||
Reference in New Issue
Block a user