1.购买服务器阿里云:服务器购买地址https://t.aliyun.com/U/W9mv4W若失效,可用地址
阿里云:
服务器购买地址
https://t.aliyun.com/U/W9mv4W若失效,可用地址
https://www.aliyun.com/minisite/goods?source=5176.29345612&userCode=49hts92d腾讯云:
https://curl.qcloud.com/wJpWmSfU若失效,可用地址
https://cloud.tencent.com/act/cps/redirect?redirect=2446&cps_key=ad201ee2ef3b771157f72ee5464b1fea&from=console华为云
https://activity.huaweicloud.com/cps.html?fromacct=64b5cf7cc11b4840bb4ed2ea0b2f4468&utm_source=V1g3MDY4NTY=&utm_medium=cps&utm_campaign=2019052.部署教程
3.代码如下
//Epic免费游戏领取//cron: 30 7 * * 5const axios = require('axios');// 从环境变量获取Bark Keyconst BARK_KEY = process.env.BARK_PUSH || process.env.BARK_KEY;if (!BARK_KEY) {console.error(' 未找到BARK_PUSH环境变量,请先在青龙面板的配置文件config.sh中配置变量export BARK_PUSH=""');process.exit(1);}const BARK_API = `https://api.day.app/${BARK_KEY}`;async function getEpicFreeGames() {try {const response = await axios.get('https://store.epicgames.com/freeGamesPromotions',{params: {locale: 'zh-CN',country: 'CN',allowCountries: 'CN'},timeout: 10000});const elements = response.data?.data?.Catalog?.searchStore?.elements || [];const freeGames = [];const now = new Date();elements.forEach(game => {if (!game.promotions) return;// 检查促销信息const promotionalOffers = game.promotions.promotionalOffers || [];const upcomingOffers = game.promotions.upcomingPromotionalOffers || [];// 查找有效的免费促销let isFree = false;let endDate = null;// 检查当前促销for (const offerSet of promotionalOffers) {for (const offer of offerSet.promotionalOffers) {if (offer.discountSetting.discountPercentage === 0) {const startDate = new Date(offer.startDate);const endDateObj = new Date(offer.endDate);if (now >= startDate && now <= endDateObj) {isFree = true;endDate = endDateObj;break;}}}if (isFree) break;}// 检查即将开始的促销if (!isFree) {for (const offerSet of upcomingOffers) {for (const offer of offerSet.promotionalOffers) {if (offer.discountSetting.discountPercentage === 0) {const startDate = new Date(offer.startDate);const endDateObj = new Date(offer.endDate);// 如果即将在24小时内开始的免费游戏也显示if (startDate.getTime() - now.getTime() < 24 * 60 * 60 * 1000) {isFree = true;endDate = endDateObj;break;}}}if (isFree) break;}}// 添加到免费游戏列表if (isFree) {// 获取游戏图片let imageUrl = '';const keyImages = game.keyImages || [];const offerImage = keyImages.find(img => img.type === 'OfferImageWide');const thumbnail = keyImages.find(img => img.type === 'Thumbnail');if (offerImage) imageUrl = offerImage.url;else if (thumbnail) imageUrl = thumbnail.url;// 修复游戏链接问题 - 使用更可靠的链接格式let gameUrl = '';// 方法1: 尝试从catalogNs获取if (game.catalogNs?.mappings?.length > 0) {gameUrl = `https://store.epicgames.com/zh-CN/p/${game.catalogNs.mappings[0].pageSlug}`;}// 方法2: 尝试从自定义属性获取else if (game.customAttributes?.length > 0) {const productSlugAttr = game.customAttributes.find(attr => attr.key === 'com.epicgames.app.productSlug');if (productSlugAttr) {gameUrl = `https://store.epicgames.com/zh-CN/p/${productSlugAttr.value}`;}}// 方法3: 回退到使用IDelse {gameUrl = `https://store.epicgames.com/p/${game.id}`;}// 格式化结束日期为北京时间const beijingOffset = 8 * 60 * 60 * 1000; // UTC+8const beijingDate = new Date(endDate.getTime() + beijingOffset);const endDateStr =`${beijingDate.getUTCFullYear()}-${(beijingDate.getUTCMonth() + 1).toString().padStart(2, '0')}-` +`${beijingDate.getUTCDate().toString().padStart(2, '0')} ` +`${beijingDate.getUTCHours().toString().padStart(2, '0')}:${beijingDate.getUTCMinutes().toString().padStart(2, '0')}`;freeGames.push({title: game.title,url: gameUrl,image: imageUrl,endDate: endDateStr});}});return freeGames;} catch (error) {console.error('获取EPIC游戏数据失败:', error.message);throw error;}}async function sendBarkNotification(games) {if (games.length === 0) {console.log('本周没有免费游戏');return;}try {// 构造消息内容const title = `Epic本周免费游戏 (${games.length}款)`;let content = '';// 添加通用提示content += `\n 领取地址:${games.length === 1 ? "点击通知直达" : "点击通知直达"}`;games.forEach((game, index) => {content += `\n ${index + 1}. ${game.title}`;content += `\n 截止: ${game.endDate} (北京时间)\n`;// 不再显示单独的链接行,避免重复});// 智能设置点击行为let clickUrl = 'https://store.epicgames.com/free-games'; // 默认跳转总览页let copyContent = clickUrl; // 默认复制总览页链接if (games.length === 1) {// 只有一款游戏时,点击直接跳转游戏页面clickUrl = games[0].url;copyContent = games[0].url; // 复制游戏页链接}// 发送Bark通知const payload = {title: title,body: content,url: clickUrl, // 智能设置点击跳转automaticallyCopy: 1,copy: copyContent, // 智能设置复制内容group: 'Epic免费游戏领取提醒', // 修改分组名称isArchive: 1 // 保存到历史记录};// 设置通知图标(使用第一个游戏的图片)if (games[0].image) {payload.icon = games[0].image;}await axios.post(BARK_API, payload);console.log(` 成功推送 ${games.length} 款免费游戏通知`);console.log(` 分组名称: Epic周免领取提醒`);console.log(` 点击跳转: ${clickUrl}`);console.log(` 复制内容: ${copyContent}`);} catch (error) {console.error('Bark推送失败:', error.message);if (error.response) {console.error('Bark响应数据:', error.response.data);}}}async function main() {try {console.log(' 开始获取EPIC免费游戏信息...');const freeGames = await getEpicFreeGames();// 打印调试信息console.log(` 找到 ${freeGames.length} 款免费游戏:`);freeGames.forEach(game => {console.log(`- ${game.title} (截止: ${game.endDate})`);console.log(` ${game.url}`);});await sendBarkNotification(freeGames);} catch (error) {console.error(' 脚本执行失败:', error.message);}}main();
解析
本脚本是Epic 免费游戏领取脚本,主要用途:
每周按计划(
cron: 30 7 * * 5,周五 07:30)拉取 Epic 商店的周免/即将周免游戏列表,并通过 Bark 推送到你的手机。支持智能跳转:只有一款游戏时,通知点击直接进入该游戏页;多款时跳到 Epic 周免汇总页。
运行前需在环境变量配置 BARK_PUSH 或 BARK_KEY(Bark 的设备 key)。
主要方法
1) getEpicFreeGames()
调用
https://store.epicgames.com/freeGamesPromotions
(携带 locale=zh-CN, country=CN)获取游戏促销数据。
解析
promotions:当前免费:
promotionalOffers中discountPercentage === 0,并且now介于startDate ~ endDate。即将免费(24h 内开始):
upcomingPromotionalOffers同样条件,且startDate - now < 24h。抽取字段:
title、image(优先OfferImageWide再Thumbnail)url(优先catalogNs.mappings[0].pageSlug;其次自定义属性com.epicgames.app.productSlug;最后回退用id拼 URL)endDate转为北京时间字符串。
2) sendBarkNotification(games)
若无免费游戏直接记录日志返回。
组织推送内容:
标题:
Epic本周免费游戏 (N款)内容包含每款游戏标题和北京时间截止时间。
点击行为与复制内容:单款 → 指向该游戏链接;多款 → 指向周免总览页。
group分组名为Epic免费游戏领取提醒,isArchive=1归档。若有封面图,设置icon。通过
POST https://api.day.app/<BARK_KEY>发送 Bark 通知。
3) main()
顺序:打印开始 →
getEpicFreeGames()→ 输出调试列表(标题、截止、链接)→sendBarkNotification()→ 结束。顶层
try/catch捕获异常并打印错误。
注意:
本文部分变量已做脱敏处理,仅用于测试和学习研究,禁止用于商业用途,不能保证其合法性,准确性,完整性和有效性,请根据情况自行判断。技术层面需要提供帮助,可以通过打赏的方式进行探讨。
没有评论:
发表评论