This commit has no recorded session.
diff
commit ec219ef3eaf8c7a06432879fd396195ea2fcae2bAuthor: Colin Powell <colin@unbl.ink>Date: Fri Jun 5 14:41:37 2026 -0400 [tracks] Fix adding tracks without mopidy_uri@@ -93,7 +93,7 @@ fetching and simple saving. :LOGBOOK: CLOCK: [2025-07-09 Wed 09:55]--[2025-07-09 Wed 10:15] => 0:20 :END:-* Backlog [-1/13] :vrobbler:project:personal:+* Backlog [1/14] :vrobbler:project:personal: ** TODO [#C] Add sentiment parsing for Scrobbles with notes :vrobbler:project:scrobbles:sentiment: :PROPERTIES: :ID: 37781d6a-f3b0-48b2-bf98-33c2c791cf85@@ -509,6 +509,20 @@ needed import celery task. This is how the WebDAV celery task currently works. This would also be an opporunity to clean up the code around WebDAV imports and make them more re-usable for other import services. +** DONE [#B] Mopidy favorites or monthly playlist adds should look at all scrobbles :bug:mopidy:favorites:tracks:+:PROPERTIES:+:ID: 0be7d11e-e268-2fd5-836a-e5b4d210e0fa+:END:++*** Description++When favoriting a track and trying to add it to the Moidy favorite playlist, it+sometimes happens that one scrobble did not come from Mopidy, but an earlier or+later one did.++Can we scan all the scrobbles of the track for a given user to see if any have+`mopidy_uri` in the log and if so, use that to send along to Mopidy?+ * Version 45.0 [1/1] ** DONE [#B] Add ability to add mopidy tracks to Monthly playlists :feature:favorites:tracks: :PROPERTIES:@@ -576,3 +576,91 @@ def remove_favorite_from_mopidy_playlist(user_id, track_id): track=track, ) remove_track_from_mopidy_favorites_playlist(proxy)+++@shared_task+def add_scrobble_to_mopidy_queue(scrobble_id):+ from scrobbles.models import Scrobble++ scrobble = Scrobble.objects.filter(id=scrobble_id).first()+ if not scrobble:+ return++ profile = scrobble.user.profile+ mopidy_url = profile.mopidy_api_url+ if not mopidy_url:+ return++ mopidy_uri = (scrobble.log or {}).get("raw_data", {}).get("mopidy_uri")+ track = scrobble.track if scrobble.media_type == "Track" else None+ if not mopidy_uri and track:+ sibling = (+ Scrobble.objects.filter(track=track, user=scrobble.user)+ .order_by("-timestamp")+ .iterator()+ )+ for s in sibling:+ uri = (s.log or {}).get("raw_data", {}).get("mopidy_uri")+ if uri:+ mopidy_uri = uri+ break++ if not mopidy_uri:+ logger.warning(+ "No Mopidy URI found for scrobble",+ extra={"scrobble_id": scrobble_id, "user_id": scrobble.user_id},+ )+ return++ import requests++ rpc_url = mopidy_url.rstrip("/") + "/rpc"+ payload = {+ "jsonrpc": "2.0",+ "id": 1,+ "method": "core.tracklist.add",+ "params": {"uris": [mopidy_uri]},+ }+ try:+ resp = requests.post(rpc_url, json=payload, timeout=10)+ resp.raise_for_status()+ rpc_result = resp.json()+ if rpc_result.get("error"):+ logger.error(+ "Mopidy error adding to queue",+ extra={"error": rpc_result["error"], "scrobble_id": scrobble_id},+ )+ else:+ logger.info(+ "Added track to Mopidy queue",+ extra={"scrobble_id": scrobble_id, "mopidy_uri": mopidy_uri},+ )+ except requests.RequestException as e:+ logger.error(+ "Failed to add track to Mopidy queue",+ extra={"scrobble_id": scrobble_id, "error": str(e)},+ )+++@shared_task+def add_scrobble_to_mopidy_monthly_playlist(scrobble_id):+ from scrobbles.models import Scrobble+ from scrobbles.utils import add_track_to_mopidy_monthly_playlist++ scrobble = Scrobble.objects.filter(id=scrobble_id).first()+ if not scrobble:+ return++ track = scrobble.track if scrobble.media_type == "Track" else None+ if track:+ sibling = (+ Scrobble.objects.filter(track=track, user=scrobble.user)+ .order_by("-timestamp")+ .iterator()+ )+ for s in sibling:+ if (s.log or {}).get("raw_data", {}).get("mopidy_uri"):+ scrobble = s+ break++ add_track_to_mopidy_monthly_playlist(scrobble)@@ -468,9 +468,22 @@ def _ensure_mopidy_playlist(profile): return result -def add_track_to_mopidy_favorites_playlist(favorite):+def _scrobble_with_mopidy_uri(track, user):+ """Find a scrobble for this track+user that has a mopidy_uri in its log.""" from scrobbles.models import Scrobble + for scrobble in (+ Scrobble.objects.filter(track=track, user=user)+ .order_by("-timestamp")+ .iterator()+ ):+ raw_data = scrobble.log.get("raw_data") or {}+ if raw_data.get("mopidy_uri"):+ return scrobble+ return None+++def add_track_to_mopidy_favorites_playlist(favorite): if favorite.media_type != "Track" or not favorite.track: return @@ -479,15 +492,7 @@ def add_track_to_mopidy_favorites_playlist(favorite): return track = favorite.track- scrobble = (- Scrobble.objects.filter(- track=track,- user=favorite.user,- log__raw_data__mopidy_uri__isnull=False,- )- .order_by("-timestamp")- .first()- )+ scrobble = _scrobble_with_mopidy_uri(track, favorite.user) if not scrobble: logger.warning(@@ -496,7 +501,7 @@ def add_track_to_mopidy_favorites_playlist(favorite): ) return - mopidy_uri = scrobble.log["raw_data"]["mopidy_uri"]+ mopidy_uri = (scrobble.log or {}).get("raw_data", {}).get("mopidy_uri") try: playlist = _ensure_mopidy_playlist(profile)@@ -557,8 +562,6 @@ def resubmit_favorites_to_mopidy(user): def remove_track_from_mopidy_favorites_playlist(favorite):- from scrobbles.models import Scrobble- if favorite.media_type != "Track" or not favorite.track: return @@ -567,15 +570,7 @@ def remove_track_from_mopidy_favorites_playlist(favorite): return track = favorite.track- scrobble = (- Scrobble.objects.filter(- track=track,- user=favorite.user,- log__raw_data__mopidy_uri__isnull=False,- )- .order_by("-timestamp")- .first()- )+ scrobble = _scrobble_with_mopidy_uri(track, favorite.user) if not scrobble: logger.warning(@@ -584,7 +579,7 @@ def remove_track_from_mopidy_favorites_playlist(favorite): ) return - mopidy_uri = scrobble.log["raw_data"]["mopidy_uri"]+ mopidy_uri = (scrobble.log or {}).get("raw_data", {}).get("mopidy_uri") try: playlist = _ensure_mopidy_playlist(profile)@@ -655,7 +650,7 @@ def add_track_to_mopidy_monthly_playlist(scrobble): if not pattern or not profile.mopidy_api_url: return - mopidy_uri = scrobble.log.get("raw_data", {}).get("mopidy_uri")+ mopidy_uri = (scrobble.log or {}).get("raw_data", {}).get("mopidy_uri") if not mopidy_uri: return @@ -992,46 +992,11 @@ def add_to_mopidy_queue(request, uuid): ) return redirect("scrobbles:detail", uuid=uuid) - raw_data = scrobble.log.get("raw_data", {})- mopidy_uri = raw_data.get("mopidy_uri")- logger.debug(mopidy_uri)+ from scrobbles.tasks import add_scrobble_to_mopidy_queue as task - if not mopidy_uri:- messages.add_message(- request,- messages.ERROR,- "No Mopidy URI found for this scrobble.",- )- return redirect("scrobbles:detail", uuid=uuid)-- rpc_url = mopidy_url.rstrip("/") + "/rpc"- payload = {- "jsonrpc": "2.0",- "id": 1,- "method": "core.tracklist.add",- "params": {"uris": [mopidy_uri]},- }-- try:- resp = requests.post(rpc_url, json=payload, timeout=10)- resp.raise_for_status()- rpc_result = resp.json()- if rpc_result.get("error"):- messages.add_message(- request,- messages.ERROR,- f'Mopidy error: {rpc_result["error"]}',- )- else:- msg = f'Added "{scrobble.media_obj}" to Mopidy queue.'+ task.delay(scrobble.id)+ msg = f'Adding "{scrobble.media_obj}" to Mopidy queue.' messages.add_message(request, messages.SUCCESS, msg)- except requests.RequestException as e:- messages.add_message(- request,- messages.ERROR,- f"Failed to contact Mopidy: {e}",- )- return redirect("scrobbles:detail", uuid=uuid) @@ -1055,13 +1020,13 @@ def add_to_mopidy_monthly_playlist(request, uuid): now = now_user_timezone(profile) playlist_name = DateFormat(now).format(pattern) - from scrobbles.utils import add_track_to_mopidy_monthly_playlist+ from scrobbles.tasks import add_scrobble_to_mopidy_monthly_playlist as task - add_track_to_mopidy_monthly_playlist(scrobble)+ task.delay(scrobble.id) messages.add_message( request, messages.SUCCESS,- f'Added "{scrobble.media_obj}" to monthly playlist "{playlist_name}".',+ f'Adding "{scrobble.media_obj}" to monthly playlist "{playlist_name}".', ) return redirect("scrobbles:detail", uuid=uuid) @@ -1275,6 +1240,17 @@ class ScrobbleDetailView(DetailView): user=self.request.user, **{fk_field: media_obj} ).exists() + if media_type == "Track" and media_obj:+ scrobbles = Scrobble.objects.filter(+ track=media_obj, user=self.object.user+ ).order_by("-timestamp")[:20]+ context["has_mopidy_uri"] = any(+ (s.log or {}).get("raw_data", {}).get("mopidy_uri")+ for s in scrobbles+ )+ else:+ context["has_mopidy_uri"] = False+ return context @@ -66,7 +66,7 @@ <h2>{{ object.logdata.title }}</h2> {% endif %} <h3 class="text-muted">{{ object.local_timestamp }}</h3>-{% if object.media_type == "Track" and object.log.raw_data.mopidy_uri and user.profile.mopidy_api_url %}+{% if object.media_type == "Track" and has_mopidy_uri and user.profile.mopidy_api_url %} <form method="post" action="{% url 'scrobbles:add-to-mopidy-queue' object.uuid %}" class="mb-1"> {% csrf_token %} <button type="submit" class="btn btn-sm btn-outline-secondary">add to mopidy queue</button>