Add /emotes/
This commit is contained in:
parent
2b0b71cb08
commit
b8df95e317
4 changed files with 61 additions and 9 deletions
|
|
@ -162,6 +162,7 @@
|
||||||
<a href="{% url 'twitch:channel_list' %}">Channels</a> |
|
<a href="{% url 'twitch:channel_list' %}">Channels</a> |
|
||||||
<a href="{% url 'twitch:docs_rss' %}">RSS</a> |
|
<a href="{% url 'twitch:docs_rss' %}">RSS</a> |
|
||||||
<a href="{% url 'twitch:debug' %}">Debug</a> |
|
<a href="{% url 'twitch:debug' %}">Debug</a> |
|
||||||
|
<a href="{% url 'twitch:emote_gallery' %}">Emotes</a>
|
||||||
<form action="{% url 'twitch:search' %}"
|
<form action="{% url 'twitch:search' %}"
|
||||||
method="get"
|
method="get"
|
||||||
style="display: inline">
|
style="display: inline">
|
||||||
|
|
|
||||||
14
templates/twitch/emote_gallery.html
Normal file
14
templates/twitch/emote_gallery.html
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% block title %}Emotes{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<h1>Emotes</h1>
|
||||||
|
<div class="emote-gallery" style="display: flex; flex-wrap: wrap; gap: 1.5rem; justify-content: flex-start;">
|
||||||
|
{% for emote in emotes %}
|
||||||
|
<a href="{% url 'twitch:campaign_detail' emote.campaign.twitch_id %}" title="{{ emote.campaign.name }}" style="display: inline-block;">
|
||||||
|
<img src="{{ emote.image_url }}" alt="Emote" style="max-width: 96px; max-height: 96px; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.12); padding: 4px;" loading="lazy" />
|
||||||
|
</a>
|
||||||
|
{% empty %}
|
||||||
|
<p>No drop campaigns with emotes found.</p>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
@ -18,21 +18,22 @@ app_name = "twitch"
|
||||||
|
|
||||||
urlpatterns: list[URLPattern] = [
|
urlpatterns: list[URLPattern] = [
|
||||||
path("", views.dashboard, name="dashboard"),
|
path("", views.dashboard, name="dashboard"),
|
||||||
path("search/", views.search_view, name="search"),
|
|
||||||
path("debug/", views.debug_view, name="debug"),
|
|
||||||
path("campaigns/", views.drop_campaign_list_view, name="campaign_list"),
|
path("campaigns/", views.drop_campaign_list_view, name="campaign_list"),
|
||||||
path("campaigns/<str:twitch_id>/", views.drop_campaign_detail_view, name="campaign_detail"),
|
path("campaigns/<str:twitch_id>/", views.drop_campaign_detail_view, name="campaign_detail"),
|
||||||
path("games/", views.GamesGridView.as_view(), name="game_list"),
|
|
||||||
path("games/list/", views.GamesListView.as_view(), name="game_list_simple"),
|
|
||||||
path("games/<str:twitch_id>/", views.GameDetailView.as_view(), name="game_detail"),
|
|
||||||
path("organizations/", views.org_list_view, name="org_list"),
|
|
||||||
path("organizations/<str:twitch_id>/", views.organization_detail_view, name="organization_detail"),
|
|
||||||
path("channels/", views.ChannelListView.as_view(), name="channel_list"),
|
path("channels/", views.ChannelListView.as_view(), name="channel_list"),
|
||||||
path("channels/<str:twitch_id>/", views.ChannelDetailView.as_view(), name="channel_detail"),
|
path("channels/<str:twitch_id>/", views.ChannelDetailView.as_view(), name="channel_detail"),
|
||||||
path("rss/organizations/", OrganizationFeed(), name="organization_feed"),
|
path("debug/", views.debug_view, name="debug"),
|
||||||
path("rss/organizations/<str:twitch_id>/campaigns/", OrganizationCampaignFeed(), name="organization_campaign_feed"),
|
path("docs/rss/", views.docs_rss_view, name="docs_rss"),
|
||||||
|
path("emotes/", views.emote_gallery_view, name="emote_gallery"),
|
||||||
|
path("games/", views.GamesGridView.as_view(), name="game_list"),
|
||||||
|
path("games/<str:twitch_id>/", views.GameDetailView.as_view(), name="game_detail"),
|
||||||
|
path("games/list/", views.GamesListView.as_view(), name="game_list_simple"),
|
||||||
|
path("organizations/", views.org_list_view, name="org_list"),
|
||||||
|
path("organizations/<str:twitch_id>/", views.organization_detail_view, name="organization_detail"),
|
||||||
|
path("rss/campaigns/", DropCampaignFeed(), name="campaign_feed"),
|
||||||
path("rss/games/", GameFeed(), name="game_feed"),
|
path("rss/games/", GameFeed(), name="game_feed"),
|
||||||
path("rss/games/<str:twitch_id>/campaigns/", GameCampaignFeed(), name="game_campaign_feed"),
|
path("rss/games/<str:twitch_id>/campaigns/", GameCampaignFeed(), name="game_campaign_feed"),
|
||||||
path("rss/campaigns/", DropCampaignFeed(), name="campaign_feed"),
|
path("rss/organizations/", OrganizationFeed(), name="organization_feed"),
|
||||||
path("docs/rss/", views.docs_rss_view, name="docs_rss"),
|
path("rss/organizations/<str:twitch_id>/campaigns/", OrganizationCampaignFeed(), name="organization_campaign_feed"),
|
||||||
|
path("search/", views.search_view, name="search"),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,42 @@ MIN_QUERY_LENGTH_FOR_FTS = 3
|
||||||
MIN_SEARCH_RANK = 0.05
|
MIN_SEARCH_RANK = 0.05
|
||||||
|
|
||||||
|
|
||||||
|
def emote_gallery_view(request: HttpRequest) -> HttpResponse:
|
||||||
|
"""View to display all emote images (distribution_type='EMOTE'), clickable to their campaign.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request: The HTTP request.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
HttpResponse: The rendered emote gallery page.
|
||||||
|
"""
|
||||||
|
emote_benefits: QuerySet[DropBenefit, DropBenefit] = (
|
||||||
|
DropBenefit.objects
|
||||||
|
.filter(distribution_type="EMOTE")
|
||||||
|
.select_related()
|
||||||
|
.prefetch_related(
|
||||||
|
Prefetch(
|
||||||
|
"drops",
|
||||||
|
queryset=TimeBasedDrop.objects.select_related("campaign"),
|
||||||
|
to_attr="_emote_drops",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
emotes: list[dict[str, str | DropCampaign]] = []
|
||||||
|
for benefit in emote_benefits:
|
||||||
|
# Find the first drop with a campaign for this benefit
|
||||||
|
drop: TimeBasedDrop | None = next((d for d in getattr(benefit, "_emote_drops", []) if d.campaign), None)
|
||||||
|
if drop and drop.campaign:
|
||||||
|
emotes.append({
|
||||||
|
"image_url": benefit.image_best_url,
|
||||||
|
"campaign": drop.campaign,
|
||||||
|
})
|
||||||
|
|
||||||
|
context: dict[str, list[dict[str, Any]]] = {"emotes": emotes}
|
||||||
|
return render(request, "twitch/emote_gallery.html", context)
|
||||||
|
|
||||||
|
|
||||||
# MARK: /search/
|
# MARK: /search/
|
||||||
def search_view(request: HttpRequest) -> HttpResponse:
|
def search_view(request: HttpRequest) -> HttpResponse:
|
||||||
"""Search view for all models.
|
"""Search view for all models.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue