""" Shared utility functions for the bot. Extracts common logic to avoid duplication across cogs. """ from __future__ import annotations import xml.etree.ElementTree as ET from typing import TYPE_CHECKING import aiohttp import discord if TYPE_CHECKING: from discord.ext import commands # ═══════════════════════════════════════════════════════════════════════════════ # GAMING NEWS & FREE GAMES (shared between fun.py and events.py) # ═══════════════════════════════════════════════════════════════════════════════ async def fetch_gaming_news() -> list[dict[str, str]]: """Fetch latest gaming news from GameSpot RSS feed.""" url = "https://www.gamespot.com/feeds/mashup/" items: list[dict[str, str]] = [] async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=15)) as session: async with session.get(url) as response: text = await response.text() root = ET.fromstring(text) for item in root.findall("./channel/item")[:8]: title = (item.findtext("title") or "").strip() link = (item.findtext("link") or "").strip() pub_date = (item.findtext("pubDate") or "").strip() nid = f"{title}|{pub_date}" if title and link: items.append({"id": nid, "title": title, "link": link, "pub_date": pub_date}) return items async def fetch_free_games() -> list[dict[str, str]]: """Fetch free game offers from GamerPower API with enhanced details.""" url = "https://www.gamerpower.com/api/giveaways?type=game&sort-by=date" items: list[dict[str, str]] = [] async with aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=15)) as session: async with session.get(url) as response: data = await response.json(content_type=None) if not isinstance(data, list): return items allowed_stores = ("epic games store", "steam", "gog") for item in data[:30]: gid = str(item.get("id", "")).strip() title = str(item.get("title", "")).strip() link = str(item.get("open_giveaway_url", "")).strip() platform = str(item.get("platforms", "Unknown")).strip() game_type = str(item.get("type", "Game")).strip() or "Game" image = str(item.get("thumbnail", "")).strip() end_date = str(item.get("end_date", "N/A")).strip() original_price = str(item.get("worth", "N/A")).strip() or "N/A" description = str(item.get("description", "")).strip() or "Claim this free game now!" platform_l = platform.lower() if gid and title and link and any(store in platform_l for store in allowed_stores): items.append({ "id": gid, "title": title, "link": link, "platform": platform, "game_type": game_type, "image": image, "end_date": end_date, "original_price": original_price, "description": description[:200], }) if len(items) >= 12: break return items def store_icon(platform: str) -> str: """Get store icon URL for a platform name.""" platform_l = (platform or "").lower() if "epic" in platform_l: return "https://upload.wikimedia.org/wikipedia/commons/3/31/Epic_Games_logo.svg" if "steam" in platform_l: return "https://upload.wikimedia.org/wikipedia/commons/8/83/Steam_icon_logo.svg" if "gog" in platform_l: return "https://upload.wikimedia.org/wikipedia/commons/7/7f/GOG.com_logo.svg" return "https://upload.wikimedia.org/wikipedia/commons/5/59/Empty.png" # ═══════════════════════════════════════════════════════════════════════════════ # FREE GAME CLAIM VIEW (shared between fun.py and events.py) # ═══════════════════════════════════════════════════════════════════════════════ class FreeGameClaimView(discord.ui.View): """Enhanced view with claim and currency buttons for free games.""" def __init__(self, url: str, game_id: str = "") -> None: super().__init__(timeout=None) claim_btn = discord.ui.Button(label="🎮 Claim Game", style=discord.ButtonStyle.link, url=url) self.add_item(claim_btn) if game_id: currency_btn = discord.ui.Button(label="💰 Use Currency", style=discord.ButtonStyle.primary, custom_id=f"freegame:currency:{game_id}") self.add_item(currency_btn)