mirror of
https://github.com/memodack/memodack.git
synced 2026-07-22 05:35:52 +00:00
chore: migrate tooling to biome and pnpm
This commit is contained in:
parent
cb6a171b75
commit
6f3070977d
36 changed files with 4886 additions and 8306 deletions
|
|
@ -1,4 +1,4 @@
|
|||
npm run prettier
|
||||
npm run lint
|
||||
npm run lint:circulars
|
||||
npm run test
|
||||
pnpm run format
|
||||
pnpm run lint
|
||||
pnpm run lint:circulars
|
||||
pnpm run test
|
||||
16
.vscode/settings.json
vendored
Normal file
16
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
// General editor settings
|
||||
"editor.defaultFormatter": "biomejs.biome",
|
||||
"editor.formatOnSave": true,
|
||||
|
||||
// Language-specific formatter overrides
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
},
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "biomejs.biome"
|
||||
}
|
||||
}
|
||||
36
biome.json
Normal file
36
biome.json
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"$schema": "https://biomejs.dev/schemas/2.3.4/schema.json",
|
||||
"vcs": {
|
||||
"enabled": true,
|
||||
"clientKind": "git",
|
||||
"useIgnoreFile": true
|
||||
},
|
||||
"files": {
|
||||
"includes": ["**", "!!**/dist"]
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 2,
|
||||
"lineWidth": 80
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"recommended": true
|
||||
}
|
||||
},
|
||||
"javascript": {
|
||||
"formatter": {
|
||||
"quoteStyle": "double"
|
||||
}
|
||||
},
|
||||
"assist": {
|
||||
"enabled": true,
|
||||
"actions": {
|
||||
"source": {
|
||||
"organizeImports": "on"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
export default {
|
||||
extends: ['@commitlint/config-conventional'],
|
||||
extends: ["@commitlint/config-conventional"],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,45 +1,26 @@
|
|||
import { copyFile, readFile, rm, writeFile } from 'node:fs/promises';
|
||||
import { existsSync, watchFile } from "node:fs";
|
||||
import { copyFile, readFile, rm, writeFile } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { exit } from "node:process";
|
||||
import builtins from "builtin-modules";
|
||||
import CleanCSS from "clean-css";
|
||||
import { context } from "esbuild";
|
||||
|
||||
import CleanCSS from 'clean-css';
|
||||
import builtins from 'builtin-modules';
|
||||
import { context } from 'esbuild';
|
||||
import { existsSync } from 'node:fs';
|
||||
import { exit } from 'node:process';
|
||||
import { join } from 'node:path';
|
||||
import { watchFile } from 'fs';
|
||||
const isDevelopment = process.env.NODE_ENV === "development";
|
||||
const isProduction = process.env.NODE_ENV === "production";
|
||||
|
||||
const isDevelopment = process.env.NODE_ENV === 'development';
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
|
||||
const outdirPath = 'dist';
|
||||
const stylesCssFilePath = 'src/styles.css';
|
||||
|
||||
const 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,
|
||||
];
|
||||
const outdirPath = "dist";
|
||||
const stylesCssFilePath = "src/styles.css";
|
||||
|
||||
if (existsSync(outdirPath)) {
|
||||
await rm(outdirPath, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
const stylesCopy = async () => {
|
||||
const css = await readFile(stylesCssFilePath, 'utf8');
|
||||
const css = await readFile(stylesCssFilePath, "utf8");
|
||||
const minified = new CleanCSS().minify(css).styles;
|
||||
|
||||
await writeFile(join(outdirPath, 'styles.css'), minified);
|
||||
await writeFile(join(outdirPath, "styles.css"), minified);
|
||||
};
|
||||
|
||||
watchFile(stylesCssFilePath, { interval: 300 }, async () => {
|
||||
|
|
@ -47,7 +28,7 @@ watchFile(stylesCssFilePath, { interval: 300 }, async () => {
|
|||
});
|
||||
|
||||
const stylesCopyPlugin = () => ({
|
||||
name: 'styles-copy-plugin',
|
||||
name: "styles-copy-plugin",
|
||||
setup(build) {
|
||||
build.onEnd(async () => {
|
||||
await stylesCopy();
|
||||
|
|
@ -56,20 +37,37 @@ const stylesCopyPlugin = () => ({
|
|||
});
|
||||
|
||||
const manifestCopyPlugin = () => ({
|
||||
name: 'manifest-copy-plugin',
|
||||
name: "manifest-copy-plugin",
|
||||
setup(build) {
|
||||
build.onEnd(async () => {
|
||||
await copyFile('manifest.json', join(outdirPath, 'manifest.json'));
|
||||
await copyFile("manifest.json", join(outdirPath, "manifest.json"));
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const 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,
|
||||
];
|
||||
|
||||
const ctx = await context({
|
||||
entryPoints: ['src/main.ts'],
|
||||
entryPoints: ["src/main.ts"],
|
||||
outfile: `${outdirPath}/main.js`,
|
||||
bundle: true,
|
||||
minify: isProduction,
|
||||
format: 'cjs',
|
||||
format: "cjs",
|
||||
external,
|
||||
plugins: [stylesCopyPlugin(), manifestCopyPlugin()],
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,61 +0,0 @@
|
|||
import eslint from '@eslint/js';
|
||||
import globals from 'globals';
|
||||
import pluginJest from 'eslint-plugin-jest';
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
export default tseslint.config(
|
||||
// Basic JS and TS rules
|
||||
eslint.configs.recommended,
|
||||
tseslint.configs.strictTypeChecked,
|
||||
|
||||
// Language settings for regular code (without jest!)
|
||||
{
|
||||
languageOptions: {
|
||||
globals: globals.node,
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// Strict TypeScript rules
|
||||
{
|
||||
rules: {
|
||||
'@typescript-eslint/explicit-function-return-type': 'error',
|
||||
},
|
||||
},
|
||||
|
||||
// Separate block for tests
|
||||
{
|
||||
files: ['**/*.test.ts'],
|
||||
plugins: { jest: pluginJest },
|
||||
languageOptions: {
|
||||
globals: pluginJest.environments.globals.globals,
|
||||
},
|
||||
rules: {
|
||||
// Jest rules
|
||||
'jest/no-disabled-tests': 'warn',
|
||||
'jest/no-focused-tests': 'error',
|
||||
'jest/no-identical-title': 'error',
|
||||
'jest/prefer-to-have-length': 'warn',
|
||||
'jest/valid-expect': 'error',
|
||||
|
||||
// Special handling of unbound methods
|
||||
'@typescript-eslint/unbound-method': 'off',
|
||||
'jest/unbound-method': 'error',
|
||||
},
|
||||
},
|
||||
|
||||
// Ignored files
|
||||
{
|
||||
ignores: [
|
||||
'dist',
|
||||
'eslint.config.mjs',
|
||||
'commitlint.config.mjs',
|
||||
'prettier.config.mjs',
|
||||
'jest.config.mjs',
|
||||
'esbuild.config.mjs',
|
||||
],
|
||||
},
|
||||
);
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
export default {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
preset: "ts-jest",
|
||||
testEnvironment: "node",
|
||||
};
|
||||
|
|
|
|||
7967
package-lock.json
generated
7967
package-lock.json
generated
File diff suppressed because it is too large
Load diff
22
package.json
22
package.json
|
|
@ -7,35 +7,33 @@
|
|||
"scripts": {
|
||||
"build": "cross-env NODE_ENV=production node ./esbuild.config.mjs",
|
||||
"dev": "cross-env NODE_ENV=development node ./esbuild.config.mjs",
|
||||
"lint": "eslint .",
|
||||
"format": "biome format",
|
||||
"format:write": "biome format --write",
|
||||
"lint": "biome lint",
|
||||
"lint:circulars": "madge --circular --extensions ts ./",
|
||||
"lint:fix": "eslint . --fix",
|
||||
"prepare": "husky",
|
||||
"prettier": "prettier --check .",
|
||||
"prettier:fix": "prettier --write .",
|
||||
"lint:write": "biome lint --write",
|
||||
"test": "jest --forceExit"
|
||||
},
|
||||
"dependencies": {
|
||||
"pretty-bytes": "^6.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^2.3.4",
|
||||
"@commitlint/cli": "^19.8.0",
|
||||
"@commitlint/config-conventional": "^19.8.0",
|
||||
"@eslint/js": "^9.23.0",
|
||||
"@types/jest": "^29.5.14",
|
||||
"builtin-modules": "^5.0.0",
|
||||
"clean-css": "^5.3.3",
|
||||
"cross-env": "^7.0.3",
|
||||
"cross-env": "^10.1.0",
|
||||
"esbuild": "^0.25.3",
|
||||
"eslint": "^9.23.0",
|
||||
"eslint-plugin-jest": "^28.11.0",
|
||||
"husky": "^9.1.7",
|
||||
"jest": "^29.7.0",
|
||||
"madge": "^8.0.0",
|
||||
"obsidian": "^1.8.7",
|
||||
"prettier": "^3.5.3",
|
||||
"ts-jest": "^29.3.2",
|
||||
"typescript": "^5.8.2",
|
||||
"typescript-eslint": "^8.28.0"
|
||||
"typescript": "^5.8.2"
|
||||
},
|
||||
"engines": {
|
||||
"pnpm": ">=10.17.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
4564
pnpm-lock.yaml
Normal file
4564
pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load diff
2
pnpm-workspace.yaml
Normal file
2
pnpm-workspace.yaml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
onlyBuiltDependencies:
|
||||
- esbuild
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
export default {
|
||||
semi: true,
|
||||
singleQuote: true,
|
||||
trailingComma: 'all',
|
||||
printWidth: 80,
|
||||
tabWidth: 2,
|
||||
useTabs: false,
|
||||
bracketSpacing: true,
|
||||
arrowParens: 'always',
|
||||
};
|
||||
47
src/main.ts
47
src/main.ts
|
|
@ -1,27 +1,26 @@
|
|||
import { Plugin, addIcon } from 'obsidian';
|
||||
|
||||
import { AdapterService } from './services/adapter.service';
|
||||
import { AudioService } from './services/audio.service';
|
||||
import { BlitzModalService } from './services/blitz-modal.service';
|
||||
import { CacheService } from './services/cache.service';
|
||||
import { ConductorService } from './services/conductor.service';
|
||||
import { EditorService } from './services/editor.service';
|
||||
import { ManifestService } from './services/manifest.service';
|
||||
import { MppService } from './services/mpp.service';
|
||||
import { PartsService } from './services/parts.service';
|
||||
import { PathsService } from './services/paths.service';
|
||||
import { PlayerService } from './services/player.service';
|
||||
import { RibbonIconService } from './services/ribbon-icon.service';
|
||||
import { SettingTabService } from './services/setting-tab.service';
|
||||
import { TSettings } from './types';
|
||||
import { TranslateCommandService } from './services/translate-command.service';
|
||||
import { TranslationService } from './services/translation.service';
|
||||
import { TtsService } from './services/tts.service';
|
||||
import { VaultService } from './services/vault.service';
|
||||
import { WorkspaceService } from './services/workspace.service';
|
||||
import { blitzService } from './services/blitz.service';
|
||||
import { progressBarService } from './services/progress-bar.service';
|
||||
import { settingsService } from './services/settings.service';
|
||||
import { addIcon, Plugin } from "obsidian";
|
||||
import { AdapterService } from "./services/adapter.service";
|
||||
import { AudioService } from "./services/audio.service";
|
||||
import { blitzService } from "./services/blitz.service";
|
||||
import { BlitzModalService } from "./services/blitz-modal.service";
|
||||
import { CacheService } from "./services/cache.service";
|
||||
import { ConductorService } from "./services/conductor.service";
|
||||
import { EditorService } from "./services/editor.service";
|
||||
import { ManifestService } from "./services/manifest.service";
|
||||
import { MppService } from "./services/mpp.service";
|
||||
import { PartsService } from "./services/parts.service";
|
||||
import { PathsService } from "./services/paths.service";
|
||||
import { PlayerService } from "./services/player.service";
|
||||
import { progressBarService } from "./services/progress-bar.service";
|
||||
import { RibbonIconService } from "./services/ribbon-icon.service";
|
||||
import { SettingTabService } from "./services/setting-tab.service";
|
||||
import { settingsService } from "./services/settings.service";
|
||||
import { TranslateCommandService } from "./services/translate-command.service";
|
||||
import { TranslationService } from "./services/translation.service";
|
||||
import { TtsService } from "./services/tts.service";
|
||||
import { VaultService } from "./services/vault.service";
|
||||
import { WorkspaceService } from "./services/workspace.service";
|
||||
import type { TSettings } from "./types";
|
||||
|
||||
export default class MemodackPlugin extends Plugin {
|
||||
async loadSettings(): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,9 @@
|
|||
import { DataAdapter, DataWriteOptions, ListedFiles, Stat } from 'obsidian';
|
||||
import type {
|
||||
DataAdapter,
|
||||
DataWriteOptions,
|
||||
ListedFiles,
|
||||
Stat,
|
||||
} from "obsidian";
|
||||
|
||||
export interface IAdapterService {
|
||||
exists(normalizedPath: string, sensitive?: boolean): Promise<boolean>;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { ELanguage } from '../types';
|
||||
import { ICacheService } from './cache.service';
|
||||
import { IPlayerService } from './player.service';
|
||||
import { ITtsService } from './tts.service';
|
||||
import type { ELanguage } from "../types";
|
||||
import type { ICacheService } from "./cache.service";
|
||||
import type { IPlayerService } from "./player.service";
|
||||
import type { ITtsService } from "./tts.service";
|
||||
|
||||
type TPlayArgs = { source: ELanguage; value: string }[];
|
||||
|
||||
|
|
@ -66,15 +66,15 @@ export class AudioService implements IAudioService {
|
|||
const msgBuffer = new TextEncoder().encode(data);
|
||||
|
||||
// Compute the hash
|
||||
const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
|
||||
const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer);
|
||||
|
||||
// Convert the hash to a byte array
|
||||
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
||||
|
||||
// Convert the byte array to a hexadecimal string
|
||||
const hashHex = hashArray
|
||||
.map((b) => b.toString(16).padStart(2, '0'))
|
||||
.join('');
|
||||
.map((b) => b.toString(16).padStart(2, "0"))
|
||||
.join("");
|
||||
|
||||
return hashHex;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { App, Modal } from 'obsidian';
|
||||
import { type App, Modal } from "obsidian";
|
||||
|
||||
import { IBlitzService } from './blitz.service';
|
||||
import { IConductorService } from './conductor.service';
|
||||
import { IPart } from './parts.service';
|
||||
import { IProgressBarService } from './progress-bar.service';
|
||||
import type { IBlitzService } from "./blitz.service";
|
||||
import type { IConductorService } from "./conductor.service";
|
||||
import type { IPart } from "./parts.service";
|
||||
import type { IProgressBarService } from "./progress-bar.service";
|
||||
|
||||
export interface IBlitzModalService {
|
||||
setParts(parts: IPart[]): void;
|
||||
|
|
@ -65,16 +65,16 @@ export class BlitzModalService extends Modal implements IBlitzModalService {
|
|||
|
||||
void this.conductorService.playValue(blitz.question);
|
||||
|
||||
let nextButtonEl: HTMLButtonElement | undefined = undefined;
|
||||
let correctOptionEl: HTMLButtonElement | undefined = undefined;
|
||||
let nextButtonEl: HTMLButtonElement | undefined;
|
||||
let correctOptionEl: HTMLButtonElement | undefined;
|
||||
|
||||
const answersButtons: HTMLButtonElement[] = [];
|
||||
|
||||
const answersElement = contentEl.createEl('div');
|
||||
answersElement.addClass('memodack___blitz__answers');
|
||||
const answersElement = contentEl.createEl("div");
|
||||
answersElement.addClass("memodack___blitz__answers");
|
||||
|
||||
blitz.answers.forEach((item, index) => {
|
||||
const answerButtonElement = answersElement.createEl('button');
|
||||
const answerButtonElement = answersElement.createEl("button");
|
||||
|
||||
if (blitz.correctAnswerId === index) {
|
||||
correctOptionEl = answerButtonElement;
|
||||
|
|
@ -83,17 +83,17 @@ export class BlitzModalService extends Modal implements IBlitzModalService {
|
|||
answersButtons.push(answerButtonElement);
|
||||
|
||||
answerButtonElement.setText(item);
|
||||
answerButtonElement.addEventListener('click', () => {
|
||||
answerButtonElement.addEventListener("click", () => {
|
||||
answersButtons.forEach((item) => {
|
||||
item.disabled = true;
|
||||
});
|
||||
|
||||
if (blitz.correctAnswerId === index) {
|
||||
answerButtonElement.addClass('correct');
|
||||
answerButtonElement.addClass("correct");
|
||||
void this.conductorService.playTranslation(item);
|
||||
} else {
|
||||
answerButtonElement.addClass('wrong');
|
||||
correctOptionEl?.addClass('correct');
|
||||
answerButtonElement.addClass("wrong");
|
||||
correctOptionEl?.addClass("correct");
|
||||
this.blitzService.repeatBlitz(id);
|
||||
}
|
||||
|
||||
|
|
@ -115,29 +115,29 @@ export class BlitzModalService extends Modal implements IBlitzModalService {
|
|||
answersElement.appendChild(this.progressBarService.getElement());
|
||||
this.progressBarService.setValue(this.blitzService.getProgress());
|
||||
|
||||
const blitzNext = contentEl.createEl('div');
|
||||
blitzNext.addClass('memodack___blitz__next');
|
||||
const blitzNext = contentEl.createEl("div");
|
||||
blitzNext.addClass("memodack___blitz__next");
|
||||
|
||||
nextButtonEl = blitzNext.createEl('button');
|
||||
nextButtonEl.setText('Next');
|
||||
nextButtonEl = blitzNext.createEl("button");
|
||||
nextButtonEl.setText("Next");
|
||||
nextButtonEl.disabled = true;
|
||||
|
||||
nextButtonEl.addEventListener('click', () => {
|
||||
nextButtonEl.addEventListener("click", () => {
|
||||
this.createBlitz(id + 1);
|
||||
});
|
||||
}
|
||||
|
||||
private createQuestionElement(question: string): void {
|
||||
const { contentEl } = this;
|
||||
const questionH2Element = contentEl.createEl('h2');
|
||||
const questionH2Element = contentEl.createEl("h2");
|
||||
questionH2Element.setText(question);
|
||||
questionH2Element.addClass('memodack___blitz__question');
|
||||
questionH2Element.addClass("memodack___blitz__question");
|
||||
}
|
||||
|
||||
private createTextElement(text: string): void {
|
||||
const { contentEl } = this;
|
||||
const questionH2Element = contentEl.createEl('div');
|
||||
const questionH2Element = contentEl.createEl("div");
|
||||
questionH2Element.setText(text);
|
||||
questionH2Element.addClass('memodack___blitz__text');
|
||||
questionH2Element.addClass("memodack___blitz__text");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { ISettingsService, settingsService } from './settings.service';
|
||||
|
||||
import { IPart } from './parts.service';
|
||||
import type { IPart } from "./parts.service";
|
||||
import { type ISettingsService, settingsService } from "./settings.service";
|
||||
|
||||
export interface IBlitz {
|
||||
correctAnswerId: number;
|
||||
|
|
@ -55,9 +54,7 @@ export class BlitzService implements IBlitzService {
|
|||
|
||||
const shuffleAnswers = this.shuffle(answers);
|
||||
|
||||
const correctAnswerId = shuffleAnswers.findIndex(
|
||||
(shuffleAnswerItem) => shuffleAnswerItem === q1,
|
||||
);
|
||||
const correctAnswerId = shuffleAnswers.indexOf(q1);
|
||||
|
||||
this.blitzMap.set(index, {
|
||||
correctAnswerId,
|
||||
|
|
@ -93,9 +90,7 @@ export class BlitzService implements IBlitzService {
|
|||
|
||||
const blitzTranslation = blitz.answers[blitz.correctAnswerId];
|
||||
|
||||
const correctAnswerId = shuffleAnswers.findIndex(
|
||||
(shuffleAnswerItem) => shuffleAnswerItem === blitzTranslation,
|
||||
);
|
||||
const correctAnswerId = shuffleAnswers.indexOf(blitzTranslation);
|
||||
|
||||
this.blitzMap.set(this.blitzMap.size, {
|
||||
correctAnswerId,
|
||||
|
|
@ -132,7 +127,7 @@ export class BlitzService implements IBlitzService {
|
|||
): number[] {
|
||||
if (maxNumber < 1 || count < 1) {
|
||||
throw new Error(
|
||||
'The maxNumber must be greater than or equal to 1 and count must be greater than or equal to 1.',
|
||||
"The maxNumber must be greater than or equal to 1 and count must be greater than or equal to 1.",
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -145,7 +140,7 @@ export class BlitzService implements IBlitzService {
|
|||
|
||||
if (availableNumbers.size < count) {
|
||||
throw new Error(
|
||||
'Not enough unique numbers available to satisfy the count.',
|
||||
"Not enough unique numbers available to satisfy the count.",
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -167,7 +162,7 @@ export class BlitzService implements IBlitzService {
|
|||
*/
|
||||
private shuffle<T>(array: T[]): T[] {
|
||||
if (!Array.isArray(array)) {
|
||||
throw new Error('Input array cannot be null or undefined.');
|
||||
throw new Error("Input array cannot be null or undefined.");
|
||||
}
|
||||
|
||||
// Create a copy of the array to avoid modifying the original
|
||||
|
|
@ -187,7 +182,7 @@ export class BlitzService implements IBlitzService {
|
|||
/**
|
||||
* Split the text to the parts and return randomly one of it.
|
||||
*/
|
||||
private getRandomSegment(text: string, divider: string = ';'): string {
|
||||
private getRandomSegment(text: string, divider: string = ";"): string {
|
||||
const parts = text.split(divider).map((item) => item.trim());
|
||||
const index = Math.floor(Math.random() * parts.length);
|
||||
return parts[index];
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { IAdapterService } from './adapter.service';
|
||||
import { IPathsService } from './paths.service';
|
||||
import { IVaultService } from './vault.service';
|
||||
import type { IAdapterService } from "./adapter.service";
|
||||
import type { IPathsService } from "./paths.service";
|
||||
import type { IVaultService } from "./vault.service";
|
||||
|
||||
export interface ICacheService {
|
||||
add(key: string, value: string): Promise<void>;
|
||||
|
|
@ -37,7 +37,7 @@ export class CacheService implements ICacheService {
|
|||
}
|
||||
} catch (e) {
|
||||
const errorMessage = `Failed to add cache for key '${key}'.`;
|
||||
console.error(errorMessage, e instanceof Error ? e.message : '');
|
||||
console.error(errorMessage, e instanceof Error ? e.message : "");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ export class CacheService implements ICacheService {
|
|||
return await this.adapterService.read(`${cacheDirPath}/${key}`);
|
||||
} catch (e) {
|
||||
const errorMessage = `Failed to get a cache by '${key}' key.`;
|
||||
console.error(errorMessage, e instanceof Error ? e.message : '');
|
||||
console.error(errorMessage, e instanceof Error ? e.message : "");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
@ -80,7 +80,7 @@ export class CacheService implements ICacheService {
|
|||
return totalSize;
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`Failed to retrieve the cache directory size. ${e instanceof Error ? e.message : ''}`,
|
||||
`Failed to retrieve the cache directory size. ${e instanceof Error ? e.message : ""}`,
|
||||
);
|
||||
|
||||
return 0;
|
||||
|
|
@ -98,7 +98,7 @@ export class CacheService implements ICacheService {
|
|||
await this.adapterService.rmdir(cacheDirPath, true);
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`Failed to clear the cache. ${e instanceof Error ? e.message : ''}`,
|
||||
`Failed to clear the cache. ${e instanceof Error ? e.message : ""}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { EPlayVariant } from '../types';
|
||||
import { IAudioService } from './audio.service';
|
||||
import { ISettingsService } from './settings.service';
|
||||
import { EPlayVariant } from "../types";
|
||||
import type { IAudioService } from "./audio.service";
|
||||
import type { ISettingsService } from "./settings.service";
|
||||
|
||||
export interface IConductorService {
|
||||
playValue(value: string): Promise<void>;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Editor } from 'obsidian';
|
||||
import type { Editor } from "obsidian";
|
||||
|
||||
export interface IEditorService {
|
||||
getSelection(): string;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { PluginManifest } from 'obsidian';
|
||||
import type { PluginManifest } from "obsidian";
|
||||
|
||||
export interface IManifestService {
|
||||
getId(): string;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { IConductorService } from './conductor.service';
|
||||
import type { IConductorService } from "./conductor.service";
|
||||
|
||||
export interface IMppService {
|
||||
getPostProcessor(element: HTMLElement): void;
|
||||
|
|
@ -15,10 +15,13 @@ export class MppService implements IMppService {
|
|||
const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT);
|
||||
|
||||
const nodesToReplace = [];
|
||||
let node;
|
||||
let node: Node | null;
|
||||
|
||||
while ((node = walker.nextNode())) {
|
||||
if (node.nodeValue && node.nodeValue.match(/\{.*?\|.*?\}/)) {
|
||||
while (true) {
|
||||
node = walker.nextNode() as Text | null;
|
||||
if (!node) break;
|
||||
|
||||
if (node.nodeValue?.match(/\{.*?\|.*?\}/)) {
|
||||
nodesToReplace.push(node);
|
||||
}
|
||||
}
|
||||
|
|
@ -47,11 +50,11 @@ export class MppService implements IMppService {
|
|||
const value = match[1];
|
||||
const translation = match[2];
|
||||
|
||||
const span = createEl('span', {
|
||||
cls: 'memodack___syntax',
|
||||
const span = createEl("span", {
|
||||
cls: "memodack___syntax",
|
||||
text: value,
|
||||
attr: {
|
||||
'data-translation': match[2],
|
||||
"data-translation": match[2],
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { IVaultService } from './vault.service';
|
||||
import { IWorkspaceService } from './workspace.service';
|
||||
import type { IVaultService } from "./vault.service";
|
||||
import type { IWorkspaceService } from "./workspace.service";
|
||||
|
||||
export interface IPart {
|
||||
value: string;
|
||||
|
|
@ -41,7 +41,7 @@ export class PartsService implements IPartsService {
|
|||
|
||||
const parts: IPart[] = [];
|
||||
|
||||
const texts = content.split('\n');
|
||||
const texts = content.split("\n");
|
||||
|
||||
// Generate parts array
|
||||
matches.forEach((match) => {
|
||||
|
|
@ -90,7 +90,7 @@ export class PartsService implements IPartsService {
|
|||
|
||||
if (selection && selection.rangeCount > 0 && selection.toString().length) {
|
||||
const ranges = selection.getRangeAt(0);
|
||||
const spans = document.querySelectorAll('.memodack___syntax');
|
||||
const spans = document.querySelectorAll(".memodack___syntax");
|
||||
|
||||
// Iterate over all <span> elements
|
||||
spans.forEach((span) => {
|
||||
|
|
@ -99,8 +99,8 @@ export class PartsService implements IPartsService {
|
|||
|
||||
// Check if the selection intersects with the <span> element
|
||||
if (ranges.intersectsNode(span)) {
|
||||
const beforeText = span.previousSibling?.textContent?.trim() || '';
|
||||
const afterText = span.nextSibling?.textContent?.trim() || '';
|
||||
const beforeText = span.previousSibling?.textContent?.trim() || "";
|
||||
const afterText = span.nextSibling?.textContent?.trim() || "";
|
||||
|
||||
const value = span.textContent;
|
||||
|
||||
|
|
@ -108,7 +108,7 @@ export class PartsService implements IPartsService {
|
|||
return;
|
||||
}
|
||||
|
||||
const translation = span.getAttribute('data-translation');
|
||||
const translation = span.getAttribute("data-translation");
|
||||
|
||||
const text = `${beforeText} ${value} ${afterText}`.trim();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { IManifestService } from './manifest.service';
|
||||
import { IVaultService } from './vault.service';
|
||||
import type { IManifestService } from "./manifest.service";
|
||||
import type { IVaultService } from "./vault.service";
|
||||
|
||||
export interface IPathsService {
|
||||
getCacheDirPath(): string;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { ISettingsService } from './settings.service';
|
||||
import type { ISettingsService } from "./settings.service";
|
||||
|
||||
export interface IPlayerService {
|
||||
play(audioUrl: string): Promise<void>;
|
||||
|
|
@ -14,7 +14,7 @@ export class PlayerService implements IPlayerService {
|
|||
|
||||
async play(audioUrl: string): Promise<void> {
|
||||
if (!audioUrl) {
|
||||
throw new Error('The audioUrl is required for audio playback.');
|
||||
throw new Error("The audioUrl is required for audio playback.");
|
||||
}
|
||||
|
||||
this.audio.volume = 0;
|
||||
|
|
@ -28,7 +28,7 @@ export class PlayerService implements IPlayerService {
|
|||
|
||||
await new Promise<void>((resolve) => {
|
||||
this.audio.addEventListener(
|
||||
'ended',
|
||||
"ended",
|
||||
() => {
|
||||
resolve();
|
||||
},
|
||||
|
|
@ -36,7 +36,7 @@ export class PlayerService implements IPlayerService {
|
|||
);
|
||||
});
|
||||
} catch (e) {
|
||||
const errorMessage = 'Audio playback error.';
|
||||
const errorMessage = "Audio playback error.";
|
||||
|
||||
if (e instanceof Error) {
|
||||
console.error(e.message || errorMessage);
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ export class ProgressBarService implements IProgressBarService {
|
|||
private _progressElement: HTMLProgressElement | null = null;
|
||||
|
||||
create(contentEl: HTMLElement, max: number, value: number): void {
|
||||
this._progressElement = contentEl.createEl('progress');
|
||||
this._progressElement.addClass('memodack___blitz__progress');
|
||||
this._progressElement = contentEl.createEl("progress");
|
||||
this._progressElement.addClass("memodack___blitz__progress");
|
||||
|
||||
this.setMax(max);
|
||||
this.setValue(value);
|
||||
|
|
@ -35,7 +35,7 @@ export class ProgressBarService implements IProgressBarService {
|
|||
|
||||
private get progressElement(): HTMLProgressElement {
|
||||
if (!this._progressElement) {
|
||||
throw new Error('The progress element has not been created.');
|
||||
throw new Error("The progress element has not been created.");
|
||||
}
|
||||
|
||||
return this._progressElement;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { IPart, IPartsService } from './parts.service';
|
||||
import { Notice } from "obsidian";
|
||||
|
||||
import { BlitzModalService } from './blitz-modal.service';
|
||||
import { IWorkspaceService } from './workspace.service';
|
||||
import { Notice } from 'obsidian';
|
||||
import type { BlitzModalService } from "./blitz-modal.service";
|
||||
import type { IPart, IPartsService } from "./parts.service";
|
||||
import type { IWorkspaceService } from "./workspace.service";
|
||||
|
||||
export interface IRibbonIconService {
|
||||
getCallback: () => Promise<void>;
|
||||
|
|
@ -15,8 +15,8 @@ const svg = `
|
|||
`;
|
||||
|
||||
export class RibbonIconService implements IRibbonIconService {
|
||||
static readonly id = 'memodack';
|
||||
static readonly title = 'Memodack';
|
||||
static readonly id = "memodack";
|
||||
static readonly title = "Memodack";
|
||||
static readonly svg = svg;
|
||||
|
||||
private workspaceService: IWorkspaceService;
|
||||
|
|
@ -37,7 +37,7 @@ export class RibbonIconService implements IRibbonIconService {
|
|||
const isReadingMode = this.workspaceService.isReadingMode();
|
||||
|
||||
if (!isReadingMode) {
|
||||
new Notice('Only in Reading Mode.');
|
||||
new Notice("Only in Reading Mode.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -50,12 +50,12 @@ export class RibbonIconService implements IRibbonIconService {
|
|||
}
|
||||
|
||||
if (!parts.length) {
|
||||
new Notice('No parts provided.');
|
||||
new Notice("No parts provided.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (parts.length < 4) {
|
||||
new Notice('At least 4 parts required.');
|
||||
new Notice("At least 4 parts required.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,15 @@
|
|||
import { App, Notice, PluginSettingTab, Setting } from 'obsidian';
|
||||
import { type App, Notice, PluginSettingTab, Setting } from "obsidian";
|
||||
import prettyBytes from "pretty-bytes";
|
||||
import {
|
||||
ELanguage,
|
||||
EPlayVariant,
|
||||
EVoiceOverSpeed,
|
||||
TMemodackPlugin,
|
||||
} from '../types';
|
||||
|
||||
import { ICacheService } from './cache.service';
|
||||
import { ISettingsService } from './settings.service';
|
||||
import { ITranslationService } from './translation.service';
|
||||
import { ITtsService } from './tts.service';
|
||||
import prettyBytes from 'pretty-bytes';
|
||||
type TMemodackPlugin,
|
||||
} from "../types";
|
||||
import type { ICacheService } from "./cache.service";
|
||||
import type { ISettingsService } from "./settings.service";
|
||||
import type { ITranslationService } from "./translation.service";
|
||||
import type { ITtsService } from "./tts.service";
|
||||
|
||||
export class SettingTabService extends PluginSettingTab {
|
||||
private readonly plugin: TMemodackPlugin;
|
||||
|
|
@ -50,11 +49,11 @@ export class SettingTabService extends PluginSettingTab {
|
|||
|
||||
containerEl.empty();
|
||||
|
||||
new Setting(containerEl).setName('Provider (Google)').setHeading();
|
||||
new Setting(containerEl).setName("Provider (Google)").setHeading();
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('API Key')
|
||||
.setDesc('API key for translation and text-to-speech services.')
|
||||
.setName("API Key")
|
||||
.setDesc("API key for translation and text-to-speech services.")
|
||||
.addText((text) => {
|
||||
text
|
||||
.setValue(this.settingsService.getApiKey())
|
||||
|
|
@ -64,22 +63,22 @@ export class SettingTabService extends PluginSettingTab {
|
|||
this.settingsService.setApiKey(value);
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
.inputEl.setAttribute('type', 'password');
|
||||
.inputEl.setAttribute("type", "password");
|
||||
});
|
||||
|
||||
this.checkSettings = new Setting(containerEl)
|
||||
.setName('Connection')
|
||||
.setDesc('Check access to services by API key.')
|
||||
.setName("Connection")
|
||||
.setDesc("Check access to services by API key.")
|
||||
.addButton((btn) =>
|
||||
btn
|
||||
.setButtonText('Check')
|
||||
.setButtonText("Check")
|
||||
.setCta()
|
||||
.onClick(async () => {
|
||||
await this.check();
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl).setName('Language').setHeading();
|
||||
new Setting(containerEl).setName("Language").setHeading();
|
||||
|
||||
const options: Record<string, string> = {};
|
||||
|
||||
|
|
@ -88,8 +87,8 @@ export class SettingTabService extends PluginSettingTab {
|
|||
});
|
||||
|
||||
this.nativeLanguageSettings = new Setting(containerEl)
|
||||
.setName('Native')
|
||||
.setDesc('This is the language you speak natively.')
|
||||
.setName("Native")
|
||||
.setDesc("This is the language you speak natively.")
|
||||
.addDropdown((dropdown) => {
|
||||
dropdown
|
||||
.addOptions(options)
|
||||
|
|
@ -101,8 +100,8 @@ export class SettingTabService extends PluginSettingTab {
|
|||
});
|
||||
|
||||
this.documentLanguageSettings = new Setting(containerEl)
|
||||
.setName('Document')
|
||||
.setDesc('This is the language of the document.')
|
||||
.setName("Document")
|
||||
.setDesc("This is the language of the document.")
|
||||
.addDropdown((dropdown) => {
|
||||
dropdown
|
||||
.addOptions(options)
|
||||
|
|
@ -113,38 +112,38 @@ export class SettingTabService extends PluginSettingTab {
|
|||
});
|
||||
});
|
||||
|
||||
new Setting(containerEl).setName('Voiceover').setHeading();
|
||||
new Setting(containerEl).setName("Voiceover").setHeading();
|
||||
|
||||
this.playbackSpeedSettings = new Setting(containerEl)
|
||||
.setName('Playback speed')
|
||||
.setDesc('The speed at which the voiceover will be performed.')
|
||||
.setName("Playback speed")
|
||||
.setDesc("The speed at which the voiceover will be performed.")
|
||||
.addDropdown((dropdown) => {
|
||||
dropdown
|
||||
.addOptions({
|
||||
[EVoiceOverSpeed.Normal]: 'Normal',
|
||||
[EVoiceOverSpeed.x2]: 'x2',
|
||||
[EVoiceOverSpeed.x3]: 'x3',
|
||||
[EVoiceOverSpeed.Normal]: "Normal",
|
||||
[EVoiceOverSpeed.x2]: "x2",
|
||||
[EVoiceOverSpeed.x3]: "x3",
|
||||
})
|
||||
.setValue(this.settingsService.getVoiceOverSpeed().toString())
|
||||
.onChange(async (value): Promise<void> => {
|
||||
this.settingsService.setVoiceOverSpeed(parseInt(value));
|
||||
this.settingsService.setVoiceOverSpeed(parseInt(value, 10));
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
new Setting(containerEl).setName('Actions').setHeading();
|
||||
new Setting(containerEl).setName("Actions").setHeading();
|
||||
|
||||
this.playVariantSettings = new Setting(containerEl)
|
||||
.setName('When pressed play')
|
||||
.setDesc('Will be voiced when you click on a part.')
|
||||
.setName("When pressed play")
|
||||
.setDesc("Will be voiced when you click on a part.")
|
||||
.addDropdown((dropdown) => {
|
||||
dropdown
|
||||
.addOptions({
|
||||
[EPlayVariant.Nothing]: 'Nothing',
|
||||
[EPlayVariant.Value]: 'Value',
|
||||
[EPlayVariant.Translation]: 'Translation',
|
||||
[EPlayVariant.ValueAndTranslation]: 'Value + Translation',
|
||||
[EPlayVariant.TranslationAndValue]: 'Translation + Value',
|
||||
[EPlayVariant.Nothing]: "Nothing",
|
||||
[EPlayVariant.Value]: "Value",
|
||||
[EPlayVariant.Translation]: "Translation",
|
||||
[EPlayVariant.ValueAndTranslation]: "Value + Translation",
|
||||
[EPlayVariant.TranslationAndValue]: "Translation + Value",
|
||||
})
|
||||
.setValue(this.settingsService.getPlayVariant())
|
||||
.onChange(async (value): Promise<void> => {
|
||||
|
|
@ -153,10 +152,10 @@ export class SettingTabService extends PluginSettingTab {
|
|||
});
|
||||
});
|
||||
|
||||
new Setting(containerEl).setName('Extra').setHeading();
|
||||
new Setting(containerEl).setName("Extra").setHeading();
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Divider')
|
||||
.setName("Divider")
|
||||
.setDesc('Split translation values using the ";" symbol.')
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
|
|
@ -167,14 +166,14 @@ export class SettingTabService extends PluginSettingTab {
|
|||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl).setName('Optimization').setHeading();
|
||||
new Setting(containerEl).setName("Optimization").setHeading();
|
||||
|
||||
const cacheSetting = new Setting(containerEl)
|
||||
.setName('Cache')
|
||||
.setName("Cache")
|
||||
.setDesc(prettyBytes(this.cacheSize))
|
||||
.addButton((btn) =>
|
||||
btn
|
||||
.setButtonText('Clear')
|
||||
.setButtonText("Clear")
|
||||
.setCta()
|
||||
.onClick(async () => {
|
||||
await this.cacheService.clear();
|
||||
|
|
@ -191,7 +190,7 @@ export class SettingTabService extends PluginSettingTab {
|
|||
const apiKey = this.settingsService.getApiKey();
|
||||
|
||||
if (!apiKey) {
|
||||
new Notice('No API key entered.');
|
||||
new Notice("No API key entered.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
import { ELanguage, EPlayVariant, EVoiceOverSpeed, TSettings } from '../types';
|
||||
import {
|
||||
ELanguage,
|
||||
EPlayVariant,
|
||||
EVoiceOverSpeed,
|
||||
type TSettings,
|
||||
} from "../types";
|
||||
|
||||
export const defaultSettings: TSettings = {
|
||||
apiKey: '',
|
||||
apiKey: "",
|
||||
source: ELanguage.English,
|
||||
target: ELanguage.Ukrainian,
|
||||
playVariant: EPlayVariant.ValueAndTranslation,
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
import { IConductorService } from './conductor.service';
|
||||
import { IEditorService } from './editor.service';
|
||||
import { ISettingsService } from './settings.service';
|
||||
import { ITranslationService } from './translation.service';
|
||||
import type { IConductorService } from "./conductor.service";
|
||||
import type { IEditorService } from "./editor.service";
|
||||
import type { ISettingsService } from "./settings.service";
|
||||
import type { ITranslationService } from "./translation.service";
|
||||
|
||||
export interface ITranslateCommandService {
|
||||
getCallback: () => Promise<void>;
|
||||
}
|
||||
|
||||
export class TranslateCommandService implements ITranslateCommandService {
|
||||
static readonly id = 'translate';
|
||||
static readonly name = 'Translate';
|
||||
static readonly id = "translate";
|
||||
static readonly name = "Translate";
|
||||
|
||||
private editorService: IEditorService;
|
||||
private translationService: ITranslationService;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { Notice, RequestUrlResponsePromise, requestUrl } from 'obsidian';
|
||||
|
||||
import { ELanguage } from '../types';
|
||||
import { ISettingsService } from './settings.service';
|
||||
import { Notice, type RequestUrlResponsePromise, requestUrl } from "obsidian";
|
||||
import { ELanguage } from "../types";
|
||||
import type { ISettingsService } from "./settings.service";
|
||||
|
||||
export interface ITranslationService {
|
||||
translate(
|
||||
|
|
@ -51,7 +50,7 @@ export class TranslationService implements ITranslationService {
|
|||
return json.data.translations[0].translatedText || null;
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`Failed to process translation. ${e instanceof Error ? e.message : ''}`,
|
||||
`Failed to process translation. ${e instanceof Error ? e.message : ""}`,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
|
@ -62,18 +61,18 @@ export class TranslationService implements ITranslationService {
|
|||
const response = await this.translate(
|
||||
ELanguage.English,
|
||||
ELanguage.Ukrainian,
|
||||
'ping',
|
||||
"ping",
|
||||
);
|
||||
|
||||
if (!response) {
|
||||
new Notice('The translation service is not working.');
|
||||
new Notice("The translation service is not working.");
|
||||
return;
|
||||
}
|
||||
|
||||
new Notice('The translation service is working.');
|
||||
new Notice("The translation service is working.");
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
} catch (e) {
|
||||
new Notice('The translation service is not working.');
|
||||
} catch (_e) {
|
||||
new Notice("The translation service is not working.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -92,7 +91,7 @@ export class TranslationService implements ITranslationService {
|
|||
q: text,
|
||||
source,
|
||||
target,
|
||||
format: 'text',
|
||||
format: "text",
|
||||
};
|
||||
|
||||
return JSON.stringify(body);
|
||||
|
|
@ -100,9 +99,9 @@ export class TranslationService implements ITranslationService {
|
|||
|
||||
private request(url: string, body: string): RequestUrlResponsePromise {
|
||||
return requestUrl({
|
||||
method: 'POST',
|
||||
method: "POST",
|
||||
url,
|
||||
contentType: 'application/json',
|
||||
contentType: "application/json",
|
||||
body,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { Notice, RequestUrlResponsePromise, requestUrl } from 'obsidian';
|
||||
|
||||
import { ELanguage } from '../types';
|
||||
import { ISettingsService } from './settings.service';
|
||||
import { Notice, type RequestUrlResponsePromise, requestUrl } from "obsidian";
|
||||
import { ELanguage } from "../types";
|
||||
import type { ISettingsService } from "./settings.service";
|
||||
|
||||
export interface ITtsService {
|
||||
tts(language: ELanguage, value: string): Promise<string | null>;
|
||||
|
|
@ -39,7 +38,7 @@ export class TtsService implements ITtsService {
|
|||
return json.audioContent || null;
|
||||
} catch (e) {
|
||||
console.error(
|
||||
`Failed to process TTS. ${e instanceof Error ? e.message : ''}`,
|
||||
`Failed to process TTS. ${e instanceof Error ? e.message : ""}`,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
|
@ -47,17 +46,17 @@ export class TtsService implements ITtsService {
|
|||
|
||||
async test(): Promise<void> {
|
||||
try {
|
||||
const response = await this.tts(ELanguage.English, 'ping');
|
||||
const response = await this.tts(ELanguage.English, "ping");
|
||||
|
||||
if (!response) {
|
||||
new Notice('The text-to-speech service is not working.');
|
||||
new Notice("The text-to-speech service is not working.");
|
||||
return;
|
||||
}
|
||||
|
||||
new Notice('The text-to-speech service is working.');
|
||||
new Notice("The text-to-speech service is working.");
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
} catch (e) {
|
||||
new Notice('The text-to-speech service is not working.');
|
||||
} catch (_e) {
|
||||
new Notice("The text-to-speech service is not working.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,9 +75,9 @@ export class TtsService implements ITtsService {
|
|||
input: { text: value },
|
||||
voice: {
|
||||
languageCode: language,
|
||||
ssmlGender: 'NEUTRAL',
|
||||
ssmlGender: "NEUTRAL",
|
||||
},
|
||||
audioConfig: { audioEncoding: 'MP3' },
|
||||
audioConfig: { audioEncoding: "MP3" },
|
||||
};
|
||||
|
||||
return JSON.stringify(body);
|
||||
|
|
@ -86,9 +85,9 @@ export class TtsService implements ITtsService {
|
|||
|
||||
private request(url: string, body: string): RequestUrlResponsePromise {
|
||||
return requestUrl({
|
||||
method: 'POST',
|
||||
method: "POST",
|
||||
url,
|
||||
contentType: 'application/json',
|
||||
contentType: "application/json",
|
||||
body,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { TFile, TFolder, Vault } from 'obsidian';
|
||||
import type { TFile, TFolder, Vault } from "obsidian";
|
||||
|
||||
export interface IVaultService {
|
||||
read(file: TFile): Promise<string>;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { MarkdownView, TFile, Workspace } from 'obsidian';
|
||||
import { MarkdownView, type TFile, type Workspace } from "obsidian";
|
||||
|
||||
export interface IWorkspaceService {
|
||||
getActiveFile(): TFile | null;
|
||||
|
|
@ -18,7 +18,7 @@ export class WorkspaceService implements IWorkspaceService {
|
|||
|
||||
isReadingMode(): boolean {
|
||||
return (
|
||||
this.workspace.getActiveViewOfType(MarkdownView)?.getMode() === 'preview'
|
||||
this.workspace.getActiveViewOfType(MarkdownView)?.getMode() === "preview"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
38
src/types.ts
38
src/types.ts
|
|
@ -1,13 +1,13 @@
|
|||
import { Plugin } from 'obsidian';
|
||||
import type { Plugin } from "obsidian";
|
||||
|
||||
export type TMemodackPlugin = Plugin & { saveSettings: () => Promise<void> };
|
||||
|
||||
export enum EPlayVariant {
|
||||
Nothing = 'nothing',
|
||||
Value = 'value',
|
||||
Translation = 'translation',
|
||||
ValueAndTranslation = 'value-and-translation',
|
||||
TranslationAndValue = 'translation-and-value',
|
||||
Nothing = "nothing",
|
||||
Value = "value",
|
||||
Translation = "translation",
|
||||
ValueAndTranslation = "value-and-translation",
|
||||
TranslationAndValue = "translation-and-value",
|
||||
}
|
||||
|
||||
export enum EVoiceOverSpeed {
|
||||
|
|
@ -17,19 +17,19 @@ export enum EVoiceOverSpeed {
|
|||
}
|
||||
|
||||
export enum ELanguage {
|
||||
Ukrainian = 'uk',
|
||||
English = 'en',
|
||||
MandarinChinese = 'zh-CN',
|
||||
Hindi = 'hi',
|
||||
Spanish = 'es',
|
||||
StandardArabic = 'ar',
|
||||
French = 'fr',
|
||||
Bengali = 'bn',
|
||||
Portuguese = 'pt',
|
||||
Urdu = 'ur',
|
||||
Indonesian = 'id',
|
||||
German = 'de',
|
||||
Japanese = 'ja',
|
||||
Ukrainian = "uk",
|
||||
English = "en",
|
||||
MandarinChinese = "zh-CN",
|
||||
Hindi = "hi",
|
||||
Spanish = "es",
|
||||
StandardArabic = "ar",
|
||||
French = "fr",
|
||||
Bengali = "bn",
|
||||
Portuguese = "pt",
|
||||
Urdu = "ur",
|
||||
Indonesian = "id",
|
||||
German = "de",
|
||||
Japanese = "ja",
|
||||
}
|
||||
|
||||
export type TSettings = {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
it('should evaluate the condition', () => {
|
||||
it("should evaluate the condition", () => {
|
||||
expect(1 + 2).toEqual(3);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue