Skip to content

Commit

Permalink
Merge pull request #6 from mProjectsCode/master
Browse files Browse the repository at this point in the history
merge master into release for 0.1.8
  • Loading branch information
mProjectsCode authored May 19, 2022
2 parents e138b19 + 41ca791 commit abab2cd
Show file tree
Hide file tree
Showing 21 changed files with 479 additions and 149 deletions.
93 changes: 42 additions & 51 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## Obsidian Media DB Plugin

A plugin that can query multiple APIs for movies, series, anime and games, and import them into your vault.
A plugin that can query multiple APIs for movies, series, anime, games, music and wiki articles, and import them into your vault.

### Features
#### Search by Title
Expand All @@ -10,72 +10,63 @@ Search a movie, series, anime or game by its name across multiple APIs.
Allows you to search by an ID that varies from API to API. Concrete info can be found in the description of the individual APIs.

#### Templates
The plugin allows you to set a template note that gets added to the end of any note created by this plugin.
The plugin also offers simple "template tgs". E.g. if the template includes `{{ title }}`, it will be replaced by the title of the movie, show or game.
The plugin allows you to set a template note that gets added to the end of any note created by this plugin.
The plugin also offers simple "template tgs". E.g. if the template includes `{{ title }}`, it will be replaced by the title of the movie, show or game.
Note that "template tags" are surrounded with two curly braces and that the spaces inside the curly braces are important.

For arrays there are two special ways of displaying them.
- using `{{ LIST:variable_name }}` will result in
```
- element 1
- element 2
- element 3
- ...
```
```
- element 1
- element 2
- element 3
- ...
```
- using `{{ ENUM:variable_name }}` will result in
```
element 1, element 2, element 3, ...
```
```
element 1, element 2, element 3, ...
```


I also published my own templates [here](https://github.com/mProjectsCode/obsidian-media-db-templates).

### Currently supported media types
- movies (including specials)
- series (including OVAs)
- games
- music releases
- wiki articles

### Currently supported APIs:
- [Jikan](https://jikan.moe/), an API that uses [My Anime List](https://myanimelist.net)
- supported formats
- series
- movies
- specials
- OVAs
- authentication
- no authentication or API key needed
- SFW filter support
- yes
- Search by ID
- the ID you need is the ID of the anime on [My Anime List](https://myanimelist.net)
- you can find this ID in the URL
- e.g. for "Beyond the Boundary" the URL looks like this `https://myanimelist.net/anime/18153/Kyoukai_no_Kanata` so the ID is `18153`
- notes
- sometimes the api is very slow, this is normal
- you need to use the title the anime has on [My Anime List](https://myanimelist.net), which is in most cases the japanese title
- e.g. instead of "Demon Slayer" you have to search "Kimetsu no Yaiba"
- the API is rate limited to
- 60 requests per minute
- 3 requests per second
| Name | Description | Supported formats | Authentification | Rate limiting | SFW filter support |
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ------------------------------ | ---------------------------------------------------------------------------- | ------------------------------ | ------------------ |
| [Jikan](https://jikan.moe/) | Jikan is an API that uses [My Anime List](https://myanimelist.net) and offers metadata for anime. | series, movies, specials, OVAs | No | 60 per minute and 3 per second | Yes |
| [OMDb](https://www.omdbapi.com/) | OMDb is an API that offers metadata for movie, series and games. | series, movies, games | Yes, you can get a free key here [here](https://www.omdbapi.com/apikey.aspx) | 1000 per day | No |
| [MusicBrainz](https://musicbrainz.org/) | MusicBrainz is an API that offers information about music releases. | music releases | No | 50 per second | No |
| [Wikipedia](https://en.wikipedia.org/wiki/Main_Page) | The Wikipedia API allows acces to all Wikipedia articles. | wiki articles | No | None | No | | | | | | |

#### Notes
- [Jikan](https://jikan.moe/)
- sometimes the api is very slow, this is normal
- you need to use the title the anime has on [My Anime List](https://myanimelist.net), which is in most cases the japanese title
- e.g. instead of "Demon Slayer" you have to search "Kimetsu no Yaiba"

#### Search by ID
- [Jikan](https://jikan.moe/)
- the ID you need is the ID of the anime on [My Anime List](https://myanimelist.net)
- you can find this ID in the URL
- e.g. for "Beyond the Boundary" the URL looks like this `https://myanimelist.net/anime/18153/Kyoukai_no_Kanata` so the ID is `18153`
- [OMDb](https://www.omdbapi.com/)
- supported formats
- series
- movies
- games
- authentication
- an API key is needed
- you can get one [here](https://www.omdbapi.com/apikey.aspx) for free
- SFW filter support
- no, but I haven't encountered any NSFW content while developing this plugin
- Search by ID
- the ID you need is the ID of the movie or show on [IMDb](https://www.imdb.com)
- you can find this ID in the URL
- e.g. for "Rogue One" the URL looks like this `https://www.imdb.com/title/tt3748528/` so the ID is `tt3748528`
- notes
- the api is rate limited to 1000 requests a day

- the ID you need is the ID of the movie or show on [IMDb](https://www.imdb.com)
- you can find this ID in the URL
- e.g. for "Rogue One" the URL looks like this `https://www.imdb.com/title/tt3748528/` so the ID is `tt3748528`
- [MusicBrainz](https://musicbrainz.org/)
- the id of a release is not easyly accessibe, you are better of just searching by title
- [Wikipedia](https://en.wikipedia.org/wiki/Main_Page)
- [here](https://en.wikipedia.org/wiki/Wikipedia:Finding_a_Wikidata_ID) is a guide to finding the Wikipedia ID for an article

### Contributions
Thank you for wanting to contribute to this project.
Thank you for wanting to contribute to this project.

Contributions are always welcome. If you have an idea, feel free to open a feature request under the issue tab or even create a pull request.

Expand Down
4 changes: 2 additions & 2 deletions manifest.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"id": "obsidian-media-db-plugin",
"name": "Media DB Plugin",
"version": "0.1.7",
"version": "0.1.8",
"minAppVersion": "0.14.0",
"description": "A plugin that can query multiple APIs for movies, series, anime and games, and import them into your vault.",
"description": "A plugin that can query multiple APIs for movies, series, anime, games, music and wiki articles, and import them into your vault. ",
"author": "Moritz Jung",
"authorUrl": "https://mprojectscode.github.io/",
"isDesktopOnly": false
Expand Down
14 changes: 2 additions & 12 deletions src/api/APIManager.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {APIModel} from './APIModel';
import {MediaTypeModel} from '../models/MediaTypeModel';
import {debugLog} from '../utils/Utils';

export class APIManager {
apis: APIModel[];
Expand All @@ -9,28 +10,17 @@ export class APIManager {
}

async query(query: string, apisToQuery: any): Promise<MediaTypeModel[]> {
console.log('MDB | api manager queried');
debugLog(`MDB | api manager queried with "${query}"`);

let res: MediaTypeModel[] = [];

for (const api of this.apis) {
if (Object.keys(apisToQuery).contains(api.apiName) && apisToQuery[api.apiName]) {
const apiRes = await api.searchByTitle(query);
// console.log(apiRes);
res = res.concat(apiRes);
}
}

/*
for (const api of this.apis) {
if (types.length === 0 || api.hasTypeOverlap(types)) {
const apiRes = await api.searchByTitle(query);
// console.log(apiRes);
res = res.concat(apiRes);
}
}
*/

return res;
}

Expand Down
1 change: 1 addition & 0 deletions src/api/APIModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export abstract class APIModel {
return this.types.contains(type);
}

// for future use (https://github.com/mProjectsCode/obsidian-media-db-plugin/issues/5)
hasTypeOverlap(types: string[]): boolean {
for (const type of types) {
if (this.hasType(type)) {
Expand Down
65 changes: 65 additions & 0 deletions src/api/apis/LocGovAPI.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import {APIModel} from '../APIModel';
import {MediaTypeModel} from '../../models/MediaTypeModel';
import MediaDbPlugin from '../../main';
import {debugLog} from '../../utils/Utils';

// WIP
export class LocGovAPI extends APIModel {
plugin: MediaDbPlugin;
typeMappings: Map<string, string>;

constructor(plugin: MediaDbPlugin) {
super();

this.plugin = plugin;
this.apiName = 'loc.gov API';
this.apiDescription = 'A free API for the Library of Congress collections.';
this.apiUrl = 'https://libraryofcongress.github.io/data-exploration/index.html';
this.types = [];
this.typeMappings = new Map<string, string>();
// this.typeMappings.set('movie', 'movie');
}

async searchByTitle(title: string): Promise<MediaTypeModel[]> {
console.log(`MDB | api "${this.apiName}" queried by Title`);

const searchUrl = `https://www.loc.gov/search/?q=${encodeURIComponent(title)}&fo=json&c=20`;
const fetchData = await fetch(searchUrl);
debugLog(fetchData);

if (fetchData.status !== 200) {
throw Error(`MDB | Received status code ${fetchData.status} from an API.`);
}

const data = await fetchData.json();
debugLog(data);
let ret: MediaTypeModel[] = [];

throw new Error('MDB | Under construction, API implementation not finished');

// return ret;
}

async getById(item: MediaTypeModel): Promise<MediaTypeModel> {
console.log(`MDB | api "${this.apiName}" queried by ID`);

const searchUrl = `https://www.loc.gov/item/${item.id}/?fo=json`;
const fetchData = await fetch(searchUrl);
if (fetchData.status !== 200) {
throw Error(`MDB | Received status code ${fetchData.status} from an API.`);
}

const data = await fetchData.json();
debugLog(data);
const result = data.data;

const type = this.typeMappings.get(result.type.toLowerCase());
if (type === undefined) {
throw Error(`${result.type.toLowerCase()} is an unsupported type.`);
}

throw new Error('MDB | Under construction, API implementation not finished');

// return;
}
}
18 changes: 10 additions & 8 deletions src/api/apis/MALAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {MediaTypeModel} from '../../models/MediaTypeModel';
import {MovieModel} from '../../models/MovieModel';
import MediaDbPlugin from '../../main';
import {SeriesModel} from '../../models/SeriesModel';
import {debugLog} from '../../utils/Utils';

export class MALAPI extends APIModel {
plugin: MediaDbPlugin;
Expand All @@ -24,18 +25,18 @@ export class MALAPI extends APIModel {
}

async searchByTitle(title: string): Promise<MediaTypeModel[]> {
console.log(`MDB | api "${this.apiName}" queried`);
console.log(`MDB | api "${this.apiName}" queried by Title`);

const searchUrl = `https://api.jikan.moe/v4/anime?q=${title}&limit=20${this.plugin.settings.sfwFilter ? '&sfw' : ''}`;
const searchUrl = `https://api.jikan.moe/v4/anime?q=${encodeURIComponent(title)}&limit=20${this.plugin.settings.sfwFilter ? '&sfw' : ''}`;

const fetchData = await fetch(searchUrl);
console.log(fetchData);
debugLog(fetchData);
if (fetchData.status !== 200) {
throw Error(`Received status code ${fetchData.status} from an API.`);
throw Error(`MDB | Received status code ${fetchData.status} from an API.`);
}
const data = await fetchData.json();

console.log(data);
debugLog(data);

let ret: MediaTypeModel[] = [];

Expand Down Expand Up @@ -69,16 +70,17 @@ export class MALAPI extends APIModel {
}

async getById(item: MediaTypeModel): Promise<MediaTypeModel> {
console.log(`MDB | api "${this.apiName}" queried by ID`);

const searchUrl = `https://api.jikan.moe/v4/anime/${item.id}`;

const fetchData = await fetch(searchUrl);

if (fetchData.status !== 200) {
throw Error(`Received status code ${fetchData.status} from an API.`);
throw Error(`MDB | Received status code ${fetchData.status} from an API.`);
}

const data = await fetchData.json();
console.log(data);
debugLog(data);
const result = data.data;

const type = this.typeMappings.get(result.type.toLowerCase());
Expand Down
97 changes: 97 additions & 0 deletions src/api/apis/MusicBrainzAPI.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import {APIModel} from '../APIModel';
import {MediaTypeModel} from '../../models/MediaTypeModel';
import MediaDbPlugin from '../../main';
import {requestUrl} from 'obsidian';
import {MusicReleaseModel} from '../../models/MusicReleaseModel';
import {contactEmail, debugLog, mediaDbVersion, pluginName} from '../../utils/Utils';

export class MusicBrainzAPI extends APIModel {
plugin: MediaDbPlugin;

constructor(plugin: MediaDbPlugin) {
super();

this.plugin = plugin;
this.apiName = 'MusicBrainz API';
this.apiDescription = 'Free API for music albums.';
this.apiUrl = 'https://musicbrainz.org/';
this.types = ['music'];
}

async searchByTitle(title: string): Promise<MediaTypeModel[]> {
console.log(`MDB | api "${this.apiName}" queried by Title`);

const searchUrl = `https://musicbrainz.org/ws/2/release-group?query=${encodeURIComponent(title)}&limit=20&fmt=json`;

const fetchData = await requestUrl({
url: searchUrl,
headers: {
'User-Agent': `${pluginName}/${mediaDbVersion} (${contactEmail})`,
},
});

debugLog(fetchData);

if (fetchData.status !== 200) {
throw Error(`MDB | Received status code ${fetchData.status} from an API.`);
}

const data = await fetchData.json;
debugLog(data);
let ret: MediaTypeModel[] = [];

for (const result of data['release-groups']) {
ret.push(new MusicReleaseModel({
type: 'musicRelease',
title: result.title,
englishTitle: result.title,
year: (new Date(result['first-release-date'])).getFullYear().toString(),
dataSource: this.apiName,
url: '',
id: result.id,

artists: result['artist-credit'].map((a: any) => a.name),
subType: result['primary-type'],
} as MusicReleaseModel));
}

return ret;
}

async getById(item: MediaTypeModel): Promise<MediaTypeModel> {
console.log(`MDB | api "${this.apiName}" queried by ID`);

const searchUrl = `https://musicbrainz.org/ws/2/release-group/${encodeURIComponent(item.id)}?inc=releases+artists+tags+ratings+genres&fmt=json`;
const fetchData = await requestUrl({
url: searchUrl,
headers: {
'User-Agent': `${pluginName}/0.1.7 (${contactEmail})`,
},
});

if (fetchData.status !== 200) {
throw Error(`MDB | Received status code ${fetchData.status} from an API.`);
}

const data = await fetchData.json;
debugLog(data);
const result = data;

const model = new MusicReleaseModel({
type: 'musicRelease',
title: result.title,
englishTitle: result.title,
year: (new Date(result['first-release-date'])).getFullYear().toString(),
dataSource: this.apiName,
url: '',
id: result.id,

artists: result['artist-credit'].map((a: any) => a.name),
genres: result.genres.map((g: any) => g.name),
subType: result['primary-type'],
rating: result.rating.value * 2,
} as MusicReleaseModel);

return model;
}
}
Loading

0 comments on commit abab2cd

Please sign in to comment.