Merge branch 'develop' of codeberg.org:calckey/calckey into develop

This commit is contained in:
ThatOneCalculator 2023-04-29 19:15:47 -07:00
commit d493665922
No known key found for this signature in database
GPG Key ID: 8703CACD01000000
12 changed files with 151 additions and 78 deletions

View File

@ -0,0 +1,23 @@
export class LibreTranslate1682777547198 {
name = "LibreTranslate1682777547198";
async up(queryRunner) {
await queryRunner.query(`
ALTER TABLE "meta"
ADD "libreTranslateApiUrl" character varying(512)
`);
await queryRunner.query(`
ALTER TABLE "meta"
ADD "libreTranslateApiKey" character varying(128)
`);
}
async down(queryRunner) {
await queryRunner.query(`
ALTER TABLE "meta" DROP COLUMN "libreTranslateApiKey"
`);
await queryRunner.query(`
ALTER TABLE "meta" DROP COLUMN "libreTranslateApiUrl"
`);
}
}

View File

@ -89,6 +89,11 @@ export type Source = {
authKey?: string; authKey?: string;
isPro?: boolean; isPro?: boolean;
}; };
libreTranslate: {
managed?: boolean;
apiUrl?: string;
apiKey?: string;
};
email: { email: {
managed?: boolean; managed?: boolean;
address?: string; address?: string;

View File

@ -386,6 +386,18 @@ export class Meta {
}) })
public deeplIsPro: boolean; public deeplIsPro: boolean;
@Column('varchar', {
length: 512,
nullable: true,
})
public libreTranslateApiUrl: string | null;
@Column('varchar', {
length: 128,
nullable: true,
})
public libreTranslateApiKey: string | null;
@Column('varchar', { @Column('varchar', {
length: 512, length: 512,
nullable: true, nullable: true,

View File

@ -30,6 +30,17 @@ export default define(meta, paramDef, async (ps, me) => {
set.deeplIsPro = config.deepl.isPro; set.deeplIsPro = config.deepl.isPro;
} }
} }
if (
config.libreTranslate.managed != null &&
config.libreTranslate.managed === true
) {
if (typeof config.libreTranslate.apiUrl === "string") {
set.libreTranslateApiUrl = config.libreTranslate.apiUrl;
}
if (typeof config.libreTranslate.apiKey === "string") {
set.libreTranslateApiKey = config.libreTranslate.apiKey;
}
}
if (config.email.managed != null && config.email.managed === true) { if (config.email.managed != null && config.email.managed === true) {
set.enableEmail = true; set.enableEmail = true;
if (typeof config.email.address === "string") { if (typeof config.email.address === "string") {

View File

@ -512,7 +512,8 @@ export default define(meta, paramDef, async (ps, me) => {
enableGithubIntegration: instance.enableGithubIntegration, enableGithubIntegration: instance.enableGithubIntegration,
enableDiscordIntegration: instance.enableDiscordIntegration, enableDiscordIntegration: instance.enableDiscordIntegration,
enableServiceWorker: instance.enableServiceWorker, enableServiceWorker: instance.enableServiceWorker,
translatorAvailable: instance.deeplAuthKey != null, translatorAvailable:
instance.deeplAuthKey != null || instance.libreTranslateApiUrl != null,
pinnedPages: instance.pinnedPages, pinnedPages: instance.pinnedPages,
pinnedClipId: instance.pinnedClipId, pinnedClipId: instance.pinnedClipId,
cacheRemoteFiles: instance.cacheRemoteFiles, cacheRemoteFiles: instance.cacheRemoteFiles,
@ -564,6 +565,8 @@ export default define(meta, paramDef, async (ps, me) => {
objectStorageS3ForcePathStyle: instance.objectStorageS3ForcePathStyle, objectStorageS3ForcePathStyle: instance.objectStorageS3ForcePathStyle,
deeplAuthKey: instance.deeplAuthKey, deeplAuthKey: instance.deeplAuthKey,
deeplIsPro: instance.deeplIsPro, deeplIsPro: instance.deeplIsPro,
libreTranslateApiUrl: instance.libreTranslateApiUrl,
libreTranslateApiKey: instance.libreTranslateApiKey,
enableIpLogging: instance.enableIpLogging, enableIpLogging: instance.enableIpLogging,
enableActiveEmailValidation: instance.enableActiveEmailValidation, enableActiveEmailValidation: instance.enableActiveEmailValidation,
}; };

View File

@ -124,6 +124,8 @@ export const paramDef = {
summalyProxy: { type: "string", nullable: true }, summalyProxy: { type: "string", nullable: true },
deeplAuthKey: { type: "string", nullable: true }, deeplAuthKey: { type: "string", nullable: true },
deeplIsPro: { type: "boolean" }, deeplIsPro: { type: "boolean" },
libreTranslateApiUrl: { type: "string", nullable: true },
libreTranslateApiKey: { type: "string", nullable: true },
enableTwitterIntegration: { type: "boolean" }, enableTwitterIntegration: { type: "boolean" },
twitterConsumerKey: { type: "string", nullable: true }, twitterConsumerKey: { type: "string", nullable: true },
twitterConsumerSecret: { type: "string", nullable: true }, twitterConsumerSecret: { type: "string", nullable: true },
@ -515,6 +517,22 @@ export default define(meta, paramDef, async (ps, me) => {
set.deeplIsPro = ps.deeplIsPro; set.deeplIsPro = ps.deeplIsPro;
} }
if (ps.libreTranslateApiUrl !== undefined) {
if (ps.libreTranslateApiUrl === "") {
set.libreTranslateApiUrl = null;
} else {
set.libreTranslateApiUrl = ps.libreTranslateApiUrl;
}
}
if (ps.libreTranslateApiKey !== undefined) {
if (ps.libreTranslateApiKey === "") {
set.libreTranslateApiKey = null;
} else {
set.libreTranslateApiKey = ps.libreTranslateApiKey;
}
}
if (ps.enableIpLogging !== undefined) { if (ps.enableIpLogging !== undefined) {
set.enableIpLogging = ps.enableIpLogging; set.enableIpLogging = ps.enableIpLogging;
} }

View File

@ -482,7 +482,8 @@ export default define(meta, paramDef, async (ps, me) => {
enableServiceWorker: instance.enableServiceWorker, enableServiceWorker: instance.enableServiceWorker,
translatorAvailable: instance.deeplAuthKey != null, translatorAvailable:
instance.deeplAuthKey != null || instance.libreTranslateApiUrl != null,
defaultReaction: instance.defaultReaction, defaultReaction: instance.defaultReaction,
...(ps.detail ...(ps.detail

View File

@ -51,15 +51,54 @@ export default define(meta, paramDef, async (ps, user) => {
const instance = await fetchMeta(); const instance = await fetchMeta();
if (instance.deeplAuthKey == null) { if (instance.deeplAuthKey == null && instance.libreTranslateApiUrl == null) {
return 204; // TODO: 良い感じのエラー返す return 204; // TODO: 良い感じのエラー返す
} }
let targetLang = ps.targetLang; let targetLang = ps.targetLang;
if (targetLang.includes("-")) targetLang = targetLang.split("-")[0]; if (targetLang.includes("-")) targetLang = targetLang.split("-")[0];
if (instance.libreTranslateApiUrl != null) {
const jsonBody = {
q: note.text,
source: "auto",
target: targetLang,
format: "text",
api_key: instance.libreTranslateApiKey ?? "",
};
const url = new URL(instance.libreTranslateApiUrl);
if (url.pathname.endsWith("/")) {
url.pathname = url.pathname.slice(0, -1);
}
if (!url.pathname.endsWith("/translate")) {
url.pathname += "/translate";
}
const res = await fetch(url.toString(), {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(jsonBody),
agent: getAgentByUrl,
});
const json = (await res.json()) as {
detectedLanguage?: {
confidence: number;
language: string;
};
translatedText: string;
};
return {
sourceLang: json.detectedLanguage?.language,
text: json.translatedText,
};
}
const params = new URLSearchParams(); const params = new URLSearchParams();
params.append("auth_key", instance.deeplAuthKey); params.append("auth_key", instance.deeplAuthKey ?? "");
params.append("text", note.text); params.append("text", note.text);
params.append("target_lang", targetLang); params.append("target_lang", targetLang);

View File

@ -1,7 +0,0 @@
node_modules
/built
/coverage
/.eslintrc.js
/jest.config.ts
/test
/test-d

View File

@ -1,65 +0,0 @@
module.exports = {
root: true,
parser: "@typescript-eslint/parser",
parserOptions: {
tsconfigRootDir: __dirname,
project: ["./tsconfig.json"],
},
plugins: ["@typescript-eslint"],
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
rules: {
indent: [
"error",
"tab",
{
SwitchCase: 1,
MemberExpression: "off",
flatTernaryExpressions: true,
ArrayExpression: "first",
ObjectExpression: "first",
},
],
"eol-last": ["error", "always"],
semi: ["error", "always"],
quotes: ["error", "single"],
"comma-dangle": ["error", "always-multiline"],
"keyword-spacing": [
"error",
{
before: true,
after: true,
},
],
"key-spacing": [
"error",
{
beforeColon: false,
afterColon: true,
},
],
"space-infix-ops": ["error"],
"space-before-blocks": ["error", "always"],
"object-curly-spacing": ["error", "always"],
"nonblock-statement-body-position": ["error", "beside"],
eqeqeq: ["error", "always", { null: "ignore" }],
"no-multiple-empty-lines": ["error", { max: 1 }],
"no-multi-spaces": ["error"],
"no-var": ["error"],
"prefer-arrow-callback": ["error"],
"no-throw-literal": ["error"],
"no-param-reassign": ["warn"],
"no-constant-condition": ["warn"],
"no-empty-pattern": ["warn"],
"@typescript-eslint/no-unnecessary-condition": ["error"],
"@typescript-eslint/no-inferrable-types": ["warn"],
"@typescript-eslint/no-non-null-assertion": ["warn"],
"@typescript-eslint/explicit-function-return-type": ["warn"],
"@typescript-eslint/no-misused-promises": [
"error",
{
checksVoidReturn: false,
},
],
"@typescript-eslint/consistent-type-imports": "error",
},
};

View File

@ -9,9 +9,8 @@
"tsd": "tsd", "tsd": "tsd",
"api": "pnpm api-extractor run --local --verbose", "api": "pnpm api-extractor run --local --verbose",
"api-prod": "pnpm api-extractor run --verbose", "api-prod": "pnpm api-extractor run --verbose",
"eslint": "eslint . --ext .js,.jsx,.ts,.tsx",
"typecheck": "tsc --noEmit", "typecheck": "tsc --noEmit",
"lint": "pnpm typecheck && pnpm eslint", "lint": "pnpm typecheck && pnpm rome check \"src/*.ts\"",
"jest": "jest --coverage --detectOpenHandles", "jest": "jest --coverage --detectOpenHandles",
"test": "pnpm jest && pnpm tsd" "test": "pnpm jest && pnpm tsd"
}, },

View File

@ -371,6 +371,34 @@
<template #label>Pro account</template> <template #label>Pro account</template>
</FormSwitch> </FormSwitch>
</FormSection> </FormSection>
<FormSection>
<template #label>Libre Translate</template>
<FormInput
v-model="libreTranslateApiUrl"
class="_formBlock"
>
<template #prefix
><i class="ph-link ph-bold ph-lg"></i
></template>
<template #label
>Libre Translate API URL</template
>
</FormInput>
<FormInput
v-model="libreTranslateApiKey"
class="_formBlock"
>
<template #prefix
><i class="ph-key ph-bold ph-lg"></i
></template>
<template #label
>Libre Translate API Key</template
>
</FormInput>
</FormSection>
</div> </div>
</FormSuspense> </FormSuspense>
</MkSpacer> </MkSpacer>
@ -422,6 +450,8 @@ let swPublicKey: any = $ref(null);
let swPrivateKey: any = $ref(null); let swPrivateKey: any = $ref(null);
let deeplAuthKey: string = $ref(""); let deeplAuthKey: string = $ref("");
let deeplIsPro: boolean = $ref(false); let deeplIsPro: boolean = $ref(false);
let libreTranslateApiUrl: string = $ref("");
let libreTranslateApiKey: string = $ref("");
let defaultReaction: string = $ref(""); let defaultReaction: string = $ref("");
let defaultReactionCustom: string = $ref(""); let defaultReactionCustom: string = $ref("");
@ -456,6 +486,8 @@ async function init() {
swPrivateKey = meta.swPrivateKey; swPrivateKey = meta.swPrivateKey;
deeplAuthKey = meta.deeplAuthKey; deeplAuthKey = meta.deeplAuthKey;
deeplIsPro = meta.deeplIsPro; deeplIsPro = meta.deeplIsPro;
libreTranslateApiUrl = meta.libreTranslateApiUrl;
libreTranslateApiKey = meta.libreTranslateApiKey;
defaultReaction = ["⭐", "👍", "❤️"].includes(meta.defaultReaction) defaultReaction = ["⭐", "👍", "❤️"].includes(meta.defaultReaction)
? meta.defaultReaction ? meta.defaultReaction
: "custom"; : "custom";
@ -498,6 +530,8 @@ function save() {
swPrivateKey, swPrivateKey,
deeplAuthKey, deeplAuthKey,
deeplIsPro, deeplIsPro,
libreTranslateApiUrl,
libreTranslateApiKey,
defaultReaction, defaultReaction,
}).then(() => { }).then(() => {
fetchInstance(); fetchInstance();