9d49a99916
Chrome extension for PokemonCenter monitoring with Discord notifications. Includes Python scripts for Target monitoring. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
184 lines
5.5 KiB
Python
184 lines
5.5 KiB
Python
"""
|
|
Discord webhook notifications for stock alerts
|
|
Sends rich embeds with product info and direct links
|
|
"""
|
|
|
|
import logging
|
|
import requests
|
|
from datetime import datetime
|
|
from typing import Optional
|
|
from config import DISCORD_WEBHOOK_URL
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Colors for different notification types
|
|
COLOR_RESTOCK = 0x00FF00 # Green - item back in stock
|
|
COLOR_NEW_DROP = 0x0099FF # Blue - new product listing
|
|
COLOR_PREORDER = 0xFFAA00 # Orange - pre-order available
|
|
COLOR_ERROR = 0xFF0000 # Red - error notification
|
|
|
|
# Site icons/emojis
|
|
SITE_EMOJIS = {
|
|
"pokemoncenter": "\U0001F7E1", # Yellow circle
|
|
"target": "\U0001F534", # Red circle
|
|
"walmart": "\U0001F535", # Blue circle
|
|
"bestbuy": "\U0001F7E1", # Yellow circle
|
|
}
|
|
|
|
|
|
def send_stock_alert(
|
|
product_name: str,
|
|
product_url: str,
|
|
price: str,
|
|
site: str,
|
|
alert_type: str = "restock",
|
|
image_url: Optional[str] = None,
|
|
):
|
|
"""
|
|
Send a Discord notification for a stock alert
|
|
|
|
Args:
|
|
product_name: Name of the product
|
|
product_url: Direct link to the product
|
|
price: Price string (e.g., "$49.99")
|
|
site: Site name (pokemoncenter, target, etc.)
|
|
alert_type: "restock", "new_drop", or "preorder"
|
|
image_url: Optional product image URL
|
|
"""
|
|
if DISCORD_WEBHOOK_URL == "YOUR_WEBHOOK_URL_HERE":
|
|
logger.error("Discord webhook URL not configured! Update config.py")
|
|
return False
|
|
|
|
# Choose color based on alert type
|
|
if alert_type == "restock":
|
|
color = COLOR_RESTOCK
|
|
title = f"\U0001F6A8 RESTOCK ALERT"
|
|
elif alert_type == "new_drop":
|
|
color = COLOR_NEW_DROP
|
|
title = f"\U0001F195 NEW DROP"
|
|
elif alert_type == "preorder":
|
|
color = COLOR_PREORDER
|
|
title = f"\u23F0 PRE-ORDER AVAILABLE"
|
|
else:
|
|
color = COLOR_RESTOCK
|
|
title = f"\U0001F514 STOCK ALERT"
|
|
|
|
site_emoji = SITE_EMOJIS.get(site.lower(), "\U0001F6D2")
|
|
site_display = site.replace("pokemoncenter", "Pokemon Center").title()
|
|
|
|
# Build the embed
|
|
embed = {
|
|
"title": title,
|
|
"description": f"**{product_name}**",
|
|
"url": product_url,
|
|
"color": color,
|
|
"fields": [
|
|
{"name": "Price", "value": price or "See link", "inline": True},
|
|
{"name": "Store", "value": f"{site_emoji} {site_display}", "inline": True},
|
|
{"name": "Link", "value": f"[\U0001F6D2 BUY NOW]({product_url})", "inline": False},
|
|
],
|
|
"footer": {"text": "Pokemon Stock Monitor"},
|
|
"timestamp": datetime.utcnow().isoformat(),
|
|
}
|
|
|
|
if image_url:
|
|
embed["thumbnail"] = {"url": image_url}
|
|
|
|
payload = {
|
|
"content": "@everyone", # Ping everyone
|
|
"embeds": [embed],
|
|
}
|
|
|
|
try:
|
|
response = requests.post(
|
|
DISCORD_WEBHOOK_URL,
|
|
json=payload,
|
|
timeout=10,
|
|
)
|
|
response.raise_for_status()
|
|
logger.info(f"Discord notification sent for: {product_name}")
|
|
return True
|
|
except requests.exceptions.RequestException as e:
|
|
logger.error(f"Failed to send Discord notification: {e}")
|
|
return False
|
|
|
|
|
|
def send_error_notification(error_message: str, site: str = "Unknown"):
|
|
"""Send an error notification to Discord"""
|
|
if DISCORD_WEBHOOK_URL == "YOUR_WEBHOOK_URL_HERE":
|
|
return False
|
|
|
|
embed = {
|
|
"title": "\u26A0\uFE0F Monitor Error",
|
|
"description": error_message,
|
|
"color": COLOR_ERROR,
|
|
"fields": [{"name": "Site", "value": site, "inline": True}],
|
|
"footer": {"text": "Pokemon Stock Monitor"},
|
|
"timestamp": datetime.utcnow().isoformat(),
|
|
}
|
|
|
|
payload = {"embeds": [embed]}
|
|
|
|
try:
|
|
response = requests.post(DISCORD_WEBHOOK_URL, json=payload, timeout=10)
|
|
response.raise_for_status()
|
|
return True
|
|
except requests.exceptions.RequestException as e:
|
|
logger.error(f"Failed to send error notification: {e}")
|
|
return False
|
|
|
|
|
|
def send_startup_notification():
|
|
"""Send a notification that the monitor has started"""
|
|
if DISCORD_WEBHOOK_URL == "YOUR_WEBHOOK_URL_HERE":
|
|
return False
|
|
|
|
embed = {
|
|
"title": "\u2705 Monitor Started",
|
|
"description": "Pokemon Stock Monitor is now running and watching for restocks!",
|
|
"color": 0x00FF00,
|
|
"footer": {"text": "Pokemon Stock Monitor"},
|
|
"timestamp": datetime.utcnow().isoformat(),
|
|
}
|
|
|
|
payload = {"embeds": [embed]}
|
|
|
|
try:
|
|
response = requests.post(DISCORD_WEBHOOK_URL, json=payload, timeout=10)
|
|
response.raise_for_status()
|
|
return True
|
|
except requests.exceptions.RequestException as e:
|
|
logger.error(f"Failed to send startup notification: {e}")
|
|
return False
|
|
|
|
|
|
def test_webhook():
|
|
"""Test the Discord webhook connection"""
|
|
print("Testing Discord webhook...")
|
|
|
|
if DISCORD_WEBHOOK_URL == "YOUR_WEBHOOK_URL_HERE":
|
|
print("ERROR: Webhook URL not configured!")
|
|
print("Edit config.py and set DISCORD_WEBHOOK_URL")
|
|
return False
|
|
|
|
# Send a test notification
|
|
success = send_stock_alert(
|
|
product_name="Test Product - Pokemon TCG Booster",
|
|
product_url="https://www.pokemoncenter.com/test",
|
|
price="$4.99",
|
|
site="pokemoncenter",
|
|
alert_type="restock",
|
|
)
|
|
|
|
if success:
|
|
print("SUCCESS! Check your Discord channel for the test message.")
|
|
else:
|
|
print("FAILED! Check the webhook URL and try again.")
|
|
|
|
return success
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# Run webhook test
|
|
test_webhook()
|