commit
30208ea71a
25 changed files with 627 additions and 161 deletions
67
README.md
67
README.md
|
|
@ -4,32 +4,60 @@ A plugin that can query multiple APIs for movies, series, anime, games, music an
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
#### Search by Title
|
#### Search by Title
|
||||||
Search a movie, series, anime or game by its name across multiple APIs.
|
Search a movie, series, anime, game, music release or wiki article by its name across multiple APIs.
|
||||||
|
|
||||||
#### Search by ID
|
#### Search by ID
|
||||||
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.
|
Allows you to search by an ID that varies from API to API. Concrete information on this feature can be found in the description of the individual APIs.
|
||||||
|
|
||||||
#### Templates
|
#### 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 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 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.
|
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.
|
For arrays there are two special ways of displaying them.
|
||||||
- using `{{ LIST:variable_name }}` will result in
|
- using `{{ LIST:variable_name }}` will result in
|
||||||
```
|
```
|
||||||
- element 1
|
- element 1
|
||||||
- element 2
|
- element 2
|
||||||
- element 3
|
- element 3
|
||||||
- ...
|
- ...
|
||||||
```
|
```
|
||||||
- using `{{ ENUM:variable_name }}` will result in
|
- using `{{ ENUM:variable_name }}` will result in
|
||||||
```
|
```
|
||||||
element 1, element 2, element 3, ...
|
element 1, element 2, element 3, ...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Available variables that can be used in template tags are the same variables from the metadata of the note.
|
||||||
|
|
||||||
I also published my own templates [here](https://github.com/mProjectsCode/obsidian-media-db-templates).
|
I also published my own templates [here](https://github.com/mProjectsCode/obsidian-media-db-templates).
|
||||||
|
|
||||||
|
### How to install
|
||||||
|
Currently, you have to manually download the zip archive from the latest release here on GitHub.
|
||||||
|
After downloading, extract the archive into the `.obsidian/plugins` folder in your vault.
|
||||||
|
|
||||||
|
The folder structure should look like this:
|
||||||
|
```
|
||||||
|
[path to your vault]
|
||||||
|
|_ .obsidian
|
||||||
|
|_ plugins
|
||||||
|
|_ obsidian-media-db-plugin
|
||||||
|
|_ main.js
|
||||||
|
|_ manifest.json
|
||||||
|
|_ styles.css
|
||||||
|
```
|
||||||
|
|
||||||
|
Once the plugin submission goes through, the plugin will also be installable directly through obsidian's plugin installer.
|
||||||
|
|
||||||
|
### How to use
|
||||||
|
(pictures are coming)
|
||||||
|
|
||||||
|
Once you have installed this plugin, you will find a database icon in the left ribbon.
|
||||||
|
When using this or the `Add new Media DB entry` command, a popup will open.
|
||||||
|
Here you can enter the title of what you want to search for and then select in which APIs to search.
|
||||||
|
|
||||||
|
After clicking search, a new popup will open prompting you to select from the search results.
|
||||||
|
Now you select the result you want and the plugin will cast it's magic and create a new note in your vault, that contains the metadata of the selected search result.
|
||||||
|
|
||||||
### Currently supported media types
|
### Currently supported media types
|
||||||
- movies (including specials)
|
- movies (including specials)
|
||||||
- series (including OVAs)
|
- series (including OVAs)
|
||||||
|
|
@ -39,11 +67,12 @@ I also published my own templates [here](https://github.com/mProjectsCode/obsidi
|
||||||
|
|
||||||
### Currently supported APIs:
|
### Currently supported APIs:
|
||||||
| Name | Description | Supported formats | Authentification | Rate limiting | SFW filter support |
|
| 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 |
|
| [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 |
|
| [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 |
|
| [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 | | | | | | |
|
| [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 |
|
||||||
|
|
||||||
#### Notes
|
#### Notes
|
||||||
- [Jikan](https://jikan.moe/)
|
- [Jikan](https://jikan.moe/)
|
||||||
|
|
@ -61,9 +90,15 @@ I also published my own templates [here](https://github.com/mProjectsCode/obsidi
|
||||||
- you can find this ID in the URL
|
- 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`
|
- 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/)
|
- [MusicBrainz](https://musicbrainz.org/)
|
||||||
- the id of a release is not easily accessibe, you are better of just searching by title
|
- the id of a release is not easily accessible, you are better off just searching by title
|
||||||
- [Wikipedia](https://en.wikipedia.org/wiki/Main_Page)
|
- [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
|
- [here](https://en.wikipedia.org/wiki/Wikipedia:Finding_a_Wikidata_ID) is a guide to finding the Wikipedia ID for an article
|
||||||
|
- [Steam](https://store.steampowered.com/)
|
||||||
|
- you can find this ID in the URL
|
||||||
|
- e.g. for "Factorio" the URL looks like this `https://store.steampowered.com/app/427520/Factorio/` so the ID is `427520`
|
||||||
|
|
||||||
|
### Problems, unexpected behavior or improvement suggestions?
|
||||||
|
You are more than welcome to open an issue on [GitHub](https://github.com/mProjectsCode/obsidian-media-db-plugin/issues).
|
||||||
|
|
||||||
### Contributions
|
### Contributions
|
||||||
Thank you for wanting to contribute to this project.
|
Thank you for wanting to contribute to this project.
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,13 @@ export class APIManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
async queryDetailedInfo(item: MediaTypeModel): Promise<MediaTypeModel> {
|
async queryDetailedInfo(item: MediaTypeModel): Promise<MediaTypeModel> {
|
||||||
|
return await this.queryDetailedInfoById(item.id, item.dataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
async queryDetailedInfoById(id: string, dataSource: string): Promise<MediaTypeModel> {
|
||||||
for (const api of this.apis) {
|
for (const api of this.apis) {
|
||||||
if (api.apiName === item.dataSource) {
|
if (api.apiName === dataSource) {
|
||||||
return api.getById(item);
|
return api.getById(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ export abstract class APIModel {
|
||||||
*/
|
*/
|
||||||
abstract searchByTitle(title: string): Promise<MediaTypeModel[]>;
|
abstract searchByTitle(title: string): Promise<MediaTypeModel[]>;
|
||||||
|
|
||||||
abstract getById(item: MediaTypeModel): Promise<MediaTypeModel>;
|
abstract getById(id: string): Promise<MediaTypeModel>;
|
||||||
|
|
||||||
hasType(type: string): boolean {
|
hasType(type: string): boolean {
|
||||||
return this.types.contains(type);
|
return this.types.contains(type);
|
||||||
|
|
|
||||||
|
|
@ -40,10 +40,10 @@ export class LocGovAPI extends APIModel {
|
||||||
// return ret;
|
// return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getById(item: MediaTypeModel): Promise<MediaTypeModel> {
|
async getById(id: string): Promise<MediaTypeModel> {
|
||||||
console.log(`MDB | api "${this.apiName}" queried by ID`);
|
console.log(`MDB | api "${this.apiName}" queried by ID`);
|
||||||
|
|
||||||
const searchUrl = `https://www.loc.gov/item/${item.id}/?fo=json`;
|
const searchUrl = `https://www.loc.gov/item/${encodeURIComponent(id)}/?fo=json`;
|
||||||
const fetchData = await fetch(searchUrl);
|
const fetchData = await fetch(searchUrl);
|
||||||
if (fetchData.status !== 200) {
|
if (fetchData.status !== 200) {
|
||||||
throw Error(`MDB | Received status code ${fetchData.status} from an API.`);
|
throw Error(`MDB | Received status code ${fetchData.status} from an API.`);
|
||||||
|
|
|
||||||
|
|
@ -69,10 +69,10 @@ export class MALAPI extends APIModel {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getById(item: MediaTypeModel): Promise<MediaTypeModel> {
|
async getById(id: string): Promise<MediaTypeModel> {
|
||||||
console.log(`MDB | api "${this.apiName}" queried by ID`);
|
console.log(`MDB | api "${this.apiName}" queried by ID`);
|
||||||
|
|
||||||
const searchUrl = `https://api.jikan.moe/v4/anime/${item.id}`;
|
const searchUrl = `https://api.jikan.moe/v4/anime/${encodeURIComponent(id)}`;
|
||||||
const fetchData = await fetch(searchUrl);
|
const fetchData = await fetch(searchUrl);
|
||||||
|
|
||||||
if (fetchData.status !== 200) {
|
if (fetchData.status !== 200) {
|
||||||
|
|
@ -107,9 +107,11 @@ export class MALAPI extends APIModel {
|
||||||
released: true,
|
released: true,
|
||||||
premiere: (new Date(result.aired?.from)).toLocaleDateString() ?? 'unknown',
|
premiere: (new Date(result.aired?.from)).toLocaleDateString() ?? 'unknown',
|
||||||
|
|
||||||
watched: false,
|
userData: {
|
||||||
lastWatched: '',
|
watched: false,
|
||||||
personalRating: 0,
|
lastWatched: '',
|
||||||
|
personalRating: 0,
|
||||||
|
},
|
||||||
} as MovieModel);
|
} as MovieModel);
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
|
|
@ -135,9 +137,11 @@ export class MALAPI extends APIModel {
|
||||||
airedTo: (new Date(result.aired?.to)).toLocaleDateString() ?? 'unknown',
|
airedTo: (new Date(result.aired?.to)).toLocaleDateString() ?? 'unknown',
|
||||||
airing: result.airing,
|
airing: result.airing,
|
||||||
|
|
||||||
watched: false,
|
userData: {
|
||||||
lastWatched: '',
|
watched: false,
|
||||||
personalRating: 0,
|
lastWatched: '',
|
||||||
|
personalRating: 0,
|
||||||
|
},
|
||||||
} as SeriesModel);
|
} as SeriesModel);
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
|
|
|
||||||
|
|
@ -58,14 +58,14 @@ export class MusicBrainzAPI extends APIModel {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getById(item: MediaTypeModel): Promise<MediaTypeModel> {
|
async getById(id: string): Promise<MediaTypeModel> {
|
||||||
console.log(`MDB | api "${this.apiName}" queried by ID`);
|
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 searchUrl = `https://musicbrainz.org/ws/2/release-group/${encodeURIComponent(id)}?inc=releases+artists+tags+ratings+genres&fmt=json`;
|
||||||
const fetchData = await requestUrl({
|
const fetchData = await requestUrl({
|
||||||
url: searchUrl,
|
url: searchUrl,
|
||||||
headers: {
|
headers: {
|
||||||
'User-Agent': `${pluginName}/0.1.7 (${contactEmail})`,
|
'User-Agent': `${pluginName}/${mediaDbVersion} (${contactEmail})`,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -90,6 +90,10 @@ export class MusicBrainzAPI extends APIModel {
|
||||||
genres: result.genres.map((g: any) => g.name),
|
genres: result.genres.map((g: any) => g.name),
|
||||||
subType: result['primary-type'],
|
subType: result['primary-type'],
|
||||||
rating: result.rating.value * 2,
|
rating: result.rating.value * 2,
|
||||||
|
|
||||||
|
userData: {
|
||||||
|
personalRating: 0,
|
||||||
|
},
|
||||||
} as MusicReleaseModel);
|
} as MusicReleaseModel);
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
|
|
|
||||||
|
|
@ -88,10 +88,10 @@ export class OMDbAPI extends APIModel {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getById(item: MediaTypeModel): Promise<MediaTypeModel> {
|
async getById(id: string): Promise<MediaTypeModel> {
|
||||||
console.log(`MDB | api "${this.apiName}" queried by ID`);
|
console.log(`MDB | api "${this.apiName}" queried by ID`);
|
||||||
|
|
||||||
const searchUrl = `http://www.omdbapi.com/?i=${item.id}&apikey=${this.plugin.settings.OMDbKey}`;
|
const searchUrl = `http://www.omdbapi.com/?i=${encodeURIComponent(id)}&apikey=${this.plugin.settings.OMDbKey}`;
|
||||||
const fetchData = await fetch(searchUrl);
|
const fetchData = await fetch(searchUrl);
|
||||||
|
|
||||||
if (fetchData.status === 401) {
|
if (fetchData.status === 401) {
|
||||||
|
|
@ -132,9 +132,11 @@ export class OMDbAPI extends APIModel {
|
||||||
released: true,
|
released: true,
|
||||||
premiere: (new Date(result.Released)).toLocaleDateString() ?? 'unknown',
|
premiere: (new Date(result.Released)).toLocaleDateString() ?? 'unknown',
|
||||||
|
|
||||||
watched: false,
|
userData: {
|
||||||
lastWatched: '',
|
watched: false,
|
||||||
personalRating: 0,
|
lastWatched: '',
|
||||||
|
personalRating: 0,
|
||||||
|
},
|
||||||
} as MovieModel);
|
} as MovieModel);
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
|
|
@ -160,9 +162,11 @@ export class OMDbAPI extends APIModel {
|
||||||
airedFrom: (new Date(result.Released)).toLocaleDateString() ?? 'unknown',
|
airedFrom: (new Date(result.Released)).toLocaleDateString() ?? 'unknown',
|
||||||
airedTo: 'unknown',
|
airedTo: 'unknown',
|
||||||
|
|
||||||
watched: false,
|
userData: {
|
||||||
lastWatched: '',
|
watched: false,
|
||||||
personalRating: 0,
|
lastWatched: '',
|
||||||
|
personalRating: 0,
|
||||||
|
},
|
||||||
} as SeriesModel);
|
} as SeriesModel);
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
|
|
@ -183,8 +187,10 @@ export class OMDbAPI extends APIModel {
|
||||||
released: true,
|
released: true,
|
||||||
releaseDate: (new Date(result.Released)).toLocaleDateString() ?? 'unknown',
|
releaseDate: (new Date(result.Released)).toLocaleDateString() ?? 'unknown',
|
||||||
|
|
||||||
played: false,
|
userData: {
|
||||||
personalRating: 0,
|
played: false,
|
||||||
|
personalRating: 0,
|
||||||
|
},
|
||||||
} as GameModel);
|
} as GameModel);
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
|
|
|
||||||
119
src/api/apis/SteamAPI.ts
Normal file
119
src/api/apis/SteamAPI.ts
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
import {APIModel} from '../APIModel';
|
||||||
|
import {MediaTypeModel} from '../../models/MediaTypeModel';
|
||||||
|
import MediaDbPlugin from '../../main';
|
||||||
|
import {GameModel} from '../../models/GameModel';
|
||||||
|
import {debugLog} from '../../utils/Utils';
|
||||||
|
import {requestUrl} from 'obsidian';
|
||||||
|
import {MediaType} from '../../utils/MediaType';
|
||||||
|
|
||||||
|
export class SteamAPI extends APIModel {
|
||||||
|
plugin: MediaDbPlugin;
|
||||||
|
typeMappings: Map<string, string>;
|
||||||
|
|
||||||
|
constructor(plugin: MediaDbPlugin) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.apiName = 'SteamAPI';
|
||||||
|
this.apiDescription = 'A free API for all Steam games.';
|
||||||
|
this.apiUrl = 'http://www.steampowered.com/';
|
||||||
|
this.types = ['games'];
|
||||||
|
this.typeMappings = new Map<string, string>();
|
||||||
|
this.typeMappings.set('game', 'game');
|
||||||
|
}
|
||||||
|
|
||||||
|
async searchByTitle(title: string): Promise<MediaTypeModel[]> {
|
||||||
|
console.log(`MDB | api "${this.apiName}" queried by Title`);
|
||||||
|
|
||||||
|
const searchUrl = `http://api.steampowered.com/ISteamApps/GetAppList/v0002/?format=json`;
|
||||||
|
const fetchData = await requestUrl({
|
||||||
|
url: searchUrl,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (fetchData.status !== 200) {
|
||||||
|
throw Error(`MDB | Received status code ${fetchData.status} from an API.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await fetchData.json;
|
||||||
|
|
||||||
|
debugLog(data);
|
||||||
|
|
||||||
|
let filteredData = [];
|
||||||
|
|
||||||
|
for (const app of data.applist.apps) {
|
||||||
|
if (app.name.toLowerCase().includes(title.toLowerCase())) {
|
||||||
|
filteredData.push(app);
|
||||||
|
}
|
||||||
|
if (filteredData.length > 20) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ret: MediaTypeModel[] = [];
|
||||||
|
|
||||||
|
for (const result of filteredData) {
|
||||||
|
ret.push(new GameModel({
|
||||||
|
type: MediaType.Game,
|
||||||
|
title: result.name,
|
||||||
|
englishTitle: result.name,
|
||||||
|
year: '',
|
||||||
|
dataSource: this.apiName,
|
||||||
|
id: result.appid,
|
||||||
|
} as GameModel));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getById(id: string): Promise<MediaTypeModel> {
|
||||||
|
console.log(`MDB | api "${this.apiName}" queried by ID`);
|
||||||
|
|
||||||
|
const searchUrl = `http://store.steampowered.com/api/appdetails?appids=${encodeURIComponent(id)}`;
|
||||||
|
const fetchData = await requestUrl({
|
||||||
|
url: searchUrl,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (fetchData.status !== 200) {
|
||||||
|
throw Error(`MDB | Received status code ${fetchData.status} from an API.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
debugLog(await fetchData.json);
|
||||||
|
|
||||||
|
let result;
|
||||||
|
for (const [key, value] of Object.entries(await fetchData.json)) {
|
||||||
|
if (key == id) {
|
||||||
|
result = value.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!result) {
|
||||||
|
throw Error(`MDB | API returned invalid data.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
debugLog(result);
|
||||||
|
|
||||||
|
const model = new GameModel({
|
||||||
|
type: MediaType.Game,
|
||||||
|
title: result.name,
|
||||||
|
englishTitle: result.name,
|
||||||
|
year: (new Date(result.release_date.date)).getFullYear().toString(),
|
||||||
|
dataSource: this.apiName,
|
||||||
|
url: `https://store.steampowered.com/app/${result.id}`,
|
||||||
|
id: result.steam_appid,
|
||||||
|
|
||||||
|
genres: result.genres?.map((x: any) => x.description) ?? [],
|
||||||
|
onlineRating: Number.parseFloat(result.metacritic?.score ?? 0),
|
||||||
|
image: result.header_image ?? '',
|
||||||
|
|
||||||
|
released: !result.release_date?.comming_soon,
|
||||||
|
releaseDate: (new Date(result.release_date?.date)).toLocaleDateString() ?? 'unknown',
|
||||||
|
|
||||||
|
userData: {
|
||||||
|
played: false,
|
||||||
|
personalRating: 0,
|
||||||
|
},
|
||||||
|
} as GameModel);
|
||||||
|
|
||||||
|
return model;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -46,10 +46,10 @@ export class WikipediaAPI extends APIModel {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getById(item: MediaTypeModel): Promise<MediaTypeModel> {
|
async getById(id: string): Promise<MediaTypeModel> {
|
||||||
console.log(`MDB | api "${this.apiName}" queried by ID`);
|
console.log(`MDB | api "${this.apiName}" queried by ID`);
|
||||||
|
|
||||||
const searchUrl = `https://en.wikipedia.org/w/api.php?action=query&prop=info&pageids=${item.id}&inprop=url&format=json&origin=*`;
|
const searchUrl = `https://en.wikipedia.org/w/api.php?action=query&prop=info&pageids=${encodeURIComponent(id)}&inprop=url&format=json&origin=*`;
|
||||||
const fetchData = await fetch(searchUrl);
|
const fetchData = await fetch(searchUrl);
|
||||||
|
|
||||||
if (fetchData.status !== 200) {
|
if (fetchData.status !== 200) {
|
||||||
|
|
@ -71,6 +71,8 @@ export class WikipediaAPI extends APIModel {
|
||||||
wikiUrl: result.fullurl,
|
wikiUrl: result.fullurl,
|
||||||
lastUpdated: (new Date(result.touched)).toLocaleDateString() ?? 'unknown',
|
lastUpdated: (new Date(result.touched)).toLocaleDateString() ?? 'unknown',
|
||||||
length: result.length,
|
length: result.length,
|
||||||
|
|
||||||
|
userData: {},
|
||||||
} as WikiModel);
|
} as WikiModel);
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
|
|
|
||||||
110
src/main.ts
110
src/main.ts
|
|
@ -1,8 +1,8 @@
|
||||||
import {Notice, Plugin, TFile} from 'obsidian';
|
import {FrontMatterCache, Notice, Plugin, TFile} from 'obsidian';
|
||||||
import {DEFAULT_SETTINGS, MediaDbPluginSettings, MediaDbSettingTab} from './settings/Settings';
|
import {DEFAULT_SETTINGS, MediaDbPluginSettings, MediaDbSettingTab} from './settings/Settings';
|
||||||
import {APIManager} from './api/APIManager';
|
import {APIManager} from './api/APIManager';
|
||||||
import {MediaTypeModel} from './models/MediaTypeModel';
|
import {MediaTypeModel} from './models/MediaTypeModel';
|
||||||
import {replaceIllegalFileNameCharactersInString, replaceTags} from './utils/Utils';
|
import {replaceIllegalFileNameCharactersInString} from './utils/Utils';
|
||||||
import {OMDbAPI} from './api/apis/OMDbAPI';
|
import {OMDbAPI} from './api/apis/OMDbAPI';
|
||||||
import {MediaDbAdvancedSearchModal} from './modals/MediaDbAdvancedSearchModal';
|
import {MediaDbAdvancedSearchModal} from './modals/MediaDbAdvancedSearchModal';
|
||||||
import {MediaDbSearchResultModal} from './modals/MediaDbSearchResultModal';
|
import {MediaDbSearchResultModal} from './modals/MediaDbSearchResultModal';
|
||||||
|
|
@ -10,17 +10,20 @@ import {MALAPI} from './api/apis/MALAPI';
|
||||||
import {MediaDbIdSearchModal} from './modals/MediaDbIdSearchModal';
|
import {MediaDbIdSearchModal} from './modals/MediaDbIdSearchModal';
|
||||||
import {WikipediaAPI} from './api/apis/WikipediaAPI';
|
import {WikipediaAPI} from './api/apis/WikipediaAPI';
|
||||||
import {MusicBrainzAPI} from './api/apis/MusicBrainzAPI';
|
import {MusicBrainzAPI} from './api/apis/MusicBrainzAPI';
|
||||||
|
import {MediaTypeManager} from './utils/MediaTypeManager';
|
||||||
|
import {SteamAPI} from './api/apis/SteamAPI';
|
||||||
|
|
||||||
export default class MediaDbPlugin extends Plugin {
|
export default class MediaDbPlugin extends Plugin {
|
||||||
settings: MediaDbPluginSettings;
|
settings: MediaDbPluginSettings;
|
||||||
apiManager: APIManager;
|
apiManager: APIManager;
|
||||||
|
mediaTypeManager: MediaTypeManager;
|
||||||
|
|
||||||
async onload() {
|
async onload() {
|
||||||
await this.loadSettings();
|
await this.loadSettings();
|
||||||
|
|
||||||
// add icon to the left ribbon
|
// add icon to the left ribbon
|
||||||
const ribbonIconEl = this.addRibbonIcon('database', 'Add new Media DB entry', (evt: MouseEvent) =>
|
const ribbonIconEl = this.addRibbonIcon('database', 'Add new Media DB entry', (evt: MouseEvent) =>
|
||||||
this.createMediaDbNote(this.openMediaDbSearchModal.bind(this)),
|
this.createMediaDbNote(this.openMediaDbAdvancedSearchModal.bind(this)),
|
||||||
);
|
);
|
||||||
ribbonIconEl.addClass('obsidian-media-db-plugin-ribbon-class');
|
ribbonIconEl.addClass('obsidian-media-db-plugin-ribbon-class');
|
||||||
|
|
||||||
|
|
@ -28,7 +31,7 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
this.addCommand({
|
this.addCommand({
|
||||||
id: 'open-media-db-search-modal',
|
id: 'open-media-db-search-modal',
|
||||||
name: 'Add new Media DB entry',
|
name: 'Add new Media DB entry',
|
||||||
callback: () => this.createMediaDbNote(this.openMediaDbSearchModal.bind(this)),
|
callback: () => this.createMediaDbNote(this.openMediaDbAdvancedSearchModal.bind(this)),
|
||||||
});
|
});
|
||||||
// register command to open id search modal
|
// register command to open id search modal
|
||||||
this.addCommand({
|
this.addCommand({
|
||||||
|
|
@ -36,6 +39,20 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
name: 'Add new Media DB entry by id',
|
name: 'Add new Media DB entry by id',
|
||||||
callback: () => this.createMediaDbNote(this.openMediaDbIdSearchModal.bind(this)),
|
callback: () => this.createMediaDbNote(this.openMediaDbIdSearchModal.bind(this)),
|
||||||
});
|
});
|
||||||
|
// register command to update the open note
|
||||||
|
this.addCommand({
|
||||||
|
id: 'update-media-db-note',
|
||||||
|
name: 'Update the open note, if it is a Media DB entry.',
|
||||||
|
checkCallback: (checking: boolean) => {
|
||||||
|
if (!this.app.workspace.getActiveFile()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!checking) {
|
||||||
|
this.updateActiveNote()
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// register the settings tab
|
// register the settings tab
|
||||||
this.addSettingTab(new MediaDbSettingTab(this.app, this));
|
this.addSettingTab(new MediaDbSettingTab(this.app, this));
|
||||||
|
|
@ -47,45 +64,43 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
this.apiManager.registerAPI(new MALAPI(this));
|
this.apiManager.registerAPI(new MALAPI(this));
|
||||||
this.apiManager.registerAPI(new WikipediaAPI(this));
|
this.apiManager.registerAPI(new WikipediaAPI(this));
|
||||||
this.apiManager.registerAPI(new MusicBrainzAPI(this));
|
this.apiManager.registerAPI(new MusicBrainzAPI(this));
|
||||||
|
this.apiManager.registerAPI(new SteamAPI(this));
|
||||||
// this.apiManager.registerAPI(new LocGovAPI(this)); // TODO: parse data
|
// this.apiManager.registerAPI(new LocGovAPI(this)); // TODO: parse data
|
||||||
|
|
||||||
|
this.mediaTypeManager = new MediaTypeManager(this.settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
async createMediaDbNote(modal: () => Promise<MediaTypeModel>): Promise<void> {
|
async createMediaDbNote(modal: () => Promise<MediaTypeModel>): Promise<void> {
|
||||||
try {
|
try {
|
||||||
let data: MediaTypeModel = await modal();
|
let data: MediaTypeModel = await modal();
|
||||||
console.log('MDB | Creating new note...');
|
|
||||||
|
|
||||||
data = await this.apiManager.queryDetailedInfo(data);
|
data = await this.apiManager.queryDetailedInfo(data);
|
||||||
|
|
||||||
// console.log(data);
|
await this.createMediaDbNoteFromModel(data);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(e);
|
||||||
|
new Notice(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let fileContent = `---\n${data.toMetaData()}---\n`;
|
async createMediaDbNoteFromModel(mediaTypeModel: MediaTypeModel): Promise<void> {
|
||||||
|
try {
|
||||||
|
console.log('MDB | Creating new note...');
|
||||||
|
// console.log(mediaTypeModel);
|
||||||
|
|
||||||
let templateFile: TFile = null;
|
let fileContent = `---\n${mediaTypeModel.toMetaData()}---\n`;
|
||||||
|
|
||||||
if (data.type === 'movie' && this.settings.movieTemplate) {
|
if (this.settings.templates) {
|
||||||
templateFile = this.app.vault.getFiles().filter((f: TFile) => f.name === this.settings.movieTemplate).first();
|
fileContent += await this.mediaTypeManager.getContent(mediaTypeModel, this.app);
|
||||||
} else if (data.type === 'series' && this.settings.seriesTemplate) {
|
|
||||||
templateFile = this.app.vault.getFiles().filter((f: TFile) => f.name === this.settings.seriesTemplate).first();
|
|
||||||
} else if (data.type === 'game' && this.settings.gameTemplate) {
|
|
||||||
templateFile = this.app.vault.getFiles().filter((f: TFile) => f.name === this.settings.gameTemplate).first();
|
|
||||||
} else if (data.type === 'wiki' && this.settings.wikiTemplate) {
|
|
||||||
templateFile = this.app.vault.getFiles().filter((f: TFile) => f.name === this.settings.wikiTemplate).first();
|
|
||||||
} else if (data.type === 'musicRelease' && this.settings.musicReleaseTemplate) {
|
|
||||||
templateFile = this.app.vault.getFiles().filter((f: TFile) => f.name === this.settings.musicReleaseTemplate).first();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (templateFile) {
|
const fileName = replaceIllegalFileNameCharactersInString(this.mediaTypeManager.getFileName(mediaTypeModel));
|
||||||
let template = await this.app.vault.cachedRead(templateFile);
|
|
||||||
// console.log(template);
|
|
||||||
if (this.settings.templates) {
|
|
||||||
template = replaceTags(template, data);
|
|
||||||
}
|
|
||||||
fileContent += template;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fileName = replaceIllegalFileNameCharactersInString(data.getFileName());
|
|
||||||
const filePath = `${this.settings.folder.replace(/\/$/, '')}/${fileName}.md`;
|
const filePath = `${this.settings.folder.replace(/\/$/, '')}/${fileName}.md`;
|
||||||
|
|
||||||
|
const file = this.app.vault.getAbstractFileByPath(filePath);
|
||||||
|
if (file) {
|
||||||
|
await this.app.vault.delete(file);
|
||||||
|
}
|
||||||
|
|
||||||
const targetFile = await this.app.vault.create(filePath, fileContent);
|
const targetFile = await this.app.vault.create(filePath, fileContent);
|
||||||
|
|
||||||
// open file
|
// open file
|
||||||
|
|
@ -95,17 +110,18 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await activeLeaf.openFile(targetFile, {state: {mode: 'source'}});
|
await activeLeaf.openFile(targetFile, {state: {mode: 'source'}});
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn(e);
|
console.warn(e);
|
||||||
new Notice(e.toString());
|
new Notice(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async openMediaDbSearchModal(): Promise<MediaTypeModel> {
|
async openMediaDbAdvancedSearchModal(): Promise<MediaTypeModel> {
|
||||||
return new Promise(((resolve, reject) => {
|
return new Promise(((resolve, reject) => {
|
||||||
new MediaDbAdvancedSearchModal(this.app, this.apiManager, (err, results) => {
|
new MediaDbAdvancedSearchModal(this.app, this, (err, results) => {
|
||||||
if (err) return reject(err);
|
if (err) return reject(err);
|
||||||
new MediaDbSearchResultModal(this.app, results, (err2, res) => {
|
new MediaDbSearchResultModal(this.app, this, results, (err2, res) => {
|
||||||
if (err2) return reject(err2);
|
if (err2) return reject(err2);
|
||||||
resolve(res);
|
resolve(res);
|
||||||
}).open();
|
}).open();
|
||||||
|
|
@ -115,18 +131,46 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
|
|
||||||
async openMediaDbIdSearchModal(): Promise<MediaTypeModel> {
|
async openMediaDbIdSearchModal(): Promise<MediaTypeModel> {
|
||||||
return new Promise(((resolve, reject) => {
|
return new Promise(((resolve, reject) => {
|
||||||
new MediaDbIdSearchModal(this.app, this.apiManager, (err, res) => {
|
new MediaDbIdSearchModal(this.app, this, (err, res) => {
|
||||||
if (err) return reject(err);
|
if (err) return reject(err);
|
||||||
resolve(res);
|
resolve(res);
|
||||||
}).open();
|
}).open();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateActiveNote() {
|
||||||
|
const activeFile: TFile = this.app.workspace.getActiveFile();
|
||||||
|
if (!activeFile) {
|
||||||
|
throw new Error('MDB | there is no active note');
|
||||||
|
}
|
||||||
|
|
||||||
|
let metadata: FrontMatterCache = this.app.metadataCache.getFileCache(activeFile).frontmatter;
|
||||||
|
|
||||||
|
if (!metadata?.type || !metadata?.dataSource || !metadata?.id) {
|
||||||
|
throw new Error('MDB | active note is not a Media DB entry or is missing metadata');
|
||||||
|
}
|
||||||
|
|
||||||
|
delete metadata.position; // remove unnecessary data from the FrontMatterCache
|
||||||
|
let oldMediaTypeModel = this.mediaTypeManager.createMediaTypeModelFromMediaType(metadata, metadata.type);
|
||||||
|
|
||||||
|
let newMediaTypeModel = await this.apiManager.queryDetailedInfoById(metadata.id, metadata.dataSource);
|
||||||
|
if (!newMediaTypeModel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
newMediaTypeModel = Object.assign(oldMediaTypeModel, newMediaTypeModel.getWithOutUserData());
|
||||||
|
|
||||||
|
console.log('MDB | deleting old entry');
|
||||||
|
await this.app.vault.delete(activeFile);
|
||||||
|
await this.createMediaDbNoteFromModel(newMediaTypeModel);
|
||||||
|
}
|
||||||
|
|
||||||
async loadSettings() {
|
async loadSettings() {
|
||||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveSettings() {
|
async saveSettings() {
|
||||||
|
this.mediaTypeManager.updateTemplates(this.settings);
|
||||||
await this.saveData(this.settings);
|
await this.saveData(this.settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,22 @@
|
||||||
import {App, ButtonComponent, Component, Modal, Notice, Setting, TextComponent, ToggleComponent} from 'obsidian';
|
import {App, ButtonComponent, Component, Modal, Notice, Setting, TextComponent, ToggleComponent} from 'obsidian';
|
||||||
import {MediaTypeModel} from '../models/MediaTypeModel';
|
import {MediaTypeModel} from '../models/MediaTypeModel';
|
||||||
import {APIManager} from '../api/APIManager';
|
|
||||||
import {debugLog} from '../utils/Utils';
|
import {debugLog} from '../utils/Utils';
|
||||||
|
import MediaDbPlugin from '../main';
|
||||||
|
|
||||||
export class MediaDbAdvancedSearchModal extends Modal {
|
export class MediaDbAdvancedSearchModal extends Modal {
|
||||||
query: string;
|
query: string;
|
||||||
isBusy: boolean;
|
isBusy: boolean;
|
||||||
apiManager: APIManager;
|
plugin: MediaDbPlugin;
|
||||||
searchBtn: ButtonComponent;
|
searchBtn: ButtonComponent;
|
||||||
selectedApis: any;
|
selectedApis: any;
|
||||||
onSubmit: (err: Error, result?: MediaTypeModel[]) => void;
|
onSubmit: (err: Error, result?: MediaTypeModel[]) => void;
|
||||||
|
|
||||||
constructor(app: App, apiManager: APIManager, onSubmit?: (err: Error, result?: MediaTypeModel[]) => void) {
|
constructor(app: App, plugin: MediaDbPlugin, onSubmit?: (err: Error, result?: MediaTypeModel[]) => void) {
|
||||||
super(app);
|
super(app);
|
||||||
this.apiManager = apiManager;
|
this.plugin = plugin;
|
||||||
this.onSubmit = onSubmit;
|
this.onSubmit = onSubmit;
|
||||||
this.selectedApis = [];
|
this.selectedApis = [];
|
||||||
for (const api of this.apiManager.apis) {
|
for (const api of this.plugin.apiManager.apis) {
|
||||||
this.selectedApis[api.apiName] = false;
|
this.selectedApis[api.apiName] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -56,7 +56,7 @@ export class MediaDbAdvancedSearchModal extends Modal {
|
||||||
|
|
||||||
console.log(`MDB | query started with title ${this.query}`);
|
console.log(`MDB | query started with title ${this.query}`);
|
||||||
|
|
||||||
const res = await this.apiManager.query(this.query, this.selectedApis);
|
const res = await this.plugin.apiManager.query(this.query, this.selectedApis);
|
||||||
this.onSubmit(null, res);
|
this.onSubmit(null, res);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.onSubmit(e);
|
this.onSubmit(e);
|
||||||
|
|
@ -84,7 +84,7 @@ export class MediaDbAdvancedSearchModal extends Modal {
|
||||||
contentEl.createEl('h3', {text: 'APIs to search'});
|
contentEl.createEl('h3', {text: 'APIs to search'});
|
||||||
|
|
||||||
const apiToggleComponents: Component[] = [];
|
const apiToggleComponents: Component[] = [];
|
||||||
for (const api of this.apiManager.apis) {
|
for (const api of this.plugin.apiManager.apis) {
|
||||||
const apiToggleListElementWrapper = contentEl.createEl('div', {cls: 'media-db-plugin-list-wrapper'});
|
const apiToggleListElementWrapper = contentEl.createEl('div', {cls: 'media-db-plugin-list-wrapper'});
|
||||||
|
|
||||||
const apiToggleTextWrapper = apiToggleListElementWrapper.createEl('div', {cls: 'media-db-plugin-list-text-wrapper'});
|
const apiToggleTextWrapper = apiToggleListElementWrapper.createEl('div', {cls: 'media-db-plugin-list-text-wrapper'});
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
import {App, ButtonComponent, DropdownComponent, Modal, Notice, Setting, TextComponent} from 'obsidian';
|
import {App, ButtonComponent, DropdownComponent, Modal, Notice, Setting, TextComponent} from 'obsidian';
|
||||||
import {MediaTypeModel} from '../models/MediaTypeModel';
|
import {MediaTypeModel} from '../models/MediaTypeModel';
|
||||||
import {APIManager} from '../api/APIManager';
|
|
||||||
import {debugLog} from '../utils/Utils';
|
import {debugLog} from '../utils/Utils';
|
||||||
|
import MediaDbPlugin from '../main';
|
||||||
|
|
||||||
export class MediaDbIdSearchModal extends Modal {
|
export class MediaDbIdSearchModal extends Modal {
|
||||||
query: string;
|
query: string;
|
||||||
isBusy: boolean;
|
isBusy: boolean;
|
||||||
apiManager: APIManager;
|
plugin: MediaDbPlugin;
|
||||||
searchBtn: ButtonComponent;
|
searchBtn: ButtonComponent;
|
||||||
selectedApi: string;
|
selectedApi: string;
|
||||||
onSubmit: (err: Error, result?: MediaTypeModel) => void;
|
onSubmit: (err: Error, result?: MediaTypeModel) => void;
|
||||||
|
|
||||||
constructor(app: App, apiManager: APIManager, onSubmit?: (err: Error, result?: MediaTypeModel) => void) {
|
constructor(app: App, plugin: MediaDbPlugin, onSubmit?: (err: Error, result?: MediaTypeModel) => void) {
|
||||||
super(app);
|
super(app);
|
||||||
this.apiManager = apiManager;
|
this.plugin = plugin;
|
||||||
this.onSubmit = onSubmit;
|
this.onSubmit = onSubmit;
|
||||||
this.selectedApi = '';
|
this.selectedApi = '';
|
||||||
}
|
}
|
||||||
|
|
@ -46,7 +46,7 @@ export class MediaDbIdSearchModal extends Modal {
|
||||||
|
|
||||||
console.log(`MDB | query started with id ${this.query}`);
|
console.log(`MDB | query started with id ${this.query}`);
|
||||||
|
|
||||||
const api = this.apiManager.getApiByName(this.selectedApi);
|
const api = this.plugin.apiManager.getApiByName(this.selectedApi);
|
||||||
if (!api) {
|
if (!api) {
|
||||||
this.onSubmit(new Error('the selected api does not exist'));
|
this.onSubmit(new Error('the selected api does not exist'));
|
||||||
}
|
}
|
||||||
|
|
@ -83,7 +83,7 @@ export class MediaDbIdSearchModal extends Modal {
|
||||||
apiSelectorComponent.onChange((value: string) => {
|
apiSelectorComponent.onChange((value: string) => {
|
||||||
this.selectedApi = value;
|
this.selectedApi = value;
|
||||||
});
|
});
|
||||||
for (const api of this.apiManager.apis) {
|
for (const api of this.plugin.apiManager.apis) {
|
||||||
apiSelectorComponent.addOption(api.apiName, api.apiName);
|
apiSelectorComponent.addOption(api.apiName, api.apiName);
|
||||||
}
|
}
|
||||||
apiSelectorWrapper.appendChild(apiSelectorComponent.selectEl);
|
apiSelectorWrapper.appendChild(apiSelectorComponent.selectEl);
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,15 @@
|
||||||
import {App, SuggestModal} from 'obsidian';
|
import {App, SuggestModal} from 'obsidian';
|
||||||
import {MediaTypeModel} from '../models/MediaTypeModel';
|
import {MediaTypeModel} from '../models/MediaTypeModel';
|
||||||
|
import MediaDbPlugin from '../main';
|
||||||
|
|
||||||
export class MediaDbSearchResultModal extends SuggestModal<MediaTypeModel> {
|
export class MediaDbSearchResultModal extends SuggestModal<MediaTypeModel> {
|
||||||
suggestion: MediaTypeModel[];
|
suggestion: MediaTypeModel[];
|
||||||
|
plugin: MediaDbPlugin;
|
||||||
onChoose: (error: Error, result?: MediaTypeModel) => void;
|
onChoose: (error: Error, result?: MediaTypeModel) => void;
|
||||||
|
|
||||||
constructor(app: App, suggestion: MediaTypeModel[], onChoose: (error: Error, result?: MediaTypeModel) => void) {
|
constructor(app: App, plugin: MediaDbPlugin, suggestion: MediaTypeModel[], onChoose: (error: Error, result?: MediaTypeModel) => void) {
|
||||||
super(app);
|
super(app);
|
||||||
|
this.plugin = plugin;
|
||||||
this.suggestion = suggestion;
|
this.suggestion = suggestion;
|
||||||
this.onChoose = onChoose;
|
this.onChoose = onChoose;
|
||||||
}
|
}
|
||||||
|
|
@ -20,9 +23,9 @@ export class MediaDbSearchResultModal extends SuggestModal<MediaTypeModel> {
|
||||||
|
|
||||||
// Renders each suggestion item.
|
// Renders each suggestion item.
|
||||||
renderSuggestion(item: MediaTypeModel, el: HTMLElement) {
|
renderSuggestion(item: MediaTypeModel, el: HTMLElement) {
|
||||||
el.createEl('div', {text: item.getFileName()});
|
el.createEl('div', {text: this.plugin.mediaTypeManager.getFileName(item)});
|
||||||
el.createEl('small', {text: `${item.englishTitle}\n`});
|
el.createEl('small', {text: `${item.englishTitle}\n`});
|
||||||
el.createEl('small', {text: `${item.type.toUpperCase()} from ${item.dataSource}`});
|
el.createEl('small', {text: `${item.type.toUpperCase() + (item.subType ? ` (${item.subType})` : '')} from ${item.dataSource}`});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform action on the selected suggestion.
|
// Perform action on the selected suggestion.
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import {MediaTypeModel} from './MediaTypeModel';
|
import {MediaTypeModel} from './MediaTypeModel';
|
||||||
import {stringifyYaml} from 'obsidian';
|
|
||||||
import {mediaDbTag} from '../utils/Utils';
|
import {mediaDbTag} from '../utils/Utils';
|
||||||
|
import {MediaType} from '../utils/MediaType';
|
||||||
|
|
||||||
|
|
||||||
export class GameModel extends MediaTypeModel {
|
export class GameModel extends MediaTypeModel {
|
||||||
type: string;
|
type: string;
|
||||||
|
subType: string;
|
||||||
title: string;
|
title: string;
|
||||||
englishTitle: string;
|
englishTitle: string;
|
||||||
year: string;
|
year: string;
|
||||||
|
|
@ -19,26 +20,26 @@ export class GameModel extends MediaTypeModel {
|
||||||
released: boolean;
|
released: boolean;
|
||||||
releaseDate: string;
|
releaseDate: string;
|
||||||
|
|
||||||
played: boolean;
|
userData: {
|
||||||
personalRating: number;
|
played: boolean;
|
||||||
|
personalRating: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
constructor(obj: any = {}) {
|
constructor(obj: any = {}) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
Object.assign(this, obj);
|
Object.assign(this, obj);
|
||||||
}
|
|
||||||
|
|
||||||
toMetaData(): string {
|
this.type = this.getMediaType();
|
||||||
return stringifyYaml({...this, tags: '#' + this.getTags().join('/')});
|
|
||||||
}
|
|
||||||
|
|
||||||
getFileName(): string {
|
|
||||||
return this.title + (this.year ? ` (${this.year})` : '');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getTags(): string[] {
|
getTags(): string[] {
|
||||||
return [mediaDbTag, 'game'];
|
return [mediaDbTag, 'game'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getMediaType(): MediaType {
|
||||||
|
return MediaType.Game;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
|
import {MediaType} from '../utils/MediaType';
|
||||||
|
import {YAMLConverter} from '../utils/YAMLConverter';
|
||||||
|
|
||||||
export abstract class MediaTypeModel {
|
export abstract class MediaTypeModel {
|
||||||
type: string;
|
type: string;
|
||||||
|
subType: string;
|
||||||
title: string;
|
title: string;
|
||||||
englishTitle: string;
|
englishTitle: string;
|
||||||
year: string;
|
year: string;
|
||||||
|
|
@ -7,9 +11,20 @@ export abstract class MediaTypeModel {
|
||||||
url: string;
|
url: string;
|
||||||
id: string;
|
id: string;
|
||||||
|
|
||||||
abstract toMetaData(): string;
|
userData: object;
|
||||||
|
|
||||||
abstract getFileName(): string;
|
abstract getMediaType(): MediaType;
|
||||||
|
|
||||||
abstract getTags(): string[];
|
abstract getTags(): string[];
|
||||||
|
|
||||||
|
toMetaData(): string {
|
||||||
|
return YAMLConverter.toYaml({...this.getWithOutUserData(), ...this.userData, tags: '#' + this.getTags().join('/')});
|
||||||
|
}
|
||||||
|
|
||||||
|
getWithOutUserData(): object {
|
||||||
|
const copy = JSON.parse(JSON.stringify(this));
|
||||||
|
delete copy.userData;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import {MediaTypeModel} from './MediaTypeModel';
|
import {MediaTypeModel} from './MediaTypeModel';
|
||||||
import {stringifyYaml} from 'obsidian';
|
|
||||||
import {mediaDbTag} from '../utils/Utils';
|
import {mediaDbTag} from '../utils/Utils';
|
||||||
|
import {MediaType} from '../utils/MediaType';
|
||||||
|
|
||||||
|
|
||||||
export class MovieModel extends MediaTypeModel {
|
export class MovieModel extends MediaTypeModel {
|
||||||
type: string;
|
type: string;
|
||||||
|
subType: string;
|
||||||
title: string;
|
title: string;
|
||||||
englishTitle: string;
|
englishTitle: string;
|
||||||
year: string;
|
year: string;
|
||||||
|
|
@ -21,27 +22,26 @@ export class MovieModel extends MediaTypeModel {
|
||||||
released: boolean;
|
released: boolean;
|
||||||
premiere: string;
|
premiere: string;
|
||||||
|
|
||||||
watched: boolean;
|
userData: {
|
||||||
lastWatched: string;
|
watched: boolean;
|
||||||
personalRating: number;
|
lastWatched: string;
|
||||||
|
personalRating: number;
|
||||||
|
};
|
||||||
|
|
||||||
constructor(obj: any = {}) {
|
constructor(obj: any = {}) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
Object.assign(this, obj);
|
Object.assign(this, obj);
|
||||||
}
|
|
||||||
|
|
||||||
toMetaData(): string {
|
this.type = this.getMediaType();
|
||||||
return stringifyYaml({...this, tags: '#' + this.getTags().join('/')});
|
|
||||||
}
|
|
||||||
|
|
||||||
getFileName(): string {
|
|
||||||
return this.title + (this.year ? ` (${this.year})` : '');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getTags(): string[] {
|
getTags(): string[] {
|
||||||
return [mediaDbTag, 'tv', 'movie'];
|
return [mediaDbTag, 'tv', 'movie'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getMediaType(): MediaType {
|
||||||
|
return MediaType.Movie;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import {MediaTypeModel} from './MediaTypeModel';
|
import {MediaTypeModel} from './MediaTypeModel';
|
||||||
import {stringifyYaml} from 'obsidian';
|
|
||||||
import {mediaDbTag} from '../utils/Utils';
|
import {mediaDbTag} from '../utils/Utils';
|
||||||
|
import {MediaType} from '../utils/MediaType';
|
||||||
|
|
||||||
|
|
||||||
export class MusicReleaseModel extends MediaTypeModel {
|
export class MusicReleaseModel extends MediaTypeModel {
|
||||||
type: string;
|
type: string;
|
||||||
|
subType: string;
|
||||||
title: string;
|
title: string;
|
||||||
englishTitle: string;
|
englishTitle: string;
|
||||||
year: string;
|
year: string;
|
||||||
|
|
@ -14,27 +15,26 @@ export class MusicReleaseModel extends MediaTypeModel {
|
||||||
|
|
||||||
genres: string[];
|
genres: string[];
|
||||||
artists: string[];
|
artists: string[];
|
||||||
subType: string;
|
|
||||||
rating: number;
|
rating: number;
|
||||||
|
|
||||||
personalRating: number;
|
userData: {
|
||||||
|
personalRating: number;
|
||||||
|
};
|
||||||
|
|
||||||
constructor(obj: any = {}) {
|
constructor(obj: any = {}) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
Object.assign(this, obj);
|
Object.assign(this, obj);
|
||||||
}
|
|
||||||
|
|
||||||
toMetaData(): string {
|
this.type = this.getMediaType();
|
||||||
return stringifyYaml({...this, tags: '#' + this.getTags().join('/')});
|
|
||||||
}
|
|
||||||
|
|
||||||
getFileName(): string {
|
|
||||||
return this.title + ' (' + this.artists.join(', ') + ' - ' + this.year + ' - ' + this.subType + ')';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getTags(): string[] {
|
getTags(): string[] {
|
||||||
return [mediaDbTag, 'music', 'album'];
|
return [mediaDbTag, 'music', this.subType];
|
||||||
|
}
|
||||||
|
|
||||||
|
getMediaType(): MediaType {
|
||||||
|
return MediaType.MusicRelease;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import {MediaTypeModel} from './MediaTypeModel';
|
import {MediaTypeModel} from './MediaTypeModel';
|
||||||
import {stringifyYaml} from 'obsidian';
|
|
||||||
import {mediaDbTag} from '../utils/Utils';
|
import {mediaDbTag} from '../utils/Utils';
|
||||||
|
import {MediaType} from '../utils/MediaType';
|
||||||
|
|
||||||
|
|
||||||
export class SeriesModel extends MediaTypeModel {
|
export class SeriesModel extends MediaTypeModel {
|
||||||
type: string;
|
type: string;
|
||||||
|
subType: string;
|
||||||
title: string;
|
title: string;
|
||||||
englishTitle: string;
|
englishTitle: string;
|
||||||
year: string;
|
year: string;
|
||||||
|
|
@ -24,27 +25,26 @@ export class SeriesModel extends MediaTypeModel {
|
||||||
airedFrom: string;
|
airedFrom: string;
|
||||||
airedTo: string;
|
airedTo: string;
|
||||||
|
|
||||||
watched: boolean;
|
userData: {
|
||||||
lastWatched: string;
|
watched: boolean;
|
||||||
personalRating: number;
|
lastWatched: string;
|
||||||
|
personalRating: number;
|
||||||
|
};
|
||||||
|
|
||||||
constructor(obj: any = {}) {
|
constructor(obj: any = {}) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
Object.assign(this, obj);
|
Object.assign(this, obj);
|
||||||
}
|
|
||||||
|
|
||||||
toMetaData(): string {
|
this.type = this.getMediaType();
|
||||||
return stringifyYaml({...this, tags: '#' + this.getTags().join('/')});
|
|
||||||
}
|
|
||||||
|
|
||||||
getFileName(): string {
|
|
||||||
return this.title + ' (' + this.year + ')';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getTags(): string[] {
|
getTags(): string[] {
|
||||||
return [mediaDbTag, 'tv', 'series'];
|
return [mediaDbTag, 'tv', 'series'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getMediaType(): MediaType {
|
||||||
|
return MediaType.Series;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import {MediaTypeModel} from './MediaTypeModel';
|
import {MediaTypeModel} from './MediaTypeModel';
|
||||||
import {stringifyYaml} from 'obsidian';
|
|
||||||
import {mediaDbTag} from '../utils/Utils';
|
import {mediaDbTag} from '../utils/Utils';
|
||||||
|
import {MediaType} from '../utils/MediaType';
|
||||||
|
|
||||||
|
|
||||||
export class WikiModel extends MediaTypeModel {
|
export class WikiModel extends MediaTypeModel {
|
||||||
type: string;
|
type: string;
|
||||||
|
subType: string;
|
||||||
title: string;
|
title: string;
|
||||||
englishTitle: string;
|
englishTitle: string;
|
||||||
year: string;
|
year: string;
|
||||||
|
|
@ -16,23 +17,22 @@ export class WikiModel extends MediaTypeModel {
|
||||||
lastUpdated: string;
|
lastUpdated: string;
|
||||||
length: number;
|
length: number;
|
||||||
|
|
||||||
|
userData: {};
|
||||||
|
|
||||||
constructor(obj: any = {}) {
|
constructor(obj: any = {}) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
Object.assign(this, obj);
|
Object.assign(this, obj);
|
||||||
}
|
|
||||||
|
|
||||||
toMetaData(): string {
|
this.type = this.getMediaType();
|
||||||
return stringifyYaml({...this, tags: '#' + this.getTags().join('/')});
|
|
||||||
}
|
|
||||||
|
|
||||||
getFileName(): string {
|
|
||||||
return this.title;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getTags(): string[] {
|
getTags(): string[] {
|
||||||
return [mediaDbTag, 'wiki'];
|
return [mediaDbTag, 'wiki'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getMediaType(): MediaType {
|
||||||
|
return MediaType.Wiki;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,23 +9,39 @@ export interface MediaDbPluginSettings {
|
||||||
folder: string,
|
folder: string,
|
||||||
sfwFilter: boolean,
|
sfwFilter: boolean,
|
||||||
OMDbKey: string,
|
OMDbKey: string,
|
||||||
|
|
||||||
movieTemplate: string,
|
movieTemplate: string,
|
||||||
seriesTemplate: string,
|
seriesTemplate: string,
|
||||||
gameTemplate: string,
|
gameTemplate: string,
|
||||||
wikiTemplate: string,
|
wikiTemplate: string,
|
||||||
musicReleaseTemplate: string,
|
musicReleaseTemplate: string,
|
||||||
|
|
||||||
|
movieFileNameTemplate: string,
|
||||||
|
seriesFileNameTemplate: string,
|
||||||
|
gameFileNameTemplate: string,
|
||||||
|
wikiFileNameTemplate: string,
|
||||||
|
musicReleaseFileNameTemplate: string,
|
||||||
|
|
||||||
templates: boolean,
|
templates: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DEFAULT_SETTINGS: MediaDbPluginSettings = {
|
export const DEFAULT_SETTINGS: MediaDbPluginSettings = {
|
||||||
folder: '',
|
folder: 'Media DB',
|
||||||
sfwFilter: true,
|
sfwFilter: true,
|
||||||
OMDbKey: '',
|
OMDbKey: '',
|
||||||
|
|
||||||
movieTemplate: '',
|
movieTemplate: '',
|
||||||
seriesTemplate: '',
|
seriesTemplate: '',
|
||||||
gameTemplate: '',
|
gameTemplate: '',
|
||||||
wikiTemplate: '',
|
wikiTemplate: '',
|
||||||
musicReleaseTemplate: '',
|
musicReleaseTemplate: '',
|
||||||
|
|
||||||
|
movieFileNameTemplate: '{{ title }} ({{ year }})',
|
||||||
|
seriesFileNameTemplate: '{{ title }} ({{ year }})',
|
||||||
|
gameFileNameTemplate: '{{ title }} ({{ year }})',
|
||||||
|
wikiFileNameTemplate: '{{ title }}',
|
||||||
|
musicReleaseFileNameTemplate: '{{ title }} (by {{ ENUM:artists }} - {{ year }})',
|
||||||
|
|
||||||
templates: true,
|
templates: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -57,6 +73,29 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName('OMDb API key')
|
||||||
|
.setDesc('API key for "www.omdbapi.com".')
|
||||||
|
.addText(cb => {
|
||||||
|
cb.setPlaceholder('API key')
|
||||||
|
.setValue(this.plugin.settings.OMDbKey)
|
||||||
|
.onChange(data => {
|
||||||
|
this.plugin.settings.OMDbKey = data;
|
||||||
|
this.plugin.saveSettings();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName('SFW filter')
|
||||||
|
.setDesc('Only shows SFW results for APIs that offer filtering.')
|
||||||
|
.addToggle(cb => {
|
||||||
|
cb.setValue(this.plugin.settings.sfwFilter)
|
||||||
|
.onChange(data => {
|
||||||
|
this.plugin.settings.sfwFilter = data;
|
||||||
|
this.plugin.saveSettings();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('Resolve {{ tags }} in templates')
|
.setName('Resolve {{ tags }} in templates')
|
||||||
.setDesc('Whether to resolve {{ tags }} in templates. The spaces inside the curly braces are important.')
|
.setDesc('Whether to resolve {{ tags }} in templates. The spaces inside the curly braces are important.')
|
||||||
|
|
@ -68,6 +107,9 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
containerEl.createEl('h3', {text: 'Template Settings'});
|
||||||
|
// region templates
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('Movie template')
|
.setName('Movie template')
|
||||||
.setDesc('Template file to be used when creating a new note for a movie.')
|
.setDesc('Template file to be used when creating a new note for a movie.')
|
||||||
|
|
@ -132,29 +174,71 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
this.plugin.saveSettings();
|
this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
containerEl.createEl('h3', {text: 'File Name Settings'});
|
||||||
|
// region file name templates
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('OMDb API key')
|
.setName('Movie file name template')
|
||||||
.setDesc('API key for "www.omdbapi.com".')
|
.setDesc('Template for the file name used when creating a new note for a movie.')
|
||||||
.addText(cb => {
|
.addSearch(cb => {
|
||||||
cb.setPlaceholder('API key')
|
cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.movieFileNameTemplate}`)
|
||||||
.setValue(this.plugin.settings.OMDbKey)
|
.setValue(this.plugin.settings.movieFileNameTemplate)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.OMDbKey = data;
|
this.plugin.settings.movieFileNameTemplate = data;
|
||||||
this.plugin.saveSettings();
|
this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('SFW filter')
|
.setName('Series file name template')
|
||||||
.setDesc('Only shows SFW results for APIs that offer filtering.')
|
.setDesc('Template for the file name used when creating a new note for a series.')
|
||||||
.addToggle(cb => {
|
.addSearch(cb => {
|
||||||
cb.setValue(this.plugin.settings.sfwFilter)
|
cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.seriesFileNameTemplate}`)
|
||||||
|
.setValue(this.plugin.settings.seriesFileNameTemplate)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.sfwFilter = data;
|
this.plugin.settings.seriesFileNameTemplate = data;
|
||||||
this.plugin.saveSettings();
|
this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName('Game file name template')
|
||||||
|
.setDesc('Template for the file name used when creating a new note for a game.')
|
||||||
|
.addSearch(cb => {
|
||||||
|
cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.gameFileNameTemplate}`)
|
||||||
|
.setValue(this.plugin.settings.gameFileNameTemplate)
|
||||||
|
.onChange(data => {
|
||||||
|
this.plugin.settings.gameFileNameTemplate = data;
|
||||||
|
this.plugin.saveSettings();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName('Wiki file name template')
|
||||||
|
.setDesc('Template for the file name used when creating a new note for a wiki entry.')
|
||||||
|
.addSearch(cb => {
|
||||||
|
cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.wikiFileNameTemplate}`)
|
||||||
|
.setValue(this.plugin.settings.wikiFileNameTemplate)
|
||||||
|
.onChange(data => {
|
||||||
|
this.plugin.settings.wikiFileNameTemplate = data;
|
||||||
|
this.plugin.saveSettings();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
new Setting(containerEl)
|
||||||
|
.setName('Music Release file name template')
|
||||||
|
.setDesc('Template for the file name used when creating a new note for a music release.')
|
||||||
|
.addSearch(cb => {
|
||||||
|
cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.musicReleaseFileNameTemplate}`)
|
||||||
|
.setValue(this.plugin.settings.musicReleaseFileNameTemplate)
|
||||||
|
.onChange(data => {
|
||||||
|
this.plugin.settings.musicReleaseFileNameTemplate = data;
|
||||||
|
this.plugin.saveSettings();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
27
src/tests/TestAPI.ts
Normal file
27
src/tests/TestAPI.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import {APIModel} from '../api/APIModel';
|
||||||
|
import {MediaTypeModel} from '../models/MediaTypeModel';
|
||||||
|
import MediaDbPlugin from '../main';
|
||||||
|
|
||||||
|
export class TestAPI extends APIModel {
|
||||||
|
plugin: MediaDbPlugin;
|
||||||
|
|
||||||
|
|
||||||
|
constructor(plugin: MediaDbPlugin) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.apiName = 'TestAPI';
|
||||||
|
this.apiDescription = 'A test API for automated testing.';
|
||||||
|
this.apiUrl = '';
|
||||||
|
this.types = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async getById(item: MediaTypeModel): Promise<MediaTypeModel> {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
async searchByTitle(title: string): Promise<MediaTypeModel[]> {
|
||||||
|
return [] as MediaTypeModel[];
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/utils/MediaType.ts
Normal file
7
src/utils/MediaType.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
export enum MediaType {
|
||||||
|
Movie = 'movie',
|
||||||
|
Series = 'series',
|
||||||
|
Game = 'game',
|
||||||
|
MusicRelease = 'musicRelease',
|
||||||
|
Wiki = 'wiki',
|
||||||
|
}
|
||||||
73
src/utils/MediaTypeManager.ts
Normal file
73
src/utils/MediaTypeManager.ts
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
import {MediaDbPluginSettings} from '../settings/Settings';
|
||||||
|
import {MediaType} from './MediaType';
|
||||||
|
import {MediaTypeModel} from '../models/MediaTypeModel';
|
||||||
|
import {replaceTags} from './Utils';
|
||||||
|
import {App, TFile} from 'obsidian';
|
||||||
|
import {MovieModel} from '../models/MovieModel';
|
||||||
|
import {SeriesModel} from '../models/SeriesModel';
|
||||||
|
import {GameModel} from '../models/GameModel';
|
||||||
|
import {WikiModel} from '../models/WikiModel';
|
||||||
|
import {MusicReleaseModel} from '../models/MusicReleaseModel';
|
||||||
|
|
||||||
|
export class MediaTypeManager {
|
||||||
|
mediaFileNameTemplateMap: Map<MediaType, string>;
|
||||||
|
mediaTemplateMap: Map<MediaType, string>;
|
||||||
|
|
||||||
|
constructor(settings: MediaDbPluginSettings) {
|
||||||
|
this.updateTemplates(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTemplates(settings: MediaDbPluginSettings) {
|
||||||
|
this.mediaFileNameTemplateMap = new Map<MediaType, string>();
|
||||||
|
this.mediaFileNameTemplateMap.set(MediaType.Movie, settings.movieFileNameTemplate);
|
||||||
|
this.mediaFileNameTemplateMap.set(MediaType.Series, settings.seriesFileNameTemplate);
|
||||||
|
this.mediaFileNameTemplateMap.set(MediaType.Game, settings.gameFileNameTemplate);
|
||||||
|
this.mediaFileNameTemplateMap.set(MediaType.Wiki, settings.wikiFileNameTemplate);
|
||||||
|
this.mediaFileNameTemplateMap.set(MediaType.MusicRelease, settings.musicReleaseFileNameTemplate);
|
||||||
|
|
||||||
|
this.mediaTemplateMap = new Map<MediaType, string>();
|
||||||
|
this.mediaTemplateMap.set(MediaType.Movie, settings.movieTemplate);
|
||||||
|
this.mediaTemplateMap.set(MediaType.Series, settings.seriesTemplate);
|
||||||
|
this.mediaTemplateMap.set(MediaType.Game, settings.gameTemplate);
|
||||||
|
this.mediaTemplateMap.set(MediaType.Wiki, settings.wikiTemplate);
|
||||||
|
this.mediaTemplateMap.set(MediaType.MusicRelease, settings.musicReleaseTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
|
getFileName(mediaTypeModel: MediaTypeModel): string {
|
||||||
|
return replaceTags(this.mediaFileNameTemplateMap.get(mediaTypeModel.getMediaType()), mediaTypeModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getContent(mediaTypeModel: MediaTypeModel, app: App) {
|
||||||
|
const templateFileName = this.mediaTemplateMap.get(mediaTypeModel.getMediaType());
|
||||||
|
|
||||||
|
if (!templateFileName) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const templateFile: TFile = app.vault.getFiles().filter((f: TFile) => f.name === templateFileName).first();
|
||||||
|
|
||||||
|
if (!templateFile) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const template = await app.vault.cachedRead(templateFile);
|
||||||
|
// console.log(template);
|
||||||
|
return replaceTags(template, mediaTypeModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
createMediaTypeModelFromMediaType(obj: any, mediaType: MediaType): MediaTypeModel {
|
||||||
|
if (mediaType === MediaType.Movie) {
|
||||||
|
return new MovieModel(obj);
|
||||||
|
} else if (mediaType === MediaType.Series) {
|
||||||
|
return new SeriesModel(obj);
|
||||||
|
} else if (mediaType === MediaType.Game) {
|
||||||
|
return new GameModel(obj);
|
||||||
|
} else if (mediaType === MediaType.Wiki) {
|
||||||
|
return new WikiModel(obj);
|
||||||
|
} else if (mediaType === MediaType.MusicRelease) {
|
||||||
|
return new MusicReleaseModel(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,7 +7,6 @@ export const mediaDbTag: string = 'mediaDB';
|
||||||
export const mediaDbVersion: string = '0.1.8';
|
export const mediaDbVersion: string = '0.1.8';
|
||||||
export const debug: boolean = false;
|
export const debug: boolean = false;
|
||||||
|
|
||||||
|
|
||||||
export function wrapAround(value: number, size: number): number {
|
export function wrapAround(value: number, size: number): number {
|
||||||
return ((value % size) + size) % size;
|
return ((value % size) + size) % size;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
39
src/utils/YAMLConverter.ts
Normal file
39
src/utils/YAMLConverter.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
export class YAMLConverter {
|
||||||
|
static toYaml(obj: any): string {
|
||||||
|
let output = '';
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(obj)) {
|
||||||
|
output += `${key}: ${YAMLConverter.toYamlString(value, 0)}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static toYamlString(value: any, indentation: number): string {
|
||||||
|
if (typeof value === 'boolean') {
|
||||||
|
return value ? 'true' : 'false';
|
||||||
|
} else if (typeof value === 'number') {
|
||||||
|
return value.toString();
|
||||||
|
} else if (typeof value === 'string') {
|
||||||
|
return '"' + value + '"';
|
||||||
|
} else if (typeof value === 'object') {
|
||||||
|
let output = '';
|
||||||
|
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
for (const valueElement of value) {
|
||||||
|
output += `\n${YAMLConverter.calculateSpacing(indentation)} - ${YAMLConverter.toYamlString(valueElement, indentation + 1)}`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (const [objKey, objValue] of Object.entries(value)) {
|
||||||
|
output += `\n${YAMLConverter.calculateSpacing(indentation)} ${objKey}: ${YAMLConverter.toYamlString(objValue, indentation + 1)}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static calculateSpacing(indentation: number): string {
|
||||||
|
return ' '.repeat(indentation * 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue