npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

steam-agent-command

v1.0.4

Published

Steam Agent Command:统一 sta CLI(登录、用户资料、游戏详情、Mod、价格、发现与本地扫描)

Readme

Steam 用户资料采集器

一个基于 Node.js 的两段式工具:

  1. auth/ —— 通过 Steam OpenID 2.0 引导用户在浏览器里授权登录, 拿到 SteamID64 并写入 auth/steam-id.json
  2. userinfo/ —— 读取上一步得到的 SteamID64 + .env 里的 STEAM_WEB_API_KEY, 并行调用 Steam Web API + 社区页面,产出一份完整的 玩家资料 JSON 报告

零第三方依赖除 express + openid;使用 Node 内置 https 模块直接调用 Web API。


目录结构

.
├── auth/
│   ├── index.js              # Express 服务器 + Steam OpenID 校验(入口)
│   ├── public/index.html     # 登录首页
│   └── steam-id.json         # 登录成功后写入(首次登录后自动生成)
│
├── userinfo/
│   ├── index.js              # 汇总入口(CLI)
│   ├── collectors/           # 7 个独立采集器
│   │   ├── summary.js        #   基础身份
│   │   ├── ownedGames.js     #   游戏库
│   │   ├── recentGames.js    #   最近 2 周游玩
│   │   ├── level.js          #   Steam 等级
│   │   ├── badges.js         #   徽章(API + 社区页详情)
│   │   ├── friends.js        #   好友(可自动补充昵称/头像)
│   │   └── achievements.js   #   单游戏完整成就(含全球完成率)
│   ├── lib/
│   │   ├── config.js         #   读取 SteamID / .env
│   │   ├── http.js           #   最小 https 封装
│   │   ├── logger.js         #   彩色标签日志
│   │   └── schema.js         #   字段字典(供 --schema 打印)
│   └── output/               # 生成的报告 JSON(gitignore 建议加)
│
├── gamediscovery/            # Steam 发现榜单(独立模块,无需登录/API Key)
│   ├── index.js              # 汇总入口(CLI,一次并行拉 4 分类合成一份报告)
│   ├── collectors/           # 4 个自包含的独立入口(各自 fetch + normalize)
│   │   ├── publicSpecials.js
│   │   ├── publicTopSellers.js
│   │   ├── publicNewReleases.js
│   │   └── publicComingSoon.js
│   ├── lib/
│   │   ├── http.js           #   最小 https 封装
│   │   ├── logger.js         #   彩色标签日志
│   │   ├── schema.js         #   4 个分类的字段字典(供 --schema 打印)
│   │   └── runner.js         #   4 个入口共享的通用 CLI 运行器
│   └── output/               #   steam-discovery-<category>-<CC>-<lang>.json
│                             #   steam-discovery-all-<CC>-<lang>.json(汇总入口产出)
│
├── gamedetail/               # Steam 商店详情(根据 AppID/游戏名,无需登录/API Key)
│   ├── index.js              # 入口(支持 appid/游戏名)
│   ├── lib/
│   │   ├── http.js
│   │   ├── logger.js
│   │   └── schema.js
│   └── output/               # steam-gamedetail-<appid>-<CC>-<lang>.json
│
├── gamemanager/              # Steam 游戏管理(下载/卸载,Steam URI)
│   ├── install.js            # 下载/安装入口(steam://install/<appid>)
│   ├── uninstall.js          # 卸载入口(steam://uninstall/<appid>)
│   ├── lib/
│   │   ├── logger.js
│   │   ├── runner.js
│   │   ├── schema.js
│   │   └── steamUri.js
│   └── output/               # steam-gamemanager-install.json / uninstall.json
│
├── gameadd/                  # Steam 商店唤起(steam://store/<appid>)
│   ├── index.js              # 打开商店入口(支持多个 appid)
│   ├── lib/
│   │   ├── logger.js
│   │   ├── runner.js
│   │   ├── schema.js
│   │   └── steamUri.js
│   └── output/               # steam-gameadd-store.json
│
├── gamenews/                 # Steam 游戏新闻(按 AppID)
│   ├── index.js              # 入口(ISteamNews/GetNewsForApp)
│   ├── lib/
│   │   ├── http.js
│   │   ├── logger.js
│   │   └── schema.js
│   └── output/               # steam-gamenews-<appid>.json
│
├── downloadmods/             # 本机 Workshop Mod 扫描(仅 workshop/content)
│   ├── index.js              # 入口(可做 Mod 名称↔ModID 互查)
│   ├── lib/
│   │   ├── http.js
│   │   ├── logger.js
│   │   └── schema.js
│   └── output/               # steam-downloaded-mods.json
│
├── .env                      # STEAM_WEB_API_KEY 等
├── package.json
└── README.md

快速开始

# 1. 安装依赖(只有 express + openid)
npm install

# 2. 生成/配置 .env(推荐)
sta envsetting
# 或手动填写 STEAM_WEB_API_KEY / ITAD_* 变量


# 3. 授权登录(auth 仅保留 login 命令)
sta login

# 4. 采集用户资料(支持子命令分发)
sta userinfo
sta userinfo list
sta userinfo schema

# 5. 根据 AppID / 游戏名获取商店详情(无需 API Key)
sta gamedetail --appid=105600

# 5.1 根据 ModID 获取 Workshop Mod 详情
sta moddetail --modid=2619954303

# 5.2 安装游戏(Steam install 协议)
sta gameinstall --appid=570

# 5.3 安装 Mod(打开 Workshop 页面订阅)
sta modinstall --modid=2619954303

# 6. 打开商店与管理
sta gameadd --appid=570
sta gameuninstall --appid=730

# 7. 按 AppID 获取游戏新闻(数量参数)
sta gamenews --appid=105600 --count=20
sta gamenews --appid=730 --limit=30

# 8. 发现榜单(支持子命令分发)
sta gamediscovery
sta gamediscovery publicTopSellers --cc=US --lang=english

环境变量(.env

项目根目录 .env 会在启动时自动加载(无第三方依赖):

STEAM_WEB_API_KEY=你的Key

# 可选:覆盖默认端口
# PORT=4050
# 可选:部署到公网时使用真实域名
# HOST=https://your-domain.com
# 可选:跳过 auth 步骤,直接指定 SteamID64 让 userinfo 使用
# STEAM_ID64=76561198000000000

只想拿 SteamID64(sta login不需要 STEAM_WEB_API_KEY。 想跑 npm run userinfo 就必需。


第一步:sta login —— 先写 .env,再 OpenID 登录

启动后:

  1. 终端打印服务地址(默认 http://localhost:4050
  2. 自动打开系统默认浏览器,跳转到 Steam 官方授权页
  3. 用户在 Steam 完成登录
  4. Steam 回跳,服务端校验签名并解析出 SteamID64
  5. 结果写入 auth/steam-id.json,浏览器展示 SteamID64
  6. 服务器自动关闭端口并退出进程(一次性使用)

auth/steam-id.json 示例:

{
  "steamId64": "76561198000000000",
  "claimedId": "https://steamcommunity.com/openid/id/76561198000000000",
  "profileUrl": "https://steamcommunity.com/profiles/76561198000000000",
  "loggedAt": "2026-07-03T07:00:00.000Z"
}

部署到公网

Steam OpenID 会把用户带回启动时配置的 returnUrl,部署时改 HOST 环境变量即可:

# Linux / macOS
HOST=https://your-domain.com PORT=4050 node auth/index.js

# Windows PowerShell
$env:HOST="https://your-domain.com"; $env:PORT="4050"; node auth/index.js

realmreturnUrl 会随 HOST 自动生成,无需改代码。

auth 路由

| 路由 | 说明 | | --- | --- | | GET / | 登录首页 | | GET /auth/steam | 生成 Steam 授权链接并 302 跳转 | | GET /auth/steam/return | Steam 授权回调,返回结果页 + 写文件 + 关闭服务器 |


第二步:npm run userinfo —— 采集用户资料

CLI 参数

node userinfo/index.js [options]

  --only=a,b        只运行指定 collector(可选值见 --list)
  --exclude=a,b     排除指定 collector
  --include-locked  成就同时列出未解锁项(默认已开启,兼容参数)
  --only-unlocked   仅输出已解锁成就(旧行为)
  --no-save         不写入 output/*.json
  --no-print        不把 JSON 打印到 stdout
  --compact         打印为紧凑 JSON(默认 pretty)
  --quiet           关闭 stderr 日志(只保留最终 JSON)
  --schema          只打印字段说明并退出
  --list            列出全部 collector 名并退出
  -h, --help        显示帮助

对应的 npm 脚本:

npm run userinfo             # 全量采集
npm run userinfo:list        # 列出所有 collector
npm run userinfo:schema      # 打印字段字典(人类可读的字段说明)
npm run userinfo:help        # 显示帮助

常用例:

# 只抓 身份 + 徽章,紧凑输出
node userinfo/index.js --only=summary,badges --compact

# 除了好友都抓,且不写文件
node userinfo/index.js --exclude=friends --no-save

# 成就把 **未解锁的** 也一并列出(默认只列已解锁)
node userinfo/index.js --include-locked

# 用其他 SteamID 跑一次(跳过 auth)
STEAM_ID64=76561199183026488 npm run userinfo    # PowerShell 用 $env:STEAM_ID64="..."

数据来源

| collector | Steam 接口 | 描述 | | --- | --- | --- | | summary | ISteamUser/GetPlayerSummaries | 基础身份:昵称/头像/在线状态/资料可见性/注册时间等 | | ownedGames | IPlayerService/GetOwnedGames | 拥有的全部游戏(含玩过的免费游戏),按总时长降序 | | recentGames | IPlayerService/GetRecentlyPlayedGames | 最近 2 周游玩过的游戏 | | level | IPlayerService/GetSteamLevel | Steam 账号等级 | | badges | IPlayerService/GetBadges + 社区徽章页 HTML | 徽章列表 + 徽章名称/描述/图片(抓 HTML) | | friends | ISteamUser/GetFriendList (+ GetPlayerSummaries) | 好友列表;默认自动补昵称/头像 | | achievements | ISteamUserStats/GetPlayerAchievements + GetSchemaForGame + GetGlobalAchievementPercentagesForApp | 单游戏完整成就:解锁状态 + 名称/图标/描述 + 全球完成率 |

achievements 默认对 最近游玩前 3 款 + 拥有时长前 3 款 采集(并集,去重)。

成就默认输出全部(含未解锁);未解锁项的 unlockTime 会是 null(Steam 官方不会返回时间戳)。 每个游戏对象仍带有 total / unlocked / locked / completionRate,可完整反映进度。 如果你只想看已解锁项,使用 --only-unlocked

输出

  • stdout:完整 JSON 报告(--no-print 可关)
  • 文件:按 collector 分开保存到 userinfo/output/--no-save 可关),例如:
    • steam-userinfo-summary-<steamId64>.json
    • steam-userinfo-ownedGames-<steamId64>.json
    • steam-userinfo-recentGames-<steamId64>.json
    • steam-userinfo-level-<steamId64>.json
    • steam-userinfo-badges-<steamId64>.json
    • steam-userinfo-friends-<steamId64>.json
    • steam-userinfo-achievements-<steamId64>.json
  • stderr:进度日志和摘要(--quiet 可全静默)

顶层结构

{
  "generatedAt": "2026-07-03T07:12:34.000Z",   // 报告生成时间(UTC)
  "steamId64":  "76561198000000000",
  "profileUrl": "https://steamcommunity.com/profiles/76561198000000000",

  "summary":      { "success": true, "data": { /* 见字段字典 */ } },
  "ownedGames":   { "success": true, "data": { "gameCount": 123, "games": [...] } },
  "recentGames":  { "success": true, "data": { "totalCount": 5,  "games": [...] } },
  "level":        { "success": true, "data": { "level": 42 } },
  "badges":       { "success": true, "data": { "badgeCount": 30, "badges": [...] } },
  "friends":      { "success": true, "data": { "count": 88, "private": false, "friends": [...] } },
  "achievements": [ /* 每款游戏一个对象,见字段字典 */ ]
}

每个 collector 的 success/error 都是局部的——某个失败不会中断其它 collector。 完整字段字典执行 npm run userinfo:schema 直接打印。


第三步(可选):gamedetail/ —— Steam 商店详情(根据 AppID / 游戏名)

gamedetail/ 调用 Steam 商店公开接口(无需 STEAM_WEB_API_KEY):

  • 接口:https://store.steampowered.com/api/appdetails?appids=<appid>
  • 支持参数:appidsccl(语言)、filters
  • 支持一个或多个 AppID(逗号分隔)
  • 支持按游戏名传入(会先通过 storesearch 自动映射 AppID)

CLI 参数

npm run gamedetail -- [--appid=<id[,id2...]>] [--name=<game[,game2...]>] [options]

  --appid=<id[,id2...]>  一个或多个 AppID(逗号分隔)
  --name=<g1[,g2...]>    一个或多个游戏名(逗号分隔,会先搜索映射 AppID)
  --cc=<CC>              国家/地区代码(默认 CN;影响价格货币)
  --lang=<lang>          语言(默认 schinese;也可用 --l=)
  --filters=<fields>     透传 appdetails filters(减少返回字段)
  --no-save              不写入 output/*.json
  --no-print             不把 JSON 打印到 stdout
  --compact              打印为紧凑 JSON(默认 pretty)
  --quiet                关闭 stderr 日志(只保留最终 JSON)
  --schema               只打印字段说明并退出
  -h, --help             显示帮助

对应 npm 脚本:

npm run gamedetail -- --appid=105600
npm run gamedetail:schema
npm run gamedetail:help

常用例:

# Terraria(105600)
npm run gamedetail -- --appid=105600

# 按游戏名查询
npm run gamedetail -- --name=Terraria

# 多个 appid,美区英文
npm run gamedetail -- --appid=105600,730 --cc=US --lang=english

# 只取基础和价格字段,紧凑输出,不落盘
npm run gamedetail -- --appid=105600 --filters=basic,price_overview --compact --no-save

输出会按 appid 分开落盘到 gamedetail/output/

  • steam-gamedetail-105600-CN-schinese.json
  • steam-gamedetail-730-US-english.json

报告中包含你关心的核心字段:基础信息、描述、价格、发布日期、开发商/发行商、分类、类型、媒体资源、平台支持、DLC、成就总数、推荐数、Metacritic、PC 配置、是否支持简体中文等(npm run gamedetail:schema 可查看完整字典)。


第三步(补充):moddetail/ —— Steam Workshop Mod 详情(根据 ModID)

moddetail/ 调用 Steam 接口 GetPublishedFileDetails(无需 STEAM_WEB_API_KEY):

  • 接口:https://api.steampowered.com/ISteamRemoteStorage/GetPublishedFileDetails/v1/
  • 通过 modid 查询 Mod 详情(支持逗号传多个)
  • 输出结构与 gamedetail 一致:顶层报告 + 按 id 聚合 details

CLI 参数

npm run moddetail -- --modid=<id[,id2...]> [options]

  --modid=<id[,id2...]>  一个或多个 Workshop ModID(必填)
  --no-save              不写入 output/*.json
  --no-print             不把 JSON 打印到 stdout
  --compact              打印为紧凑 JSON(默认 pretty)
  --quiet                关闭 stderr 日志(只保留最终 JSON)
  --schema               只打印字段说明并退出
  -h, --help             显示帮助

对应 npm 脚本:

npm run moddetail -- --modid=2619954303
npm run moddetail:schema
npm run moddetail:help

常用例:

# 单个 mod
npm run moddetail -- --modid=2619954303

# 多个 mod
npm run moddetail -- --modid=2619954303,2669644269

# 不落盘,紧凑输出
npm run moddetail -- --modid=2619954303 --no-save --compact

输出会按 modid 分开落盘到 moddetail/output/

  • steam-moddetail-2619954303.json
  • steam-moddetail-2669644269.json

报告中包含标题、描述(原文+纯文本)、所属 appId、标签、订阅/收藏/浏览统计、创建/更新时间、可见性等字段(npm run moddetail:schema 可查看完整字典)。


第四步(可选):gamemanager/ —— Steam 游戏下载/卸载(Steam URI)

gamemanager/ 提供两个独立程序

  • gamemanager/install.js:下载/安装(steam://install/<appid>
  • gamemanager/uninstall.js:卸载(steam://uninstall/<appid>

Steam URI 协议本身跨平台统一,差别只在调用方式:

  • Windows:Start-Process "steam://install/<appid>" / Start-Process "steam://uninstall/<appid>"
  • macOS:open "steam://install/<appid>" / open "steam://uninstall/<appid>"

本模块会自动按平台分支调用(win32 / darwin),并输出执行报告。

下载程序(install)

npm run gamemanager:install -- --appid=<id[,id2...]> [options]

# npm scripts
npm run gamemanager:install -- --appid=570
npm run gamemanager:install:help
npm run gamemanager:install:schema

卸载程序(uninstall)

npm run gamemanager:uninstall -- --appid=<id[,id2...]> [options]

# npm scripts
npm run gamemanager:uninstall -- --appid=730
npm run gamemanager:uninstall:help
npm run gamemanager:uninstall:schema

公共参数:

  • --appid=<id[,id2...]>:一个或多个 AppID(必填)
  • --dry-run:仅演练,不真正唤起 Steam
  • --no-save / --no-print / --compact / --quiet / --schema / --help

常用例:

# 安装 Dota 2(570)
npm run gamemanager:install -- --appid=570

# 卸载 CS2(730),先 dry-run
npm run gamemanager:uninstall -- --appid=730 --dry-run

输出文件:

  • gamemanager/output/steam-gamemanager-install.json
  • gamemanager/output/steam-gamemanager-uninstall.json

第四步(补充):gameadd/ —— 打开 Steam 游戏商店页(Steam URI)

gameadd/ 使用 Steam 协议:

  • steam://store/<appid>

按你给的 appid 直接唤起 Steam 对应游戏商店页面,形式与 gamemanager 保持一致(同样支持 --dry-run / --schema / --help 等)。

CLI 参数

npm run gameadd -- --appid=<id[,id2...]> [options]

  --appid=<id[,id2...]>   一个或多个 AppID(必填)
  --dry-run               仅演练,不真正唤起 Steam
  --no-save               不写入 output/*.json
  --no-print              不把 JSON 打印到 stdout
  --compact               打印为紧凑 JSON(默认 pretty)
  --quiet                 关闭 stderr 日志(只保留最终 JSON)
  --schema                只打印字段说明并退出
  -h, --help              显示帮助

对应 npm 脚本:

npm run gameadd -- --appid=570
npm run gameadd:help
npm run gameadd:schema

输出文件:

  • gameadd/output/steam-gameadd-store.json

第四步(补充):modmanager/ —— 打开 Steam Workshop Mod 页面(Steam URI)

modmanager/ 使用 Steam 协议:

  • steam://url/CommunityFilePage/<modid>

按你给的 modid 直接唤起 Steam 对应 Mod 页面,形式与 gameadd / gamemanager 保持一致(同样支持 --dry-run / --schema / --help 等)。

CLI 参数

npm run modmanager -- --modid=<id[,id2...]> [options]

  --modid=<id[,id2...]>   一个或多个 Workshop ModID(必填)
  --dry-run               仅演练,不真正唤起 Steam
  --no-save               不写入 output/*.json
  --no-print              不把 JSON 打印到 stdout
  --compact               打印为紧凑 JSON(默认 pretty)
  --quiet                 关闭 stderr 日志(只保留最终 JSON)
  --schema                只打印字段说明并退出
  -h, --help              显示帮助

对应 npm 脚本:

npm run modmanager -- --modid=2619954303
npm run modmanager:help
npm run modmanager:schema

输出文件:

  • modmanager/output/steam-modmanager-workshop.json

第五步(可选):gamenews/ —— Steam 游戏新闻(按 AppID)

gamenews/ 调用 ISteamNews/GetNewsForApp,一个 AppID 对应一条新闻流。

CLI 参数

npm run gamenews -- --appid=<id> [options]

  --appid=<id>            Steam AppID(必填)
  --count=<n>             返回条数(默认 20)
  --maxlength=<n>         限制每条 contents 最大长度(可选)
  --feeds=<a,b>           指定新闻 feeds(可选,逗号分隔)
  --no-save               不写入 output/*.json
  --no-print              不把 JSON 打印到 stdout
  --compact               打印为紧凑 JSON(默认 pretty)
  --quiet                 关闭 stderr 日志(只保留最终 JSON)
  --schema                只打印字段说明并退出
  -h, --help              显示帮助

对应 npm 脚本:

npm run gamenews -- --appid=105600
npm run gamenews:help
npm run gamenews:schema

常用例:

# Terraria 新闻
npm run gamenews -- --appid=105600 --count=20

# CS2 最近 50 条
npm run gamenews -- --appid=730 --count=50

输出文件:

  • gamenews/output/steam-gamenews-<appid>.json

第六步(可选):downloadgame/ —— 本机已下载游戏扫描(按文件夹)

downloadgame/ 不依赖 Steam API,核心逻辑就是扫描本机 SteamLibrary/steamapps/common 目录, 读取 common 下的一级子文件夹名称并列出(每个子文件夹名即一个已下载游戏目录名)。

CLI 参数

node downloadgame/index.js [options]

  --common=<p1,p2>      直接指定一个或多个 steamapps/common 路径
  --library=<p1,p2>     指定一个或多个 SteamLibrary 根路径(自动拼 steamapps/common)
  --no-save             不写入 output/*.json
  --no-print            不把 JSON 打印到 stdout
  --compact             打印为紧凑 JSON(默认 pretty)
  --quiet               关闭 stderr 日志(只保留最终 JSON)
  --schema              只打印字段说明并退出
  -h, --help            显示帮助

对应 npm 脚本:

npm run downloadgame
npm run downloadgame:schema
npm run downloadgame:help

常用例:

# 直接指定 common 目录
node downloadgame/index.js --common="D:/SteamLibrary/steamapps/common"

# 指定 SteamLibrary 根目录(可多个)
node downloadgame/index.js --library="D:/SteamLibrary,E:/SteamLibrary"

# 不落盘,只输出紧凑 JSON
node downloadgame/index.js --common="D:/SteamLibrary/steamapps/common" --no-save --compact

默认会尝试扫描一些常见路径(如 C:/Program Files (x86)/Steam/steamapps/commonD:/SteamLibrary/steamapps/common 等)。 输出文件:downloadgame/output/steam-downloaded-games.json


第七步(可选):downloadmods/ —— 仅扫描 Workshop Mod

downloadmods/ 现在只扫描:

  • SteamLibrary/steamapps/workshop/content/<AppID>/<PublishedFileId>

并会同步识别:

  • SteamLibrary/steamapps/workshop/appworkshop_<AppID>.acf

报告中重点字段包含:

  • modIdappId
  • modName(名称)
  • modDescription(原始描述)
  • modDescriptionPlain(纯文本描述)
  • 以及 tagspreviewUrlsubscriptionsfavoritedfileSize

CLI 参数

npm run downloadmods -- [options]

  --appid=<id[,id2...]>          仅扫描这些 AppID(可多个,逗号分隔)
  --library=<p1,p2>              指定 SteamLibrary 根路径(可多个)
  --workshop-content=<p1,p2>     直接指定 workshop/content 目录(可多个)
  --resolve / --no-resolve       启用/关闭详情补全(默认启用)
  --no-save                      不写入 output/*.json
  --no-print                     不把 JSON 打印到 stdout
  --compact                      打印为紧凑 JSON(默认 pretty)
  --quiet                        关闭 stderr 日志(只保留最终 JSON)
  --schema                       只打印字段说明并退出
  -h, --help                     显示帮助

对应 npm 脚本:

npm run downloadmods
npm run downloadmods:schema
npm run downloadmods:help

常用例:

# 自动识别 Steam Library 后扫描 workshop/content
npm run downloadmods

# 只扫指定 AppID
npm run downloadmods -- --appid=431960,262060

# 直接指定 workshop/content 路径
npm run downloadmods -- --workshop-content="D:/SteamLibrary/steamapps/workshop/content"

输出文件:downloadmods/output/steam-downloaded-mods.json


第八步(可选):gamediscovery/ —— Steam 发现榜单(4 个独立子程序)

gamediscovery/ 是一个独立模块(不依赖 SteamID / API Key), 调用 Steam 商店公开接口。每个榜单一个独立入口,各自负责一件事:

| 子程序 | 入口 | Steam 接口 | 描述 | | --- | --- | --- | --- | | publicSpecials | gamediscovery/collectors/publicSpecials.js | /api/featuredcategories#specials | 公共今日特惠(Public Specials) | | publicTopSellers | gamediscovery/collectors/publicTopSellers.js | /api/featuredcategories#top_sellers | 公共热销榜(Public Top Sellers) | | publicNewReleases | gamediscovery/collectors/publicNewReleases.js | /api/featuredcategories#new_releases | 公共新品(Public New Releases) | | publicComingSoon | gamediscovery/collectors/publicComingSoon.js | /api/featuredcategories#coming_soon | 公共即将推出(Public Coming Soon) |

4 个子程序共享同一份 lib/collectors/,但 CLI、日志、报告文件都完全独立。 报告分开落盘:gamediscovery/output/steam-discovery-<category>-<CC>-<lang>.json

CLI 参数(4 个子程序完全一致)

node gamediscovery/collectors/<category>.js [options]

  --cc=<CC>         国家/地区代码(默认 CN;影响价格和货币)
  --lang=<lang>     语言(默认 schinese;如 english、japanese、tchinese)
  --no-save         不写入 output/*.json
  --no-print        不把 JSON 打印到 stdout
  --compact         打印为紧凑 JSON(默认 pretty)
  --quiet           关闭 stderr 日志(只保留最终 JSON)
  --schema          只打印字段说明并退出
  -h, --help        显示帮助

对应的 npm 脚本(每个子程序 3 条:主命令 / schema / help):

npm run publicSpecials              # 拉取公共今日特惠(CN + schinese)
npm run publicSpecials:schema       # 打印 publicSpecials 的字段字典
npm run publicSpecials:help         # 显示 publicSpecials 帮助

npm run publicTopSellers            # 公共热销榜
npm run publicTopSellers:schema
npm run publicTopSellers:help

npm run publicNewReleases           # 公共新品
npm run publicNewReleases:schema
npm run publicNewReleases:help

npm run publicComingSoon            # 公共即将推出
npm run publicComingSoon:schema
npm run publicComingSoon:help

常用例:

# 公共今日特惠
node gamediscovery/collectors/publicSpecials.js

# 抓美区英文公共热销榜,紧凑输出
node gamediscovery/collectors/publicTopSellers.js --cc=US --lang=english --compact

# 静默采集公共新品,不写文件(只把 JSON 打到 stdout,可管道消费)
node gamediscovery/collectors/publicNewReleases.js --quiet --no-save

汇总入口:gamediscovery/index.js(一次拉 4 分类)

如果不想分 4 次跑,可以直接用 gamediscovery/index.js——并行拉 4 个分类, 合成一份报告(结构类似 userinfo/index.js 的产物):

# 全 4 分类,CN + schinese,每分类全部条目
npm run discovery

# 只跑 publicSpecials + publicTopSellers,美区英文
node gamediscovery/index.js --only=publicSpecials,publicTopSellers --cc=US --lang=english

# 排除 publicComingSoon,紧凑 JSON、不落盘
node gamediscovery/index.js --exclude=publicComingSoon --compact --no-save

# 打印字段字典 / 列出所有 collector
npm run discovery:schema
npm run discovery:list

CLI 参数比单入口多出:--only=a,b--exclude=a,b--list。落盘文件名固定为 gamediscovery/output/steam-discovery-all-<CC>-<lang>.json,报告顶层结构:

{
  "generatedAt": "2026-07-03T12:21:56.742Z",
  "cc": "CN",
  "language": "schinese",
  "currency": "CNY",
  "categories": {
    "publicSpecials":    { "success": true, "api": "publicSpecials", "source": "...", "name": "优惠",     "count": 10, "items": [ /* 见下 */ ] },
    "publicTopSellers":  { "success": true, "api": "publicTopSellers", "source": "...", "name": "热销商品", "count": 10, "items": [...] },
    "publicNewReleases": { "success": true, "api": "publicNewReleases", "source": "...", "name": "新品",     "count": 30, "items": [...] },
    "publicComingSoon":  { "success": true, "api": "publicComingSoon", "source": "...", "name": "即将推出", "count": 10, "items": [...] }
    // 某分类失败 → { "success": false, "error": "...", "count": 0, "items": [] }
  }
}

每个分类的 success/error 局部隔离,某个失败不会中断其它 3 个。 items[] 的字段 shape 与单入口完全一致(见下节),字段字典执行 npm run discovery:schema 打印。

报告顶层结构(每个子程序输出一份独立 JSON)

{
  "generatedAt": "2026-07-03T12:11:51.339Z",
  "category":    "publicSpecials", // publicSpecials / publicTopSellers / publicNewReleases / publicComingSoon
  "cc":          "CN",
  "language":    "schinese",
  "currency":    "CNY",
  "api":         "publicSpecials",
  "source":      "store.steampowered.com/api/featuredcategories#specials",
  "success":     true,
  "name":        "优惠",           // Steam 返回的本地化分类名
  "count":       10,
  "items":       [ /* … */ ]
}

每个 item 的关键字段(4 个分类同一 shape):

{
  "appId": 1091500,
  "name":  "赛博朋克 2077",
  "discounted": true,
  "discountPercent": 70,
  "originalPrice":     29800,        // 最小货币单位(CNY 分)
  "finalPrice":         8940,
  "originalPriceText": "¥298.00",    // 已换算文本
  "finalPriceText":    "¥89.40",
  "currency": "CNY",
  "discountExpiresAt": "2026-07-09T17:00:00.000Z",  // 无到期为 null
  "headerImage":       "https://...",
  "largeCapsuleImage": "https://...",
  "smallCapsuleImage": "https://...",
  "platforms": { "windows": true, "mac": true, "linux": false, "streamingVideo": false },
  "controllerSupport": "full",
  "storeUrl": "https://store.steampowered.com/app/1091500/"
}

完整字段字典执行 npm run publicSpecials:schema 等命令直接打印。


常见问题

1. 成就返回 Profile is not public / HTTP 403

Steam 的 游戏详情(Game details) 隐私跟"个人资料公开"是两个独立开关。 去 https://steamcommunity.com/my/edit/settings 把:

  • 我的个人资料 → 公开
  • 游戏详情 → 公开
  • "始终将游戏时间保持为私密"复选框取消勾选 ← 最容易忽略!

改完等 3~15 分钟(Steam Web API 有缓存),重跑 npm run userinfo

想立即验证是否已生效,浏览器直接开 https://steamcommunity.com/profiles/<你的ID>/stats/<AppID>/?xml=1 看能不能看到 XML。

2. 成就返回 Requested app has no stats / HTTP 400

游戏本身没接入 Steam 成就系统(比如某些 Demo、工具类应用、部分早期访问版本)——属于数据源没有,跳过即可。

3. 好友列表全空 / private: true

对方"好友列表"权限不是公开的,Steam 会返 401,本项目会把这种情况转成 { private: true, friends: [] }

4. 只想跑其中一部分 collector

--only--exclude

node userinfo/index.js --only=summary,level,badges
node userinfo/index.js --exclude=friends,achievements

5. 可以在 localhost 测试吗?

可以,Steam OpenID 支持 http://localhost:<port>/... 回调。

6. STEAM_WEB_API_KEY 泄露怎么办?

https://steamcommunity.com/dev/apikeyRevoke My Steam Web API Key, 再 Register 一个新 Key,粘回 .env 即可。整个过程 10 秒。


依赖

  • express —— 只用在 auth/ 里的一次性登录服务器
  • openid —— 通用 OpenID 2.0 Relying Party
  • Node 内置 https / fs / path —— userinfo/ 全模块使用,无外部依赖

Node.js 版本建议 >= 18(用了 Promise.all + 现代语法,未使用 fetch)。

npm 分发(发布到 npm)

# 1) 登录 npm
npm login

# 2) 检查包名是否可用(如果已被占用,改为 @你的scope/steam-agent-command)
npm view steam-agent-command name

# 3) 本地预览将发布的文件
npm pack --dry-run

# 4) 正式发布
npm publish

安装与使用:

# 全局安装
npm i -g steam-agent-command

# 验证 CLI
sta --help

如果你用 scope 包名(例如 @yourname/steam-agent-command),安装命令改为:

npm i -g @yourname/steam-agent-command

npm 分发(发布到 npm)

# 1) 登录 npm
npm login

# 2) 检查包名是否可用(如果已被占用,改为 @你的scope/steam-agent-command)
npm view steam-agent-command name

# 3) 本地预览将发布的文件
npm pack --dry-run

# 4) 正式发布
npm publish

安装与使用:

# 全局安装
npm i -g steam-agent-command

# 验证 CLI
sta --help

如果你用 scope 包名(例如 @yourname/steam-agent-command),安装命令改为: