From 6861e28ac6e971563e849cfa1a45f41e1e51e1d8 Mon Sep 17 00:00:00 2001 From: Colin Powell Date: Mon, 13 Jul 2026 19:09:32 -0400 Subject: [PATCH] [drinks] Add Drink as a scrobbleable media --- vrobbler/apps/drinks/admin.py | 15 +++ ...ptions_alter_beerstyle_options_and_more.py | 90 ++++++++++++++++ vrobbler/apps/drinks/models.py | 35 ++++-- vrobbler/apps/drinks/urls.py | 11 ++ vrobbler/apps/drinks/views.py | 34 +++++- vrobbler/apps/scrobbles/constants.py | 7 +- ...ritemedia_drink_scrobble_drink_and_more.py | 102 ++++++++++++++++++ vrobbler/apps/scrobbles/models.py | 12 ++- vrobbler/apps/scrobbles/scrobblers.py | 77 ++++++++++++- vrobbler/apps/scrobbles/views.py | 1 + vrobbler/templates/base.html | 6 ++ vrobbler/templates/drinks/drink_detail.html | 80 ++++++++++++++ vrobbler/templates/drinks/drink_list.html | 23 ++++ vrobbler/templates/drinks/water_detail.html | 79 ++++++++++++++ .../scrobbles/_scrobble_all_content.html | 2 + 15 files changed, 560 insertions(+), 14 deletions(-) create mode 100644 vrobbler/apps/drinks/migrations/0010_alter_beerproducer_options_alter_beerstyle_options_and_more.py create mode 100644 vrobbler/apps/scrobbles/migrations/0102_favoritemedia_drink_scrobble_drink_and_more.py create mode 100644 vrobbler/templates/drinks/drink_detail.html create mode 100644 vrobbler/templates/drinks/drink_list.html create mode 100644 vrobbler/templates/drinks/water_detail.html diff --git a/vrobbler/apps/drinks/admin.py b/vrobbler/apps/drinks/admin.py index fc90c82..82eb960 100644 --- a/vrobbler/apps/drinks/admin.py +++ b/vrobbler/apps/drinks/admin.py @@ -5,6 +5,7 @@ from drinks.models import ( BeerStyle, Coffee, CoffeeRoaster, + Drink, Wine, WineGrape, WineProducer, @@ -97,3 +98,17 @@ class CoffeeAdmin(admin.ModelAdmin): inlines = [ ScrobbleInline, ] + + +@admin.register(Drink) +class DrinkAdmin(admin.ModelAdmin): + date_hierarchy = "created" + list_display = ( + "uuid", + "title", + ) + ordering = ("-created",) + search_fields = ("title",) + inlines = [ + ScrobbleInline, + ] diff --git a/vrobbler/apps/drinks/migrations/0010_alter_beerproducer_options_alter_beerstyle_options_and_more.py b/vrobbler/apps/drinks/migrations/0010_alter_beerproducer_options_alter_beerstyle_options_and_more.py new file mode 100644 index 0000000..5a9147c --- /dev/null +++ b/vrobbler/apps/drinks/migrations/0010_alter_beerproducer_options_alter_beerstyle_options_and_more.py @@ -0,0 +1,90 @@ +# Generated by Django 4.2.29 on 2026-07-13 18:26 + +from django.db import migrations, models +import django_extensions.db.fields +import taggit.managers +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ("scrobbles", "0101_favoritemedia_coffee_favoritemedia_wine_and_more"), + ("taggit", "0004_alter_taggeditem_content_type_alter_taggeditem_tag"), + ("drinks", "0009_coffeeroaster_winegrape_wineproducer_wineregion_and_more"), + ] + + operations = [ + migrations.AlterModelOptions( + name="beerproducer", + options={}, + ), + migrations.AlterModelOptions( + name="beerstyle", + options={}, + ), + migrations.AddField( + model_name="wine", + name="non_alcoholic", + field=models.BooleanField(default=False), + ), + migrations.CreateModel( + name="Drink", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "created", + django_extensions.db.fields.CreationDateTimeField( + auto_now_add=True, verbose_name="created" + ), + ), + ( + "modified", + django_extensions.db.fields.ModificationDateTimeField( + auto_now=True, verbose_name="modified" + ), + ), + ( + "uuid", + models.UUIDField( + blank=True, default=uuid.uuid4, editable=False, null=True + ), + ), + ("title", models.CharField(blank=True, max_length=255, null=True)), + ("base_run_time_seconds", models.IntegerField(blank=True, null=True)), + ("calories", models.PositiveIntegerField(blank=True, null=True)), + ("is_alcoholic", models.BooleanField(default=False)), + ( + "genre", + taggit.managers.TaggableManager( + blank=True, + help_text="A comma-separated list of tags.", + through="scrobbles.ObjectWithGenres", + to="scrobbles.Genre", + verbose_name="Genre", + ), + ), + ( + "tags", + taggit.managers.TaggableManager( + blank=True, + help_text="A comma-separated list of tags.", + through="taggit.TaggedItem", + to="taggit.Tag", + verbose_name="Tags", + ), + ), + ], + options={ + "db_table": "drinks_drink", + }, + ), + ] diff --git a/vrobbler/apps/drinks/models.py b/vrobbler/apps/drinks/models.py index 47eb643..b1ecbe1 100644 --- a/vrobbler/apps/drinks/models.py +++ b/vrobbler/apps/drinks/models.py @@ -75,7 +75,7 @@ class DrinkLogData(BaseLogData): @property def size_oz(self) -> Optional[float]: if self.size_ml: - return round(self.size_ml / ML_PER_OZ, 1) + return round(float(self.size_ml) / ML_PER_OZ, 1) return None @property @@ -146,16 +146,27 @@ class CoffeeLogData(DrinkLogData): class Drink(ScrobblableMixin): calories = models.PositiveIntegerField(**BNULL) + is_alcoholic = models.BooleanField(default=False) class Meta: - abstract = True + db_table = "drinks_drink" + + def __str__(self): + return self.title or "Drink" + + @classmethod + def find_or_create_water(cls) -> "Drink": + water, _ = cls.objects.get_or_create( + title="Water", defaults={"calories": 0, "base_run_time_seconds": 120} + ) + return water + + def get_absolute_url(self) -> str: + return reverse("drinks:drink_detail", kwargs={"slug": self.uuid}) @property - def is_alcoholic(self) -> bool: - return True - - -# --- Beer models --- + def logdata_cls(self): + return DrinkLogData class BeerStyle(TimeStampedModel): @@ -188,11 +199,12 @@ class BeerProducer(TimeStampedModel): db_table = "beers_beerproducer" -class Beer(Drink): +class Beer(ScrobblableMixin): description = models.TextField(**BNULL) ibu = models.SmallIntegerField(**BNULL) abv = models.FloatField(**BNULL) styles = models.ManyToManyField(BeerStyle, related_name="styles") + calories = models.PositiveIntegerField(**BNULL) non_alcoholic = models.BooleanField(default=False) beeradvocate_id = models.CharField(max_length=255, **BNULL) beeradvocate_score = models.SmallIntegerField(**BNULL) @@ -322,8 +334,10 @@ class WineProducer(TimeStampedModel): return self.name -class Wine(Drink): +class Wine(ScrobblableMixin): description = models.TextField(**BNULL) + calories = models.PositiveIntegerField(**BNULL) + non_alcoholic = models.BooleanField(default=False) wine_type = models.CharField(max_length=20, choices=WineType.choices, **BNULL) grapes = models.ManyToManyField(WineGrape, related_name="wines", blank=True) region = models.ForeignKey(WineRegion, on_delete=models.DO_NOTHING, **BNULL) @@ -476,8 +490,9 @@ class CoffeeRoaster(TimeStampedModel): return self.name -class Coffee(Drink): +class Coffee(ScrobblableMixin): description = models.TextField(**BNULL) + calories = models.PositiveIntegerField(**BNULL) origin = models.CharField(max_length=255, **BNULL) roaster = models.ForeignKey(CoffeeRoaster, on_delete=models.DO_NOTHING, **BNULL) roastdb_id = models.CharField(max_length=255, **BNULL) diff --git a/vrobbler/apps/drinks/urls.py b/vrobbler/apps/drinks/urls.py index 2f7b3b1..4b2fb86 100644 --- a/vrobbler/apps/drinks/urls.py +++ b/vrobbler/apps/drinks/urls.py @@ -23,4 +23,15 @@ urlpatterns = [ views.CoffeeDetailView.as_view(), name="coffee_detail", ), + path("drinks/", views.DrinkListView.as_view(), name="drink_list"), + path( + "drinks//", + views.DrinkDetailView.as_view(), + name="drink_detail", + ), + path( + "quick-water/", + views.QuickWaterScrobbleView.as_view(), + name="quick_water_scrobble", + ), ] diff --git a/vrobbler/apps/drinks/views.py b/vrobbler/apps/drinks/views.py index e29ad39..427ff0a 100644 --- a/vrobbler/apps/drinks/views.py +++ b/vrobbler/apps/drinks/views.py @@ -1,4 +1,7 @@ -from drinks.models import Beer, Coffee, Wine +from django.contrib import messages +from django.http import HttpResponseRedirect +from django.views import View +from drinks.models import Beer, Coffee, Drink, Wine from scrobbles.views import ScrobbleableDetailView, ScrobbleableListView @@ -24,3 +27,32 @@ class CoffeeListView(ScrobbleableListView): class CoffeeDetailView(ScrobbleableDetailView): model = Coffee + + +class DrinkListView(ScrobbleableListView): + model = Drink + + +class DrinkDetailView(ScrobbleableDetailView): + model = Drink + + +class QuickWaterScrobbleView(View): + def post(self, request, *args, **kwargs): + if not request.user.is_authenticated: + messages.error(request, "You must be logged in to scrobble water.") + return HttpResponseRedirect("/") + + from scrobbles.scrobblers import manual_scrobble_water + + scrobble = manual_scrobble_water(user_id=request.user.id) + + if scrobble: + messages.success(request, "Water scrobbled!") + return HttpResponseRedirect(scrobble.redirect_url(request.user.id)) + + messages.error(request, "Failed to scrobble water.") + return HttpResponseRedirect("/") + + def get(self, request, *args, **kwargs): + return self.post(request, *args, **kwargs) diff --git a/vrobbler/apps/scrobbles/constants.py b/vrobbler/apps/scrobbles/constants.py index 88d1fad..c89cbdf 100644 --- a/vrobbler/apps/scrobbles/constants.py +++ b/vrobbler/apps/scrobbles/constants.py @@ -27,6 +27,7 @@ AUTO_FINISH_MEDIA = { "tracks": "Track", "videos": "Video", "moods": "Mood", + "drinks": "Drink", } PLAY_AGAIN_MEDIA = { @@ -40,6 +41,9 @@ PLAY_AGAIN_MEDIA = { "locations": "GeoLocation", "trails": "Trail", "drinks": "Beer", + "drinks": "Wine", + "drinks": "Coffee", + "drinks": "Drink", "puzzles": "Puzzle", "foods": "Food", "tasks": "Task", @@ -52,7 +56,7 @@ PLAY_AGAIN_MEDIA = { "discgolf": "DiscGolfCourse", } -DRINK_MODELS = ["Beer", "Wine", "Coffee"] +DRINK_MODELS = ["Beer", "Wine", "Coffee", "Drink"] MEDIA_END_PADDING_SECONDS = { "Video": 3600, # 60 min @@ -93,6 +97,7 @@ MANUAL_SCROBBLE_FNS = { "-l": "manual_scrobble_brickset", "-c": "manual_scrobble_book", "-f": "manual_scrobble_food", + "-d": "manual_scrobble_drink", "-h": "manual_scrobble_twitch_channel", "-dg": "manual_scrobble_discgolf", "-pp": "manual_scrobble_paper", diff --git a/vrobbler/apps/scrobbles/migrations/0102_favoritemedia_drink_scrobble_drink_and_more.py b/vrobbler/apps/scrobbles/migrations/0102_favoritemedia_drink_scrobble_drink_and_more.py new file mode 100644 index 0000000..5eeda83 --- /dev/null +++ b/vrobbler/apps/scrobbles/migrations/0102_favoritemedia_drink_scrobble_drink_and_more.py @@ -0,0 +1,102 @@ +# Generated by Django 4.2.29 on 2026-07-13 18:31 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ("drinks", "0010_alter_beerproducer_options_alter_beerstyle_options_and_more"), + ("scrobbles", "0101_favoritemedia_coffee_favoritemedia_wine_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="favoritemedia", + name="drink", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="drinks.drink", + ), + ), + migrations.AddField( + model_name="scrobble", + name="drink", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.DO_NOTHING, + to="drinks.drink", + ), + ), + migrations.AlterField( + model_name="favoritemedia", + name="media_type", + field=models.CharField( + choices=[ + ("Video", "Video"), + ("Track", "Track"), + ("PodcastEpisode", "Podcast episode"), + ("SportEvent", "Sport event"), + ("Book", "Book"), + ("Paper", "Paper"), + ("VideoGame", "Video game"), + ("BoardGame", "Board game"), + ("GeoLocation", "GeoLocation"), + ("Trail", "Trail"), + ("Beer", "Beer"), + ("Wine", "Wine"), + ("Coffee", "Coffee"), + ("Drink", "Drink"), + ("Puzzle", "Puzzle"), + ("Food", "Food"), + ("Task", "Task"), + ("WebPage", "Web Page"), + ("LifeEvent", "Life event"), + ("Mood", "Mood"), + ("BrickSet", "Brick set"), + ("Channel", "Channel"), + ("BirdingLocation", "Birding location"), + ("DiscGolfCourse", "Disc golf"), + ], + max_length=20, + ), + ), + migrations.AlterField( + model_name="scrobble", + name="media_type", + field=models.CharField( + choices=[ + ("Video", "Video"), + ("Track", "Track"), + ("PodcastEpisode", "Podcast episode"), + ("SportEvent", "Sport event"), + ("Book", "Book"), + ("Paper", "Paper"), + ("VideoGame", "Video game"), + ("BoardGame", "Board game"), + ("GeoLocation", "GeoLocation"), + ("Trail", "Trail"), + ("Beer", "Beer"), + ("Wine", "Wine"), + ("Coffee", "Coffee"), + ("Drink", "Drink"), + ("Puzzle", "Puzzle"), + ("Food", "Food"), + ("Task", "Task"), + ("WebPage", "Web Page"), + ("LifeEvent", "Life event"), + ("Mood", "Mood"), + ("BrickSet", "Brick set"), + ("Channel", "Channel"), + ("BirdingLocation", "Birding location"), + ("DiscGolfCourse", "Disc golf"), + ], + default="Video", + max_length=20, + ), + ), + ] diff --git a/vrobbler/apps/scrobbles/models.py b/vrobbler/apps/scrobbles/models.py index 0f2e359..d7550fc 100644 --- a/vrobbler/apps/scrobbles/models.py +++ b/vrobbler/apps/scrobbles/models.py @@ -9,7 +9,7 @@ from zoneinfo import ZoneInfo import pendulum import pytz -from drinks.models import Beer, Wine, Coffee +from drinks.models import Beer, Wine, Coffee, Drink from birds.models import BirdingLocation from discgolf.models import DiscGolfCourse from boardgames.models import BoardGame @@ -686,6 +686,7 @@ TYPE_FK_PREFETCHES: dict[str, tuple[str, ...]] = { "Beer": ("beer",), "Wine": ("wine",), "Coffee": ("coffee",), + "Drink": ("drink",), "Puzzle": ("puzzle",), "Food": ("food",), "Task": ("task",), @@ -716,6 +717,7 @@ class ScrobbleQuerySet(models.QuerySet): "beer", "wine", "coffee", + "drink", "puzzle", "food", "trail", @@ -769,6 +771,7 @@ class Scrobble(TimeStampedModel): BEER = "Beer", "Beer" WINE = "Wine", "Wine" COFFEE = "Coffee", "Coffee" + DRINK = "Drink", "Drink" PUZZLE = "Puzzle", "Puzzle" FOOD = "Food", "Food" TASK = "Task", "Task" @@ -800,6 +803,7 @@ class Scrobble(TimeStampedModel): beer = models.ForeignKey(Beer, on_delete=models.DO_NOTHING, **BNULL) wine = models.ForeignKey(Wine, on_delete=models.DO_NOTHING, **BNULL) coffee = models.ForeignKey(Coffee, on_delete=models.DO_NOTHING, **BNULL) + drink = models.ForeignKey(Drink, 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) @@ -1382,6 +1386,8 @@ class Scrobble(TimeStampedModel): media_obj = self.wine if self.coffee: media_obj = self.coffee + if self.drink: + media_obj = self.drink if self.puzzle: media_obj = self.puzzle if self.task: @@ -1945,6 +1951,7 @@ class FavoriteMedia(TimeStampedModel): beer = models.ForeignKey(Beer, on_delete=models.CASCADE, **BNULL) wine = models.ForeignKey(Wine, on_delete=models.CASCADE, **BNULL) coffee = models.ForeignKey(Coffee, on_delete=models.CASCADE, **BNULL) + drink = models.ForeignKey(Drink, on_delete=models.CASCADE, **BNULL) puzzle = models.ForeignKey(Puzzle, on_delete=models.CASCADE, **BNULL) food = models.ForeignKey(Food, on_delete=models.CASCADE, **BNULL) trail = models.ForeignKey(Trail, on_delete=models.CASCADE, **BNULL) @@ -2003,6 +2010,8 @@ class FavoriteMedia(TimeStampedModel): media_obj = self.wine if self.coffee: media_obj = self.coffee + if self.drink: + media_obj = self.drink if self.puzzle: media_obj = self.puzzle if self.task: @@ -2037,6 +2046,7 @@ class FavoriteMedia(TimeStampedModel): "Beer": "beer", "Wine": "wine", "Coffee": "coffee", + "Drink": "drink", "Puzzle": "puzzle", "Food": "food", "Trail": "trail", diff --git a/vrobbler/apps/scrobbles/scrobblers.py b/vrobbler/apps/scrobbles/scrobblers.py index 86b0888..a501015 100644 --- a/vrobbler/apps/scrobbles/scrobblers.py +++ b/vrobbler/apps/scrobbles/scrobblers.py @@ -15,7 +15,7 @@ from bricksets.models import BrickSet from dateutil.parser import parse from discgolf.models import DiscGolfCourse from django.utils import timezone -from drinks.models import Beer, Coffee, Wine +from drinks.models import Beer, Coffee, Wine, Drink, DrinkFormat from foods.models import Food from foods.sources.rscraper import RecipeScraperService from locations.constants import LOCATION_PROVIDERS @@ -1350,6 +1350,37 @@ def manual_scrobble_coffee( return Scrobble.create_or_update(coffee, user_id, scrobble_dict) +def manual_scrobble_water( + user_id: int = None, + source: str = "Vrobbler", + action: Optional[str] = None, +): + water = Drink.find_or_create_water() + + if not water: + logger.error("Could not find or create Water instance") + return + + scrobble_dict = { + "user_id": user_id, + "timestamp": timezone.now(), + "playback_position_seconds": 0, + "source": source, + "log": {"format": DrinkFormat.BY_THE_GLASS, "size_ml": 250}, + } + logger.info( + "[vrobbler-scrobble] water scrobble request received", + extra={ + "water_id": water.id, + "user_id": user_id, + "scrobble_dict": scrobble_dict, + "media_type": Scrobble.MediaType.DRINK, + }, + ) + + return Scrobble.create_or_update(water, user_id, scrobble_dict) + + def manual_scrobble_puzzle( ipdb_id: str, user_id: int, @@ -1461,6 +1492,50 @@ def manual_scrobble_food( return Scrobble.create_or_update(food, user_id, scrobble_dict) +def manual_scrobble_drink( + item_id: str, + user_id: int, + source: str = "Vrobbler", + action: Optional[str] = None, +): + match = re.match(r"(.+?)\s+-\s+(\d+)", item_id) + if not match: + logger.info( + "[manual_scrobble_drink] invalid format, expected 'Drink Name - calories'", + extra={"item_id": item_id, "user_id": user_id}, + ) + return + + drink_name = match.group(1).strip() + calories = int(match.group(2)) + + drink = Drink.objects.filter(title=drink_name).first() + if not drink: + drink = Drink.objects.create( + title=drink_name, + calories=calories, + ) + + scrobble_dict = { + "user_id": user_id, + "timestamp": timezone.now(), + "playback_position_seconds": 0, + "source": source, + } + + logger.info( + "[scrobblers] manual drink scrobble request received", + extra={ + "drink_id": drink.id, + "user_id": user_id, + "scrobble_dict": scrobble_dict, + "media_type": Scrobble.MediaType.DRINK, + }, + ) + + return Scrobble.create_or_update(drink, user_id, scrobble_dict) + + def manual_scrobble_discgolf( item_id: str, user_id: int, diff --git a/vrobbler/apps/scrobbles/views.py b/vrobbler/apps/scrobbles/views.py index f171cfa..95558ce 100644 --- a/vrobbler/apps/scrobbles/views.py +++ b/vrobbler/apps/scrobbles/views.py @@ -1164,6 +1164,7 @@ def toggle_favorite(request, media_type, object_id): "Beer": ("drinks", "Beer"), "Wine": ("drinks", "Wine"), "Coffee": ("drinks", "Coffee"), + "Water": ("drinks", "Water"), "Puzzle": ("puzzles", "Puzzle"), "Food": ("foods", "Food"), "Trail": ("trails", "Trail"), diff --git a/vrobbler/templates/base.html b/vrobbler/templates/base.html index d839749..4978d65 100644 --- a/vrobbler/templates/base.html +++ b/vrobbler/templates/base.html @@ -280,6 +280,12 @@ + diff --git a/vrobbler/templates/drinks/drink_detail.html b/vrobbler/templates/drinks/drink_detail.html new file mode 100644 index 0000000..97c5baa --- /dev/null +++ b/vrobbler/templates/drinks/drink_detail.html @@ -0,0 +1,80 @@ +{% extends "base_list.html" %} +{% load mathfilters %} +{% load static %} +{% load naturalduration %} + +{% block title %}{{object.title}}{% endblock %} + +{% block head_extra %} + +{% endblock %} + +{% block lists %} + +
+
+ {% if object.description%} +

{{object.description|safe|linebreaks|truncatewords:160}}

+
+ {% endif %} +

+ +

+
+
+
+

{{scrobbles.count}} scrobbles

+

+ Drink again +

+
+
+
+

Last scrobbles

+
+ + + + + + + + + + {% for scrobble in scrobbles.all|dictsortreversed:"timestamp" %} + + + + + + {% endfor %} + +
DateFormatSize
{{scrobble.local_timestamp}}{{ scrobble.logdata.format_display }} + {% if scrobble.logdata.size_ml %} + {% if request.user.profile.volume_unit == "imperial" %} + {{ scrobble.logdata.size_oz }} oz + {% else %} + {{ scrobble.logdata.size_ml }} mL + {% endif %} + {% endif %} +
+
+
+
+{% endblock %} diff --git a/vrobbler/templates/drinks/drink_list.html b/vrobbler/templates/drinks/drink_list.html new file mode 100644 index 0000000..801c067 --- /dev/null +++ b/vrobbler/templates/drinks/drink_list.html @@ -0,0 +1,23 @@ +{% extends "base_list.html" %} + +{% block title %}Drinks{% endblock %} + +{% block head_extra %} + +{% endblock %} + +{% block lists %} +
+ +
+
+ {% include "_scrobblable_list.html" %} +
+
+
+{% endblock %} diff --git a/vrobbler/templates/drinks/water_detail.html b/vrobbler/templates/drinks/water_detail.html new file mode 100644 index 0000000..c0e67b1 --- /dev/null +++ b/vrobbler/templates/drinks/water_detail.html @@ -0,0 +1,79 @@ +{% extends "base_list.html" %} +{% load static %} + +{% block title %}{{object.title}}{% endblock %} + +{% block head_extra %} + +{% endblock %} + +{% block lists %} + +
+
+ {% if object.description%} +

{{object.description|safe|linebreaks|truncatewords:160}}

+
+ {% endif %} +
+
+
+

{{scrobbles.count}} scrobbles

+

+ Drink again +

+
+
+
+

Last scrobbles

+
+ + + + + + + + + + + + {% for scrobble in scrobbles.all|dictsortreversed:"timestamp" %} + + + + + + + + {% endfor %} + +
DateFormatSizeTemperatureSparkling
{{scrobble.local_timestamp}}{{ scrobble.logdata.format_display }} + {% if scrobble.logdata.size_ml %} + {% if request.user.profile.volume_unit == "imperial" %} + {{ scrobble.logdata.size_oz }} oz + {% else %} + {{ scrobble.logdata.size_ml }} mL + {% endif %} + {% endif %} + {{ scrobble.logdata.temperature|title }}{% if scrobble.logdata.carbonated %}Yes{% elif scrobble.logdata.carbonated == False %}No{% endif %}
+
+
+
+{% endblock %} diff --git a/vrobbler/templates/scrobbles/_scrobble_all_content.html b/vrobbler/templates/scrobbles/_scrobble_all_content.html index f0fe55a..c95873a 100644 --- a/vrobbler/templates/scrobbles/_scrobble_all_content.html +++ b/vrobbler/templates/scrobbles/_scrobble_all_content.html @@ -93,6 +93,8 @@ {{ scrobble.wine.title }} {% elif scrobble.coffee %} {{ scrobble.coffee.title }} + {% elif scrobble.water %} + {{ scrobble.water.title }} {% elif scrobble.web_page %} {{ scrobble.web_page.title }} {% elif scrobble.podcast_episode %}