[scrobbles] Fix mood starting, and clean up code

This commit is contained in:
2024-08-10 17:41:26 -04:00
parent f3fc58e2c0
commit 0ce19527a2
9 changed files with 205 additions and 17 deletions

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.13 on 2024-08-10 20:43
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("moods", "0001_initial"),
]
operations = [
migrations.AddField(
model_name="mood",
name="image",
field=models.ImageField(blank=True, null=True, upload_to="moods/"),
),
]

View File

@ -1,10 +1,12 @@
import logging
from uuid import uuid4
from django.contrib.auth import get_user_model
from django.db import models
from django.urls import reverse
from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFit
from scrobbles.mixins import ScrobblableMixin
from vrobbler.apps.scrobbles.dataclasses import MoodLogData
logger = logging.getLogger(__name__)
@ -14,6 +16,19 @@ User = get_user_model()
class Mood(ScrobblableMixin):
description = models.TextField(**BNULL)
image = models.ImageField(upload_to="moods/", **BNULL)
image_small = ImageSpecField(
source="thumbnail",
processors=[ResizeToFit(100, 100)],
format="JPEG",
options={"quality": 60},
)
image_medium = ImageSpecField(
source="thumbnail",
processors=[ResizeToFit(300, 300)],
format="JPEG",
options={"quality": 75},
)
def __str__(self):
if self.title:
@ -23,6 +38,19 @@ class Mood(ScrobblableMixin):
def get_absolute_url(self):
return reverse("moods:mood-detail", kwargs={"slug": self.uuid})
def get_start_url(self):
return reverse("scrobbles:start", kwargs={"uuid": self.uuid})
@property
def subtitle(self) -> str:
return ""
@property
def logdata_cls(self):
return MoodLogData
@property
def primary_image_url(self) -> str:
if self.image:
return self.image.url
return ""

View File

@ -12,6 +12,7 @@ PLAY_AGAIN_MEDIA = {
"videogames": "VideoGame",
"books": "Book",
"boardgames": "BoardGame",
"moods": "Mood",
}
MEDIA_END_PADDING_SECONDS = {

View File

@ -2,12 +2,14 @@ import logging
from typing import Optional
from uuid import uuid4
from django.apps import apps
from django.db import models
from django.urls import reverse
from django.utils import timezone
from django_extensions.db.models import TimeStampedModel
from taggit.managers import TaggableManager
from scrobbles.utils import get_scrobbles_for_media
from taggit.models import TagBase, GenericTaggedItemBase
from taggit.managers import TaggableManager
from taggit.models import GenericTaggedItemBase, TagBase
BNULL = {"blank": True, "null": True}
@ -33,6 +35,7 @@ class ObjectWithGenres(GenericTaggedItemBase):
class ScrobblableMixin(TimeStampedModel):
SECONDS_TO_STALE = 1600
COMPLETION_PERCENT = 100
uuid = models.UUIDField(default=uuid4, editable=False, **BNULL)
title = models.CharField(max_length=255, **BNULL)
@ -44,21 +47,53 @@ class ScrobblableMixin(TimeStampedModel):
class Meta:
abstract = True
def basic_scrobble_data(self, user_id) -> dict:
return {
"user_id": user_id,
"timestamp": timezone.now(),
"playback_position_seconds": 0,
"source": "Vrobbler",
}
def scrobble_for_user(self, user_id):
Scrobble = apps.get_model("scrobbles", "Scrobble")
scrobble_data = self.basic_scrobble_data(user_id)
logger.info(
"[scrobble_for_user] called",
extra={
"webpage_id": self.id,
"user_id": user_id,
"scrobble_data": scrobble_data,
"media_type": Scrobble.MediaType.WEBPAGE,
},
)
return Scrobble.create_or_update(self, user_id, scrobble_data)
@property
def primary_image_url(self) -> str:
logger.warn(f"Not implemented yet")
return ""
def fix_metadata(self):
@property
def logdata_cls(self) -> None:
logger.warn("logdata_cls() not implemented yet")
return None
@property
def subtitle(self) -> str:
return ""
def fix_metadata(self) -> None:
logger.warn("fix_metadata() not implemented yet")
@classmethod
def find_or_create(cls):
def find_or_create(cls) -> None:
logger.warn("find_or_create() not implemented yet")
def scrobble(self, user_id, **kwargs):
"""Given a user ID and a dictionary of data, attempts to scrobble it"""
from scrobbles.models import Scrobble
Scrobble.create_or_update(self, user_id, **kwargs)

View File

@ -904,7 +904,7 @@ class Scrobble(TimeStampedModel):
.order_by("-timestamp")
.first()
)
source = scrobble_data.get("source")
source = scrobble_data.get("source", "Vrobbler")
mtype = media.__class__.__name__
mopidy_status = scrobble_data.get("mopidy_status", None)

View File

@ -69,12 +69,13 @@ class ScrobbleableListView(ListView):
if not self.request.user.is_anonymous:
queryset = queryset.annotate(
scrobble_count=Count("scrobble"),
filter=Q(user=self.request.user),
filter=Q(scrobble__user=self.request.user),
).order_by("-scrobble_count")
else:
queryset = queryset.annotate(
scrobble_count=Count("scrobble")
).order_by("-scrobble_count")
return queryset
class ScrobbleableDetailView(DetailView):
@ -85,8 +86,8 @@ class ScrobbleableDetailView(DetailView):
context_data = super().get_context_data(**kwargs)
context_data["scrobbles"] = list()
if not self.request.user.is_anonymous:
context_data["scrobbles"] = self.object.scrobbles(
self.request.user
context_data["scrobbles"] = self.object.scrobble_set.filter(
user=self.request.user
)
return context_data
@ -429,6 +430,10 @@ def import_audioscrobbler_file(request):
@permission_classes([IsAuthenticated])
@api_view(["GET"])
def scrobble_start(request, uuid):
logger.info(
"[scrobble_start] called",
extra={"request": request, "uuid": uuid},
)
user = request.user
success_url = request.META.get("HTTP_REFERER")
@ -443,19 +448,17 @@ def scrobble_start(request, uuid):
break
if not media_obj:
logger.info(
"[scrobble_start] media object not found",
extra={"uuid": uuid, "user_id": user.id},
)
# TODO Log that we couldn't find a media obj to scrobble
return
scrobble = None
user_id = request.user.id
if media_obj:
if media_obj.__class__.__name__ == Scrobble.MediaType.BOOK:
scrobble = manual_scrobble_book(media_obj.openlibrary_id, user_id)
if media_obj.__class__.__name__ == Scrobble.MediaType.VIDEO_GAME:
scrobble = manual_scrobble_video_game(media_obj.hltb_id, user_id)
if media_obj.__class__.__name__ == Scrobble.MediaType.BOARD_GAME:
scrobble = manual_scrobble_board_game(media_obj.bggeek_id, user_id)
if media_obj.__class__.__name__ == Scrobble.MediaType.WEBPAGE:
scrobble = manual_scrobble_webpage(media_obj.url, user_id)
media_obj.scrobble_for_user(user_id)
if scrobble:
messages.add_message(

View File

@ -89,6 +89,28 @@ class WebPage(ScrobblableMixin):
def subtitle(self):
return self.domain
@property
def primary_image_url(self) -> str:
# TODO Figure out how to add a preview?
return ""
def scrobble_for_user(self, user_id):
Scrobble = apps.get_model("scrobbles", "Scrobble")
scrobble_data = self.basic_scrobble_data(user_id)
logger.info(
"[scrobble_for_user] called for webpage",
extra={
"webpage_id": self.id,
"user_id": user_id,
"scrobble_data": scrobble_data,
"media_type": Scrobble.MediaType.WEBPAGE,
},
)
scrobble = Scrobble.create_or_update(self, user_id, scrobble_data)
# TODO Possibly make this async?
scrobble.push_to_archivebox()
return scrobble
def scrobbles(self, user):
Scrobble = apps.get_model("scrobbles", "Scrobble")
return Scrobble.objects.filter(user=user, web_page=self).order_by(

View File

@ -0,0 +1,39 @@
{% extends "base_list.html" %}
{% load static %}
{% block title %}{{object.title}}{% endblock %}
{% block lists %}
<div class="row webpage">
<div class="webpage-metadata">
<p>{{object.description}}</p>
</div>
{% if object.extract %}
<div class="webpage-body" id="article">
{{object.extract|linebreaks}}
</div>
{% endif %}
<hr/>
</div>
<div class="row">
<div class="col-md">
<h3>Last scrobbles</h3>
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th scope="col">Date</th>
</tr>
</thead>
<tbody>
{% for scrobble in object.scrobble_set.all %}
<tr>
<td>{{scrobble.timestamp}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,42 @@
{% extends "base_list.html" %}
{% block title %}Moods{% endblock %}
{% block head_extra %}
<style>
dl { width: 210px; float:left; margin-right: 10px; }
dt a { color:white; text-decoration: none; font-size:smaller; }
img { height:200px; width: 200px; object-fit: cover; }
dd .right { float:right; }
</style>
{% endblock %}
{% block lists %}
<div class="row">
<div class="col-md">
<div class="table-responsive">
<table class="table table-striped table-sm">
<thead>
<tr>
<th scope="col">Title</th>
<th scope="col">Scrobbles</th>
<th scope="col">Start</th>
</tr>
</thead>
<tbody>
{% for mood in object_list %}
<tr>
<td><a href="{{mood.get_absolute_url}}">{{mood}}</a></td>
{% if request.user.is_authenticated %}
<td>{{mood.scrobble_count}}</td>
<td><a type="button" class="btn btn-sm btn-primary" href="{{mood.get_start_url}}">Scrobble</a></td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}