Skip to content

Commit a0a2ef3

Browse files
Merge pull request #42 from CedricFinance/add-board-game-geek
Add BoardGameGeekAPI
2 parents 2e89905 + c4643ae commit a0a2ef3

File tree

7 files changed

+188
-1
lines changed

7 files changed

+188
-1
lines changed

src/api/apis/BoardGameGeekAPI.ts

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import {APIModel} from '../APIModel';
2+
import {MediaTypeModel} from '../../models/MediaTypeModel';
3+
import MediaDbPlugin from '../../main';
4+
import {BoardGameModel} from 'src/models/BoardGameModel';
5+
import {debugLog} from '../../utils/Utils';
6+
import {requestUrl} from 'obsidian';
7+
import {MediaType} from '../../utils/MediaType';
8+
9+
export class BoardGameGeekAPI extends APIModel {
10+
plugin: MediaDbPlugin;
11+
12+
constructor(plugin: MediaDbPlugin) {
13+
super();
14+
15+
this.plugin = plugin;
16+
this.apiName = 'BoardGameGeekAPI';
17+
this.apiDescription = 'A free API for BoardGameGeek things.';
18+
this.apiUrl = 'https://api.geekdo.com/xmlapi';
19+
this.types = ['boardgames'];
20+
}
21+
22+
async searchByTitle(title: string): Promise<MediaTypeModel[]> {
23+
console.log(`MDB | api "${this.apiName}" queried by Title`);
24+
25+
const searchUrl = `${this.apiUrl}/search?search=${encodeURIComponent(title)}`;
26+
const fetchData = await requestUrl({
27+
url: searchUrl,
28+
});
29+
30+
if (fetchData.status !== 200) {
31+
throw Error(`MDB | Received status code ${fetchData.status} from an API.`);
32+
}
33+
34+
const data = fetchData.text;
35+
const response = new window.DOMParser().parseFromString(data, "text/xml")
36+
37+
debugLog(response);
38+
39+
let ret: MediaTypeModel[] = [];
40+
41+
for (const boardgame of Array.from(response.querySelectorAll("boardgame"))) {
42+
const id = boardgame.attributes.getNamedItem("objectid")!.value;
43+
const title = boardgame.querySelector("name")!.textContent!;
44+
const year = boardgame.querySelector("yearpublished")?.textContent ?? "";
45+
46+
ret.push(new BoardGameModel({
47+
dataSource: this.apiName,
48+
id,
49+
title,
50+
englishTitle: title,
51+
year,
52+
} as BoardGameModel));
53+
}
54+
55+
return ret;
56+
}
57+
58+
async getById(id: string): Promise<MediaTypeModel> {
59+
console.log(`MDB | api "${this.apiName}" queried by ID`);
60+
61+
const searchUrl = `${this.apiUrl}/boardgame/${encodeURIComponent(id)}?stats=1`;
62+
const fetchData = await requestUrl({
63+
url: searchUrl,
64+
});
65+
66+
if (fetchData.status !== 200) {
67+
throw Error(`MDB | Received status code ${fetchData.status} from an API.`);
68+
}
69+
70+
const data = fetchData.text;
71+
const response = new window.DOMParser().parseFromString(data, "text/xml")
72+
debugLog(response);
73+
74+
const boardgame = response.querySelector("boardgame")!;
75+
const title = boardgame.querySelector("name")!.textContent!;
76+
const year = boardgame.querySelector("yearpublished")?.textContent ?? "";
77+
const image = boardgame.querySelector("image")?.textContent ?? undefined;
78+
const onlineRating = Number.parseFloat(boardgame.querySelector("statistics ratings average")?.textContent ?? "");
79+
const genres = Array.from(boardgame.querySelectorAll("boardgamecategory")).map(n => n!.textContent!);
80+
81+
const model = new BoardGameModel({
82+
type: MediaType.BoardGame,
83+
title,
84+
englishTitle: title,
85+
year: year === "0" ? "" : year,
86+
dataSource: this.apiName,
87+
url: `https://boardgamegeek.com/boardgame/${id}`,
88+
id,
89+
90+
genres,
91+
onlineRating,
92+
image,
93+
released: true,
94+
95+
userData: {
96+
played: false,
97+
personalRating: 0,
98+
},
99+
} as BoardGameModel);
100+
101+
return model;
102+
103+
}
104+
}

src/main.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {WikipediaAPI} from './api/apis/WikipediaAPI';
1212
import {MusicBrainzAPI} from './api/apis/MusicBrainzAPI';
1313
import {MediaTypeManager} from './utils/MediaTypeManager';
1414
import {SteamAPI} from './api/apis/SteamAPI';
15+
import {BoardGameGeekAPI} from './api/apis/BoardGameGeekAPI';
1516
import {ModelPropertyMapper} from './settings/ModelPropertyMapper';
1617
import {YAMLConverter} from './utils/YAMLConverter';
1718
import {MediaDbFolderImportModal} from './modals/MediaDbFolderImportModal';
@@ -79,6 +80,7 @@ export default class MediaDbPlugin extends Plugin {
7980
this.apiManager.registerAPI(new WikipediaAPI(this));
8081
this.apiManager.registerAPI(new MusicBrainzAPI(this));
8182
this.apiManager.registerAPI(new SteamAPI(this));
83+
this.apiManager.registerAPI(new BoardGameGeekAPI(this));
8284
// this.apiManager.registerAPI(new LocGovAPI(this)); // TODO: parse data
8385

8486
this.mediaTypeManager = new MediaTypeManager(this.settings);

src/models/BoardGameModel.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import {MediaTypeModel} from './MediaTypeModel';
2+
import {mediaDbTag} from '../utils/Utils';
3+
import {MediaType} from '../utils/MediaType';
4+
5+
6+
export class BoardGameModel extends MediaTypeModel {
7+
genres: string[];
8+
onlineRating: number;
9+
image?: string;
10+
11+
released: boolean;
12+
13+
userData: {
14+
played: boolean;
15+
personalRating: number;
16+
};
17+
18+
19+
constructor(obj: any = {}) {
20+
super();
21+
22+
Object.assign(this, obj);
23+
24+
this.type = this.getMediaType();
25+
}
26+
27+
getTags(): string[] {
28+
return [mediaDbTag, 'boardgame'];
29+
}
30+
31+
getMediaType(): MediaType {
32+
return MediaType.BoardGame;
33+
}
34+
35+
}

src/settings/ModelPropertyMapper.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export class ModelPropertyMapper {
1616
this.conversionRulesMap.set(MediaType.Game, settings.gamePropertyConversionRules);
1717
this.conversionRulesMap.set(MediaType.Wiki, settings.wikiPropertyConversionRules);
1818
this.conversionRulesMap.set(MediaType.MusicRelease, settings.musicReleasePropertyConversionRules);
19+
this.conversionRulesMap.set(MediaType.BoardGame, settings.boardgamePropertyConversionRules);
1920
}
2021

2122
convertObject(obj: object): object {

src/settings/Settings.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,21 @@ export interface MediaDbPluginSettings {
1818
gameTemplate: string,
1919
wikiTemplate: string,
2020
musicReleaseTemplate: string,
21+
boardgameTemplate: string,
2122

2223
movieFileNameTemplate: string,
2324
seriesFileNameTemplate: string,
2425
gameFileNameTemplate: string,
2526
wikiFileNameTemplate: string,
2627
musicReleaseFileNameTemplate: string,
28+
boardgameFileNameTemplate: string,
2729

2830
moviePropertyConversionRules: string,
2931
seriesPropertyConversionRules: string,
3032
gamePropertyConversionRules: string,
3133
wikiPropertyConversionRules: string,
3234
musicReleasePropertyConversionRules: string,
35+
boardgamePropertyConversionRules: string,
3336

3437
}
3538

@@ -45,19 +48,21 @@ export const DEFAULT_SETTINGS: MediaDbPluginSettings = {
4548
gameTemplate: '',
4649
wikiTemplate: '',
4750
musicReleaseTemplate: '',
51+
boardgameTemplate: '',
4852

4953
movieFileNameTemplate: '{{ title }} ({{ year }})',
5054
seriesFileNameTemplate: '{{ title }} ({{ year }})',
5155
gameFileNameTemplate: '{{ title }} ({{ year }})',
5256
wikiFileNameTemplate: '{{ title }}',
5357
musicReleaseFileNameTemplate: '{{ title }} (by {{ ENUM:artists }} - {{ year }})',
58+
boardgameFileNameTemplate: '{{ title }} ({{ year }})',
5459

5560
moviePropertyConversionRules: '',
5661
seriesPropertyConversionRules: '',
5762
gamePropertyConversionRules: '',
5863
wikiPropertyConversionRules: '',
5964
musicReleasePropertyConversionRules: '',
60-
65+
boardgamePropertyConversionRules: '',
6166

6267
};
6368

@@ -201,6 +206,19 @@ export class MediaDbSettingTab extends PluginSettingTab {
201206
this.plugin.saveSettings();
202207
});
203208
});
209+
210+
new Setting(containerEl)
211+
.setName('Board Game template')
212+
.setDesc('Template file to be used when creating a new note for a boardgame.')
213+
.addSearch(cb => {
214+
new FileSuggest(this.app, cb.inputEl);
215+
cb.setPlaceholder('Example: boardgameTemplate.md')
216+
.setValue(this.plugin.settings.boardgameTemplate)
217+
.onChange(data => {
218+
this.plugin.settings.boardgameTemplate = data;
219+
this.plugin.saveSettings();
220+
});
221+
});
204222
// endregion
205223

206224
containerEl.createEl('h3', {text: 'File Name Settings'});
@@ -264,6 +282,18 @@ export class MediaDbSettingTab extends PluginSettingTab {
264282
this.plugin.saveSettings();
265283
});
266284
});
285+
286+
new Setting(containerEl)
287+
.setName('Board Game file name template')
288+
.setDesc('Template for the file name used when creating a new note for a boardgame.')
289+
.addText(cb => {
290+
cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.boardgameFileNameTemplate}`)
291+
.setValue(this.plugin.settings.boardgameFileNameTemplate)
292+
.onChange(data => {
293+
this.plugin.settings.boardgameFileNameTemplate = data;
294+
this.plugin.saveSettings();
295+
});
296+
});
267297
// endregion
268298

269299
containerEl.createEl('h3', {text: 'Property Mappings'});
@@ -327,6 +357,18 @@ export class MediaDbSettingTab extends PluginSettingTab {
327357
this.plugin.saveSettings();
328358
});
329359
});
360+
361+
new Setting(containerEl)
362+
.setName('Board Game model property mappings')
363+
.setDesc('Mappings for the property names of a boardgame.')
364+
.addTextArea(cb => {
365+
cb.setPlaceholder(`Example: \ntitle -> name\nyear -> releaseYear`)
366+
.setValue(this.plugin.settings.boardgamePropertyConversionRules)
367+
.onChange(data => {
368+
this.plugin.settings.boardgamePropertyConversionRules = data;
369+
this.plugin.saveSettings();
370+
});
371+
});
330372
// endregion
331373

332374
}

src/utils/MediaType.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ export enum MediaType {
44
Game = 'game',
55
MusicRelease = 'musicRelease',
66
Wiki = 'wiki',
7+
BoardGame = 'boardgame',
78
}

src/utils/MediaTypeManager.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@ export class MediaTypeManager {
2424
this.mediaFileNameTemplateMap.set(MediaType.Game, settings.gameFileNameTemplate);
2525
this.mediaFileNameTemplateMap.set(MediaType.Wiki, settings.wikiFileNameTemplate);
2626
this.mediaFileNameTemplateMap.set(MediaType.MusicRelease, settings.musicReleaseFileNameTemplate);
27+
this.mediaFileNameTemplateMap.set(MediaType.BoardGame, settings.boardgameFileNameTemplate);
2728

2829
this.mediaTemplateMap = new Map<MediaType, string>();
2930
this.mediaTemplateMap.set(MediaType.Movie, settings.movieTemplate);
3031
this.mediaTemplateMap.set(MediaType.Series, settings.seriesTemplate);
3132
this.mediaTemplateMap.set(MediaType.Game, settings.gameTemplate);
3233
this.mediaTemplateMap.set(MediaType.Wiki, settings.wikiTemplate);
3334
this.mediaTemplateMap.set(MediaType.MusicRelease, settings.musicReleaseTemplate);
35+
this.mediaTemplateMap.set(MediaType.BoardGame, settings.boardgameTemplate);
3436
}
3537

3638
getFileName(mediaTypeModel: MediaTypeModel): string {

0 commit comments

Comments
 (0)