[longplay] Add ability to undo finishes
Some checks failed
build / test (push) Has been cancelled

This commit is contained in:
2026-06-15 14:55:58 -04:00
parent 7d3f615ed7
commit c0be131e3d
6 changed files with 41 additions and 15 deletions

View File

@ -594,6 +594,7 @@ named constants for maintainability.
- ~vrobbler/apps/webpages/models.py~ (line 290) -- ="url"=
- ~vrobbler/apps/scrobbles/importers/tsv.py~ (line 55) -- ="S"= completion status
** TODO [#C] Show time per scrobble in long play lists and total time playing :templates:longplay:scrobbles:
** DONE [#B] Allow marking media as long play complete from detail page :templates:scrobbles:longplay:
:PROPERTIES:
:ID: 2c314768-be97-9b10-d13c-9cfd0f38a64e

View File

@ -909,6 +909,28 @@ def scrobble_longplay_finish(request, uuid):
if not user.is_authenticated:
return HttpResponseRedirect(success_url)
# Try scrobble UUID first
scrobble = Scrobble.objects.filter(uuid=uuid, user=user).first()
if scrobble:
if scrobble.long_play_complete == True:
scrobble.long_play_complete = None
scrobble.save(update_fields=["long_play_complete"])
messages.add_message(
request,
messages.INFO,
f"Long play of {scrobble.media_obj} marked as not complete.",
)
else:
scrobble.long_play_complete = True
scrobble.save(update_fields=["long_play_complete"])
messages.add_message(
request,
messages.SUCCESS,
f"Long play of {scrobble.media_obj} finished.",
)
return HttpResponseRedirect(success_url)
# Fall back to media UUID (existing behavior)
media_obj = None
for app, model in LONG_PLAY_MEDIA.items():
media_model = apps.get_model(app_label=app, model_name=model)
@ -917,10 +939,21 @@ def scrobble_longplay_finish(request, uuid):
break
if not media_obj:
return
messages.add_message(
request, messages.ERROR, f"Media with uuid {uuid} not found."
)
return HttpResponseRedirect(success_url)
last_scrobble = media_obj.last_long_play_scrobble_for_user(user)
if last_scrobble and last_scrobble.long_play_complete == False:
if last_scrobble and last_scrobble.long_play_complete == True:
last_scrobble.long_play_complete = None
last_scrobble.save(update_fields=["long_play_complete"])
messages.add_message(
request,
messages.INFO,
f"Long play of {media_obj} marked as not complete.",
)
elif last_scrobble:
last_scrobble.long_play_complete = True
last_scrobble.save(update_fields=["long_play_complete"])
messages.add_message(
@ -928,12 +961,6 @@ def scrobble_longplay_finish(request, uuid):
messages.SUCCESS,
f"Long play of {media_obj} finished.",
)
elif last_scrobble and last_scrobble.long_play_complete == True:
messages.add_message(
request,
messages.INFO,
f"Long play of {media_obj} was already completed.",
)
else:
messages.add_message(
request, messages.ERROR, f"Media with uuid {uuid} not found."

View File

@ -36,7 +36,6 @@
<p>{{scrobbles.count}} scrobbles</p>
<p><a href="{{object.resume_start_url}}">Resume reading</a></p>
<p><a class="btn btn-sm btn-warning" href="{{object.get_longplay_finish_url}}">Finish long play</a></p>
</div>
{% if charts %}
<div class="row">
@ -62,7 +61,7 @@
{% for scrobble in scrobbles.all|dictsortreversed:"timestamp" %}
<tr>
<td><a href="{{scrobble.get_absolute_url}}">{{scrobble.local_timestamp}}</a></td>
<td>{% if scrobble.long_play_complete == True %}Yes{% else %}No{% endif %}</td>
<td>{% if scrobble.long_play_complete == True %}Yes <small><a href="{% url 'scrobbles:longplay-finish' uuid=scrobble.uuid %}">(not complete?)</a></small>{% else %}<a href="{% url 'scrobbles:longplay-finish' uuid=scrobble.uuid %}">No</a>{% endif %}</td>
<td>{% if scrobble.in_progress %}Now reading{% else %}{{scrobble.session_pages_read}}{% endif %}</td>
<td>{% for author in scrobble.book.authors.all %}<a href="{{author.get_absolute_url}}">{{author}}</a>{% if not forloop.last %}, {% endif %}{% endfor %}</td>
</tr>

View File

@ -27,7 +27,6 @@
</div>
<div class="row">
<p>{{scrobbles.count}} scrobbles</p>
<p><a class="btn btn-sm btn-warning" href="{{object.get_longplay_finish_url}}">Finish long play</a></p>
</div>
<div class="row">
<div class="col-md">
@ -45,7 +44,7 @@
{% for scrobble in scrobbles.all|dictsortreversed:"timestamp" %}
<tr>
<td><a href="{{scrobble.get_absolute_url}}">{{scrobble.local_timestamp}}</a></td>
<td>{% if scrobble.long_play_complete == True %}Yes{% else %}No{% endif %}</td>
<td>{% if scrobble.long_play_complete == True %}Yes <small><a href="{% url 'scrobbles:longplay-finish' uuid=scrobble.uuid %}">(not complete?)</a></small>{% else %}<a href="{% url 'scrobbles:longplay-finish' uuid=scrobble.uuid %}">No</a>{% endif %}</td>
<td>{% if scrobble.in_progress %}Now reading{% else %}{{scrobble.session_pages_read}}{% endif %}</td>
</tr>
{% endfor %}

View File

@ -53,7 +53,6 @@
<p>{{scrobbles.count}} scrobbles</p>
<p>
<a href="{{object.start_url}}">Play again</a>
<a class="btn btn-sm btn-warning" href="{{object.get_longplay_finish_url}}">Finish long play</a>
</p>
</div>
<div class="row">
@ -68,6 +67,7 @@
<th scope="col">Title</th>
<th scope="col">Notes</th>
<th scope="col">Source</th>
<th scope="col">Completed</th>
</tr>
</thead>
<tbody>
@ -77,6 +77,7 @@
<td><a href="{{scrobble.get_media_source_url}}">{{scrobble.logdata.title}}</a></td>
<td>{{scrobble.logdata.notes_as_str}}</td>
<td>{{scrobble.source}}</td>
<td>{% if scrobble.long_play_complete == True %}Yes <small><a href="{% url 'scrobbles:longplay-finish' uuid=scrobble.uuid %}">(not complete?)</a></small>{% else %}<a href="{% url 'scrobbles:longplay-finish' uuid=scrobble.uuid %}">No</a>{% endif %}</td>
</tr>
{% endfor %}
</tbody>

View File

@ -62,7 +62,6 @@
<p>{{scrobbles.count}} scrobbles</p>
<p>
<a href="">Play again</a>
<a class="btn btn-sm btn-warning" href="{{object.get_longplay_finish_url}}">Finish long play</a>
</p>
</div>
<div class="row">
@ -84,7 +83,7 @@
<tr>
<td><a href="{{scrobble.get_absolute_url}}">{{scrobble.local_timestamp}}</a></td>
<td>{% if scrobble.long_play_complete == True %}Yes{% else %}Not yet{% endif %}</td>
<td>{% if scrobble.long_play_complete == True %}Yes <small><a href="{% url 'scrobbles:longplay-finish' uuid=scrobble.uuid %}">(not complete?)</a></small>{% else %}<a href="{% url 'scrobbles:longplay-finish' uuid=scrobble.uuid %}">Not yet</a>{% endif %}</td>
<td>{% if scrobble.in_progress %}Now playing{% else %}{{scrobble.playback_position_seconds|natural_duration}}{% endif %}</td>
<td>{% for platform in scrobble.video_game.platforms.all %}<a href="{{platform.get_absolute_url}}">{{platform}}</a>{% if not forloop.last %}, {% endif %}{% endfor %}</td>
<td>{% if scrobble.videogame_save_data %}<a href="{{scrobble.videogame_save_data.url}}">Save data</a>{% else %}Not yet{% endif %}</td>