fix some issues; migrate to bun'
This commit is contained in:
parent
cf3d5c6d6f
commit
54293ac3a1
56 changed files with 1360 additions and 764 deletions
13
.github/workflows/release.yml
vendored
13
.github/workflows/release.yml
vendored
|
|
@ -1,4 +1,6 @@
|
||||||
name: Build obsidian plugin
|
name: Build Obsidian Plugin
|
||||||
|
|
||||||
|
# adapted from https://github.com/argenos/nldates-obsidian/blob/master/.github/workflows/release.yml
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
|
@ -15,15 +17,14 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Use Node.js
|
- uses: oven-sh/setup-bun@v1
|
||||||
uses: actions/setup-node@v3
|
|
||||||
with:
|
with:
|
||||||
node-version: '16.x' # You might need to adjust this value to your own version
|
bun-version: latest
|
||||||
- name: Build
|
- name: Build
|
||||||
id: build
|
id: build
|
||||||
run: |
|
run: |
|
||||||
yarn
|
bun install
|
||||||
yarn run build --if-present
|
bun run build
|
||||||
mkdir ${{ env.PLUGIN_NAME }}
|
mkdir ${{ env.PLUGIN_NAME }}
|
||||||
cp main.js manifest.json styles.css ${{ env.PLUGIN_NAME }}
|
cp main.js manifest.json styles.css ${{ env.PLUGIN_NAME }}
|
||||||
zip -r ${{ env.PLUGIN_NAME }}.zip ${{ env.PLUGIN_NAME }}
|
zip -r ${{ env.PLUGIN_NAME }}.zip ${{ env.PLUGIN_NAME }}
|
||||||
|
|
|
||||||
38
automation/build/buildBanner.ts
Normal file
38
automation/build/buildBanner.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
import manifest from '../../manifest.json' assert { type: 'json' };
|
||||||
|
|
||||||
|
export function getBuildBanner(buildType: string, getVersion: (version: string) => string) {
|
||||||
|
return `/*
|
||||||
|
-------------------------------------------
|
||||||
|
${manifest.name} - ${buildType}
|
||||||
|
-------------------------------------------
|
||||||
|
By: ${manifest.author} (${manifest.authorUrl})
|
||||||
|
Time: ${new Date().toUTCString()}
|
||||||
|
Version: ${getVersion(manifest.version)}
|
||||||
|
-------------------------------------------
|
||||||
|
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
||||||
|
if you want to view the source, please visit the github repository of this plugin
|
||||||
|
-------------------------------------------
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) ${new Date().getFullYear()} ${manifest.author}
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
@ -1,21 +1,10 @@
|
||||||
import esbuild from 'esbuild';
|
|
||||||
import builtins from 'builtin-modules';
|
import builtins from 'builtin-modules';
|
||||||
|
import esbuild from 'esbuild';
|
||||||
import esbuildSvelte from 'esbuild-svelte';
|
import esbuildSvelte from 'esbuild-svelte';
|
||||||
import sveltePreprocess from 'svelte-preprocess';
|
import sveltePreprocess from 'svelte-preprocess';
|
||||||
import manifest from './manifest.json' assert { type: 'json' };
|
import { getBuildBanner } from 'build/buildBanner';
|
||||||
|
|
||||||
const banner = `/*
|
const banner = getBuildBanner('Release Build', version => version);
|
||||||
-------------------------------------------
|
|
||||||
${manifest.name} - Release Build
|
|
||||||
-------------------------------------------
|
|
||||||
By: ${manifest.author} (${manifest.authorUrl})
|
|
||||||
Time: ${new Date().toUTCString()}
|
|
||||||
Version: ${manifest.version}
|
|
||||||
-------------------------------------------
|
|
||||||
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
|
||||||
if you want to view the source, please visit the github repository of this plugin
|
|
||||||
*/
|
|
||||||
`;
|
|
||||||
|
|
||||||
const build = await esbuild.build({
|
const build = await esbuild.build({
|
||||||
banner: {
|
banner: {
|
||||||
|
|
@ -47,14 +36,22 @@ const build = await esbuild.build({
|
||||||
outfile: 'main.js',
|
outfile: 'main.js',
|
||||||
minify: true,
|
minify: true,
|
||||||
metafile: true,
|
metafile: true,
|
||||||
|
define: {
|
||||||
|
MB_GLOBAL_CONFIG_DEV_BUILD: 'false',
|
||||||
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
esbuildSvelte({
|
esbuildSvelte({
|
||||||
compilerOptions: { css: 'injected' },
|
compilerOptions: { css: 'injected', dev: false, sveltePath: 'svelte' },
|
||||||
preprocess: sveltePreprocess(),
|
preprocess: sveltePreprocess(),
|
||||||
filterWarnings: warning => {
|
filterWarnings: warning => {
|
||||||
// we don't want warnings from node modules that we can do nothing about
|
// we don't want warnings from node modules that we can do nothing about
|
||||||
return !warning.filename.includes('node_modules');
|
return !warning.filename?.includes('node_modules');
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const file = Bun.file('meta.txt');
|
||||||
|
await Bun.write(file, JSON.stringify(build.metafile, null, '\t'));
|
||||||
|
|
||||||
|
process.exit(0);
|
||||||
65
automation/build/esbuild.dev.config.ts
Normal file
65
automation/build/esbuild.dev.config.ts
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
import esbuild from 'esbuild';
|
||||||
|
import copy from 'esbuild-plugin-copy-watch';
|
||||||
|
import esbuildSvelte from 'esbuild-svelte';
|
||||||
|
import sveltePreprocess from 'svelte-preprocess';
|
||||||
|
import manifest from '../../manifest.json' assert { type: 'json' };
|
||||||
|
import { getBuildBanner } from 'build/buildBanner';
|
||||||
|
|
||||||
|
const banner = getBuildBanner('Dev Build', _ => 'Dev Build');
|
||||||
|
|
||||||
|
const context = await esbuild.context({
|
||||||
|
banner: {
|
||||||
|
js: banner,
|
||||||
|
},
|
||||||
|
entryPoints: ['src/main.ts'],
|
||||||
|
bundle: true,
|
||||||
|
external: [
|
||||||
|
'obsidian',
|
||||||
|
'electron',
|
||||||
|
'@codemirror/autocomplete',
|
||||||
|
'@codemirror/collab',
|
||||||
|
'@codemirror/commands',
|
||||||
|
'@codemirror/language',
|
||||||
|
'@codemirror/lint',
|
||||||
|
'@codemirror/search',
|
||||||
|
'@codemirror/state',
|
||||||
|
'@codemirror/view',
|
||||||
|
'@lezer/common',
|
||||||
|
'@lezer/highlight',
|
||||||
|
'@lezer/lr',
|
||||||
|
],
|
||||||
|
format: 'cjs',
|
||||||
|
target: 'es2018',
|
||||||
|
logLevel: 'info',
|
||||||
|
sourcemap: 'inline',
|
||||||
|
treeShaking: true,
|
||||||
|
outdir: `exampleVault/.obsidian/plugins/${manifest.id}/`,
|
||||||
|
outbase: 'src',
|
||||||
|
define: {
|
||||||
|
MB_GLOBAL_CONFIG_DEV_BUILD: 'true',
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
copy({
|
||||||
|
paths: [
|
||||||
|
{
|
||||||
|
from: './styles.css',
|
||||||
|
to: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
from: './manifest.json',
|
||||||
|
to: '',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
esbuildSvelte({
|
||||||
|
compilerOptions: { css: 'injected', dev: true, sveltePath: 'svelte' },
|
||||||
|
preprocess: sveltePreprocess(),
|
||||||
|
filterWarnings: warning => {
|
||||||
|
// we don't want warnings from node modules that we can do nothing about
|
||||||
|
return !warning.filename?.includes('node_modules');
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
await context.watch();
|
||||||
5
automation/config.json
Normal file
5
automation/config.json
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"devBranch": "master",
|
||||||
|
"releaseBranch": "release",
|
||||||
|
"github": "https://github.com/mProjectsCode/obsidian-media-db-plugin"
|
||||||
|
}
|
||||||
171
automation/release.ts
Normal file
171
automation/release.ts
Normal file
|
|
@ -0,0 +1,171 @@
|
||||||
|
import { UserError } from 'utils/utils';
|
||||||
|
import { CanaryVersion, Version, getIncrementOptions, parseVersion, stringifyVersion } from 'utils/versionUtils';
|
||||||
|
import config from './config.json';
|
||||||
|
import { $choice as $choice, $confirm, $seq, CMD_FMT, Verboseness } from 'utils/shellUtils';
|
||||||
|
|
||||||
|
async function runPreconditions(): Promise<void> {
|
||||||
|
// run preconditions
|
||||||
|
await $seq(
|
||||||
|
[`bun run format`, `bun run lint:fix`, `bun run test`],
|
||||||
|
(cmd: string) => {
|
||||||
|
throw new UserError(`precondition "${cmd}" failed`);
|
||||||
|
},
|
||||||
|
() => {},
|
||||||
|
undefined,
|
||||||
|
Verboseness.VERBOSE,
|
||||||
|
);
|
||||||
|
|
||||||
|
// add changed files
|
||||||
|
await $seq(
|
||||||
|
[`git add .`],
|
||||||
|
() => {
|
||||||
|
throw new UserError('failed to add preconditions changes to git');
|
||||||
|
},
|
||||||
|
() => {},
|
||||||
|
undefined,
|
||||||
|
Verboseness.NORMAL,
|
||||||
|
);
|
||||||
|
|
||||||
|
// check if there were any changes
|
||||||
|
let changesToCommit = false;
|
||||||
|
await $seq(
|
||||||
|
[`git diff --quiet`, `git diff --cached --quiet`],
|
||||||
|
() => {
|
||||||
|
changesToCommit = true;
|
||||||
|
},
|
||||||
|
() => {},
|
||||||
|
undefined,
|
||||||
|
Verboseness.QUITET,
|
||||||
|
);
|
||||||
|
|
||||||
|
// if there were any changes, commit them
|
||||||
|
if (changesToCommit) {
|
||||||
|
await $seq(
|
||||||
|
[`git commit -m "[auto] run release preconditions"`],
|
||||||
|
() => {
|
||||||
|
throw new UserError('failed to add preconditions changes to git');
|
||||||
|
},
|
||||||
|
() => {},
|
||||||
|
undefined,
|
||||||
|
Verboseness.NORMAL,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
console.log('looking for untracked changes ...');
|
||||||
|
|
||||||
|
// check for any uncommited files and exit if there are any
|
||||||
|
await $seq(
|
||||||
|
[`git add .`, `git diff --quiet`, `git diff --cached --quiet`, `git checkout ${config.devBranch}`],
|
||||||
|
() => {
|
||||||
|
throw new UserError('there are still untracked changes');
|
||||||
|
},
|
||||||
|
() => {},
|
||||||
|
undefined,
|
||||||
|
Verboseness.QUITET,
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('\nrunning preconditions ...\n');
|
||||||
|
|
||||||
|
await runPreconditions();
|
||||||
|
|
||||||
|
console.log('\nbumping versions ...\n');
|
||||||
|
|
||||||
|
const manifestFile = Bun.file('./manifest.json');
|
||||||
|
const manifest = await manifestFile.json();
|
||||||
|
|
||||||
|
const versionString: string = manifest.version;
|
||||||
|
const currentVersion: Version = parseVersion(versionString);
|
||||||
|
const currentVersionString = stringifyVersion(currentVersion);
|
||||||
|
|
||||||
|
const versionIncrementOptions = getIncrementOptions(currentVersion);
|
||||||
|
|
||||||
|
const selectedIndex = await $choice(
|
||||||
|
`Current version "${currentVersionString}". Select new version`,
|
||||||
|
versionIncrementOptions.map(x => stringifyVersion(x)),
|
||||||
|
);
|
||||||
|
const newVersion = versionIncrementOptions[selectedIndex];
|
||||||
|
const newVersionString = stringifyVersion(newVersion);
|
||||||
|
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
await $confirm(`Version will be updated "${currentVersionString}" -> "${newVersionString}". Are you sure`, () => {
|
||||||
|
throw new UserError('user canceled script');
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!(newVersion instanceof CanaryVersion)) {
|
||||||
|
manifest.version = newVersionString;
|
||||||
|
}
|
||||||
|
|
||||||
|
await Bun.write(manifestFile, JSON.stringify(manifest, null, '\t'));
|
||||||
|
|
||||||
|
const betaManifest = structuredClone(manifest);
|
||||||
|
betaManifest.version = newVersionString;
|
||||||
|
|
||||||
|
const betaManifestFile = Bun.file('./manifest-beta.json');
|
||||||
|
await Bun.write(betaManifestFile, JSON.stringify(betaManifest, null, '\t'));
|
||||||
|
|
||||||
|
if (!(newVersion instanceof CanaryVersion)) {
|
||||||
|
const versionsFile = Bun.file('./versions.json');
|
||||||
|
const versionsJson = await versionsFile.json();
|
||||||
|
|
||||||
|
versionsJson[newVersionString] = manifest.minAppVersion;
|
||||||
|
|
||||||
|
await Bun.write(versionsFile, JSON.stringify(versionsJson, null, '\t'));
|
||||||
|
|
||||||
|
const packageFile = Bun.file('./package.json');
|
||||||
|
const packageJson = await packageFile.json();
|
||||||
|
|
||||||
|
packageJson.version = newVersionString;
|
||||||
|
|
||||||
|
await Bun.write(packageFile, JSON.stringify(packageJson, null, '\t'));
|
||||||
|
}
|
||||||
|
|
||||||
|
await $seq(
|
||||||
|
[`bun run format`, `git add .`, `git commit -m "[auto] bump version to \`${newVersionString}\`"`],
|
||||||
|
() => {
|
||||||
|
throw new UserError('failed to add preconditions changes to git');
|
||||||
|
},
|
||||||
|
() => {},
|
||||||
|
undefined,
|
||||||
|
Verboseness.NORMAL,
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('\ncreating release tag ...\n');
|
||||||
|
|
||||||
|
await $seq(
|
||||||
|
[
|
||||||
|
`git checkout ${config.releaseBranch}`,
|
||||||
|
`git merge ${config.devBranch} --commit -m "[auto] merge \`${newVersionString}\` release commit"`,
|
||||||
|
`git push origin ${config.releaseBranch}`,
|
||||||
|
`git tag -a ${newVersionString} -m "release version ${newVersionString}"`,
|
||||||
|
`git push origin ${newVersionString}`,
|
||||||
|
`git checkout ${config.devBranch}`,
|
||||||
|
`git merge ${config.releaseBranch}`,
|
||||||
|
`git push origin ${config.devBranch}`,
|
||||||
|
],
|
||||||
|
() => {
|
||||||
|
throw new UserError('failed to merge or create tag');
|
||||||
|
},
|
||||||
|
() => {},
|
||||||
|
undefined,
|
||||||
|
Verboseness.NORMAL,
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('');
|
||||||
|
|
||||||
|
console.log(`${CMD_FMT.BgGreen}done${CMD_FMT.Reset}`);
|
||||||
|
console.log(`${config.github}`);
|
||||||
|
console.log(`${config.github}/releases/tag/${newVersionString}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await run();
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof UserError) {
|
||||||
|
console.error(e.message);
|
||||||
|
} else {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
160
automation/stats.ts
Normal file
160
automation/stats.ts
Normal file
|
|
@ -0,0 +1,160 @@
|
||||||
|
import * as fs from 'fs';
|
||||||
|
|
||||||
|
interface Stat {
|
||||||
|
fileType: string;
|
||||||
|
count: number;
|
||||||
|
lines: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class StatsBase {
|
||||||
|
parent: StatsBase | undefined;
|
||||||
|
path: string;
|
||||||
|
name: string;
|
||||||
|
stats: Stat[];
|
||||||
|
|
||||||
|
constructor(parent: StatsBase | undefined, path: string, name: string, stats: Stat[]) {
|
||||||
|
this.parent = parent;
|
||||||
|
|
||||||
|
this.path = path;
|
||||||
|
this.name = name;
|
||||||
|
this.stats = stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract addChild(child: StatsBase): void;
|
||||||
|
|
||||||
|
abstract mergeStats(stats: Stat[]): void;
|
||||||
|
|
||||||
|
abstract print(depth: number, lastChildArr: boolean[]): void;
|
||||||
|
|
||||||
|
abstract sort(): void;
|
||||||
|
|
||||||
|
getPrefix(depth: number, lastChildArr: boolean[]): string {
|
||||||
|
let prefix = '';
|
||||||
|
for (let i = 0; i < depth; i++) {
|
||||||
|
prefix += lastChildArr[i] ? ' ' : '│ ';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastChildArr.at(-1)) {
|
||||||
|
prefix += '└─ ';
|
||||||
|
} else {
|
||||||
|
prefix += '├─ ';
|
||||||
|
}
|
||||||
|
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FolderStats extends StatsBase {
|
||||||
|
children: StatsBase[];
|
||||||
|
|
||||||
|
constructor(parent: StatsBase | undefined, path: string, name: string) {
|
||||||
|
super(parent, path, name, []);
|
||||||
|
|
||||||
|
this.children = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
addChild(child: StatsBase) {
|
||||||
|
this.children.push(child);
|
||||||
|
this.mergeStats(child.stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
mergeStats(stats: Stat[]): void {
|
||||||
|
// console.log(this, stats);
|
||||||
|
for (const stat of stats) {
|
||||||
|
const existingStat = this.stats.find(s => s.fileType === stat.fileType);
|
||||||
|
if (existingStat) {
|
||||||
|
existingStat.count += stat.count;
|
||||||
|
existingStat.lines += stat.lines;
|
||||||
|
} else {
|
||||||
|
this.stats.push(structuredClone(stat));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.parent?.mergeStats(stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
print(depth: number, lastChildArr: boolean[]): void {
|
||||||
|
console.log(
|
||||||
|
`${this.getPrefix(depth, lastChildArr)}${this.name} | ${this.stats.reduce((acc, s) => acc + s.count, 0)} files | ${this.stats.reduce((acc, s) => acc + s.lines, 0)} lines`,
|
||||||
|
);
|
||||||
|
for (let i = 0; i < this.children.length; i++) {
|
||||||
|
const child = this.children[i];
|
||||||
|
child.print(depth + 1, [...lastChildArr, i === this.children.length - 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort(): void {
|
||||||
|
this.children.sort((a, b) => {
|
||||||
|
if (a instanceof FolderStats && b instanceof FileStats) {
|
||||||
|
return 1;
|
||||||
|
} else if (a instanceof FileStats && b instanceof FolderStats) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return a.name.localeCompare(b.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.children.forEach(c => c.sort());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FileStats extends StatsBase {
|
||||||
|
constructor(parent: StatsBase, path: string, name: string, stats: Stat[]) {
|
||||||
|
super(parent, path, name, stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
addChild(_child: StatsBase): void {
|
||||||
|
throw new Error('Cannot add child to file');
|
||||||
|
}
|
||||||
|
|
||||||
|
mergeStats(_stats: Stat[]): void {
|
||||||
|
throw new Error('Cannot merge stats to file');
|
||||||
|
}
|
||||||
|
|
||||||
|
print(depth: number, lastChildArr: boolean[]): void {
|
||||||
|
console.log(`${this.getPrefix(depth, lastChildArr)}${this.name} | ${this.stats[0].lines} lines`);
|
||||||
|
}
|
||||||
|
|
||||||
|
sort(): void {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectStats() {
|
||||||
|
const root = new FolderStats(undefined, './src', 'src');
|
||||||
|
const ignore = ['node_modules', 'extraTypes', 'bun.lockb'];
|
||||||
|
|
||||||
|
const todo: FolderStats[] = [root];
|
||||||
|
|
||||||
|
while (todo.length > 0) {
|
||||||
|
const current = todo.pop()!;
|
||||||
|
const children = fs.readdirSync(current.path, { withFileTypes: true });
|
||||||
|
|
||||||
|
for (const child of children) {
|
||||||
|
if (ignore.includes(child.name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child.isDirectory()) {
|
||||||
|
const folder = new FolderStats(current, `${current.path}/${child.name}`, child.name);
|
||||||
|
current.addChild(folder);
|
||||||
|
|
||||||
|
todo.push(folder);
|
||||||
|
} else {
|
||||||
|
const content = fs.readFileSync(`${current.path}/${child.name}`, 'utf-8');
|
||||||
|
|
||||||
|
const file = new FileStats(current, `${current.path}/${child.name}`, child.name, [
|
||||||
|
{
|
||||||
|
fileType: child.name.split('.').splice(1).join('.'),
|
||||||
|
count: 1,
|
||||||
|
lines: content.split('\n').length,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
current.addChild(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
root.sort();
|
||||||
|
|
||||||
|
root.print(0, [true]);
|
||||||
|
}
|
||||||
|
|
||||||
|
collectStats();
|
||||||
20
automation/tsconfig.json
Normal file
20
automation/tsconfig.json
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"module": "ESNext",
|
||||||
|
"target": "ESNext",
|
||||||
|
"allowJs": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"strict": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"importHelpers": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"lib": ["DOM", "ES5", "ES6", "ES7", "Es2021"],
|
||||||
|
"types": ["bun-types"],
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"resolveJsonModule": true
|
||||||
|
},
|
||||||
|
"include": ["**/*.ts"]
|
||||||
|
}
|
||||||
168
automation/utils/shellUtils.ts
Normal file
168
automation/utils/shellUtils.ts
Normal file
|
|
@ -0,0 +1,168 @@
|
||||||
|
import { Subprocess } from 'bun';
|
||||||
|
import stringArgv from 'string-argv';
|
||||||
|
|
||||||
|
export enum Verboseness {
|
||||||
|
QUITET,
|
||||||
|
NORMAL,
|
||||||
|
VERBOSE,
|
||||||
|
}
|
||||||
|
|
||||||
|
function exec(c: string, cwd?: string): Subprocess<'ignore', 'pipe', 'inherit'> {
|
||||||
|
return Bun.spawn(stringArgv(c), { cwd: cwd });
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function $(cmd: string, cwd?: string | undefined, verboseness: Verboseness = Verboseness.NORMAL): Promise<{ stdout: string; stderr: string; exit: number }> {
|
||||||
|
if (verboseness === Verboseness.NORMAL || verboseness === Verboseness.VERBOSE) {
|
||||||
|
if (cwd !== undefined) {
|
||||||
|
console.log(`\n${CMD_FMT.Bright}running${CMD_FMT.Reset} in ${cwd} - ${cmd}\n`);
|
||||||
|
} else {
|
||||||
|
console.log(`\n${CMD_FMT.Bright}running${CMD_FMT.Reset} - ${cmd}\n`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const proc = exec(cmd, cwd);
|
||||||
|
const stdout = await new Response(proc.stdout).text();
|
||||||
|
const stderr = await new Response(proc.stderr).text();
|
||||||
|
|
||||||
|
if (verboseness === Verboseness.VERBOSE) {
|
||||||
|
if (stdout !== '') {
|
||||||
|
console.log(
|
||||||
|
stdout
|
||||||
|
.split('\n')
|
||||||
|
.map(x => `${CMD_FMT.FgGray}>${CMD_FMT.Reset} ${x}\n`)
|
||||||
|
.join(''),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stderr !== '') {
|
||||||
|
console.log(
|
||||||
|
stderr
|
||||||
|
.split('\n')
|
||||||
|
.map(x => `${CMD_FMT.FgRed}>${CMD_FMT.Reset} ${x}\n`)
|
||||||
|
.join(''),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const exit = await proc.exited;
|
||||||
|
|
||||||
|
if (verboseness === Verboseness.NORMAL || verboseness === Verboseness.VERBOSE) {
|
||||||
|
if (exit === 0) {
|
||||||
|
console.log(`${CMD_FMT.FgGreen}success${CMD_FMT.Reset} - ${cmd}\n`);
|
||||||
|
} else {
|
||||||
|
console.log(`${CMD_FMT.FgRed}fail${CMD_FMT.Reset} - ${cmd} - code ${exit}\n`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
stdout,
|
||||||
|
stderr,
|
||||||
|
exit,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function $seq(
|
||||||
|
cmds: string[],
|
||||||
|
onError: (cmd: string, index: number) => void,
|
||||||
|
onSuccess: () => void,
|
||||||
|
cwd?: string | undefined,
|
||||||
|
verboseness: Verboseness = Verboseness.NORMAL,
|
||||||
|
): Promise<void> {
|
||||||
|
const results = [];
|
||||||
|
for (let i = 0; i < cmds.length; i += 1) {
|
||||||
|
const cmd = cmds[i];
|
||||||
|
const result = await $(cmd, cwd, verboseness);
|
||||||
|
|
||||||
|
if (result.exit !== 0) {
|
||||||
|
onError(cmd, i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
results.push(result);
|
||||||
|
}
|
||||||
|
onSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function $input(message: string): Promise<string> {
|
||||||
|
console.write(`${message} `);
|
||||||
|
const stdin = Bun.stdin.stream();
|
||||||
|
const reader = stdin.getReader();
|
||||||
|
const chunk = await reader.read();
|
||||||
|
reader.releaseLock();
|
||||||
|
const text = Buffer.from(chunk.value ?? '').toString();
|
||||||
|
return text.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function $choice(message: string, options: string[]): Promise<number> {
|
||||||
|
console.log(`${message} `);
|
||||||
|
|
||||||
|
let optionNumbers = new Map<string, number>();
|
||||||
|
|
||||||
|
for (let i = 0; i < options.length; i++) {
|
||||||
|
const option = options[i];
|
||||||
|
console.log(`[${i}] ${option}`);
|
||||||
|
|
||||||
|
optionNumbers.set(i.toString(), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ret: undefined | number = undefined;
|
||||||
|
|
||||||
|
while (ret === undefined) {
|
||||||
|
const selectedStr = await $input(`Select [${[...optionNumbers.keys()].join('/')}]:`);
|
||||||
|
|
||||||
|
ret = optionNumbers.get(selectedStr);
|
||||||
|
|
||||||
|
if (ret === undefined) {
|
||||||
|
console.log(`${CMD_FMT.FgRed}invalid selection, please select a valid option${CMD_FMT.Reset}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function $confirm(message: string, onReject: () => void): Promise<void> {
|
||||||
|
while (true) {
|
||||||
|
const answer = await $input(`${message} [Y/N]?`);
|
||||||
|
|
||||||
|
if (answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (answer.toLowerCase() === 'n' || answer.toLowerCase() === 'no') {
|
||||||
|
onReject();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`${CMD_FMT.FgRed}invalid selection, please select a valid option${CMD_FMT.Reset}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CMD_FMT = {
|
||||||
|
Reset: '\x1b[0m',
|
||||||
|
Bright: '\x1b[1m',
|
||||||
|
Dim: '\x1b[2m',
|
||||||
|
Underscore: '\x1b[4m',
|
||||||
|
Blink: '\x1b[5m',
|
||||||
|
Reverse: '\x1b[7m',
|
||||||
|
Hidden: '\x1b[8m',
|
||||||
|
|
||||||
|
FgBlack: '\x1b[30m',
|
||||||
|
FgRed: '\x1b[31m',
|
||||||
|
FgGreen: '\x1b[32m',
|
||||||
|
FgYellow: '\x1b[33m',
|
||||||
|
FgBlue: '\x1b[34m',
|
||||||
|
FgMagenta: '\x1b[35m',
|
||||||
|
FgCyan: '\x1b[36m',
|
||||||
|
FgWhite: '\x1b[37m',
|
||||||
|
FgGray: '\x1b[90m',
|
||||||
|
|
||||||
|
BgBlack: '\x1b[40m',
|
||||||
|
BgRed: '\x1b[41m',
|
||||||
|
BgGreen: '\x1b[42m',
|
||||||
|
BgYellow: '\x1b[43m',
|
||||||
|
BgBlue: '\x1b[44m',
|
||||||
|
BgMagenta: '\x1b[45m',
|
||||||
|
BgCyan: '\x1b[46m',
|
||||||
|
BgWhite: '\x1b[47m',
|
||||||
|
BgGray: '\x1b[100m',
|
||||||
|
};
|
||||||
6
automation/utils/utils.ts
Normal file
6
automation/utils/utils.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
export class UserError extends Error {}
|
||||||
|
|
||||||
|
export interface ProjectConfig {
|
||||||
|
corePackages: string[];
|
||||||
|
packages: string[];
|
||||||
|
}
|
||||||
108
automation/utils/versionUtils.ts
Normal file
108
automation/utils/versionUtils.ts
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
import { Parser } from '@lemons_dev/parsinom/lib/Parser';
|
||||||
|
import { P_UTILS } from '@lemons_dev/parsinom/lib/ParserUtils';
|
||||||
|
import { P } from '@lemons_dev/parsinom/lib/ParsiNOM';
|
||||||
|
import Moment from 'moment';
|
||||||
|
import { UserError } from 'utils/utils';
|
||||||
|
|
||||||
|
export class Version {
|
||||||
|
major: number;
|
||||||
|
minor: number;
|
||||||
|
patch: number;
|
||||||
|
|
||||||
|
constructor(major: number, minor: number, patch: number) {
|
||||||
|
this.major = major;
|
||||||
|
this.minor = minor;
|
||||||
|
this.patch = patch;
|
||||||
|
}
|
||||||
|
|
||||||
|
toString(): string {
|
||||||
|
return `${this.major}.${this.minor}.${this.patch}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CanaryVersion extends Version {
|
||||||
|
canary: string;
|
||||||
|
|
||||||
|
constructor(major: number, minor: number, patch: number, canary: string) {
|
||||||
|
super(major, minor, patch);
|
||||||
|
this.canary = canary;
|
||||||
|
}
|
||||||
|
|
||||||
|
toString(): string {
|
||||||
|
return `${super.toString()}-canary.${this.canary}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const numberParser: Parser<number> = P_UTILS.digits()
|
||||||
|
.map(x => Number.parseInt(x))
|
||||||
|
.chain(x => {
|
||||||
|
if (Number.isNaN(x)) {
|
||||||
|
return P.fail('a number');
|
||||||
|
} else {
|
||||||
|
return P.succeed(x);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const canaryParser: Parser<string> = P.sequenceMap(
|
||||||
|
(_, c1, c2, c3) => {
|
||||||
|
return c1 + c2 + c3;
|
||||||
|
},
|
||||||
|
P.string('-canary.'),
|
||||||
|
P_UTILS.digit()
|
||||||
|
.repeat(8, 8)
|
||||||
|
.map(x => x.join('')),
|
||||||
|
P.string('T'),
|
||||||
|
P_UTILS.digit()
|
||||||
|
.repeat(6, 6)
|
||||||
|
.map(x => x.join('')),
|
||||||
|
);
|
||||||
|
|
||||||
|
export const versionParser: Parser<Version> = P.or(
|
||||||
|
P.sequenceMap(
|
||||||
|
(major, _1, minor, _2, patch) => {
|
||||||
|
return new Version(major, minor, patch);
|
||||||
|
},
|
||||||
|
numberParser,
|
||||||
|
P.string('.'),
|
||||||
|
numberParser,
|
||||||
|
P.string('.'),
|
||||||
|
numberParser,
|
||||||
|
P_UTILS.eof(),
|
||||||
|
),
|
||||||
|
P.sequenceMap(
|
||||||
|
(major, _1, minor, _2, patch, canary) => {
|
||||||
|
return new CanaryVersion(major, minor, patch, canary);
|
||||||
|
},
|
||||||
|
numberParser,
|
||||||
|
P.string('.'),
|
||||||
|
numberParser,
|
||||||
|
P.string('.'),
|
||||||
|
numberParser,
|
||||||
|
canaryParser,
|
||||||
|
P_UTILS.eof(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
export function parseVersion(str: string): Version {
|
||||||
|
const parserRes = versionParser.tryParse(str);
|
||||||
|
if (parserRes.success) {
|
||||||
|
return parserRes.value;
|
||||||
|
} else {
|
||||||
|
throw new UserError(`failed to parse manifest version "${str}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stringifyVersion(version: Version): string {
|
||||||
|
return version.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getIncrementOptions(version: Version): [Version, Version, Version, CanaryVersion] {
|
||||||
|
const moment = Moment();
|
||||||
|
const canary = moment.utcOffset(0).format('YYYYMMDDTHHmmss');
|
||||||
|
return [
|
||||||
|
new Version(version.major + 1, 0, 0),
|
||||||
|
new Version(version.major, version.minor + 1, 0),
|
||||||
|
new Version(version.major, version.minor, version.patch + 1),
|
||||||
|
new CanaryVersion(version.major, version.minor, version.patch, canary),
|
||||||
|
];
|
||||||
|
}
|
||||||
BIN
bun.lockb
Executable file
BIN
bun.lockb
Executable file
Binary file not shown.
|
|
@ -1,63 +0,0 @@
|
||||||
import esbuild from 'esbuild';
|
|
||||||
import process from 'process';
|
|
||||||
import builtins from 'builtin-modules';
|
|
||||||
import esbuildSvelte from 'esbuild-svelte';
|
|
||||||
import sveltePreprocess from 'svelte-preprocess';
|
|
||||||
import manifest from './manifest.json' assert { type: 'json' };
|
|
||||||
|
|
||||||
const banner = `/*
|
|
||||||
-------------------------------------------
|
|
||||||
${manifest.name} - Dev Build
|
|
||||||
-------------------------------------------
|
|
||||||
By: ${manifest.author} (${manifest.authorUrl})
|
|
||||||
Time: ${new Date().toUTCString()}
|
|
||||||
Version: Dev Build
|
|
||||||
-------------------------------------------
|
|
||||||
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
|
||||||
if you want to view the source, please visit the github repository of this plugin
|
|
||||||
*/
|
|
||||||
`;
|
|
||||||
|
|
||||||
const context = await esbuild
|
|
||||||
.context({
|
|
||||||
banner: {
|
|
||||||
js: banner,
|
|
||||||
},
|
|
||||||
entryPoints: ['src/main.ts'],
|
|
||||||
bundle: true,
|
|
||||||
external: [
|
|
||||||
'obsidian',
|
|
||||||
'electron',
|
|
||||||
'@codemirror/autocomplete',
|
|
||||||
'@codemirror/collab',
|
|
||||||
'@codemirror/commands',
|
|
||||||
'@codemirror/language',
|
|
||||||
'@codemirror/lint',
|
|
||||||
'@codemirror/search',
|
|
||||||
'@codemirror/state',
|
|
||||||
'@codemirror/view',
|
|
||||||
'@lezer/common',
|
|
||||||
'@lezer/highlight',
|
|
||||||
'@lezer/lr',
|
|
||||||
...builtins,
|
|
||||||
],
|
|
||||||
format: 'cjs',
|
|
||||||
target: 'es2018',
|
|
||||||
logLevel: 'info',
|
|
||||||
sourcemap: 'inline',
|
|
||||||
treeShaking: true,
|
|
||||||
outfile: 'main.js',
|
|
||||||
plugins: [
|
|
||||||
esbuildSvelte({
|
|
||||||
compilerOptions: { css: 'injected' },
|
|
||||||
preprocess: sveltePreprocess(),
|
|
||||||
filterWarnings: warning => {
|
|
||||||
// we don't want warnings from node modules that we can do nothing about
|
|
||||||
return !warning.filename.includes('node_modules');
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
})
|
|
||||||
.catch(() => process.exit(1));
|
|
||||||
|
|
||||||
await context.watch();
|
|
||||||
1
exampleVault/.obsidian/app.json
vendored
Normal file
1
exampleVault/.obsidian/app.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
{}
|
||||||
4
exampleVault/.obsidian/appearance.json
vendored
Normal file
4
exampleVault/.obsidian/appearance.json
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"accentColor": "",
|
||||||
|
"theme": "obsidian"
|
||||||
|
}
|
||||||
1
exampleVault/.obsidian/community-plugins.json
vendored
Normal file
1
exampleVault/.obsidian/community-plugins.json
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
["obsidian-media-db-plugin"]
|
||||||
31
exampleVault/.obsidian/core-plugins-migration.json
vendored
Normal file
31
exampleVault/.obsidian/core-plugins-migration.json
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
"file-explorer": true,
|
||||||
|
"global-search": true,
|
||||||
|
"switcher": true,
|
||||||
|
"graph": true,
|
||||||
|
"backlink": true,
|
||||||
|
"canvas": true,
|
||||||
|
"outgoing-link": true,
|
||||||
|
"tag-pane": true,
|
||||||
|
"properties": false,
|
||||||
|
"page-preview": true,
|
||||||
|
"daily-notes": true,
|
||||||
|
"templates": true,
|
||||||
|
"note-composer": true,
|
||||||
|
"command-palette": true,
|
||||||
|
"slash-command": false,
|
||||||
|
"editor-status": true,
|
||||||
|
"bookmarks": true,
|
||||||
|
"markdown-importer": false,
|
||||||
|
"zk-prefixer": false,
|
||||||
|
"random-note": false,
|
||||||
|
"outline": true,
|
||||||
|
"word-count": true,
|
||||||
|
"slides": false,
|
||||||
|
"audio-recorder": false,
|
||||||
|
"workspaces": false,
|
||||||
|
"file-recovery": true,
|
||||||
|
"publish": false,
|
||||||
|
"sync": false,
|
||||||
|
"browser": false
|
||||||
|
}
|
||||||
20
exampleVault/.obsidian/core-plugins.json
vendored
Normal file
20
exampleVault/.obsidian/core-plugins.json
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
[
|
||||||
|
"file-explorer",
|
||||||
|
"global-search",
|
||||||
|
"switcher",
|
||||||
|
"graph",
|
||||||
|
"backlink",
|
||||||
|
"canvas",
|
||||||
|
"outgoing-link",
|
||||||
|
"tag-pane",
|
||||||
|
"page-preview",
|
||||||
|
"daily-notes",
|
||||||
|
"templates",
|
||||||
|
"note-composer",
|
||||||
|
"command-palette",
|
||||||
|
"editor-status",
|
||||||
|
"bookmarks",
|
||||||
|
"outline",
|
||||||
|
"word-count",
|
||||||
|
"file-recovery"
|
||||||
|
]
|
||||||
8
exampleVault/.obsidian/hotkeys.json
vendored
Normal file
8
exampleVault/.obsidian/hotkeys.json
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"app:reload": [
|
||||||
|
{
|
||||||
|
"modifiers": ["Mod"],
|
||||||
|
"key": "R"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
0
exampleVault/.obsidian/plugins/obsidian-media-db-plugin/.hotreload
vendored
Normal file
0
exampleVault/.obsidian/plugins/obsidian-media-db-plugin/.hotreload
vendored
Normal file
10
exampleVault/.obsidian/plugins/obsidian-media-db-plugin/manifest.json
vendored
Normal file
10
exampleVault/.obsidian/plugins/obsidian-media-db-plugin/manifest.json
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"id": "obsidian-media-db-plugin",
|
||||||
|
"name": "Media DB",
|
||||||
|
"version": "0.6.0",
|
||||||
|
"minAppVersion": "1.5.0",
|
||||||
|
"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://www.moritzjung.dev",
|
||||||
|
"isDesktopOnly": false
|
||||||
|
}
|
||||||
126
exampleVault/.obsidian/plugins/obsidian-media-db-plugin/styles.css
vendored
Normal file
126
exampleVault/.obsidian/plugins/obsidian-media-db-plugin/styles.css
vendored
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
.media-db-plugin-list-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-content: center;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-list-toggle {
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-list-text-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-list-text {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
small.media-db-plugin-list-text {
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-select-modal {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-select-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin: 5px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-select-element {
|
||||||
|
cursor: pointer;
|
||||||
|
border-left: 5px solid transparent;
|
||||||
|
padding: 5px;
|
||||||
|
margin: 5px 0 5px 0;
|
||||||
|
border-radius: 5px;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-select-element-selected {
|
||||||
|
border-left: 5px solid var(--interactive-accent) !important;
|
||||||
|
background: var(--background-secondary-alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-select-element-hover {
|
||||||
|
background: var(--background-secondary-alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-preview-modal {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-preview-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-spacer {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* region property mappings */
|
||||||
|
.media-db-plugin-property-mappings-model-container {
|
||||||
|
border: 1px solid var(--background-modifier-border);
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 10px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-property-mappings-container {
|
||||||
|
margin: 10px 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-property-mapping-element {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-property-mapping-element-property-name-wrapper {
|
||||||
|
min-width: 160px;
|
||||||
|
background: var(--background-modifier-form-field);
|
||||||
|
padding: 2px 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-property-mapping-element-property-name {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-property-mappings-save-button {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-property-mapping-to {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-property-mapping-validation {
|
||||||
|
color: var(--text-error);
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-button:focus {
|
||||||
|
/*outline: 1px solid white;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-preview {
|
||||||
|
border-radius: var(--modal-radius);
|
||||||
|
border: var(--modal-border-width) solid var(--modal-border-color);
|
||||||
|
padding: var(--size-4-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* endregion */
|
||||||
151
exampleVault/.obsidian/workspace.json
vendored
Normal file
151
exampleVault/.obsidian/workspace.json
vendored
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
{
|
||||||
|
"main": {
|
||||||
|
"id": "9618d22a4d8c511c",
|
||||||
|
"type": "split",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "982b4a04c4a0e996",
|
||||||
|
"type": "tabs",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "b912b847e62b0980",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "empty",
|
||||||
|
"state": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"direction": "vertical"
|
||||||
|
},
|
||||||
|
"left": {
|
||||||
|
"id": "a448fa9a0495e7a4",
|
||||||
|
"type": "split",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "0148e129668970ae",
|
||||||
|
"type": "tabs",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "5f549c8ae9af971e",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "file-explorer",
|
||||||
|
"state": {
|
||||||
|
"sortOrder": "alphabetical"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b782c94865111b8f",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "search",
|
||||||
|
"state": {
|
||||||
|
"query": "",
|
||||||
|
"matchingCase": false,
|
||||||
|
"explainSearch": false,
|
||||||
|
"collapseAll": false,
|
||||||
|
"extraContext": false,
|
||||||
|
"sortOrder": "alphabetical"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "942c8e2bba79177d",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "bookmarks",
|
||||||
|
"state": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"direction": "horizontal",
|
||||||
|
"width": 300
|
||||||
|
},
|
||||||
|
"right": {
|
||||||
|
"id": "8a6d32cd2e32c39d",
|
||||||
|
"type": "split",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "b712a27a0deec50f",
|
||||||
|
"type": "tabs",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "81240f6821eb54dc",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "backlink",
|
||||||
|
"state": {
|
||||||
|
"collapseAll": false,
|
||||||
|
"extraContext": false,
|
||||||
|
"sortOrder": "alphabetical",
|
||||||
|
"showSearch": false,
|
||||||
|
"searchQuery": "",
|
||||||
|
"backlinkCollapsed": false,
|
||||||
|
"unlinkedCollapsed": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2dda1a67c07f367d",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "outgoing-link",
|
||||||
|
"state": {
|
||||||
|
"linksCollapsed": false,
|
||||||
|
"unlinkedCollapsed": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "cb0aecbffefcb594",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "tag",
|
||||||
|
"state": {
|
||||||
|
"sortOrder": "frequency",
|
||||||
|
"useHierarchy": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1be09685a129aa6e",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "outline",
|
||||||
|
"state": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"direction": "horizontal",
|
||||||
|
"width": 300,
|
||||||
|
"collapsed": true
|
||||||
|
},
|
||||||
|
"left-ribbon": {
|
||||||
|
"hiddenItems": {
|
||||||
|
"obsidian-media-db-plugin:Add new Media DB entry": false,
|
||||||
|
"switcher:Open quick switcher": false,
|
||||||
|
"graph:Open graph view": false,
|
||||||
|
"canvas:Create new canvas": false,
|
||||||
|
"daily-notes:Open today's daily note": false,
|
||||||
|
"templates:Insert template": false,
|
||||||
|
"command-palette:Open command palette": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": "b912b847e62b0980",
|
||||||
|
"lastOpenFiles": [
|
||||||
|
"Media DB/games/Limbo (2010).md",
|
||||||
|
"Media DB/games/Hollow Knight (2017).md",
|
||||||
|
"Media DB/movies/2001 - A Space Odyssey (1968).md",
|
||||||
|
"Media DB/games",
|
||||||
|
"Media DB/movies",
|
||||||
|
"Media DB"
|
||||||
|
]
|
||||||
|
}
|
||||||
0
exampleVault/index.md
Normal file
0
exampleVault/index.md
Normal file
|
|
@ -1,7 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
roots: ['<rootDir>/src', '<rootDir>'],
|
|
||||||
testMatch: ['**/__tests__/**/*.+(ts|tsx|js)', '**/?(*.)+(spec|test).+(ts|tsx|js)'],
|
|
||||||
transform: {
|
|
||||||
'^.+\\.(ts|tsx)$': 'ts-jest',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
10
manifest-beta.json
Normal file
10
manifest-beta.json
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"id": "obsidian-media-db-plugin",
|
||||||
|
"name": "Media DB",
|
||||||
|
"version": "0.6.0",
|
||||||
|
"minAppVersion": "1.5.0",
|
||||||
|
"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://www.moritzjung.dev",
|
||||||
|
"isDesktopOnly": false
|
||||||
|
}
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
"id": "obsidian-media-db-plugin",
|
"id": "obsidian-media-db-plugin",
|
||||||
"name": "Media DB",
|
"name": "Media DB",
|
||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
"minAppVersion": "0.14.0",
|
"minAppVersion": "1.5.0",
|
||||||
"description": "A plugin that can query multiple APIs for movies, series, anime, games, music and wiki articles, 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",
|
"author": "Moritz Jung",
|
||||||
"authorUrl": "https://mprojectscode.github.io/",
|
"authorUrl": "https://www.moritzjung.dev",
|
||||||
"isDesktopOnly": false
|
"isDesktopOnly": false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
54
package.json
54
package.json
|
|
@ -4,34 +4,48 @@
|
||||||
"description": "A plugin that can query multiple APIs for movies, series, anime, games, music and wiki articles, 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.",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "node esbuild.dev.config.mjs",
|
"dev": "bun run automation/build/esbuild.dev.config.ts",
|
||||||
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
|
"build": "bun run tsc && bun run automation/build/esbuild.config.ts",
|
||||||
"version": "node version-bump.mjs && git add manifest.json versions.json",
|
"tsc": "tsc -noEmit -skipLibCheck",
|
||||||
"test": "jest",
|
"test": "bun test",
|
||||||
"format": "prettier --write ."
|
"test:log": "LOG_TESTS=true bun test",
|
||||||
|
"format": "prettier --write --plugin prettier-plugin-svelte .",
|
||||||
|
"format:check": "prettier --check --plugin prettier-plugin-svelte .",
|
||||||
|
"lint": "eslint --max-warnings=0 src/**",
|
||||||
|
"lint:fix": "eslint --max-warnings=0 --fix src/**",
|
||||||
|
"svelte-check": "svelte-check --compiler-warnings \"unused-export-let:ignore\"",
|
||||||
|
"check": "bun run format:check && bun run tsc && bun run lint && bun run test",
|
||||||
|
"check:fix": "bun run format && bun run tsc && bun run lint:fix && bun run test",
|
||||||
|
"release": "bun run automation/release.ts",
|
||||||
|
"stats": "bun run automation/stats.ts"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "Moritz Jung",
|
"author": "Moritz Jung",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
"@tsconfig/svelte": "^5.0.2",
|
"@lemons_dev/parsinom": "^0.0.12",
|
||||||
"@types/jest": "^29.5.11",
|
"@happy-dom/global-registrator": "^14.3.6",
|
||||||
"@types/node": "^20.10.4",
|
"@tsconfig/svelte": "^5.0.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.14.0",
|
"@types/bun": "^1.0.10",
|
||||||
"@typescript-eslint/parser": "^6.14.0",
|
"@typescript-eslint/eslint-plugin": "^7.3.1",
|
||||||
|
"@typescript-eslint/parser": "^7.3.1",
|
||||||
"builtin-modules": "^3.3.0",
|
"builtin-modules": "^3.3.0",
|
||||||
"esbuild": "^0.19.9",
|
"esbuild": "^0.20.2",
|
||||||
|
"esbuild-plugin-copy-watch": "^2.1.0",
|
||||||
"esbuild-svelte": "^0.8.0",
|
"esbuild-svelte": "^0.8.0",
|
||||||
|
"eslint": "^8.57.0",
|
||||||
|
"eslint-plugin-import": "^2.29.1",
|
||||||
|
"eslint-plugin-isaacscript": "^3.12.2",
|
||||||
"eslint-plugin-only-warn": "^1.1.0",
|
"eslint-plugin-only-warn": "^1.1.0",
|
||||||
"jest": "^29.7.0",
|
"obsidian": "latest",
|
||||||
"jest-fetch-mock": "^3.0.3",
|
"prettier": "^3.2.5",
|
||||||
"obsidian": "^1.4.11",
|
"prettier-plugin-svelte": "^3.2.2",
|
||||||
"prettier": "3.1.1",
|
"string-argv": "^0.3.2",
|
||||||
"svelte": "^4.2.8",
|
"svelte": "^4.2.12",
|
||||||
"svelte-preprocess": "^5.1.2",
|
"svelte-check": "^3.6.8",
|
||||||
"ts-jest": "^29.1.1",
|
"svelte-preprocess": "^5.1.3",
|
||||||
"tslib": "2.6.2",
|
"tslib": "^2.6.2",
|
||||||
"typescript": "^5.3.3"
|
"typescript": "^5.4.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,12 @@ export class APIManager {
|
||||||
|
|
||||||
for (const api of this.apis) {
|
for (const api of this.apis) {
|
||||||
if (apisToQuery.contains(api.apiName)) {
|
if (apisToQuery.contains(api.apiName)) {
|
||||||
const apiRes = await api.searchByTitle(query);
|
try {
|
||||||
res = res.concat(apiRes);
|
const apiRes = await api.searchByTitle(query);
|
||||||
|
res = res.concat(apiRes);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import { MediaTypeModel } from '../models/MediaTypeModel';
|
import { MediaTypeModel } from '../models/MediaTypeModel';
|
||||||
import { MediaType } from '../utils/MediaType';
|
import { MediaType } from '../utils/MediaType';
|
||||||
import { MediaDbPluginSettings } from 'src/settings/Settings';
|
|
||||||
import MediaDbPlugin from '../main';
|
import MediaDbPlugin from '../main';
|
||||||
|
|
||||||
export abstract class APIModel {
|
export abstract class APIModel {
|
||||||
|
|
@ -20,7 +19,10 @@ export abstract class APIModel {
|
||||||
abstract getById(id: string): Promise<MediaTypeModel>;
|
abstract getById(id: string): Promise<MediaTypeModel>;
|
||||||
|
|
||||||
hasType(type: MediaType): boolean {
|
hasType(type: MediaType): boolean {
|
||||||
if (this.types.contains(type) && (Boolean((this.plugin.settings.apiToggle as any)?.[this.apiName]?.[type] as MediaDbPluginSettings) === true || (this.plugin.settings.apiToggle as any)?.[this.apiName]?.[type] as MediaDbPluginSettings === undefined)) {
|
if (
|
||||||
|
this.types.contains(type) &&
|
||||||
|
(Boolean((this.plugin.settings.apiToggle as any)?.[this.apiName]?.[type]) === true || (this.plugin.settings.apiToggle as any)?.[this.apiName]?.[type] === undefined)
|
||||||
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
import { APIModel } from '../APIModel';
|
|
||||||
import { MediaTypeModel } from '../../models/MediaTypeModel';
|
|
||||||
import MediaDbPlugin from '../../main';
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
console.debug(fetchData);
|
|
||||||
|
|
||||||
if (fetchData.status !== 200) {
|
|
||||||
throw Error(`MDB | Received status code ${fetchData.status} from an API.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await fetchData.json();
|
|
||||||
console.debug(data);
|
|
||||||
let ret: MediaTypeModel[] = [];
|
|
||||||
|
|
||||||
throw new Error('MDB | Under construction, API implementation not finished');
|
|
||||||
|
|
||||||
// return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getById(id: string): Promise<MediaTypeModel> {
|
|
||||||
console.log(`MDB | api "${this.apiName}" queried by ID`);
|
|
||||||
|
|
||||||
const searchUrl = `https://www.loc.gov/item/${encodeURIComponent(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();
|
|
||||||
console.debug(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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -41,7 +41,13 @@ export class SteamAPI extends APIModel {
|
||||||
const filteredData = [];
|
const filteredData = [];
|
||||||
|
|
||||||
for (const app of data.applist.apps) {
|
for (const app of data.applist.apps) {
|
||||||
if (app.name.toLowerCase().includes(title.toLowerCase())) {
|
if (
|
||||||
|
app.name
|
||||||
|
.normalize('NFD')
|
||||||
|
.replace(/\p{Diacritic}/gu, '')
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(title.toLowerCase())
|
||||||
|
) {
|
||||||
filteredData.push(app);
|
filteredData.push(app);
|
||||||
}
|
}
|
||||||
if (filteredData.length > 20) {
|
if (filteredData.length > 20) {
|
||||||
|
|
|
||||||
105
src/main.ts
105
src/main.ts
|
|
@ -22,11 +22,19 @@ import { BoardGameGeekAPI } from './api/apis/BoardGameGeekAPI';
|
||||||
import { OpenLibraryAPI } from './api/apis/OpenLibraryAPI';
|
import { OpenLibraryAPI } from './api/apis/OpenLibraryAPI';
|
||||||
import { MobyGamesAPI } from './api/apis/MobyGamesAPI';
|
import { MobyGamesAPI } from './api/apis/MobyGamesAPI';
|
||||||
import { PropertyMapper } from './settings/PropertyMapper';
|
import { PropertyMapper } from './settings/PropertyMapper';
|
||||||
import { YAMLConverter } from './utils/YAMLConverter';
|
|
||||||
import { MediaDbFolderImportModal } from './modals/MediaDbFolderImportModal';
|
import { MediaDbFolderImportModal } from './modals/MediaDbFolderImportModal';
|
||||||
import { PropertyMapping, PropertyMappingModel } from './settings/PropertyMapping';
|
import { PropertyMapping, PropertyMappingModel } from './settings/PropertyMapping';
|
||||||
import { ModalHelper, ModalResultCode, SearchModalOptions } from './utils/ModalHelper';
|
import { ModalHelper, ModalResultCode, SearchModalOptions } from './utils/ModalHelper';
|
||||||
import { DateFormatter } from './utils/DateFormatter';
|
import { DateFormatter } from './utils/DateFormatter';
|
||||||
|
import { MediaType } from 'src/utils/MediaType';
|
||||||
|
|
||||||
|
export type Metadata = Record<string, unknown>;
|
||||||
|
|
||||||
|
export interface MediaTypeModelObj {
|
||||||
|
id: string;
|
||||||
|
type: MediaType;
|
||||||
|
dataSource: string;
|
||||||
|
}
|
||||||
|
|
||||||
export default class MediaDbPlugin extends Plugin {
|
export default class MediaDbPlugin extends Plugin {
|
||||||
settings: MediaDbPluginSettings;
|
settings: MediaDbPluginSettings;
|
||||||
|
|
@ -186,7 +194,12 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
let apiSearchResults: MediaTypeModel[] = await this.modalHelper.openSearchModal(searchModalOptions ?? {}, async searchModalData => {
|
let apiSearchResults: MediaTypeModel[] = await this.modalHelper.openSearchModal(searchModalOptions ?? {}, async searchModalData => {
|
||||||
types = searchModalData.types;
|
types = searchModalData.types;
|
||||||
const apis = this.apiManager.apis.filter(x => x.hasTypeOverlap(searchModalData.types)).map(x => x.apiName);
|
const apis = this.apiManager.apis.filter(x => x.hasTypeOverlap(searchModalData.types)).map(x => x.apiName);
|
||||||
return await this.apiManager.query(searchModalData.query, apis);
|
try {
|
||||||
|
return await this.apiManager.query(searchModalData.query, apis);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!apiSearchResults) {
|
if (!apiSearchResults) {
|
||||||
|
|
@ -309,21 +322,40 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
|
|
||||||
generateMediaDbNoteFrontmatterPreview(mediaTypeModel: MediaTypeModel): string {
|
generateMediaDbNoteFrontmatterPreview(mediaTypeModel: MediaTypeModel): string {
|
||||||
const fileMetadata = this.modelPropertyMapper.convertObject(mediaTypeModel.toMetaDataObject());
|
const fileMetadata = this.modelPropertyMapper.convertObject(mediaTypeModel.toMetaDataObject());
|
||||||
return this.settings.useCustomYamlStringifier ? YAMLConverter.toYaml(fileMetadata) : stringifyYaml(fileMetadata);
|
return stringifyYaml(fileMetadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the content of a note from a media model and some options.
|
||||||
|
*
|
||||||
|
* @param mediaTypeModel
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
async generateMediaDbNoteContents(mediaTypeModel: MediaTypeModel, options: CreateNoteOptions): Promise<string> {
|
async generateMediaDbNoteContents(mediaTypeModel: MediaTypeModel, options: CreateNoteOptions): Promise<string> {
|
||||||
let template = await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app);
|
const template = await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app);
|
||||||
|
|
||||||
if (this.settings.useDefaultFrontMatter || !template) {
|
return this.generateContentWithDefaultFrontMatter(mediaTypeModel, options, template);
|
||||||
return this.generateContentWithDefaultFrontMatter(mediaTypeModel, options, template);
|
|
||||||
} else {
|
// if (this.settings.useDefaultFrontMatter || !template) {
|
||||||
return this.generateContentWithCustomFrontMatter(mediaTypeModel, options, template);
|
// return this.generateContentWithDefaultFrontMatter(mediaTypeModel, options, template);
|
||||||
}
|
// } else {
|
||||||
|
// return this.generateContentWithCustomFrontMatter(mediaTypeModel, options, template);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
async generateContentWithDefaultFrontMatter(mediaTypeModel: MediaTypeModel, options: CreateNoteOptions, template?: string): Promise<string> {
|
async generateContentWithDefaultFrontMatter(mediaTypeModel: MediaTypeModel, options: CreateNoteOptions, template?: string): Promise<string> {
|
||||||
let fileMetadata = this.modelPropertyMapper.convertObject(mediaTypeModel.toMetaDataObject());
|
let fileMetadata: Record<string, unknown>;
|
||||||
|
|
||||||
|
if (this.settings.useDefaultFrontMatter) {
|
||||||
|
fileMetadata = this.modelPropertyMapper.convertObject(mediaTypeModel.toMetaDataObject());
|
||||||
|
} else {
|
||||||
|
fileMetadata = {
|
||||||
|
id: mediaTypeModel.id,
|
||||||
|
type: mediaTypeModel.type,
|
||||||
|
dataSource: mediaTypeModel.dataSource,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
let fileContent = '';
|
let fileContent = '';
|
||||||
template = options.attachTemplate ? template : '';
|
template = options.attachTemplate ? template : '';
|
||||||
|
|
||||||
|
|
@ -331,27 +363,20 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
({ fileMetadata, fileContent } = await this.attachTemplate(fileMetadata, fileContent, template));
|
({ fileMetadata, fileContent } = await this.attachTemplate(fileMetadata, fileContent, template));
|
||||||
|
|
||||||
if (this.settings.enableTemplaterIntegration && hasTemplaterPlugin(this.app)) {
|
if (this.settings.enableTemplaterIntegration && hasTemplaterPlugin(this.app)) {
|
||||||
// Only support stringifyYaml for templater plugin
|
|
||||||
// Include the media variable in all templater commands by using a top level JavaScript execution command.
|
// Include the media variable in all templater commands by using a top level JavaScript execution command.
|
||||||
fileContent = `---\n<%* const media = ${JSON.stringify(mediaTypeModel)} %>\n${stringifyYaml(fileMetadata)}---\n${fileContent}`;
|
fileContent = `---\n<%* const media = ${JSON.stringify(mediaTypeModel)} %>\n${stringifyYaml(fileMetadata)}---\n${fileContent}`;
|
||||||
} else {
|
} else {
|
||||||
fileContent = `---\n${this.settings.useCustomYamlStringifier ? YAMLConverter.toYaml(fileMetadata) : stringifyYaml(fileMetadata)}---\n` + fileContent;
|
fileContent = `---\n${stringifyYaml(fileMetadata)}---\n${fileContent}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileContent;
|
return fileContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
async generateContentWithCustomFrontMatter(mediaTypeModel: MediaTypeModel, options: CreateNoteOptions, template: string): Promise<string> {
|
async generateContentWithCustomFrontMatter(mediaTypeModel: MediaTypeModel, options: CreateNoteOptions, template: string): Promise<string> {
|
||||||
const frontMatterRegex = /^---*\n([\s\S]*?)\n---\h*/;
|
const regExp = new RegExp(this.frontMatterRexExpPattern);
|
||||||
|
|
||||||
const match = template.match(frontMatterRegex);
|
const frontMatter = this.getMetaDataFromFileContent(template);
|
||||||
|
let fileContent: string = template.replace(regExp, '');
|
||||||
if (!match || match.length !== 2) {
|
|
||||||
throw new Error('Cannot find YAML front matter for template.');
|
|
||||||
}
|
|
||||||
|
|
||||||
let frontMatter = parseYaml(match[1]);
|
|
||||||
let fileContent: string = template.replace(frontMatterRegex, '');
|
|
||||||
|
|
||||||
// Updating a previous file
|
// Updating a previous file
|
||||||
if (options.attachFile) {
|
if (options.attachFile) {
|
||||||
|
|
@ -359,7 +384,7 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
|
|
||||||
// Use contents (below front matter) from previous file
|
// Use contents (below front matter) from previous file
|
||||||
fileContent = await this.app.vault.read(options.attachFile);
|
fileContent = await this.app.vault.read(options.attachFile);
|
||||||
const regExp = new RegExp(this.frontMatterRexExpPattern);
|
|
||||||
fileContent = fileContent.replace(regExp, '');
|
fileContent = fileContent.replace(regExp, '');
|
||||||
fileContent = fileContent.startsWith('\n') ? fileContent.substring(1) : fileContent;
|
fileContent = fileContent.startsWith('\n') ? fileContent.substring(1) : fileContent;
|
||||||
|
|
||||||
|
|
@ -391,18 +416,19 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
// Include the media variable in all templater commands by using a top level JavaScript execution command.
|
// Include the media variable in all templater commands by using a top level JavaScript execution command.
|
||||||
fileContent = `---\n<%* const media = ${JSON.stringify(mediaTypeModel)} %>\n${stringifyYaml(frontMatter)}---\n${fileContent}`;
|
fileContent = `---\n<%* const media = ${JSON.stringify(mediaTypeModel)} %>\n${stringifyYaml(frontMatter)}---\n${fileContent}`;
|
||||||
} else {
|
} else {
|
||||||
fileContent = `---\n${this.settings.useCustomYamlStringifier ? YAMLConverter.toYaml(frontMatter) : stringifyYaml(frontMatter)}---\n` + fileContent;
|
fileContent = `---\n${stringifyYaml(frontMatter)}---\n${fileContent}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileContent;
|
return fileContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
async attachFile(fileMetadata: any, fileContent: string, fileToAttach?: TFile): Promise<{ fileMetadata: any; fileContent: string }> {
|
async attachFile(fileMetadata: Metadata, fileContent: string, fileToAttach?: TFile): Promise<{ fileMetadata: Metadata; fileContent: string }> {
|
||||||
if (!fileToAttach) {
|
if (!fileToAttach) {
|
||||||
return { fileMetadata: fileMetadata, fileContent: fileContent };
|
return { fileMetadata: fileMetadata, fileContent: fileContent };
|
||||||
}
|
}
|
||||||
|
|
||||||
const attachFileMetadata: any = this.getMetadataFromFileCache(fileToAttach);
|
const attachFileMetadata: any = this.getMetadataFromFileCache(fileToAttach);
|
||||||
|
// TODO: better object merging
|
||||||
fileMetadata = Object.assign(attachFileMetadata, fileMetadata);
|
fileMetadata = Object.assign(attachFileMetadata, fileMetadata);
|
||||||
|
|
||||||
let attachFileContent: string = await this.app.vault.read(fileToAttach);
|
let attachFileContent: string = await this.app.vault.read(fileToAttach);
|
||||||
|
|
@ -414,12 +440,13 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
return { fileMetadata: fileMetadata, fileContent: fileContent };
|
return { fileMetadata: fileMetadata, fileContent: fileContent };
|
||||||
}
|
}
|
||||||
|
|
||||||
async attachTemplate(fileMetadata: any, fileContent: string, template: string): Promise<{ fileMetadata: any; fileContent: string }> {
|
async attachTemplate(fileMetadata: Metadata, fileContent: string, template: string): Promise<{ fileMetadata: Metadata; fileContent: string }> {
|
||||||
if (!template) {
|
if (!template) {
|
||||||
return { fileMetadata: fileMetadata, fileContent: fileContent };
|
return { fileMetadata: fileMetadata, fileContent: fileContent };
|
||||||
}
|
}
|
||||||
|
|
||||||
const templateMetadata: any = this.getMetaDataFromFileContent(template);
|
const templateMetadata: Metadata = this.getMetaDataFromFileContent(template);
|
||||||
|
// TODO: better object merging
|
||||||
fileMetadata = Object.assign(templateMetadata, fileMetadata);
|
fileMetadata = Object.assign(templateMetadata, fileMetadata);
|
||||||
|
|
||||||
const regExp = new RegExp(this.frontMatterRexExpPattern);
|
const regExp = new RegExp(this.frontMatterRexExpPattern);
|
||||||
|
|
@ -429,8 +456,8 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
return { fileMetadata: fileMetadata, fileContent: fileContent };
|
return { fileMetadata: fileMetadata, fileContent: fileContent };
|
||||||
}
|
}
|
||||||
|
|
||||||
getMetaDataFromFileContent(fileContent: string): any {
|
getMetaDataFromFileContent(fileContent: string): Metadata {
|
||||||
let metadata: any;
|
let metadata: Metadata;
|
||||||
|
|
||||||
const regExp = new RegExp(this.frontMatterRexExpPattern);
|
const regExp = new RegExp(this.frontMatterRexExpPattern);
|
||||||
const frontMatterRegExpResult = regExp.exec(fileContent);
|
const frontMatterRegExpResult = regExp.exec(fileContent);
|
||||||
|
|
@ -455,15 +482,9 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
getMetadataFromFileCache(file: TFile): any {
|
getMetadataFromFileCache(file: TFile): Metadata {
|
||||||
let metadata: any = this.app.metadataCache.getFileCache(file).frontmatter;
|
const metadata: Metadata | undefined = this.app.metadataCache.getFileCache(file).frontmatter;
|
||||||
if (metadata) {
|
return structuredClone(metadata ?? {});
|
||||||
metadata = Object.assign({}, metadata); // copy
|
|
||||||
delete metadata.position;
|
|
||||||
} else {
|
|
||||||
metadata = {};
|
|
||||||
}
|
|
||||||
return metadata;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -513,7 +534,7 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
throw new Error('MDB | there is no active note');
|
throw new Error('MDB | there is no active note');
|
||||||
}
|
}
|
||||||
|
|
||||||
let metadata: any = this.getMetadataFromFileCache(activeFile);
|
let metadata = this.getMetadataFromFileCache(activeFile);
|
||||||
metadata = this.modelPropertyMapper.convertObjectBack(metadata);
|
metadata = this.modelPropertyMapper.convertObjectBack(metadata);
|
||||||
|
|
||||||
console.debug(`MDB | read metadata`, metadata);
|
console.debug(`MDB | read metadata`, metadata);
|
||||||
|
|
@ -522,10 +543,12 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
throw new Error('MDB | active note is not a Media DB entry or is missing metadata');
|
throw new Error('MDB | active note is not a Media DB entry or is missing metadata');
|
||||||
}
|
}
|
||||||
|
|
||||||
const oldMediaTypeModel = this.mediaTypeManager.createMediaTypeModelFromMediaType(metadata, metadata.type);
|
const validOldMetadata: MediaTypeModelObj = metadata as unknown as MediaTypeModelObj;
|
||||||
|
|
||||||
|
const oldMediaTypeModel = this.mediaTypeManager.createMediaTypeModelFromMediaType(validOldMetadata, validOldMetadata.type);
|
||||||
// console.debug(oldMediaTypeModel);
|
// console.debug(oldMediaTypeModel);
|
||||||
|
|
||||||
let newMediaTypeModel = await this.apiManager.queryDetailedInfoById(metadata.id, metadata.dataSource);
|
let newMediaTypeModel = await this.apiManager.queryDetailedInfoById(validOldMetadata.id, validOldMetadata.dataSource);
|
||||||
if (!newMediaTypeModel) {
|
if (!newMediaTypeModel) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -533,8 +556,6 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
newMediaTypeModel = Object.assign(oldMediaTypeModel, newMediaTypeModel.getWithOutUserData());
|
newMediaTypeModel = Object.assign(oldMediaTypeModel, newMediaTypeModel.getWithOutUserData());
|
||||||
// console.debug(newMediaTypeModel);
|
// console.debug(newMediaTypeModel);
|
||||||
|
|
||||||
// deletion not happening anymore why is this log statement still here
|
|
||||||
console.debug('MDB | deleting old entry');
|
|
||||||
if (onlyMetadata) {
|
if (onlyMetadata) {
|
||||||
await this.createMediaDbNoteFromModel(newMediaTypeModel, { attachFile: activeFile, folder: activeFile.parent, openNote: true });
|
await this.createMediaDbNoteFromModel(newMediaTypeModel, { attachFile: activeFile, folder: activeFile.parent, openNote: true });
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -31,12 +31,12 @@ export abstract class MediaTypeModel {
|
||||||
|
|
||||||
abstract getTags(): string[];
|
abstract getTags(): string[];
|
||||||
|
|
||||||
toMetaDataObject(): object {
|
toMetaDataObject(): Record<string, unknown> {
|
||||||
return { ...this.getWithOutUserData(), ...this.userData, tags: this.getTags().join('/') };
|
return { ...this.getWithOutUserData(), ...this.userData, tags: this.getTags().join('/') };
|
||||||
}
|
}
|
||||||
|
|
||||||
getWithOutUserData(): object {
|
getWithOutUserData(): Record<string, unknown> {
|
||||||
const copy = Object.assign({}, this);
|
const copy = structuredClone(this) as Record<string, unknown>;
|
||||||
delete copy.userData;
|
delete copy.userData;
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ export class WikiModel extends MediaTypeModel {
|
||||||
length: number;
|
length: number;
|
||||||
article: string;
|
article: string;
|
||||||
|
|
||||||
userData: {};
|
userData: Record<string, unknown>;
|
||||||
|
|
||||||
constructor(obj: any = {}) {
|
constructor(obj: any = {}) {
|
||||||
super();
|
super();
|
||||||
|
|
@ -45,8 +45,8 @@ export class WikiModel extends MediaTypeModel {
|
||||||
return MediaType.Wiki;
|
return MediaType.Wiki;
|
||||||
}
|
}
|
||||||
|
|
||||||
override getWithOutUserData(): object {
|
override getWithOutUserData(): Record<string, unknown> {
|
||||||
const copy = Object.assign({}, this);
|
const copy = structuredClone(this) as Record<string, unknown>;
|
||||||
delete copy.userData;
|
delete copy.userData;
|
||||||
delete copy.article;
|
delete copy.article;
|
||||||
return copy;
|
return copy;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
<!--adapted from @joethei's code: https://github.com/joethei/obsidian-rss/blob/master/src/view/IconComponent.svelte-->
|
<!--adapted from @joethei's code: https://github.com/joethei/obsidian-rss/blob/master/src/view/IconComponent.svelte-->
|
||||||
<!--adapted from @javalent's code: https://discord.com/channels/686053708261228577/840286264964022302/902949764209987654-->
|
<!--adapted from @javalent's code: https://discord.com/channels/686053708261228577/840286264964022302/902949764209987654-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {setIcon} from 'obsidian';
|
import { setIcon } from 'obsidian';
|
||||||
import {onMount} from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
export let iconName: string = '';
|
export let iconName: string = '';
|
||||||
export let iconSize: number = 20;
|
export let iconSize: number = 20;
|
||||||
|
|
@ -14,23 +14,23 @@
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
|
||||||
.icon-wrapper {
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
width: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
position: absolute;
|
|
||||||
height: 20px;
|
|
||||||
width: 20px;
|
|
||||||
top: calc(50% - 10px);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
{#if iconName.length > 0}
|
{#if iconName.length > 0}
|
||||||
<div class="icon-wrapper">
|
<div class="icon-wrapper">
|
||||||
<div bind:this={iconEl} class="icon"></div>
|
<div bind:this={iconEl} class="icon"></div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.icon-wrapper {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
position: absolute;
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
top: calc(50% - 10px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -15,15 +15,13 @@ export class PropertyMapper {
|
||||||
*
|
*
|
||||||
* @param obj
|
* @param obj
|
||||||
*/
|
*/
|
||||||
convertObject(obj: object): object {
|
convertObject(obj: Record<string, unknown>): Record<string, unknown> {
|
||||||
if (!obj.hasOwnProperty('type')) {
|
if (!obj.hasOwnProperty('type')) {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
// console.log(obj.type);
|
// console.log(obj.type);
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
if (MEDIA_TYPES.filter(x => x.toString() == obj.type).length < 1) {
|
if (MEDIA_TYPES.filter(x => x.toString() == obj.type).length < 1) {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
@ -31,7 +29,7 @@ export class PropertyMapper {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const propertyMappings = this.plugin.settings.propertyMappingModels.find(x => x.type === obj.type).properties;
|
const propertyMappings = this.plugin.settings.propertyMappingModels.find(x => x.type === obj.type).properties;
|
||||||
|
|
||||||
const newObj: object = {};
|
const newObj: Record<string, unknown> = {};
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(obj)) {
|
for (const [key, value] of Object.entries(obj)) {
|
||||||
for (const propertyMapping of propertyMappings) {
|
for (const propertyMapping of propertyMappings) {
|
||||||
|
|
@ -59,20 +57,18 @@ export class PropertyMapper {
|
||||||
*
|
*
|
||||||
* @param obj
|
* @param obj
|
||||||
*/
|
*/
|
||||||
convertObjectBack(obj: object): object {
|
convertObjectBack(obj: Record<string, unknown>): Record<string, unknown> {
|
||||||
if (!obj.hasOwnProperty('type')) {
|
if (!obj.hasOwnProperty('type')) {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
if (MEDIA_TYPES.contains(obj.type as any)) {
|
||||||
if (MEDIA_TYPES.contains(obj.type)) {
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
|
||||||
const propertyMappings = this.plugin.settings.propertyMappingModels.find(x => x.type === obj.type).properties;
|
const propertyMappings = this.plugin.settings.propertyMappingModels.find(x => x.type === obj.type).properties;
|
||||||
|
|
||||||
const originalObj: object = {};
|
const originalObj: Record<string, unknown> = {};
|
||||||
|
|
||||||
objLoop: for (const [key, value] of Object.entries(obj)) {
|
objLoop: for (const [key, value] of Object.entries(obj)) {
|
||||||
// first try if it is a normal property
|
// first try if it is a normal property
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,7 @@ export class PropertyMappingModel {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
getMappedProperties() {
|
getMappedProperties(): PropertyMapping[] {
|
||||||
return this.properties.filter(x => x.mapping === PropertyMappingOption.Map);
|
return this.properties.filter(x => x.mapping === PropertyMappingOption.Map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {PropertyMappingModel, PropertyMappingOption, propertyMappingOptions} from './PropertyMapping';
|
import { PropertyMappingModel, PropertyMappingOption, propertyMappingOptions } from './PropertyMapping';
|
||||||
import {capitalizeFirstLetter} from '../utils/Utils';
|
import { capitalizeFirstLetter } from '../utils/Utils';
|
||||||
import Icon from './Icon.svelte';
|
import Icon from './Icon.svelte';
|
||||||
|
|
||||||
export let model: PropertyMappingModel;
|
export let model: PropertyMappingModel;
|
||||||
export let save: (model: PropertyMappingModel) => void;
|
export let save: (model: PropertyMappingModel) => void;
|
||||||
|
|
||||||
let validationResult: { res: boolean, err?: Error };
|
let validationResult: { res: boolean; err?: Error };
|
||||||
|
|
||||||
$: modelChanged(model);
|
$: modelChanged(model);
|
||||||
|
|
||||||
|
|
@ -15,23 +15,17 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div class="media-db-plugin-property-mappings-model-container">
|
<div class="media-db-plugin-property-mappings-model-container">
|
||||||
<div class="setting-item-name">{capitalizeFirstLetter(model.type)}</div>
|
<div class="setting-item-name">{capitalizeFirstLetter(model.type)}</div>
|
||||||
<div class="media-db-plugin-property-mappings-container">
|
<div class="media-db-plugin-property-mappings-container">
|
||||||
{ #each model.properties as property }
|
{#each model.properties as property}
|
||||||
<div class="media-db-plugin-property-mapping-element">
|
<div class="media-db-plugin-property-mapping-element">
|
||||||
<div class="media-db-plugin-property-mapping-element-property-name-wrapper">
|
<div class="media-db-plugin-property-mapping-element-property-name-wrapper">
|
||||||
<pre class="media-db-plugin-property-mapping-element-property-name"><code>{property.property}</code></pre>
|
<pre class="media-db-plugin-property-mapping-element-property-name"><code>{property.property}</code></pre>
|
||||||
</div>
|
</div>
|
||||||
{ #if property.locked }
|
{#if property.locked}
|
||||||
<div class="media-db-plugin-property-binding-text">
|
<div class="media-db-plugin-property-binding-text">property can not be remapped</div>
|
||||||
property can not be remapped
|
{:else}
|
||||||
</div>
|
|
||||||
{ :else }
|
|
||||||
<select class="dropdown" bind:value={property.mapping}>
|
<select class="dropdown" bind:value={property.mapping}>
|
||||||
{#each propertyMappingOptions as remappingOption}
|
{#each propertyMappingOptions as remappingOption}
|
||||||
<option value={remappingOption}>
|
<option value={remappingOption}>
|
||||||
|
|
@ -40,23 +34,29 @@
|
||||||
{/each}
|
{/each}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
{ #if property.mapping === PropertyMappingOption.Map }
|
{#if property.mapping === PropertyMappingOption.Map}
|
||||||
<Icon iconName="arrow-right"/>
|
<Icon iconName="arrow-right" />
|
||||||
<div class="media-db-plugin-property-mapping-to">
|
<div class="media-db-plugin-property-mapping-to">
|
||||||
<input type="text" spellcheck="false" bind:value="{property.newProperty}">
|
<input type="text" spellcheck="false" bind:value={property.newProperty} />
|
||||||
</div>
|
</div>
|
||||||
{ /if }
|
{/if}
|
||||||
{ /if }
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{ /each }
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{ #if !validationResult?.res }
|
{#if !validationResult?.res}
|
||||||
<div class="media-db-plugin-property-mapping-validation">
|
<div class="media-db-plugin-property-mapping-validation">
|
||||||
{validationResult?.err?.message}
|
{validationResult?.err?.message}
|
||||||
</div>
|
</div>
|
||||||
{ /if }
|
{/if}
|
||||||
<button
|
<button
|
||||||
class="media-db-plugin-property-mappings-save-button {validationResult?.res ? 'mod-cta' : 'mod-muted'}"
|
class="media-db-plugin-property-mappings-save-button {validationResult?.res ? 'mod-cta' : 'mod-muted'}"
|
||||||
on:click={() => { if(model.validate().res) save(model) }}>Save
|
on:click={() => {
|
||||||
|
if (model.validate().res) save(model);
|
||||||
|
}}
|
||||||
|
>Save
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,15 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {PropertyMappingModel} from './PropertyMapping';
|
import { PropertyMappingModel } from './PropertyMapping';
|
||||||
import PropertyMappingModelComponent from './PropertyMappingModelComponent.svelte';
|
import PropertyMappingModelComponent from './PropertyMappingModelComponent.svelte';
|
||||||
|
|
||||||
export let models: PropertyMappingModel[] = [];
|
export let models: PropertyMappingModel[] = [];
|
||||||
export let save: (model: PropertyMappingModel) => void;
|
export let save: (model: PropertyMappingModel) => void;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div class="setting-item" style="display: flex; gap: 10px; flex-direction: column; align-items: stretch;">
|
<div class="setting-item" style="display: flex; gap: 10px; flex-direction: column; align-items: stretch;">
|
||||||
{ #each models as model }
|
{#each models as model}
|
||||||
<PropertyMappingModelComponent model={model} save={save}></PropertyMappingModelComponent>
|
<PropertyMappingModelComponent {model} {save}></PropertyMappingModelComponent>
|
||||||
{ /each }
|
{/each}
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
<pre>{JSON.stringify(models, null, 4)}</pre>
|
<pre>{JSON.stringify(models, null, 4)}</pre>
|
||||||
|
|
@ -25,3 +21,6 @@
|
||||||
{/each}
|
{/each}
|
||||||
-->
|
-->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ export interface MediaDbPluginSettings {
|
||||||
OMDbKey: string;
|
OMDbKey: string;
|
||||||
MobyGamesKey: string;
|
MobyGamesKey: string;
|
||||||
sfwFilter: boolean;
|
sfwFilter: boolean;
|
||||||
useCustomYamlStringifier: boolean;
|
|
||||||
templates: boolean;
|
templates: boolean;
|
||||||
customDateFormat: string;
|
customDateFormat: string;
|
||||||
openNoteInNewTab: boolean;
|
openNoteInNewTab: boolean;
|
||||||
|
|
@ -24,18 +23,18 @@ export interface MediaDbPluginSettings {
|
||||||
movie: boolean;
|
movie: boolean;
|
||||||
series: boolean;
|
series: boolean;
|
||||||
game: boolean;
|
game: boolean;
|
||||||
},
|
};
|
||||||
MALAPI: {
|
MALAPI: {
|
||||||
movie: boolean;
|
movie: boolean;
|
||||||
series: boolean;
|
series: boolean;
|
||||||
},
|
};
|
||||||
SteamAPI: {
|
SteamAPI: {
|
||||||
game: boolean;
|
game: boolean;
|
||||||
},
|
};
|
||||||
MobyGamesAPI: {
|
MobyGamesAPI: {
|
||||||
game: boolean;
|
game: boolean;
|
||||||
}
|
};
|
||||||
},
|
};
|
||||||
movieTemplate: string;
|
movieTemplate: string;
|
||||||
seriesTemplate: string;
|
seriesTemplate: string;
|
||||||
mangaTemplate: string;
|
mangaTemplate: string;
|
||||||
|
|
@ -79,7 +78,6 @@ const DEFAULT_SETTINGS: MediaDbPluginSettings = {
|
||||||
OMDbKey: '',
|
OMDbKey: '',
|
||||||
MobyGamesKey: '',
|
MobyGamesKey: '',
|
||||||
sfwFilter: true,
|
sfwFilter: true,
|
||||||
useCustomYamlStringifier: true,
|
|
||||||
templates: true,
|
templates: true,
|
||||||
customDateFormat: 'L',
|
customDateFormat: 'L',
|
||||||
openNoteInNewTab: true,
|
openNoteInNewTab: true,
|
||||||
|
|
@ -100,7 +98,7 @@ const DEFAULT_SETTINGS: MediaDbPluginSettings = {
|
||||||
},
|
},
|
||||||
MobyGamesAPI: {
|
MobyGamesAPI: {
|
||||||
game: true,
|
game: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
movieTemplate: '',
|
movieTemplate: '',
|
||||||
seriesTemplate: '',
|
seriesTemplate: '',
|
||||||
|
|
@ -190,7 +188,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.OMDbKey)
|
.setValue(this.plugin.settings.OMDbKey)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.OMDbKey = data;
|
this.plugin.settings.OMDbKey = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -202,7 +200,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.MobyGamesKey)
|
.setValue(this.plugin.settings.MobyGamesKey)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.MobyGamesKey = data;
|
this.plugin.settings.MobyGamesKey = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -212,17 +210,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.addToggle(cb => {
|
.addToggle(cb => {
|
||||||
cb.setValue(this.plugin.settings.sfwFilter).onChange(data => {
|
cb.setValue(this.plugin.settings.sfwFilter).onChange(data => {
|
||||||
this.plugin.settings.sfwFilter = data;
|
this.plugin.settings.sfwFilter = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
new Setting(containerEl)
|
|
||||||
.setName('YAML formatter')
|
|
||||||
.setDesc('Add optional quotation marks around strings in the metadata block.')
|
|
||||||
.addToggle(cb => {
|
|
||||||
cb.setValue(this.plugin.settings.useCustomYamlStringifier).onChange(data => {
|
|
||||||
this.plugin.settings.useCustomYamlStringifier = data;
|
|
||||||
this.plugin.saveSettings();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -232,7 +220,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.addToggle(cb => {
|
.addToggle(cb => {
|
||||||
cb.setValue(this.plugin.settings.templates).onChange(data => {
|
cb.setValue(this.plugin.settings.templates).onChange(data => {
|
||||||
this.plugin.settings.templates = data;
|
this.plugin.settings.templates = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -241,10 +229,10 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setDesc(
|
.setDesc(
|
||||||
fragWithHTML(
|
fragWithHTML(
|
||||||
"Your custom date format. Use <em>'YYYY-MM-DD'</em> for example.<br>" +
|
"Your custom date format. Use <em>'YYYY-MM-DD'</em> for example.<br>" +
|
||||||
"For more syntax, refer to <a href='https://momentjs.com/docs/#/displaying/format/'>format reference</a>.<br>" +
|
"For more syntax, refer to <a href='https://momentjs.com/docs/#/displaying/format/'>format reference</a>.<br>" +
|
||||||
"Your current syntax looks like this: <b><a id='media-db-dateformat-preview' style='pointer-events: none; cursor: default; text-decoration: none;'>" +
|
"Your current syntax looks like this: <b><a id='media-db-dateformat-preview' style='pointer-events: none; cursor: default; text-decoration: none;'>" +
|
||||||
this.plugin.dateFormatter.getPreview() +
|
this.plugin.dateFormatter.getPreview() +
|
||||||
'</a></b>',
|
'</a></b>',
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.addText(cb => {
|
.addText(cb => {
|
||||||
|
|
@ -254,7 +242,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
const newDateFormat = data ? data : DEFAULT_SETTINGS.customDateFormat;
|
const newDateFormat = data ? data : DEFAULT_SETTINGS.customDateFormat;
|
||||||
this.plugin.settings.customDateFormat = newDateFormat;
|
this.plugin.settings.customDateFormat = newDateFormat;
|
||||||
document.getElementById('media-db-dateformat-preview').textContent = this.plugin.dateFormatter.getPreview(newDateFormat); // update preview
|
document.getElementById('media-db-dateformat-preview').textContent = this.plugin.dateFormatter.getPreview(newDateFormat); // update preview
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -264,17 +252,17 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.addToggle(cb => {
|
.addToggle(cb => {
|
||||||
cb.setValue(this.plugin.settings.openNoteInNewTab).onChange(data => {
|
cb.setValue(this.plugin.settings.openNoteInNewTab).onChange(data => {
|
||||||
this.plugin.settings.openNoteInNewTab = data;
|
this.plugin.settings.openNoteInNewTab = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
.setName('Use default front matter')
|
.setName('Use default front matter')
|
||||||
.setDesc('Wheter to use the default front matter. If disabled, the front matter from the template will be used. Same as mapping everything to remove.')
|
.setDesc('Whether to use the default front matter. If disabled, the front matter from the template will be used. Same as mapping everything to remove.')
|
||||||
.addToggle(cb => {
|
.addToggle(cb => {
|
||||||
cb.setValue(this.plugin.settings.useDefaultFrontMatter).onChange(data => {
|
cb.setValue(this.plugin.settings.useDefaultFrontMatter).onChange(data => {
|
||||||
this.plugin.settings.useDefaultFrontMatter = data;
|
this.plugin.settings.useDefaultFrontMatter = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
// Redraw settings to display/remove the property mappings
|
// Redraw settings to display/remove the property mappings
|
||||||
this.display();
|
this.display();
|
||||||
});
|
});
|
||||||
|
|
@ -288,11 +276,10 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.addToggle(cb => {
|
.addToggle(cb => {
|
||||||
cb.setValue(this.plugin.settings.enableTemplaterIntegration).onChange(data => {
|
cb.setValue(this.plugin.settings.enableTemplaterIntegration).onChange(data => {
|
||||||
this.plugin.settings.enableTemplaterIntegration = data;
|
this.plugin.settings.enableTemplaterIntegration = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
containerEl.createEl('h3', { text: 'APIs Per Media Type' });
|
containerEl.createEl('h3', { text: 'APIs Per Media Type' });
|
||||||
containerEl.createEl('h5', { text: 'Movies' });
|
containerEl.createEl('h5', { text: 'Movies' });
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
|
|
@ -301,7 +288,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.addToggle(cb => {
|
.addToggle(cb => {
|
||||||
cb.setValue(this.plugin.settings.apiToggle.OMDbAPI.movie).onChange(data => {
|
cb.setValue(this.plugin.settings.apiToggle.OMDbAPI.movie).onChange(data => {
|
||||||
this.plugin.settings.apiToggle.OMDbAPI.movie = data;
|
this.plugin.settings.apiToggle.OMDbAPI.movie = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
|
|
@ -310,7 +297,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.addToggle(cb => {
|
.addToggle(cb => {
|
||||||
cb.setValue(this.plugin.settings.apiToggle.MALAPI.movie).onChange(data => {
|
cb.setValue(this.plugin.settings.apiToggle.MALAPI.movie).onChange(data => {
|
||||||
this.plugin.settings.apiToggle.MALAPI.movie = data;
|
this.plugin.settings.apiToggle.MALAPI.movie = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
containerEl.createEl('h5', { text: 'Series' });
|
containerEl.createEl('h5', { text: 'Series' });
|
||||||
|
|
@ -320,7 +307,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.addToggle(cb => {
|
.addToggle(cb => {
|
||||||
cb.setValue(this.plugin.settings.apiToggle.OMDbAPI.series).onChange(data => {
|
cb.setValue(this.plugin.settings.apiToggle.OMDbAPI.series).onChange(data => {
|
||||||
this.plugin.settings.apiToggle.OMDbAPI.series = data;
|
this.plugin.settings.apiToggle.OMDbAPI.series = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
|
|
@ -329,7 +316,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.addToggle(cb => {
|
.addToggle(cb => {
|
||||||
cb.setValue(this.plugin.settings.apiToggle.MALAPI.series).onChange(data => {
|
cb.setValue(this.plugin.settings.apiToggle.MALAPI.series).onChange(data => {
|
||||||
this.plugin.settings.apiToggle.MALAPI.series = data;
|
this.plugin.settings.apiToggle.MALAPI.series = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
containerEl.createEl('h5', { text: 'Games' });
|
containerEl.createEl('h5', { text: 'Games' });
|
||||||
|
|
@ -339,7 +326,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.addToggle(cb => {
|
.addToggle(cb => {
|
||||||
cb.setValue(this.plugin.settings.apiToggle.OMDbAPI.game).onChange(data => {
|
cb.setValue(this.plugin.settings.apiToggle.OMDbAPI.game).onChange(data => {
|
||||||
this.plugin.settings.apiToggle.OMDbAPI.game = data;
|
this.plugin.settings.apiToggle.OMDbAPI.game = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
|
|
@ -348,7 +335,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.addToggle(cb => {
|
.addToggle(cb => {
|
||||||
cb.setValue(this.plugin.settings.apiToggle.SteamAPI.game).onChange(data => {
|
cb.setValue(this.plugin.settings.apiToggle.SteamAPI.game).onChange(data => {
|
||||||
this.plugin.settings.apiToggle.SteamAPI.game = data;
|
this.plugin.settings.apiToggle.SteamAPI.game = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
|
|
@ -357,7 +344,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.addToggle(cb => {
|
.addToggle(cb => {
|
||||||
cb.setValue(this.plugin.settings.apiToggle.MobyGamesAPI.game).onChange(data => {
|
cb.setValue(this.plugin.settings.apiToggle.MobyGamesAPI.game).onChange(data => {
|
||||||
this.plugin.settings.apiToggle.MobyGamesAPI.game = data;
|
this.plugin.settings.apiToggle.MobyGamesAPI.game = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -372,7 +359,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.movieFolder)
|
.setValue(this.plugin.settings.movieFolder)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.movieFolder = data;
|
this.plugin.settings.movieFolder = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -385,7 +372,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.seriesFolder)
|
.setValue(this.plugin.settings.seriesFolder)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.seriesFolder = data;
|
this.plugin.settings.seriesFolder = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -398,7 +385,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.mangaFolder)
|
.setValue(this.plugin.settings.mangaFolder)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.mangaFolder = data;
|
this.plugin.settings.mangaFolder = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -411,7 +398,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.gameFolder)
|
.setValue(this.plugin.settings.gameFolder)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.gameFolder = data;
|
this.plugin.settings.gameFolder = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -424,7 +411,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.wikiFolder)
|
.setValue(this.plugin.settings.wikiFolder)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.wikiFolder = data;
|
this.plugin.settings.wikiFolder = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -437,7 +424,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.musicReleaseFolder)
|
.setValue(this.plugin.settings.musicReleaseFolder)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.musicReleaseFolder = data;
|
this.plugin.settings.musicReleaseFolder = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -450,7 +437,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.boardgameFolder)
|
.setValue(this.plugin.settings.boardgameFolder)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.boardgameFolder = data;
|
this.plugin.settings.boardgameFolder = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
|
|
@ -462,7 +449,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.bookFolder)
|
.setValue(this.plugin.settings.bookFolder)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.bookFolder = data;
|
this.plugin.settings.bookFolder = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// endregion
|
// endregion
|
||||||
|
|
@ -478,7 +465,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.movieTemplate)
|
.setValue(this.plugin.settings.movieTemplate)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.movieTemplate = data;
|
this.plugin.settings.movieTemplate = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -491,7 +478,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.seriesTemplate)
|
.setValue(this.plugin.settings.seriesTemplate)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.seriesTemplate = data;
|
this.plugin.settings.seriesTemplate = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -504,7 +491,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.mangaTemplate)
|
.setValue(this.plugin.settings.mangaTemplate)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.mangaTemplate = data;
|
this.plugin.settings.mangaTemplate = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -517,7 +504,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.gameTemplate)
|
.setValue(this.plugin.settings.gameTemplate)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.gameTemplate = data;
|
this.plugin.settings.gameTemplate = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -530,7 +517,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.wikiTemplate)
|
.setValue(this.plugin.settings.wikiTemplate)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.wikiTemplate = data;
|
this.plugin.settings.wikiTemplate = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -543,7 +530,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.musicReleaseTemplate)
|
.setValue(this.plugin.settings.musicReleaseTemplate)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.musicReleaseTemplate = data;
|
this.plugin.settings.musicReleaseTemplate = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -556,7 +543,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.boardgameTemplate)
|
.setValue(this.plugin.settings.boardgameTemplate)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.boardgameTemplate = data;
|
this.plugin.settings.boardgameTemplate = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -569,7 +556,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.bookTemplate)
|
.setValue(this.plugin.settings.bookTemplate)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.bookTemplate = data;
|
this.plugin.settings.bookTemplate = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// endregion
|
// endregion
|
||||||
|
|
@ -584,7 +571,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.movieFileNameTemplate)
|
.setValue(this.plugin.settings.movieFileNameTemplate)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.movieFileNameTemplate = data;
|
this.plugin.settings.movieFileNameTemplate = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -596,7 +583,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.seriesFileNameTemplate)
|
.setValue(this.plugin.settings.seriesFileNameTemplate)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.seriesFileNameTemplate = data;
|
this.plugin.settings.seriesFileNameTemplate = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -608,7 +595,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.mangaFileNameTemplate)
|
.setValue(this.plugin.settings.mangaFileNameTemplate)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.mangaFileNameTemplate = data;
|
this.plugin.settings.mangaFileNameTemplate = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -620,7 +607,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.gameFileNameTemplate)
|
.setValue(this.plugin.settings.gameFileNameTemplate)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.gameFileNameTemplate = data;
|
this.plugin.settings.gameFileNameTemplate = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -632,7 +619,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.wikiFileNameTemplate)
|
.setValue(this.plugin.settings.wikiFileNameTemplate)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.wikiFileNameTemplate = data;
|
this.plugin.settings.wikiFileNameTemplate = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -644,7 +631,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.musicReleaseFileNameTemplate)
|
.setValue(this.plugin.settings.musicReleaseFileNameTemplate)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.musicReleaseFileNameTemplate = data;
|
this.plugin.settings.musicReleaseFileNameTemplate = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -656,7 +643,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.boardgameFileNameTemplate)
|
.setValue(this.plugin.settings.boardgameFileNameTemplate)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.boardgameFileNameTemplate = data;
|
this.plugin.settings.boardgameFileNameTemplate = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -668,7 +655,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
.setValue(this.plugin.settings.bookFileNameTemplate)
|
.setValue(this.plugin.settings.bookFileNameTemplate)
|
||||||
.onChange(data => {
|
.onChange(data => {
|
||||||
this.plugin.settings.bookFileNameTemplate = data;
|
this.plugin.settings.bookFileNameTemplate = data;
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// endregion
|
// endregion
|
||||||
|
|
@ -709,7 +696,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
|
|
||||||
this.plugin.settings.propertyMappingModels = propertyMappingModels;
|
this.plugin.settings.propertyMappingModels = propertyMappingModels;
|
||||||
new Notice(`MDB: Property Mappings for ${model.type} saved successfully.`);
|
new Notice(`MDB: Property Mappings for ${model.type} saved successfully.`);
|
||||||
this.plugin.saveSettings();
|
void this.plugin.saveSettings();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@ export abstract class TextInputSuggest<T> implements ISuggestOwner<T> {
|
||||||
(<any>this.app).keymap.popScope(this.scope);
|
(<any>this.app).keymap.popScope(this.scope);
|
||||||
|
|
||||||
this.suggest.setSuggestions([]);
|
this.suggest.setSuggestions([]);
|
||||||
this.popper.destroy();
|
this.popper?.destroy();
|
||||||
this.suggestEl.detach();
|
this.suggestEl.detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,104 +0,0 @@
|
||||||
import fetchMock, { enableFetchMocks } from 'jest-fetch-mock';
|
|
||||||
import { MediaDbPluginSettings } from 'src/settings/Settings';
|
|
||||||
import { LocGovAPI } from '../api/apis/LocGovAPI';
|
|
||||||
import { MALAPI } from '../api/apis/MALAPI';
|
|
||||||
import { MusicBrainzAPI } from '../api/apis/MusicBrainzAPI';
|
|
||||||
import { OMDbAPI } from '../api/apis/OMDbAPI';
|
|
||||||
import { SteamAPI } from '../api/apis/SteamAPI';
|
|
||||||
import { WikipediaAPI } from '../api/apis/WikipediaAPI';
|
|
||||||
import MediaDbPlugin from '../main';
|
|
||||||
import { setMALResponseMock, setMusicBrainzResponseMock, setOMDbResponseMock, setSteamResponseMock, setWikipediaResponseMock } from './mockHelpers';
|
|
||||||
import MALMockMovie from './ResponseMocks/MALMockMovie.json';
|
|
||||||
import MusicBrainzResponseMock from './ResponseMocks/MusicBrainzMockResponse.json';
|
|
||||||
import OMDBMockMovie from './ResponseMocks/OMDBMockResponse.json';
|
|
||||||
import SteamAPIResponseMock from './ResponseMocks/SteamAPIMockResponse.json';
|
|
||||||
import WikipediaMockResponse from './ResponseMocks/WikipediaMockResponse.json';
|
|
||||||
|
|
||||||
enableFetchMocks();
|
|
||||||
export let apiMock: OMDbAPI | MALAPI | LocGovAPI | MusicBrainzAPI | SteamAPI | WikipediaAPI;
|
|
||||||
|
|
||||||
describe.each([{ name: OMDbAPI }, { name: MALAPI }, { name: LocGovAPI }, { name: MusicBrainzAPI }, { name: SteamAPI }, { name: WikipediaAPI }])(
|
|
||||||
'$name.name',
|
|
||||||
({ name: parameterizedApi }) => {
|
|
||||||
beforeAll(() => {
|
|
||||||
let settingsMock: MediaDbPluginSettings = {} as MediaDbPluginSettings;
|
|
||||||
let pluginMock = {} as MediaDbPlugin;
|
|
||||||
pluginMock.settings = settingsMock;
|
|
||||||
// TODO: add fake API key?
|
|
||||||
apiMock = new parameterizedApi(pluginMock);
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
fetchMock.resetMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('searchByTitle behavior when API returns garbage data', async () => {
|
|
||||||
const garbageResponse = JSON.stringify({
|
|
||||||
data: 'string',
|
|
||||||
});
|
|
||||||
fetchMock.mockResponseOnce(garbageResponse);
|
|
||||||
await expect(apiMock.searchByTitle('sample')).resolves.toEqual([]);
|
|
||||||
// }
|
|
||||||
expect(fetch).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('searchByTitle behavior when requestUrl/fetch returns 401', async () => {
|
|
||||||
let sampleResponse = {
|
|
||||||
data: 'string',
|
|
||||||
};
|
|
||||||
fetchMock.mockResponse(JSON.stringify(sampleResponse), { status: 401 });
|
|
||||||
// TODO: Check API name and fix message
|
|
||||||
// TODO: Externalize string
|
|
||||||
await expect(apiMock.searchByTitle('sample')).rejects.toThrow(`MDB | Received status code ${401} from an API.`);
|
|
||||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('searchByTitle behavior when requestUrl/fetch returns 403', async () => {
|
|
||||||
let sampleResponse = {
|
|
||||||
data: 'string',
|
|
||||||
};
|
|
||||||
fetchMock.mockResponse(JSON.stringify(sampleResponse), { status: 403 });
|
|
||||||
// TODO: Check API name and fix message
|
|
||||||
// TODO: Externalize string/import?
|
|
||||||
await expect(apiMock.searchByTitle('sample')).rejects.toThrow(`MDB | Received status code ${403} from an API.`);
|
|
||||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('searchByTitle behavior when requestUrl/fetch returns 200', async () => {
|
|
||||||
let sampleResponse;
|
|
||||||
let ret;
|
|
||||||
switch (parameterizedApi) {
|
|
||||||
case OMDbAPI:
|
|
||||||
ret = setOMDbResponseMock();
|
|
||||||
sampleResponse = OMDBMockMovie;
|
|
||||||
break;
|
|
||||||
case WikipediaAPI:
|
|
||||||
ret = setWikipediaResponseMock();
|
|
||||||
sampleResponse = WikipediaMockResponse;
|
|
||||||
break;
|
|
||||||
case MALAPI:
|
|
||||||
// TODO: MAL needs more tests for different types of content
|
|
||||||
ret = setMALResponseMock();
|
|
||||||
sampleResponse = MALMockMovie;
|
|
||||||
case LocGovAPI:
|
|
||||||
// TODO: Add soon
|
|
||||||
break;
|
|
||||||
case SteamAPI:
|
|
||||||
sampleResponse = SteamAPIResponseMock;
|
|
||||||
ret = setSteamResponseMock();
|
|
||||||
break;
|
|
||||||
case MusicBrainzAPI:
|
|
||||||
sampleResponse = MusicBrainzResponseMock;
|
|
||||||
ret = setMusicBrainzResponseMock();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw Error();
|
|
||||||
}
|
|
||||||
fetchMock.mockResponse(JSON.stringify(sampleResponse), { status: 200 });
|
|
||||||
// TODO: Check API name and fix message
|
|
||||||
// TODO: Externalize string
|
|
||||||
await expect(apiMock.searchByTitle('Hooking Season Playtest')).resolves.toEqual(ret);
|
|
||||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
{
|
|
||||||
"data": [
|
|
||||||
{
|
|
||||||
"mal_id": 2890,
|
|
||||||
"url": "https://myanimelist.net/anime/2890/Gake_no_Ue_no_Ponyo",
|
|
||||||
"title": "Gake no Ue no Ponyo",
|
|
||||||
"title_english": "Ponyo",
|
|
||||||
"type": "Movie",
|
|
||||||
"source": "Original",
|
|
||||||
"episodes": 1,
|
|
||||||
"aired": {
|
|
||||||
"from": "2008-07-19T00:00:00+00:00",
|
|
||||||
"to": null,
|
|
||||||
"prop": {
|
|
||||||
"from": {
|
|
||||||
"day": 19,
|
|
||||||
"month": 7,
|
|
||||||
"year": 2008
|
|
||||||
},
|
|
||||||
"to": {
|
|
||||||
"day": null,
|
|
||||||
"month": null,
|
|
||||||
"year": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"string": "Jul 19, 2008"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
{
|
|
||||||
"release-groups": [
|
|
||||||
{
|
|
||||||
"id": "9cf08bf9-1948-4087-abe1-783210ea1fae",
|
|
||||||
"primary-type-id": "f529b476-6e62-324f-b0aa-1f3e33d313fc",
|
|
||||||
"title": "Halo Halo",
|
|
||||||
"first-release-date": "2013-07-08",
|
|
||||||
"primary-type": "Album",
|
|
||||||
"artist-credit": [
|
|
||||||
{
|
|
||||||
"name": "Halo Halo",
|
|
||||||
"artist": {
|
|
||||||
"name": "Halo Halo"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"releases": [
|
|
||||||
{
|
|
||||||
"id": "58dd1d57-2201-472e-9e36-5d497dcedb6f",
|
|
||||||
"title": "Halo Halo"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
{
|
|
||||||
"Search": [
|
|
||||||
{
|
|
||||||
"Title": "Guardians of the Galaxy",
|
|
||||||
"Year": "2014",
|
|
||||||
"imdbID": "tt2015381",
|
|
||||||
"Type": "movie",
|
|
||||||
"Poster": "https://m.media-amazon.com/images/M/MV5BMTAwMjU5OTgxNjZeQTJeQWpwZ15BbWU4MDUxNDYxODEx._V1_SX300.jpg"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"totalResults": "1",
|
|
||||||
"Response": "True"
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
{
|
|
||||||
"applist": {
|
|
||||||
"apps": [
|
|
||||||
{
|
|
||||||
"appid": 2076590,
|
|
||||||
"name": "Hooking Season Playtest"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"appid": 2076600,
|
|
||||||
"name": "MonsterTamer"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
{
|
|
||||||
"query": {
|
|
||||||
"searchinfo": {
|
|
||||||
"totalhits": 1199001,
|
|
||||||
"suggestion": "book",
|
|
||||||
"suggestionsnippet": "book"
|
|
||||||
},
|
|
||||||
"search": [
|
|
||||||
{
|
|
||||||
"ns": 0,
|
|
||||||
"title": "Book",
|
|
||||||
"pageid": 3778,
|
|
||||||
"size": 68829,
|
|
||||||
"wordcount": 8821,
|
|
||||||
"snippet": "called <span class=\"searchmatch\">books</span> or chapters or parts, are parts. The intellectual content in a physical book need not be a composition, nor even be called a book. <span class=\"searchmatch\">Books</span> can",
|
|
||||||
"timestamp": "2022-08-19T19:13:56Z"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
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(id: string): Promise<MediaTypeModel> {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
async searchByTitle(title: string): Promise<MediaTypeModel[]> {
|
|
||||||
return [] as MediaTypeModel[];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,95 +0,0 @@
|
||||||
import { GameModel } from '../models/GameModel';
|
|
||||||
import { MovieModel } from '../models/MovieModel';
|
|
||||||
import { MusicReleaseModel } from '../models/MusicReleaseModel';
|
|
||||||
import { WikiModel } from '../models/WikiModel';
|
|
||||||
import { MediaType } from '../utils/MediaType';
|
|
||||||
import { apiMock } from './ParameterizedAPI.test';
|
|
||||||
import MALMockMovie from './ResponseMocks/MALMockMovie.json';
|
|
||||||
import MusicBrainzResponseMock from './ResponseMocks/MusicBrainzMockResponse.json';
|
|
||||||
import OMDBMockMovie from './ResponseMocks/OMDBMockResponse.json';
|
|
||||||
import SteamAPIResponseMock from './ResponseMocks/SteamAPIMockResponse.json';
|
|
||||||
import WikipediaMockResponse from './ResponseMocks/WikipediaMockResponse.json';
|
|
||||||
|
|
||||||
export function setWikipediaResponseMock() {
|
|
||||||
let ret = [];
|
|
||||||
let wikiresponse = WikipediaMockResponse.query.search[0];
|
|
||||||
ret.push(
|
|
||||||
new WikiModel({
|
|
||||||
type: 'wiki',
|
|
||||||
title: wikiresponse.title,
|
|
||||||
englishTitle: wikiresponse.title,
|
|
||||||
year: '',
|
|
||||||
dataSource: apiMock.apiName,
|
|
||||||
id: wikiresponse.pageid,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setOMDbResponseMock() {
|
|
||||||
let ret = [];
|
|
||||||
let omdbresponse = OMDBMockMovie.Search[0];
|
|
||||||
ret.push(
|
|
||||||
new MovieModel({
|
|
||||||
type: 'wiki',
|
|
||||||
title: omdbresponse.Title,
|
|
||||||
englishTitle: omdbresponse.Title,
|
|
||||||
year: omdbresponse.Year,
|
|
||||||
dataSource: apiMock.apiName,
|
|
||||||
id: omdbresponse.imdbID,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setMALResponseMock() {
|
|
||||||
let ret = [];
|
|
||||||
let result = MALMockMovie.data[0];
|
|
||||||
ret.push(
|
|
||||||
new MovieModel({
|
|
||||||
type: result.type,
|
|
||||||
title: result.title,
|
|
||||||
englishTitle: result.title_english,
|
|
||||||
year: result.aired.prop.from.year,
|
|
||||||
dataSource: apiMock.apiName,
|
|
||||||
id: result.mal_id,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setSteamResponseMock() {
|
|
||||||
let ret = [];
|
|
||||||
let steamResponse = SteamAPIResponseMock.applist.apps[0];
|
|
||||||
ret.push(
|
|
||||||
new GameModel({
|
|
||||||
type: MediaType.Game,
|
|
||||||
title: steamResponse.name,
|
|
||||||
englishTitle: steamResponse.name,
|
|
||||||
year: '',
|
|
||||||
dataSource: apiMock.apiName,
|
|
||||||
id: steamResponse.appid,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setMusicBrainzResponseMock() {
|
|
||||||
let ret = [];
|
|
||||||
let result = MusicBrainzResponseMock['release-groups'][0];
|
|
||||||
ret.push(
|
|
||||||
new MusicReleaseModel({
|
|
||||||
type: 'musicRelease',
|
|
||||||
title: result.title,
|
|
||||||
englishTitle: result.title,
|
|
||||||
year: new Date(result['first-release-date']).getFullYear().toString(),
|
|
||||||
dataSource: apiMock.apiName,
|
|
||||||
url: '',
|
|
||||||
id: result.id,
|
|
||||||
|
|
||||||
artists: result['artist-credit'].map((a: any) => a.name),
|
|
||||||
subType: result['primary-type'],
|
|
||||||
} as MusicReleaseModel),
|
|
||||||
);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
import { containsOnlyLettersAndUnderscores, replaceIllegalFileNameCharactersInString, wrapAround } from '../utils/Utils';
|
|
||||||
|
|
||||||
test('If wrapAround wraps correctly', () => {
|
|
||||||
expect(wrapAround(100, 5)).toBe(0);
|
|
||||||
expect(wrapAround(100, 7)).toBe(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('If wrapAround errors out when dividing by zero', () => {
|
|
||||||
expect(wrapAround(100, 0)).toThrow();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('If wrapAround errors out when size is negative', () => {
|
|
||||||
expect(wrapAround(100, -5)).toThrow();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Letter and underscore string validity', () => {
|
|
||||||
expect(containsOnlyLettersAndUnderscores('asdkfj_')).toBe(true);
|
|
||||||
expect(containsOnlyLettersAndUnderscores('asdkfj0')).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
// since this is used to check if a string is a valid name for an object property, unicode characters shouldn't be allowed, thus the name of the function is misleading
|
|
||||||
test('Letter and underscore unicode char test', () => {
|
|
||||||
expect(containsOnlyLettersAndUnderscores('asdkaÈj')).toBe(true);
|
|
||||||
expect(containsOnlyLettersAndUnderscores('asdkaÈj0')).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Valid filename test', () => {
|
|
||||||
expect(replaceIllegalFileNameCharactersInString('what?is\\this:')).toBe('whatisthis -');
|
|
||||||
});
|
|
||||||
|
|
@ -28,7 +28,7 @@ export class MediaTypeManager {
|
||||||
mediaTemplateMap: Map<MediaType, string>;
|
mediaTemplateMap: Map<MediaType, string>;
|
||||||
mediaFolderMap: Map<MediaType, string>;
|
mediaFolderMap: Map<MediaType, string>;
|
||||||
|
|
||||||
constructor() { }
|
constructor() {}
|
||||||
|
|
||||||
updateTemplates(settings: MediaDbPluginSettings): void {
|
updateTemplates(settings: MediaDbPluginSettings): void {
|
||||||
this.mediaFileNameTemplateMap = new Map<MediaType, string>();
|
this.mediaFileNameTemplateMap = new Map<MediaType, string>();
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import { MediaDbSearchResultModal } from '../modals/MediaDbSearchResultModal';
|
||||||
import { Notice } from 'obsidian';
|
import { Notice } from 'obsidian';
|
||||||
import MediaDbPlugin from '../main';
|
import MediaDbPlugin from '../main';
|
||||||
import { MediaDbPreviewModal } from 'src/modals/MediaDbPreviewModal';
|
import { MediaDbPreviewModal } from 'src/modals/MediaDbPreviewModal';
|
||||||
import { CreateNoteOptions } from './Utils';
|
|
||||||
import { MediaDbSearchModal } from '../modals/MediaDbSearchModal';
|
import { MediaDbSearchModal } from '../modals/MediaDbSearchModal';
|
||||||
import { MediaType } from './MediaType';
|
import { MediaType } from './MediaType';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,9 @@ export function markdownTable(content: string[][]): string {
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fragWithHTML = (html: string) => createFragment(frag => (frag.createDiv().innerHTML = html));
|
export function fragWithHTML(html: string): DocumentFragment {
|
||||||
|
return createFragment(frag => (frag.createDiv().innerHTML = html));
|
||||||
|
}
|
||||||
|
|
||||||
export function dateToString(date: Date): string {
|
export function dateToString(date: Date): string {
|
||||||
return `${date.getMonth() + 1}-${date.getDate()}-${date.getFullYear()}`;
|
return `${date.getMonth() + 1}-${date.getDate()}-${date.getFullYear()}`;
|
||||||
|
|
@ -207,13 +209,13 @@ export function unCamelCase(str: string): string {
|
||||||
// space before last upper in a sequence followed by lower
|
// space before last upper in a sequence followed by lower
|
||||||
.replace(/\b([A-Z]+)([A-Z])([a-z])/, '$1 $2$3')
|
.replace(/\b([A-Z]+)([A-Z])([a-z])/, '$1 $2$3')
|
||||||
// uppercase the first character
|
// uppercase the first character
|
||||||
.replace(/^./, function(str) {
|
.replace(/^./, function (str) {
|
||||||
return str.toUpperCase();
|
return str.toUpperCase();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hasTemplaterPlugin(app: App) {
|
export function hasTemplaterPlugin(app: App): boolean {
|
||||||
const templater = (app as any).plugins.plugins['templater-obsidian'];
|
const templater = (app as any).plugins.plugins['templater-obsidian'];
|
||||||
|
|
||||||
return !!templater;
|
return !!templater;
|
||||||
|
|
@ -221,7 +223,7 @@ export function hasTemplaterPlugin(app: App) {
|
||||||
|
|
||||||
// Copied from https://github.com/anpigon/obsidian-book-search-plugin
|
// Copied from https://github.com/anpigon/obsidian-book-search-plugin
|
||||||
// Licensed under the MIT license. Copyright (c) 2020 Jake Runzer
|
// Licensed under the MIT license. Copyright (c) 2020 Jake Runzer
|
||||||
export async function useTemplaterPluginInFile(app: App, file: TFile) {
|
export async function useTemplaterPluginInFile(app: App, file: TFile): Promise<void> {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const templater = (app as any).plugins.plugins['templater-obsidian'];
|
const templater = (app as any).plugins.plugins['templater-obsidian'];
|
||||||
if (templater && !templater?.settings['trigger_on_file_creation']) {
|
if (templater && !templater?.settings['trigger_on_file_creation']) {
|
||||||
|
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
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 (value == null) {
|
|
||||||
return 'null';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof value === 'boolean') {
|
|
||||||
return value ? 'true' : 'false';
|
|
||||||
} else if (typeof value === 'number') {
|
|
||||||
return value.toString();
|
|
||||||
} else if (typeof value === 'string') {
|
|
||||||
return '"' + value.replace('"', '\\"') + '"';
|
|
||||||
} 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"types": ["svelte", "node", "jest"],
|
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"inlineSourceMap": true,
|
|
||||||
"inlineSources": true,
|
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"target": "ES6",
|
"target": "ES6",
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
|
|
@ -11,9 +8,9 @@
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"importHelpers": true,
|
"importHelpers": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"resolveJsonModule": true,
|
"lib": ["DOM", "ESNext"],
|
||||||
"allowSyntheticDefaultImports": true,
|
"types": ["svelte"],
|
||||||
"lib": ["DOM", "ES5", "ES6", "ES7", "Es2021"]
|
"allowSyntheticDefaultImports": true
|
||||||
},
|
},
|
||||||
"include": ["**/*.ts"]
|
"include": ["src/**/*.ts", "tests/**/*.ts"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue