You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord.py机器人实现Epic商店免费游戏更新自动通知

Epic免费游戏自动推送Discord机器人调整方案

要实现免费游戏更新时自动发通知,核心是把现有手动触发的指令逻辑,改成后台定时轮询+新内容去重校验的模式,不需要用户发送指令,机器人自动检测更新推送,具体调整步骤如下:

  • 首先把拉取Epic免费游戏的逻辑从指令函数里抽离成独立公共方法,脱离Discord指令上下文依赖,方便定时任务直接调用
  • 增加本地持久化记录,保存已经推送过的免费游戏标识(比如游戏ID或者标题),避免重复推送同一款游戏的通知,用本地json文件存储即可,不需要额外搭数据库
  • 用discord.py内置的定时任务扩展做周期轮询,建议轮询间隔设为30~60分钟,Epic免费游戏固定每周更新,轮询太频繁容易触发接口限流
  • 修复原代码的几个逻辑问题:原代码只取列表第一个游戏,多游戏同期限免会漏推;原代码接口区域和商店链接区域不匹配,会导致跳转链接失效;原代码直接捕获所有异常不打印日志,出问题无法排查

调整后可直接运行的参考代码

import discord
from discord.ext import commands, tasks
import requests
import json
import os

bot = commands.Bot(command_prefix="!", intents=discord.Intents.default())
# 配置要推送通知的频道ID,提前在Discord开发者模式下复制
NOTIFY_CHANNEL_ID = 123456789012345678
# 存储已推送游戏记录的本地文件路径
RECORD_FILE_PATH = "epic_free_games_record.json"

def load_pushed_records():
    """读取已经推送过的游戏记录"""
    if not os.path.exists(RECORD_FILE_PATH):
        return []
    with open(RECORD_FILE_PATH, "r", encoding="utf-8") as f:
        return json.load(f)

def save_pushed_records(record_list):
    """保存已推送的游戏记录到本地"""
    with open(RECORD_FILE_PATH, "w", encoding="utf-8") as f:
        json.dump(record_list, f, ensure_ascii=False, indent=2)

def fetch_current_free_games():
    """拉取当前Epic商店的免费游戏列表"""
    ENDPOINT = "https://store-site-backend-static.ak.epicgames.com/freeGamesPromotions?locale=zh-CN&country=CN&allowCountries=CN"
    resp = requests.get(ENDPOINT, timeout=10)
    resp.raise_for_status()
    raw_data = resp.json()
    game_list = raw_data["data"]["Catalog"]["searchStore"]["elements"]
    free_games = []
    for game in game_list:
        # 过滤出当前处于限免期的游戏
        promotions = game.get("promotions", {})
        if promotions and promotions.get("promotionalOffers"):
            # 提取游戏标题、商品页slug用来拼链接
            free_games.append({
                "title": game["title"],
                "slug": game.get("productSlug", "")
            })
    return free_games

@tasks.loop(minutes=60)
async def check_epic_free_games():
    """定时任务:每小时检查一次Epic免费游戏更新"""
    channel = bot.get_channel(NOTIFY_CHANNEL_ID)
    if not channel:
        return
    try:
        current_free = fetch_current_free_games()
        pushed_records = load_pushed_records()
        # 找出还没推送过的新限免游戏
        new_games = [g for g in current_free if g["title"] not in pushed_records]
        if new_games:
            for game in new_games:
                shop_url = f"https://www.epicgames.com/store/zh-CN/product/{game['slug']}"
                await channel.send(f"**{game['title']}** 现在可以在Epic商店免费领取啦!\n领取链接:{shop_url}")
                pushed_records.append(game["title"])
            # 更新本地记录
            save_pushed_records(pushed_records)
    except Exception as e:
        # 打印异常方便排查,不要裸吞错误
        print(f"检查Epic免费游戏出错:{str(e)}")

@bot.event
async def on_ready():
    # 机器人启动后开启定时检查任务
    if not check_epic_free_games.is_running():
        check_epic_free_games.start()
    print(f"机器人已登录:{bot.user}")

# 保留原来的手动查询指令
@bot.command(name='free', aliases=['fr'])
async def free(ctx):
    try:
        current_free = fetch_current_free_games()
        if not current_free:
            await ctx.send("当前没有可领取的免费游戏")
            return
        msg = "当前Epic可免费领取的游戏:\n"
        for game in current_free:
            shop_url = f"https://www.epicgames.com/store/zh-CN/product/{game['slug']}"
            msg += f"- **{game['title']}**:{shop_url}\n"
        await ctx.send(msg)
    except Exception as e:
        await ctx.send(f"查询免费游戏失败:{str(e)}")

# 替换成你自己的机器人Token
bot.run("YOUR_BOT_TOKEN_HERE")

注意事项

  • 第一次运行的时候会把当前所有在限免的游戏都推送一遍,如果不想第一次触发全量推送,可以先手动跑一次fetch_current_free_games把现有游戏标题存到记录文件里
  • 轮询间隔不要低于10分钟,过高的请求频率可能会被Epic接口拦截
  • 如果需要推送到多个频道,修改通知频道配置,遍历多个频道ID发送消息即可

内容的提问来源于stack exchange,提问作者Python Guy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 06:51:38