from __future__ import annotations
from typing import TYPE_CHECKING
from django.contrib.syndication.views import Feed
from django.db.models.query import QuerySet
from django.urls import reverse
from django.utils import timezone
from django.utils.html import format_html
from django.utils.safestring import SafeText
from twitch.models import DropCampaign
from twitch.models import Game
from twitch.models import Organization
from twitch.models import TimeBasedDrop
if TYPE_CHECKING:
import datetime
from django.db.models import Model
from django.db.models import QuerySet
from django.http import HttpRequest
# MARK: /rss/organizations/
class OrganizationFeed(Feed):
"""RSS feed for latest organizations."""
title: str = "TTVDrops Organizations"
link: str = "/organizations/"
description: str = "Latest organizations on TTVDrops"
def items(self) -> list[Organization]:
"""Return the latest 100 organizations."""
return list(Organization.objects.order_by("-updated_at")[:100])
def item_title(self, item: Model) -> SafeText:
"""Return the organization name as the item title."""
return SafeText(getattr(item, "name", str(item)))
def item_description(self, item: Model) -> SafeText:
"""Return a description of the organization."""
return SafeText(f"Organization {getattr(item, 'name', str(item))}")
def item_link(self, item: Model) -> str:
"""Return the link to the organization detail."""
return reverse("twitch:organization_detail", args=[item.pk])
# MARK: /rss/games/
class GameFeed(Feed):
"""RSS feed for latest games."""
title: str = "TTVDrops Games"
link: str = "/games/"
description: str = "Latest games on TTVDrops"
def items(self) -> list[Game]:
"""Return the latest 100 games."""
return list(Game.objects.order_by("-id")[:100])
def item_title(self, item: Model) -> SafeText:
"""Return the game name as the item title (SafeText for RSS)."""
return SafeText(str(item))
def item_description(self, item: Model) -> SafeText:
"""Return a description of the game."""
return SafeText(f"Game {getattr(item, 'display_name', str(item))}")
def item_link(self, item: Model) -> str:
"""Return the link to the game detail."""
return reverse("twitch:game_detail", args=[item.pk])
# MARK: /rss/campaigns/
class DropCampaignFeed(Feed):
"""RSS feed for latest drop campaigns."""
title: str = "Twitch Drop Campaigns"
link: str = "/campaigns/"
description: str = "Latest Twitch drop campaigns"
feed_url: str = "/rss/campaigns/"
feed_copyright: str = "Information wants to be free."
def items(self) -> list[DropCampaign]:
"""Return the latest 100 drop campaigns."""
return list(
DropCampaign.objects.select_related("game").order_by("-added_at")[:100],
)
def item_title(self, item: Model) -> SafeText:
"""Return the campaign name as the item title (SafeText for RSS)."""
game: Game | None = getattr(item, "game", None)
game_name: str = getattr(game, "display_name", str(game)) if game else ""
clean_name: str = getattr(item, "clean_name", str(item))
return SafeText(f"{game_name}: {clean_name}")
def item_description(self, item: Model) -> SafeText: # noqa: PLR0915
"""Return a description of the campaign."""
description: str = ""
image_url: str | None = getattr(item, "image_url", None)
name: str = getattr(item, "name", str(item))
if image_url:
description += format_html(
'
',
image_url,
name,
)
desc_text: str | None = getattr(item, "description", None)
if desc_text:
description += format_html("
{}
", desc_text) start_at: datetime.datetime | None = getattr(item, "start_at", None) end_at: datetime.datetime | None = getattr(item, "end_at", None) if start_at: description += f"Starts: {start_at.strftime('%Y-%m-%d %H:%M %Z')}
" if end_at: description += f"Ends: {end_at.strftime('%Y-%m-%d %H:%M %Z')}
" drops: QuerySet[TimeBasedDrop] | None = getattr( item, "time_based_drops", None, ) if drops: drops_qs: QuerySet[TimeBasedDrop] = drops.select_related().prefetch_related("benefits").all() if drops_qs: description += "| Benefits | ' 'Drop Name | ' 'Requirements | ' 'Period | ' "
|---|---|---|---|
| '
for benefit in drop.benefits.all():
if getattr(benefit, "image_asset_url", None):
description += format_html(
' | "
description += (
f'{getattr(drop, "name", str(drop))} | ' ) requirements: str = "" if getattr(drop, "required_minutes_watched", None): requirements = f"{drop.required_minutes_watched} minutes watched" if getattr(drop, "required_subs", 0) > 0: if requirements: requirements += f" and {drop.required_subs} subscriptions required" else: requirements = f"{drop.required_subs} subscriptions required" description += f'{requirements} | ' period: str = "" start_at = getattr(drop, "start_at", None) end_at = getattr(drop, "end_at", None) if start_at is not None: period += start_at.strftime("%Y-%m-%d %H:%M %Z") if end_at is not None: if period: period += " - " + end_at.strftime( "%Y-%m-%d %H:%M %Z", ) else: period = end_at.strftime("%Y-%m-%d %H:%M %Z") description += f'{period} | ' description += "