trophyutil
v8.0.0
Published
ESM-only TypeScript parsers and domain models for PSNProfiles trophy data
Maintainers
Readme
TrophyUtil
TrophyUtil is a TypeScript library for parsing, modeling, and transforming PSNProfiles ("PSNP") trophy data.
It was built as a shared domain layer for a trophy-data ecosystem: browser extensions/userscripts that enhance PSNP pages, and backend scraping jobs that normalize site HTML for storage and analysis. The package keeps brittle DOM selectors and PSNP types and logic in one tested place.
Features
- ESM-only npm package with generated TypeScript declarations and explicit subpath exports.
- Dependency-free runtime: browser callers provide the real DOM, Node callers provide a DOM implementation such as
jsdom. - Parsers for games, DLCs, trophy lists, trophies, and series pages.
- Strong domain types for PSNP entities, like:
GameListing,PlayableGame,GamePage,SeriesListing,SeriesPage,Trophy, andTrophyGroup. - Utility coverage for PSNProfiles page detection, URL parsing, trophy counts, rarity/speed conversions, UTC-safe dates, and stack labeling.
- Optional adapter types for persistence concerns such as Mongo/Mongoose document timestamps.
Installation
npm install trophyutilTrophyUtil has no runtime dependencies. If you parse HTML in Node.js, install a DOM implementation in your application:
npm install jsdomUsage
Browser DOM
import { GameListingParser, PsnpGameBase, getPsnpPageType } from 'trophyutil';
const pageType = getPsnpPageType(new URL(window.location.href));
const nodes = PsnpGameBase.getGameNodes(pageType, window.document);
const parser = new GameListingParser();
const games = nodes.map(node => parser.parse(node));
console.log(games[0]?.id);
console.log(games[0]?.slug);
console.log(games[0]?.trophyCount);Node.js With jsdom
import { JSDOM } from 'jsdom';
import { GamePageParser } from 'trophyutil/parsers';
const html = await fetch('https://psnprofiles.com/trophies/2983-the-evil-within').then(response => response.text());
const dom = new JSDOM(html, { url: 'https://psnprofiles.com/trophies/2983-the-evil-within' });
const game = new GamePageParser().parse(dom.window.document);
console.log(game.name);
console.log(game.trophyGroups.flatMap(group => group.trophies).length);Typed Parse Results
Use the tryParse parsing method if you don't want to catch errors manually:
import { GameListingParser } from 'trophyutil';
const result = new GameListingParser().tryParse(row);
if (!result.ok) {
console.error(result.error.issues);
} else {
console.log(result.data.name);
}Package Exports
Several subpath exports are available:
import { GameListingParser } from 'trophyutil';
import type { GameListing } from 'trophyutil/models';
import { parseNumber, labelStacks } from 'trophyutil/util';
import type { GameDocument } from 'trophyutil/adapters';License
MIT
