add obsidian eslint plugin, solve major issues
This commit is contained in:
parent
84214a1c3c
commit
498e2611ae
105 changed files with 5702 additions and 5308 deletions
265
packages/obsidian/src/api/apis/TMDBMovieAPI.ts
Normal file
265
packages/obsidian/src/api/apis/TMDBMovieAPI.ts
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
import createClient from 'openapi-fetch';
|
||||
import { APIModel } from 'packages/obsidian/src/api/APIModel';
|
||||
import type MediaDbPlugin from 'packages/obsidian/src/main';
|
||||
import type { MediaTypeModel } from 'packages/obsidian/src/models/MediaTypeModel';
|
||||
import { MovieModel } from 'packages/obsidian/src/models/MovieModel';
|
||||
import type { AppError } from 'packages/obsidian/src/utils/AppError';
|
||||
import { AppErrorKind, toAppError } from 'packages/obsidian/src/utils/AppError';
|
||||
import { Logger } from 'packages/obsidian/src/utils/Logger';
|
||||
import { MediaType } from 'packages/obsidian/src/utils/MediaType';
|
||||
import type { Result } from 'packages/obsidian/src/utils/result';
|
||||
import { err, fromPromise, ok } from 'packages/obsidian/src/utils/result';
|
||||
import { obsidianFetch } from 'packages/obsidian/src/utils/Utils';
|
||||
import type { paths } from 'packages/schemas/src/TMDB';
|
||||
|
||||
interface TMDBCreditMember {
|
||||
name?: string | null;
|
||||
job?: string | null;
|
||||
}
|
||||
|
||||
interface TMDBCreditsResponse {
|
||||
credits?: {
|
||||
cast?: TMDBCreditMember[];
|
||||
crew?: TMDBCreditMember[];
|
||||
};
|
||||
}
|
||||
|
||||
function isNonEmptyString(value: unknown): value is string {
|
||||
return typeof value === 'string' && value.length > 0;
|
||||
}
|
||||
|
||||
function getTopCastNames(credits: TMDBCreditsResponse['credits'], size: number): string[] {
|
||||
return (credits?.cast ?? [])
|
||||
.map(c => c.name)
|
||||
.filter(isNonEmptyString)
|
||||
.slice(0, size);
|
||||
}
|
||||
|
||||
function getCrewNamesByJob(credits: TMDBCreditsResponse['credits'], job: string): string[] {
|
||||
return (credits?.crew ?? [])
|
||||
.filter(c => c.job === job)
|
||||
.map(c => c.name)
|
||||
.filter(isNonEmptyString);
|
||||
}
|
||||
|
||||
export class TMDBMovieAPI extends APIModel {
|
||||
plugin: MediaDbPlugin;
|
||||
typeMappings: Map<string, string>;
|
||||
apiDateFormat: string = 'YYYY-MM-DD';
|
||||
|
||||
constructor(plugin: MediaDbPlugin) {
|
||||
super();
|
||||
|
||||
this.plugin = plugin;
|
||||
this.apiName = 'TMDBMovieAPI';
|
||||
this.apiDescription = 'A community built Movie DB.';
|
||||
this.apiUrl = 'https://www.themoviedb.org/';
|
||||
this.types = [MediaType.Movie];
|
||||
this.typeMappings = new Map<string, string>();
|
||||
this.typeMappings.set('movie', 'movie');
|
||||
}
|
||||
|
||||
async searchByTitle(title: string): Promise<Result<MediaTypeModel[], AppError>> {
|
||||
Logger.log(`MDB | api "${this.apiName}" queried by Title`);
|
||||
const key = this.plugin.app.secretStorage.getSecret(this.plugin.settings.TMDBKeyId);
|
||||
|
||||
if (!key) {
|
||||
return err({
|
||||
kind: AppErrorKind.Validation,
|
||||
message: `MDB | API key for ${this.apiName} missing.`,
|
||||
userMessage: `API key for ${this.apiName} missing.`,
|
||||
context: { apiName: this.apiName },
|
||||
});
|
||||
}
|
||||
|
||||
const client = createClient<paths>({ baseUrl: 'https://api.themoviedb.org' });
|
||||
const responseResult = await fromPromise(
|
||||
client.GET('/3/search/movie', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${key}`,
|
||||
},
|
||||
params: {
|
||||
query: {
|
||||
query: encodeURIComponent(title),
|
||||
include_adult: this.plugin.settings.sfwFilter ? false : true,
|
||||
},
|
||||
},
|
||||
fetch: obsidianFetch,
|
||||
}),
|
||||
cause =>
|
||||
toAppError(cause, {
|
||||
kind: AppErrorKind.Network,
|
||||
message: `MDB | Network error querying ${this.apiName}`,
|
||||
userMessage: `Network error querying ${this.apiName}`,
|
||||
context: { apiName: this.apiName, title },
|
||||
}),
|
||||
);
|
||||
|
||||
if (!responseResult.ok) {
|
||||
return err(responseResult.error);
|
||||
}
|
||||
|
||||
const response = responseResult.value;
|
||||
|
||||
if (response.response.status === 401) {
|
||||
return err({
|
||||
kind: AppErrorKind.Api,
|
||||
message: `MDB | Authentication for ${this.apiName} failed. Check the API key.`,
|
||||
userMessage: `Authentication for ${this.apiName} failed. Check the API key.`,
|
||||
context: { apiName: this.apiName },
|
||||
});
|
||||
}
|
||||
if (response.response.status !== 200) {
|
||||
return err({
|
||||
kind: AppErrorKind.Api,
|
||||
message: `MDB | Received status code ${response.response.status} from ${this.apiName}.`,
|
||||
userMessage: `Received status code ${response.response.status} from ${this.apiName}.`,
|
||||
context: { apiName: this.apiName, status: response.response.status },
|
||||
});
|
||||
}
|
||||
|
||||
const data = response.data;
|
||||
|
||||
if (!data) {
|
||||
return err({
|
||||
kind: AppErrorKind.Api,
|
||||
message: `MDB | No data received from ${this.apiName}.`,
|
||||
userMessage: `No data received from ${this.apiName}.`,
|
||||
context: { apiName: this.apiName },
|
||||
});
|
||||
}
|
||||
|
||||
if (data.total_results === 0 || !data.results) {
|
||||
return ok([]);
|
||||
}
|
||||
|
||||
// console.debug(data.results);
|
||||
|
||||
const ret: MediaTypeModel[] = [];
|
||||
|
||||
for (const result of data.results) {
|
||||
ret.push(
|
||||
new MovieModel({
|
||||
type: 'movie',
|
||||
title: result.original_title,
|
||||
englishTitle: result.title,
|
||||
year: result.release_date ? new Date(result.release_date).getFullYear().toString() : 'unknown',
|
||||
dataSource: this.apiName,
|
||||
id: result.id.toString(),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
return ok(ret);
|
||||
}
|
||||
|
||||
async getById(id: string): Promise<Result<MediaTypeModel, AppError>> {
|
||||
Logger.log(`MDB | api "${this.apiName}" queried by ID`);
|
||||
const key = this.plugin.app.secretStorage.getSecret(this.plugin.settings.TMDBKeyId);
|
||||
|
||||
if (!key) {
|
||||
return err({
|
||||
kind: AppErrorKind.Validation,
|
||||
message: `MDB | API key for ${this.apiName} missing.`,
|
||||
userMessage: `API key for ${this.apiName} missing.`,
|
||||
context: { apiName: this.apiName },
|
||||
});
|
||||
}
|
||||
|
||||
const client = createClient<paths>({ baseUrl: 'https://api.themoviedb.org' });
|
||||
const responseResult = await fromPromise(
|
||||
client.GET('/3/movie/{movie_id}', {
|
||||
headers: {
|
||||
Authorization: `Bearer ${key}`,
|
||||
},
|
||||
params: {
|
||||
path: { movie_id: parseInt(id) },
|
||||
query: {
|
||||
append_to_response: 'credits',
|
||||
},
|
||||
},
|
||||
fetch: obsidianFetch,
|
||||
}),
|
||||
cause =>
|
||||
toAppError(cause, {
|
||||
kind: AppErrorKind.Network,
|
||||
message: `MDB | Network error querying ${this.apiName}`,
|
||||
userMessage: `Network error querying ${this.apiName}`,
|
||||
context: { apiName: this.apiName, id },
|
||||
}),
|
||||
);
|
||||
|
||||
if (!responseResult.ok) {
|
||||
return err(responseResult.error);
|
||||
}
|
||||
|
||||
const response = responseResult.value;
|
||||
|
||||
if (response.response.status === 401) {
|
||||
return err({
|
||||
kind: AppErrorKind.Api,
|
||||
message: `MDB | Authentication for ${this.apiName} failed. Check the API key.`,
|
||||
userMessage: `Authentication for ${this.apiName} failed. Check the API key.`,
|
||||
context: { apiName: this.apiName },
|
||||
});
|
||||
}
|
||||
if (response.response.status !== 200) {
|
||||
return err({
|
||||
kind: AppErrorKind.Api,
|
||||
message: `MDB | Received status code ${response.response.status} from ${this.apiName}.`,
|
||||
userMessage: `Received status code ${response.response.status} from ${this.apiName}.`,
|
||||
context: { apiName: this.apiName, status: response.response.status, id },
|
||||
});
|
||||
}
|
||||
|
||||
const result = response.data;
|
||||
|
||||
if (!result) {
|
||||
return err({
|
||||
kind: AppErrorKind.Api,
|
||||
message: `MDB | No data received from ${this.apiName}.`,
|
||||
userMessage: `No data received from ${this.apiName}.`,
|
||||
context: { apiName: this.apiName, id },
|
||||
});
|
||||
}
|
||||
// console.debug(result);
|
||||
const credits = (result as TMDBCreditsResponse).credits;
|
||||
|
||||
return ok(
|
||||
new MovieModel({
|
||||
type: 'movie',
|
||||
title: result.title,
|
||||
englishTitle: result.title,
|
||||
year: result.release_date ? new Date(result.release_date).getFullYear().toString() : 'unknown',
|
||||
premiere: this.plugin.dateFormatter.format(result.release_date, this.apiDateFormat) ?? 'unknown',
|
||||
dataSource: this.apiName,
|
||||
url: `https://www.themoviedb.org/movie/${result.id}`,
|
||||
id: result.id.toString(),
|
||||
|
||||
plot: result.overview ?? '',
|
||||
genres: result.genres?.map(g => g.name).filter(isNonEmptyString) ?? [],
|
||||
writer: getCrewNamesByJob(credits, 'Screenplay'),
|
||||
director: getCrewNamesByJob(credits, 'Director'),
|
||||
studio: result.production_companies?.map(s => s.name).filter(isNonEmptyString) ?? [],
|
||||
|
||||
duration: result.runtime?.toString() ?? 'unknown',
|
||||
onlineRating: result.vote_average,
|
||||
actors: getTopCastNames(credits, 5),
|
||||
image: `https://image.tmdb.org/t/p/w780${result.poster_path}`,
|
||||
|
||||
released: ['Released'].includes(result.status!),
|
||||
streamingServices: [],
|
||||
|
||||
userData: {
|
||||
watched: false,
|
||||
lastWatched: '',
|
||||
personalRating: 0,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
getDisabledMediaTypes(): MediaType[] {
|
||||
return this.plugin.settings.TMDBMovieAPI_disabledMediaTypes;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue