Compare commits
2 commits
768d986556
...
0101a82ddf
| Author | SHA1 | Date | |
|---|---|---|---|
|
0101a82ddf |
|||
|
719e5d416b |
6 changed files with 54 additions and 59 deletions
|
|
@ -8,26 +8,26 @@
|
|||
{% if badge_sets %}
|
||||
{% for data in badge_data %}
|
||||
<h2>
|
||||
<a href="{% url 'twitch:badge_set_detail' set_id=data.set.set_id %}">[{{ data.set.set_id }}]</a>
|
||||
<a href="{% url 'twitch:badge_set_detail' set_id=data.set.set_id %}">{{ data.set.set_id }}</a>
|
||||
</h2>
|
||||
{% for badge in data.badges %}
|
||||
<table>
|
||||
{% for badge in data.badges %}
|
||||
<tr>
|
||||
<td style="width: 40px;">
|
||||
<a href="{% url 'twitch:badge_set_detail' set_id=data.set.set_id %}">
|
||||
{% picture badge.image_url_4x alt=badge.title width=36 height=36 %}
|
||||
{% picture badge.image_url_4x alt=badge.title width=36 %}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<strong>{{ badge.title }}</strong>
|
||||
{% if badge.description != badge.title %}
|
||||
<br>
|
||||
<br />
|
||||
{{ badge.description }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
{% endfor %}
|
||||
</table>
|
||||
<br />
|
||||
{% if data.badges|length > 1 %}<small>versions: {{ data.badges|length }}</small>{% endif %}
|
||||
{% endfor %}
|
||||
|
|
|
|||
|
|
@ -6,25 +6,7 @@
|
|||
{% block content %}
|
||||
<h1>{{ badge_set.set_id }}</h1>
|
||||
{% if badges %}
|
||||
<h2>
|
||||
{{ badges.count }}
|
||||
{% if badges.count == 1 %}
|
||||
version
|
||||
{% else %}
|
||||
versions
|
||||
{% endif %}
|
||||
</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th></th>
|
||||
<th>Title</th>
|
||||
<th>Description</th>
|
||||
<th>Images</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for badge in badges %}
|
||||
<tr>
|
||||
|
|
@ -32,7 +14,7 @@
|
|||
<code>{{ badge.badge_id }}</code>
|
||||
</td>
|
||||
<td>
|
||||
{% picture badge.image_url_4x alt=badge.title width=72 height=72 style="width: 72px !important; height: 72px !important; object-fit: contain" %}
|
||||
{% picture badge.image_url_4x alt=badge.title width=72 style="width: 72px !important; height: 72px !important; object-fit: contain" %}
|
||||
</td>
|
||||
<td>{{ badge.title }}</td>
|
||||
<td>{{ badge.description }}</td>
|
||||
|
|
|
|||
|
|
@ -16,19 +16,13 @@
|
|||
{% endblock extra_head %}
|
||||
{% block content %}
|
||||
<main>
|
||||
<h1>Twitch Drops</h1>
|
||||
<pre>
|
||||
Latest drops are shown first within each game. Click on a campaign or game title to see more details.
|
||||
Hover over the end time to see the exact date and time.
|
||||
</pre>
|
||||
<h1>Active Twitch Drops Campaigns</h1>
|
||||
<!-- RSS Feeds -->
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<div>
|
||||
<a href="{% url 'twitch:campaign_feed' %}"
|
||||
style="margin-right: 1rem"
|
||||
title="RSS feed for all campaigns">RSS feed for campaigns</a>
|
||||
|
|
||||
title="RSS feed for all campaigns">[rss - all campaigns]</a>
|
||||
<a href="{% url 'twitch:campaign_feed_atom' %}"
|
||||
title="Atom feed for campaigns">Atom feed for campaigns</a>
|
||||
title="Atom feed for campaigns">[atom - all campaigns]</a>
|
||||
</div>
|
||||
{% if campaigns_by_game %}
|
||||
{% for game_id, game_data in campaigns_by_game.items %}
|
||||
|
|
|
|||
|
|
@ -21,14 +21,6 @@
|
|||
{{ game.display_name }}
|
||||
{% if game.display_name != game.name and game.name %}<small>({{ game.name }})</small>{% endif %}
|
||||
</h1>
|
||||
<!-- RSS Feeds -->
|
||||
<div>
|
||||
<a href="{% url 'twitch:game_campaign_feed' game.twitch_id %}"
|
||||
title="RSS feed for {{ game.display_name }} campaigns">RSS feed for {{ game.display_name }} campaigns</a>
|
||||
|
|
||||
<a href="{% url 'twitch:game_campaign_feed_atom' game.twitch_id %}"
|
||||
title="Atom feed for {{ game.display_name }} campaigns">Atom feed for {{ game.display_name }} campaigns</a>
|
||||
</div>
|
||||
<!-- Game image -->
|
||||
{% if game.box_art_best_url %}
|
||||
{% picture game.box_art_best_url alt=game.name width=160 %}
|
||||
|
|
@ -43,6 +35,13 @@
|
|||
{% endfor %}
|
||||
</small>
|
||||
{% endif %}
|
||||
<!-- RSS Feeds -->
|
||||
<div>
|
||||
<a href="{% url 'twitch:game_campaign_feed' game.twitch_id %}"
|
||||
title="RSS feed for {{ game.display_name }} campaigns">[rss - {{ game.display_name|default:game.name|lower }}]</a>
|
||||
<a href="{% url 'twitch:game_campaign_feed_atom' game.twitch_id %}"
|
||||
title="Atom feed for {{ game.display_name }} campaigns">[atom - {{ game.display_name|default:game.name|lower }}]</a>
|
||||
</div>
|
||||
{% if active_campaigns %}
|
||||
<h5 id="active-campaigns-header">Active Campaigns</h5>
|
||||
<table id="active-campaigns-table">
|
||||
|
|
|
|||
|
|
@ -3,26 +3,21 @@
|
|||
Organizations
|
||||
{% endblock title %}
|
||||
{% block content %}
|
||||
<h1 id="page-title">Organizations</h1>
|
||||
<!-- RSS Feeds -->
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<h1>Organizations</h1>
|
||||
<div>
|
||||
<a href="{% url 'twitch:organization_feed' %}"
|
||||
style="margin-right: 1rem"
|
||||
title="RSS feed for all organizations">RSS feed for organizations</a>
|
||||
title="RSS feed for all organizations">[rss]</a>
|
||||
<a href="{% url 'twitch:organization_feed_atom' %}"
|
||||
title="Atom feed for all organizations">[atom]</a>
|
||||
</div>
|
||||
<!-- Export Options -->
|
||||
<div style="margin-bottom: 1rem; display: flex; gap: 1rem;">
|
||||
<a href="{% url 'twitch:export_organizations_csv' %}"
|
||||
title="Export all organizations as CSV">[csv]</a>
|
||||
<a href="{% url 'twitch:export_organizations_json' %}"
|
||||
title="Export all organizations as JSON">[json]</a>
|
||||
</div>
|
||||
{% if orgs %}
|
||||
<ul id="org-list">
|
||||
<ul>
|
||||
{% for organization in orgs %}
|
||||
<li id="org-{{ organization.twitch_id }}">
|
||||
<li>
|
||||
<a href="{% url 'twitch:organization_detail' organization.twitch_id %}">{{ organization.name }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
|
|
|
|||
|
|
@ -17,12 +17,14 @@ from django.core.paginator import PageNotAnInteger
|
|||
from django.core.paginator import Paginator
|
||||
from django.core.serializers import serialize
|
||||
from django.db import connection
|
||||
from django.db.models import Case
|
||||
from django.db.models import Count
|
||||
from django.db.models import Exists
|
||||
from django.db.models import F
|
||||
from django.db.models import OuterRef
|
||||
from django.db.models import Prefetch
|
||||
from django.db.models import Q
|
||||
from django.db.models import When
|
||||
from django.db.models.functions import Trim
|
||||
from django.db.models.query import QuerySet
|
||||
from django.http import FileResponse
|
||||
|
|
@ -64,10 +66,9 @@ if TYPE_CHECKING:
|
|||
from pathlib import Path
|
||||
|
||||
from debug_toolbar.utils import QueryDict
|
||||
from django.db.models.query import QuerySet
|
||||
from django.db.models import QuerySet
|
||||
from django.http import HttpRequest
|
||||
|
||||
|
||||
logger: logging.Logger = logging.getLogger("ttvdrops.views")
|
||||
|
||||
MIN_QUERY_LENGTH_FOR_FTS = 3
|
||||
|
|
@ -2234,7 +2235,31 @@ def badge_set_detail_view(request: HttpRequest, set_id: str) -> HttpResponse:
|
|||
msg = "No badge set found matching the query"
|
||||
raise Http404(msg) from exc
|
||||
|
||||
badges: QuerySet[ChatBadge] = badge_set.badges.all() # pyright: ignore[reportAttributeAccessIssue]
|
||||
def get_sorted_badges(badge_set: ChatBadgeSet) -> QuerySet[ChatBadge]:
|
||||
badges = badge_set.badges.all() # pyright: ignore[reportAttributeAccessIssue]
|
||||
|
||||
def sort_badges(badge: ChatBadge) -> tuple:
|
||||
"""Sort badges by badge_id, treating numeric IDs as integers.
|
||||
|
||||
Args:
|
||||
badge: The ChatBadge to sort.
|
||||
|
||||
Returns:
|
||||
A tuple used for sorting, where numeric badge_ids are sorted as integers.
|
||||
"""
|
||||
try:
|
||||
return (int(badge.badge_id),)
|
||||
except ValueError:
|
||||
return (badge.badge_id,)
|
||||
|
||||
sorted_badges: list[ChatBadge] = sorted(badges, key=sort_badges)
|
||||
badge_ids: list[int] = [badge.pk for badge in sorted_badges]
|
||||
preserved_order = Case(
|
||||
*[When(pk=pk, then=pos) for pos, pk in enumerate(badge_ids)],
|
||||
)
|
||||
return ChatBadge.objects.filter(pk__in=badge_ids).order_by(preserved_order)
|
||||
|
||||
badges = get_sorted_badges(badge_set)
|
||||
|
||||
# Attach award_campaigns attribute to each badge for template use
|
||||
for badge in badges:
|
||||
|
|
@ -2255,7 +2280,7 @@ def badge_set_detail_view(request: HttpRequest, set_id: str) -> HttpResponse:
|
|||
)
|
||||
set_data: list[dict[str, Any]] = json.loads(serialized_set)
|
||||
|
||||
if badges.exists():
|
||||
if badges:
|
||||
serialized_badges: str = serialize(
|
||||
"json",
|
||||
badges,
|
||||
|
|
@ -2276,7 +2301,7 @@ def badge_set_detail_view(request: HttpRequest, set_id: str) -> HttpResponse:
|
|||
set_data[0]["fields"]["badges"] = badges_data
|
||||
|
||||
badge_set_name: str = badge_set.set_id
|
||||
badge_set_description: str = f"Twitch chat badge set {badge_set_name} with {badges.count()} badge{'s' if badges.count() != 1 else ''} awarded through drop campaigns."
|
||||
badge_set_description: str = f"Twitch chat badge set {badge_set_name} with {len(badges)} badge{'s' if len(badges) != 1 else ''} awarded through drop campaigns."
|
||||
|
||||
badge_schema: dict[str, Any] = {
|
||||
"@context": "https://schema.org",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue