diff --git a/README.md b/README.md index c5016cc..b72b166 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,7 @@ Now you select the result you want and the plugin will cast it's magic and creat | [Wikipedia](https://en.wikipedia.org/wiki/Main_Page) | The Wikipedia API allows access to all Wikipedia articles. | wiki articles | No | None | No | | [Steam](https://store.steampowered.com/) | The Steam API offers information on all steam games. | games | No | 10000 per day | No | | [Open Library](https://openlibrary.org) | The OpenLibrary API offers metadata for books | books | No | Cover access is rate-limited when not using CoverID or OLID by max 100 requests/IP every 5 minutes. This plugin uses OLID so there shouldn't be a rate limit. | No | +| [Moby Games](https://www.mobygames.com) | The Moby Games API offers metadata for games for all platforms | games | Yes, by making an account [here](https://www.mobygames.com/user/register/) | API requests are limited to 360 per hour (one every ten seconds). In addition, requests should be made no more frequently than one per second. | No | #### Notes @@ -152,6 +153,10 @@ Now you select the result you want and the plugin will cast it's magic and creat - The ID you need is the "work" ID and not the "book" ID, it needs to start with `/works/`. You can find this ID in the URL - e.g. for "Fantastic Mr. Fox" the URL looks like this `https://openlibrary.org/works/OL45804W` so the ID is `/works/OL45804W` - This URL is located near the top of the page above the title, see `An edition of Fantastic Mr Fox (1970) ` +- [Moby Games](https://www.mobygames.com) + - you can find this ID in the URL + - e.g. for "Bioshock 2" the URL looks like this `https://www.mobygames.com/game/45089/bioshock-2/` so the ID is `45089` + ### Problems, unexpected behavior or improvement suggestions? diff --git a/src/api/apis/MobyGamesAPI.ts b/src/api/apis/MobyGamesAPI.ts new file mode 100644 index 0000000..a5528ab --- /dev/null +++ b/src/api/apis/MobyGamesAPI.ts @@ -0,0 +1,104 @@ +import { APIModel } from '../APIModel'; +import { MediaTypeModel } from '../../models/MediaTypeModel'; +import MediaDbPlugin from '../../main'; +import { GameModel } from '../../models/GameModel'; +import { requestUrl } from 'obsidian'; +import { MediaType } from '../../utils/MediaType'; + +export class MobyGamesAPI extends APIModel { + plugin: MediaDbPlugin; + apiDateFormat: string = 'YYYY-DD-MM'; + + constructor(plugin: MediaDbPlugin) { + super(); + + this.plugin = plugin; + this.apiName = 'MobyGamesAPI'; + this.apiDescription = 'A free API for games.'; + this.apiUrl = 'https://api.mobygames.com/v1'; + this.types = [MediaType.Game]; + } + async searchByTitle(title: string): Promise { + console.log(`MDB | api "${this.apiName}" queried by Title`); + + const searchUrl = `${this.apiUrl}/games?title=${encodeURIComponent(title)}&api_key=${this.plugin.settings.MobyGamesKey}`; + const fetchData = await requestUrl({ + url: searchUrl, + }); + + console.debug(fetchData); + + if (fetchData.status === 401) { + throw Error(`MDB | Authentication for ${this.apiName} failed. Check the API key.`); + } + if (fetchData.status === 429) { + throw Error(`MDB | Too many requests for ${this.apiName}, you've exceeded your API quota.`); + } + if (fetchData.status !== 200) { + throw Error(`MDB | Received status code ${fetchData.status} from an API.`); + } + + const data = await fetchData.json; + console.debug(data); + const ret: MediaTypeModel[] = []; + for (const result of data.games) { + ret.push( + new GameModel({ + type: MediaType.Game, + title: result.title, + englishTitle: result.title, + year: new Date(result.platforms[0].first_release_date).getFullYear().toString(), + dataSource: this.apiName, + id: result.game_id, + + } as GameModel), + ); + } + + return ret; + } + + async getById(id: string): Promise { + console.log(`MDB | api "${this.apiName}" queried by ID`); + + const searchUrl = `${this.apiUrl}/games?id=${encodeURIComponent(id)}&api_key=${this.plugin.settings.MobyGamesKey}`; + const fetchData = await requestUrl({ + url: searchUrl, + }); + console.debug(fetchData); + + if (fetchData.status !== 200) { + throw Error(`MDB | Received status code ${fetchData.status} from an API.`); + } + + const data = await fetchData.json; + console.debug(data); + const result = data.games[0]; + + const model = new GameModel({ + type: MediaType.Game, + title: result.title, + englishTitle: result.title, + year: new Date(result.platforms[0].first_release_date).getFullYear().toString(), + dataSource: this.apiName, + url: `https://www.mobygames.com/game/${result.game_id}`, + id: result.game_id, + developers: [], + publishers: [], + genres: result.genres?.map((x: any) => x.genre_name) ?? [], + onlineRating: result.moby_score, + image: result.sample_cover.image ?? '', + + released: true, + releaseDate: result.platforms[0].first_release_date ?? 'unknown', + + userData: { + played: false, + + personalRating: 0, + }, + } as GameModel); + + return model; + } +} diff --git a/src/main.ts b/src/main.ts index fc7ee25..653e107 100644 --- a/src/main.ts +++ b/src/main.ts @@ -20,6 +20,7 @@ import { MEDIA_TYPES, MediaTypeManager } from './utils/MediaTypeManager'; import { SteamAPI } from './api/apis/SteamAPI'; import { BoardGameGeekAPI } from './api/apis/BoardGameGeekAPI'; import { OpenLibraryAPI } from './api/apis/OpenLibraryAPI'; +import { MobyGamesAPI } from './api/apis/MobyGamesAPI'; import { PropertyMapper } from './settings/PropertyMapper'; import { YAMLConverter } from './utils/YAMLConverter'; import { MediaDbFolderImportModal } from './modals/MediaDbFolderImportModal'; @@ -48,6 +49,7 @@ export default class MediaDbPlugin extends Plugin { this.apiManager.registerAPI(new SteamAPI(this)); this.apiManager.registerAPI(new BoardGameGeekAPI(this)); this.apiManager.registerAPI(new OpenLibraryAPI(this)); + this.apiManager.registerAPI(new MobyGamesAPI(this)); // this.apiManager.registerAPI(new LocGovAPI(this)); // TODO: parse data this.mediaTypeManager = new MediaTypeManager(); diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index c65078d..9b089f2 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -11,6 +11,7 @@ import { fragWithHTML } from '../utils/Utils'; export interface MediaDbPluginSettings { OMDbKey: string; + MobyGamesKey: string; sfwFilter: boolean; useCustomYamlStringifier: boolean; templates: boolean; @@ -60,6 +61,7 @@ export interface MediaDbPluginSettings { const DEFAULT_SETTINGS: MediaDbPluginSettings = { OMDbKey: '', + MobyGamesKey: '', sfwFilter: true, useCustomYamlStringifier: true, templates: true, @@ -160,6 +162,18 @@ export class MediaDbSettingTab extends PluginSettingTab { }); }); + new Setting(containerEl) + .setName('Moby Games key') + .setDesc('API key for "www.mobygames.com".') + .addText(cb => { + cb.setPlaceholder('API key') + .setValue(this.plugin.settings.MobyGamesKey) + .onChange(data => { + this.plugin.settings.MobyGamesKey = data; + this.plugin.saveSettings(); + }); + }); + new Setting(containerEl) .setName('SFW filter') .setDesc('Only shows SFW results for APIs that offer filtering.')