### Install howlongtobeat npm Package Source: https://github.com/ckatzorke/howlongtobeat/blob/master/README.md This snippet shows the command to install the howlongtobeat library as a dependency for your project using npm. It is a prerequisite for using the library in your code. ```bash npm install howlongtobeat --save ``` -------------------------------- ### Recommend Games by Playtime with HowLongToBeat Source: https://context7.com/ckatzorke/howlongtobeat/llms.txt Provides an example of how to recommend games based on playtime. This function searches for 'RPG' games using `hltbService.search()`, filters them to find those with a main story completion time under a specified `maxHours`, and then logs their names, playtime, and platforms. ```typescript import { HowLongToBeatService } from 'howlongtobeat'; // Example: Build a game recommendation based on play time async function recommendByPlaytime(maxHours: number) { const hltbService = new HowLongToBeatService(); const results = await hltbService.search('RPG'); const shortGames = results.filter(game => game.gameplayMain > 0 && game.gameplayMain <= maxHours ); shortGames.forEach(game => { console.log(`${game.name}: ${game.gameplayMain}h (${game.platforms.join(', ')})`); }); } recommendByPlaytime(20); // Find RPGs under 20 hours ``` -------------------------------- ### Search Games with HowLongToBeat API (TypeScript) Source: https://context7.com/ckatzorke/howlongtobeat/llms.txt Demonstrates how to search for games using the HowLongToBeatService and process the results. It shows basic search functionality and how to extract game details such as name, playtime, similarity, and platforms. Also includes an example of using AbortSignal for request cancellation. ```typescript import { HowLongToBeatService, HowLongToBeatEntry } from 'howlongtobeat'; const hltbService = new HowLongToBeatService(); // Basic search hltbService.search('Nioh') .then(results => { results.forEach(game => { console.log(`${game.name} (ID: ${game.id})`); console.log(`Main Story: ${game.gameplayMain} hours`); console.log(`Main + Extra: ${game.gameplayMainExtra} hours`); console.log(`Completionist: ${game.gameplayCompletionist} hours`); console.log(`Similarity: ${game.similarity}`); console.log(`Platforms: ${game.platforms.join(', ')}`); console.log('---'); }); }) .catch(error => { console.error('Search failed:', error); }); // Search with AbortSignal for cancellation const controller = new AbortController(); hltbService.search('Dark Souls', controller.signal) .then(results => { const topResult = results[0]; console.log(`Found: ${topResult.name}`); console.log(`Image URL: ${topResult.imageUrl}`); }) .catch(error => { if (error.name === 'AbortError') { console.log('Search was cancelled'); } }); // Cancel after 5 seconds setTimeout(() => controller.abort(), 5000); // Expected output format: // [ // { // id: '36936', // name: 'Nioh', // imageUrl: 'https://howlongtobeat.com/games/36936_Nioh.jpg', // timeLabels: [['Main', 'Main'], ['Main + Extra', 'Main + Extra'], ['Completionist', 'Completionist']], // gameplayMain: 34, // gameplayMainExtra: 61, // gameplayCompletionist: 93, // similarity: 1, // searchTerm: 'Nioh', // platforms: ['PlayStation 4', 'PlayStation 5'], // description: '' // } // ] ``` -------------------------------- ### Get Game Details using howlongtobeat API Source: https://github.com/ckatzorke/howlongtobeat/blob/master/README.md Illustrates how to fetch detailed information for a specific game using the `detail` method of the HowLongToBeatService. This method requires a game ID and returns a Promise that resolves to a detailed game entry. Error handling is recommended as an unknown ID will throw an error. ```javascript hltbService.detail('36936').then(result => console.log(result)).catch(e => console.error(e)); ``` -------------------------------- ### TypeScript: Game Data Caching and Batch Processing with HowLongToBeat Source: https://context7.com/ckatzorke/howlongtobeat/llms.txt Demonstrates a GameDataCache class in TypeScript for efficiently retrieving and caching game details and search results from the HowLongToBeat API. It includes methods for single game lookups, searching games, batch retrieval of multiple game details with rate limiting, and clearing the cache. The example usage shows building a game library and analyzing game series, incorporating delays to respect API rate limits. ```typescript import { HowLongToBeatService, HowLongToBeatEntry } from 'howlongtobeat'; class GameDataCache { private cache: Map = new Map(); private searchCache: Map = new Map(); private hltbService: HowLongToBeatService; constructor() { this.hltbService = new HowLongToBeatService(); } async getGameDetails(gameId: string): Promise { if (this.cache.has(gameId)) { return this.cache.get(gameId)!; } const game = await this.hltbService.detail(gameId); this.cache.set(gameId, game); return game; } async searchGames(query: string): Promise { const cacheKey = query.toLowerCase().trim(); if (this.searchCache.has(cacheKey)) { return this.searchCache.get(cacheKey)!; } const results = await this.hltbService.search(query); this.searchCache.set(cacheKey, results); return results; } async batchGetDetails( gameIds: string[], delayMs: number = 1000 ): Promise> { const results = new Map(); for (const id of gameIds) { try { const game = await this.getGameDetails(id); results.set(id, game); // Rate limiting delay if (gameIds.indexOf(id) < gameIds.length - 1) { await new Promise(resolve => setTimeout(resolve, delayMs)); } } catch (error) { console.error(`Failed to fetch game ${id}:`, error.message); } } return results; } clearCache(): void { this.cache.clear(); this.searchCache.clear(); } } // Usage example const gameCache = new GameDataCache(); async function buildGameLibrary(gameNames: string[]) { const library = []; for (const name of gameNames) { const results = await gameCache.searchGames(name); if (results.length > 0) { const topMatch = results[0]; if (topMatch.similarity > 0.8) { const details = await gameCache.getGameDetails(topMatch.id); library.push({ name: details.name, mainHours: details.gameplayMain, platforms: details.platforms, imageUrl: details.imageUrl }); } } // Respectful delay between searches await new Promise(resolve => setTimeout(resolve, 1000)); } return library; } // Build library from game list const myGames = ['Dark Souls', 'Bloodborne', 'Sekiro', 'Elden Ring']; buildGameLibrary(myGames) .then(library => { console.log('Game Library:'); library.forEach(game => { console.log(`${game.name}: ${game.mainHours}h`); }); const totalHours = library.reduce((sum, g) => sum + g.mainHours, 0); console.log(`Total playtime: ${totalHours} hours`); }); // Batch processing with error recovery async function analyzeGameSeries(seriesName: string) { const cache = new GameDataCache(); const results = await cache.searchGames(seriesName); // Get details for top 5 matches const topGames = results.slice(0, 5); const gameIds = topGames.map(g => g.id); const details = await cache.batchGetDetails(gameIds, 1500); const analysis = Array.from(details.values()).map(game => ({ title: game.name, completion: { quick: game.gameplayMain, thorough: game.gameplayMainExtra, complete: game.gameplayCompletionist }, platforms: game.platforms.length })); return analysis; } analyzeGameSeries('Final Fantasy').then(console.log); ``` -------------------------------- ### Get Game Details by ID using TypeScript Source: https://context7.com/ckatzorke/howlongtobeat/llms.txt Fetches complete game information, including description, platforms, and gameplay hours, for a specific game ID. It supports both Promise-based and async/await patterns, with an option to use AbortSignal for cancellation. The method returns an object containing game details or throws an error if the game ID is not found. ```typescript import { HowLongToBeatService, HowLongToBeatEntry } from 'howlongtobeat'; const hltbService = new HowLongToBeatService(); // Fetch details for a specific game hltbService.detail('36936') .then(game => { console.log(`Game: ${game.name}`); console.log(`Description: ${game.description}`); console.log(`Platforms: ${game.platforms.join(', ')}`); console.log(`Main Story: ${game.gameplayMain} hours`); console.log(`Main + Extras: ${game.gameplayMainExtra} hours`); console.log(`Completionist: ${game.gameplayCompletionist} hours`); console.log(`Image: ${game.imageUrl}`); // Handle different time label types game.timeLabels.forEach(([key, label]) => { console.log(`Time category: ${label} -> ${game[key]} hours`); }); }) .catch(error => { console.error('Failed to fetch game details:', error); // Error thrown when game ID doesn't exist }); // Using with async/await and AbortSignal async function getGameDetails(gameId: string) { const controller = new AbortController(); try { const game: HowLongToBeatEntry = await hltbService.detail( gameId, controller.signal ); return { title: game.name, hours: { main: game.gameplayMain, extra: game.gameplayMainExtra, complete: game.gameplayCompletionist }, metadata: { platforms: game.platforms, image: game.imageUrl, description: game.description } }; } catch (error) { throw new Error(`Could not fetch game ${gameId}: ${error.message}`); } } // Usage getGameDetails('36936').then(data => console.log(data)); // Expected output: // { // id: '36936', // name: 'Nioh', // description: 'Action RPG set in feudal Japan...', // platforms: ['PlayStation 4', 'PC'], // imageUrl: 'https://howlongtobeat.com/games/36936_Nioh.jpg', // timeLabels: [ // ['gameplayMain', 'Main Story'], // ['gameplayMainExtra', 'Main + Sides'], // ['gameplayComplete', 'Completionist'] // ], // gameplayMain: 34, // gameplayMainExtra: 61, // gameplayCompletionist: 93, // similarity: 1, // searchTerm: 'Nioh' // } ``` -------------------------------- ### Import HowLongToBeatService in JavaScript and TypeScript Source: https://github.com/ckatzorke/howlongtobeat/blob/master/README.md Demonstrates how to import and instantiate the HowLongToBeatService class in both JavaScript and TypeScript. This service is the main entry point for interacting with the API. ```javascript let hltb = require('howlongtobeat'); let hltbService = new hltb.HowLongToBeatService(); ``` ```typescript import { HowLongToBeatService, HowLongToBeatEntry } from 'howlongtobeat'; let hltbService = new HowLongToBeatService(); ``` -------------------------------- ### Analyze Game Data with HowLongToBeat Source: https://context7.com/ckatzorke/howlongtobeat/llms.txt Demonstrates how to fetch detailed game information using `hltbService.detail()` and analyze it. This function checks for main story completion data, calculates the ratio of extra content to main gameplay, determines PC availability, and breaks down gameplay times by type. ```typescript import { HowLongToBeatService, HowLongToBeatEntry } from 'howlongtobeat'; // Working with entry data async function analyzeGame(gameId: string) { const hltbService = new HowLongToBeatService(); const game = await hltbService.detail(gameId); // Check if game has significant content if (game.gameplayMain === 0) { console.log(`${game.name} has no main story completion data`); } // Calculate extra content ratio const extraContent = game.gameplayCompletionist - game.gameplayMain; const ratio = game.gameplayMain > 0 ? (extraContent / game.gameplayMain * 100).toFixed(1) : 0; console.log(`Extra content adds ${ratio}% more gameplay`); // Platform availability check const isOnPC = game.platforms.some(p => p.toLowerCase().includes('pc') || p.toLowerCase().includes('windows') ); console.log(`Available on PC: ${isOnPC}`); // Handle different time label types (7 possible types) // Main Story, Main + Extras, Completionist, Single-Player, Solo, Co-Op, Vs. const timeTypes = game.timeLabels.map(([key, label]) => ({ type: label, hours: game[key as keyof HowLongToBeatEntry] as number })); return { title: game.name, totalHours: game.gameplayCompletionist, platforms: game.platforms, timeBreakdown: timeTypes }; } ``` -------------------------------- ### Search for Games using howlongtobeat API Source: https://github.com/ckatzorke/howlongtobeat/blob/master/README.md Shows how to use the `search` method of the HowLongToBeatService to find games. The method takes a game title as input and returns a Promise that resolves to an array of game entries, each containing basic information. ```javascript hltbService.search('Nioh').then(result => console.log(result)); ``` -------------------------------- ### TypeScript: Parallel Game Detail Fetching with Global Timeout Source: https://context7.com/ckatzorke/howlongtobeat/llms.txt Fetches details for multiple games in parallel using `hltbService.detail` and implements a global timeout for all concurrent requests. If any request takes too long, all ongoing requests are cancelled using a single AbortController. Results are filtered for errors and sorted by main gameplay time. ```typescript import { HowLongToBeatService } from 'howlongtobeat'; const hltbService = new HowLongToBeatService(); // Parallel requests with individual cancellation async function compareGames(gameIds: string[]) { const controller = new AbortController(); const promises = gameIds.map(id => hltbService.detail(id, controller.signal) .catch(err => ({ error: err.message, id })) ); // Cancel all if one takes too long const timeoutId = setTimeout(() => { console.log('Cancelling all requests...'); controller.abort(); }, 10000); try { const results = await Promise.all(promises); clearTimeout(timeoutId); // Filter out errors and compare const validGames = results.filter(r => !('error' in r)); return validGames.sort((a, b) => a.gameplayMain - b.gameplayMain ); } catch (error) { clearTimeout(timeoutId); throw error; } } // Usage example compareGames(['36936', '3978', '9224']) .then(games => { console.log('Games sorted by main story length:'); games.forEach(game => { console.log(`${game.name}: ${game.gameplayMain} hours`); }); }) .catch(error => { console.error('Comparison failed:', error.message); }); ``` -------------------------------- ### HowLongToBeatEntry Data Structure Definition Source: https://context7.com/ckatzorke/howlongtobeat/llms.txt Defines the `GameEntry` interface, which mirrors the structure of game data returned by the howlongtobeat library's search and detail methods. It includes properties for game ID, name, description, platforms, image URL, various completion time metrics, similarity score, and the original search term. ```typescript import { HowLongToBeatEntry } from 'howlongtobeat'; // The entry structure returned by search() and detail() interface GameEntry { id: string; // HowLongToBeat internal game ID name: string; // Game title description: string; // Game description (empty in search results) platforms: string[]; // Array of platform names playableOn: string[]; // Deprecated, same as platforms imageUrl: string; // Full URL to game cover image timeLabels: Array; // Labels for different completion types gameplayMain: number; // Hours to complete main story gameplayMainExtra: number; // Hours to complete main + extras gameplayCompletionist: number; // Hours for 100% completion similarity: number; // Similarity score (0-1) to search term searchTerm: string; // Original search query } ``` -------------------------------- ### TypeScript: Search with Custom Timeout and Cancellation Source: https://context7.com/ckatzorke/howlongtobeat/llms.txt Implements a custom timeout wrapper for the `hltbService.search` method using AbortController. It allows setting a maximum duration for the search request and throws a specific error if the timeout is exceeded. This prevents indefinite waiting for search results. ```typescript import { HowLongToBeatService } from 'howlongtobeat'; const hltbService = new HowLongToBeatService(); // Implement custom timeout wrapper async function searchWithTimeout( query: string, timeoutMs: number = 5000 ) { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeoutMs); try { const results = await hltbService.search(query, controller.signal); clearTimeout(timeoutId); return results; } catch (error) { clearTimeout(timeoutId); if (error.name === 'AbortError') { throw new Error(`Search timed out after ${timeoutMs}ms`); } throw error; } } ``` -------------------------------- ### TypeScript: User-Initiated Search Cancellation Source: https://context7.com/ckatzorke/howlongtobeat/llms.txt Provides a mechanism for cancelling ongoing search requests initiated by the user, such as during rapid typing. It uses a global `AbortController` instance (`currentSearch`) to abort any previous search before initiating a new one, preventing outdated results and unnecessary network activity. ```typescript import { HowLongToBeatService } from 'howlongtobeat'; const hltbService = new HowLongToBeatService(); // User-initiated cancellation let currentSearch: AbortController | null = null; async function cancelableSearch(query: string) { // Cancel previous search if still running if (currentSearch) { currentSearch.abort(); } currentSearch = new AbortController(); try { const results = await hltbService.search(query, currentSearch.signal); currentSearch = null; return results; } catch (error) { if (error.name !== 'AbortError') { currentSearch = null; throw error; } console.log('Search cancelled by user'); return []; } } // Simulate user typing and cancelling previous searches cancelableSearch('Dark').then(r => console.log('Dark:', r.length)); cancelableSearch('Dark Souls').then(r => console.log('Dark Souls:', r.length)); // First search is automatically cancelled ``` -------------------------------- ### Calculate Search Result Similarity using TypeScript Source: https://context7.com/ckatzorke/howlongtobeat/llms.txt Calculates the similarity percentage between two strings (e.g., game title and search query) using Levenshtein distance. This method can be used for custom filtering and ranking of search results. The `search` method in `HowLongToBeatService` also returns a `similarity` score for each result, which can be used to filter or sort games. ```typescript import { HowLongToBeatService } from 'howlongtobeat'; // Calculate similarity between strings const similarity1 = HowLongToBeatService.calcDistancePercentage( 'Dark Souls', 'Dark Souls' ); console.log(similarity1); // 1.0 (100% match) const similarity2 = HowLongToBeatService.calcDistancePercentage( 'Dark Souls', 'Dark Soul' ); console.log(similarity2); // 0.9 (90% match) const similarity3 = HowLongToBeatService.calcDistancePercentage( 'The Witcher 3: Wild Hunt', 'witcher' ); console.log(similarity3); // ~0.52 // Custom filtering by similarity threshold async function searchWithMinSimilarity( query: string, minSimilarity: number = 0.7 ) { const hltbService = new HowLongToBeatService(); const results = await hltbService.search(query); return results.filter(game => game.similarity >= minSimilarity); } // Find only close matches searchWithMinSimilarity('God of War', 0.8) .then(games => { games.forEach(game => { console.log(`${game.name} - ${(game.similarity * 100).toFixed(0)}% match`); }); }); // Custom ranking logic async function searchAndRank(query: string) { const hltbService = new HowLongToBeatService(); const results = await hltbService.search(query); // Re-rank by custom criteria return results.sort((a, b) => { const scoreA = a.similarity * 0.7 + (a.gameplayMain > 0 ? 0.3 : 0); const scoreB = b.similarity * 0.7 + (b.gameplayMain > 0 ? 0.3 : 0); return scoreB - scoreA; }); } searchAndRank('Final Fantasy').then(ranked => { console.log('Top result:', ranked[0].name); }); ``` -------------------------------- ### Set Theme Based on System Preference | JavaScript Source: https://github.com/ckatzorke/howlongtobeat/blob/master/src/test/resources/detail_guns_of_icarus_online.html This JavaScript snippet dynamically sets the website's theme based on the user's system preference or stored local storage value. It checks for 'system' preference or if no theme is set, defaulting to dark mode if the system prefers it. Otherwise, it applies the theme specified in local storage ('light' or 'dark'). ```javascript !function () { try { var d = document.documentElement, n = 'data-theme', s = 'setAttribute'; var e = localStorage.getItem('theme'); if ('system' === e || (!e && true)) { var t = '(prefers-color-scheme: dark)', m = window.matchMedia(t); if (m.media !== t || m.matches) { d.style.colorScheme = 'dark'; d[s](n, 'dark') } else { d.style.colorScheme = 'light'; d[s](n, 'light') } } else if (e) { d[s](n, e || '') } if (e === 'light' || e === 'dark') d.style.colorScheme = e } catch (e) { } }() ``` -------------------------------- ### Theme Toggler Javascript Source: https://github.com/ckatzorke/howlongtobeat/blob/master/src/test/resources/detail_street_fighter.html This Javascript code dynamically sets the theme of the webpage based on user preferences or system settings. It checks local storage for a saved theme and defaults to dark mode if no theme is set or if the system prefers dark mode. ```javascript !function () { try { var d = document.documentElement, n = 'data-theme', s = 'setAttribute'; var e = localStorage.getItem('theme'); if ('system' === e || (!e && true)) { var t = '(prefers-color-scheme: dark)', m = window.matchMedia(t); if (m.media !== t || m.matches) { d.style.colorScheme = 'dark'; d[s](n, 'dark') } else { d.style.colorScheme = 'light'; d[s](n, 'light') } } else if (e) { d[s](n, e || '') } if (e === 'light' || e === 'dark') d.style.colorScheme = e } catch (e) { } }() ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.