This commit has no recorded session.
diff
commit c7339fbe312a2113360a111191283d28e44b7c90Author: Colin Powell <colin@unbl.ink>Date: Sun Jun 7 11:06:30 2026 -0400 [templates] Clean up how str and subtitles work@@ -86,7 +86,7 @@ fetching and simple saving. **** Bookmarklet *** Metadata sources **** Scraper-* Backlog [1/13] :vrobbler:project:personal:+* Backlog [2/14] :vrobbler:project:personal: ** TODO [#C] Create small utility to clean up tracks scrobbled with wonky playback times :vrobbler:personal:bug:music:scrobbles: :PROPERTIES: :ID: 702462cf-d54b-48c6-8a7c-78b8de751deb@@ -498,6 +498,19 @@ 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] Show team or player images on sport detail and scrobble detail :sports:templates:+:PROPERTIES:+:ID: 68c17383-ee6e-4b5f-b3f5-1b637a0a3ea8+:END:++*** Description ++On the sport event detail page, we should show the images of the teams or+players invovled.++Also, those images for the sport event should be shown on the scrobble detail+page for sport event scrobble details.+ ** DONE [#B] Add fix_metadta method to Video instances :videos:metadata: :PROPERTIES: :ID: 9df5404d-1b60-4eee-b7cf-1f7e6dfade65@@ -61,9 +61,7 @@ class BirdSightingLogData(BaseLogData, WithPeopleLogData): @cached_property def bird_list(self) -> str: if self.birds:- return ", ".join(- [BirdSightingEntry(**b).__str__() for b in self.birds]- )+ return ", ".join([BirdSightingEntry(**b).__str__() for b in self.birds]) return "" def as_html(self) -> str:@@ -80,9 +78,7 @@ class BirdSightingLogData(BaseLogData, WithPeopleLogData): ) if self.area:- html_parts.append(- f'<div class="birding-area">Area: {self.area}</div>'- )+ html_parts.append(f'<div class="birding-area">Area: {self.area}</div>') if self.party_size: html_parts.append(@@ -105,9 +101,7 @@ class BirdSightingLogData(BaseLogData, WithPeopleLogData): ) if self.guide:- html_parts.append(- f'<div class="birding-guide">Guide: {self.guide}</div>'- )+ html_parts.append(f'<div class="birding-guide">Guide: {self.guide}</div>') if self.duration_minutes: html_parts.append(@@ -183,9 +177,7 @@ class Bird(TimeStampedModel): class BirdingLocation(ScrobblableMixin): description = models.TextField(**BNULL)- geo_location = models.ForeignKey(- GeoLocation, **BNULL, on_delete=models.DO_NOTHING- )+ geo_location = models.ForeignKey(GeoLocation, **BNULL, on_delete=models.DO_NOTHING) ebird_hotspot_id = models.CharField(max_length=255, **BNULL) def get_absolute_url(self):@@ -193,7 +185,7 @@ class BirdingLocation(ScrobblableMixin): @property def subtitle(self):- return ""+ return self.geo_location @property def strings(self) -> ScrobblableConstants:@@ -269,9 +261,7 @@ class BirdingCSVImport(TimeStampedModel): self.save(update_fields=["process_log", "process_count"]) return for count, scrobble in enumerate(scrobbles):- scrobble_str = (- f"{scrobble.id}\t{scrobble.timestamp}\t{scrobble.media_obj}"- )+ scrobble_str = f"{scrobble.id}\t{scrobble.timestamp}\t{scrobble.media_obj}" log_line = f"{scrobble_str}" if count > 0: log_line = "\n" + log_line@@ -266,8 +266,9 @@ class BoardGame(ScrobblableMixin): "self", **BNULL, on_delete=models.DO_NOTHING ) - def __str__(self):- return self.title+ @property+ def subtitle(self) -> str:+ return self.publisher def get_absolute_url(self): return reverse("boardgames:boardgame_detail", kwargs={"slug": self.uuid})@@ -173,11 +173,7 @@ class Book(LongPlayScrobblableMixin): genre = TaggableManager(through=ObjectWithGenres, blank=True, verbose_name="Genre") def __str__(self) -> str:- if self.issue_number and "Issue" not in str(self.title):- return f"{self.title} - Issue {self.issue_number}"- if self.volume_number and "Volume" not in str(self.title):- return f"{self.title} - Volume {self.volume_number}"- return f"{self.title}"+ return f"{self.title} - {self.subtitle}" def save(self, *args, **kwargs): if self.pages:@@ -188,7 +184,12 @@ class Book(LongPlayScrobblableMixin): @property def subtitle(self):- return f" by {self.author}"+ subtitle = self.author+ if self.issue_number and "Issue" not in str(self.title):+ subtitle += " - Issue {self.issue_number}"+ if self.volume_number and "Volume" not in str(self.title):+ subtitle += " - Volume {self.volume_number}"+ return subtitle @property def strings(self) -> ScrobblableConstants:@@ -20,6 +20,7 @@ class ScrobbleInline(admin.TabularInline): extra = 0 raw_id_fields = ( "video",+ "channel", "podcast_episode", "track", "video_game",@@ -30,6 +31,7 @@ class ScrobbleInline(admin.TabularInline): "board_game", "geo_location", "task",+ "puzzle", "mood", "brick_set", "trail",@@ -59,47 +61,38 @@ class ImportBaseAdmin(admin.ModelAdmin): @admin.register(AudioScrobblerTSVImport)-class AudioScrobblerTSVImportAdmin(ImportBaseAdmin):- ...+class AudioScrobblerTSVImportAdmin(ImportBaseAdmin): ... @admin.register(LastFmImport)-class LastFmImportAdmin(ImportBaseAdmin):- ...+class LastFmImportAdmin(ImportBaseAdmin): ... @admin.register(KoReaderImport)-class KoReaderImportAdmin(ImportBaseAdmin):- ...+class KoReaderImportAdmin(ImportBaseAdmin): ... @admin.register(RetroarchImport)-class RetroarchImportAdmin(ImportBaseAdmin):- ...+class RetroarchImportAdmin(ImportBaseAdmin): ... -class RetroarchImportAdmin(ImportBaseAdmin):- ...+class RetroarchImportAdmin(ImportBaseAdmin): ... @admin.register(BGStatsImport)-class BGStatsImportAdmin(ImportBaseAdmin):- ...+class BGStatsImportAdmin(ImportBaseAdmin): ... @admin.register(EBirdCSVImport)-class EBirdCSVImportAdmin(ImportBaseAdmin):- ...+class EBirdCSVImportAdmin(ImportBaseAdmin): ... @admin.register(ScaleCSVImport)-class ScaleCSVImportAdmin(ImportBaseAdmin):- ...+class ScaleCSVImportAdmin(ImportBaseAdmin): ... @admin.register(TrailGPXImport)-class TrailGPXImportAdmin(ImportBaseAdmin):- ...+class TrailGPXImportAdmin(ImportBaseAdmin): ... @admin.register(Genre)@@ -65,6 +65,9 @@ class ScrobblableMixin(TimeStampedModel): class Meta: abstract = True + def __str__(self) -> str:+ return f"{self.title} - {self.subtitle}"+ @property def run_time_seconds(self) -> int: run_time = 900@@ -184,7 +184,7 @@ class ScrobbleableDetailView(ChartContextMixin, DetailView): def get_context_data(self, **kwargs): context_data = super().get_context_data(**kwargs) scrobbles = []- if not self.request.user.is_anonymous:+ if not self.request.user.is_anonymous and hasattr(self.object, "scrobble_set"): scrobbles = self.object.scrobble_set.filter( user=self.request.user ).order_by("-timestamp")@@ -439,8 +439,7 @@ class ScrobbleListView(LoginRequiredMixin, ListView): full_qs = getattr(self, "_full_queryset", None) if full_qs is not None and getattr(self, "tag_list", []): total = (- full_qs.aggregate(total=Sum("playback_position_seconds"))["total"]- or 0+ full_qs.aggregate(total=Sum("playback_position_seconds"))["total"] or 0 ) ctx["total_time_seconds"] = total return ctx@@ -1245,8 +1244,7 @@ class ScrobbleDetailView(DetailView): 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+ (s.log or {}).get("raw_data", {}).get("mopidy_uri") for s in scrobbles ) else: context["has_mopidy_uri"] = False@@ -123,17 +123,17 @@ class SportEvent(ScrobblableMixin): super(SportEvent, self).save(*args, **kwargs) def __str__(self) -> str:- league = self.league- if self.league and self.league.abbreviation_str:- league = self.league.abbreviation_str- return f"{self.title} - {league}"+ return f"{self.title} - {self.subtitle}" def get_absolute_url(self): return reverse("sports:event_detail", kwargs={"slug": self.uuid}) @property def subtitle(self) -> str:- return self.comp_str+ league = self.league+ if self.league and self.league.abbreviation_str:+ league = self.league.abbreviation_str+ return f"{league} {self.get_event_type_display()}" @property def comp_str(self) -> str:@@ -163,12 +163,9 @@ class VideoGame(LongPlayScrobblableMixin): platforms = models.ManyToManyField(VideoGamePlatform) retroarch_name = models.CharField(max_length=255, **BNULL) - def __str__(self):- return self.title- @property def subtitle(self):- return f" On {self.platforms.first()}"+ return f"{self.platforms.first()}" @property def strings(self) -> ScrobblableConstants:@@ -50,7 +50,11 @@ <h1 class="d-flex align-items-center gap-2"> {% if object.media_type == "Video" %}๐ฌ{% elif object.media_type == "Track" %}๐ต{% elif object.media_type == "PodcastEpisode" %}๐๏ธ{% elif object.media_type == "SportEvent" %}โฝ{% elif object.media_type == "Book" %}๐{% elif object.media_type == "Paper" %}๐{% elif object.media_type == "VideoGame" %}๐ฎ{% elif object.media_type == "BoardGame" %}๐ฒ{% elif object.media_type == "GeoLocation" %}๐{% elif object.media_type == "Trail" %}๐ฅพ{% elif object.media_type == "Beer" %}๐บ{% elif object.media_type == "Puzzle" %}๐งฉ{% elif object.media_type == "Food" %}๐{% elif object.media_type == "Task" %}โ {% elif object.media_type == "WebPage" %}๐{% elif object.media_type == "LifeEvent" %}๐{% elif object.media_type == "Mood" %}๐{% elif object.media_type == "BrickSet" %}๐งฑ{% elif object.media_type == "Channel" %}๐บ{% endif %}-{% if object.media_obj.get_absolute_url %}<a href="{{ object.media_obj.get_absolute_url }}">{% endif %}{{ object.media_obj }}{% if object.media_obj.get_absolute_url %}</a>{% endif %}+{% if object.media_obj.get_absolute_url %}+ <a href="{{ object.media_obj.get_absolute_url }}">{% endif %}+ {{ object.media_obj.title }}+ {% if object.media_obj.get_absolute_url %}</a>+ {% endif %} {% if user.is_authenticated and object.media_obj %} <button id="favorite-btn" data-url="{% url 'scrobbles:toggle-favorite' object.media_type object.media_obj.id %}"@@ -62,7 +66,15 @@ </button> {% endif %} </h1>+<h2>{{ object.media_obj.subtitle }}</h2>+<p>+{% if object.media_type == "SportEvent" %}+{% for team in object.media_obj.teams.all %}+<img src="{{team.logo.url}}" width=150 />+{% endfor %}+{% endif %} {% if object.media_type == "Task" and object.logdata.title %}+ </p> <h2>{{ object.logdata.title }}</h2> {% endif %} <h3 class="text-muted">{{ object.local_timestamp }}</h3>@@ -1,13 +1,16 @@ {% extends "base_detail.html" %} -{% block title %}{{object}}{% endblock %}+{% block title %}{{object.title}}{% endblock %} {% block details %}-<h2>{{object.subtitle}}</h2>+<h2>{{object.league}} {{object.get_event_type_display}}</h2> <div class="row">- <h2>{{object.tv_series}}</h2> <div class="col-md">+ {% for team in object.teams.all %}+ <img src="{{team.logo.url}}" width=150 />+ {% endfor %}+ <hr /> <h3>Last scrobbles</h3> <div class="table-responsive"> <table class="table table-striped table-sm">