Prettier 3 + reformat (same as web)
This commit is contained in:
parent
829406fa62
commit
88741083fe
60 changed files with 1353 additions and 1215 deletions
3
desktop/.prettierignore
Normal file
3
desktop/.prettierignore
Normal file
|
@ -0,0 +1,3 @@
|
|||
thirdparty/
|
||||
public/
|
||||
*.md
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"tabWidth": 4,
|
||||
"trailingComma": "es5",
|
||||
"singleQuote": true,
|
||||
"bracketSameLine": true
|
||||
}
|
||||
"plugins": [
|
||||
"prettier-plugin-organize-imports",
|
||||
"prettier-plugin-packagejson"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,20 +1,30 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>ente Photos</title>
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>ente Photos</title>
|
||||
</head>
|
||||
|
||||
<body style="background-color: black;">
|
||||
<div style=" height: 95vh;width: 96vw; display: grid; place-items: center; color: white;">
|
||||
<div>
|
||||
<div style="margin-bottom: 10px;">Site unreachable, please try again later</div>
|
||||
<button onClick="window[`ElectronAPIs`].reloadWindow()">Reload</button>
|
||||
<body style="background-color: black">
|
||||
<div
|
||||
style="
|
||||
height: 95vh;
|
||||
width: 96vw;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: white;
|
||||
"
|
||||
>
|
||||
<div>
|
||||
<div style="margin-bottom: 10px">
|
||||
Site unreachable, please try again later
|
||||
</div>
|
||||
<button onClick="window[`ElectronAPIs`].reloadWindow()">
|
||||
Reload
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,30 +1,50 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>ente Photos</title>
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>ente Photos</title>
|
||||
</head>
|
||||
|
||||
<body style="background-color: black;">
|
||||
<div style="display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 90vh;">
|
||||
<div style="width:64px;"><svg version="1.1" id="L9" xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 100"
|
||||
enable-background="new 0 0 0 0" xml:space="preserve">
|
||||
<path fill="#2dc262"
|
||||
d="M73,50c0-12.7-10.3-23-23-23S27,37.3,27,50 M30.9,50c0-10.5,8.5-19.1,19.1-19.1S69.1,39.5,69.1,50">
|
||||
<animateTransform attributeName="transform" attributeType="XML" type="rotate" dur="1s"
|
||||
from="0 50 50" to="360 50 50" repeatCount="indefinite" />
|
||||
</path>
|
||||
</svg>
|
||||
<body style="background-color: black">
|
||||
<div
|
||||
style="
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 90vh;
|
||||
"
|
||||
>
|
||||
<div style="width: 64px">
|
||||
<svg
|
||||
version="1.1"
|
||||
id="L9"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 100 100"
|
||||
enable-background="new 0 0 0 0"
|
||||
xml:space="preserve"
|
||||
>
|
||||
<path
|
||||
fill="#2dc262"
|
||||
d="M73,50c0-12.7-10.3-23-23-23S27,37.3,27,50 M30.9,50c0-10.5,8.5-19.1,19.1-19.1S69.1,39.5,69.1,50"
|
||||
>
|
||||
<animateTransform
|
||||
attributeName="transform"
|
||||
attributeType="XML"
|
||||
type="rotate"
|
||||
dur="1s"
|
||||
from="0 50 50"
|
||||
to="360 50 50"
|
||||
repeatCount="indefinite"
|
||||
/>
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Electron Updater Example</title>
|
||||
</head>
|
||||
<body>
|
||||
Current version: <span id="version">vX.Y.Z</span>
|
||||
<div id="messages"></div>
|
||||
<script>
|
||||
// Display the current version
|
||||
let version = window.location.hash.substring(1);
|
||||
document.getElementById('version').innerText = version;
|
||||
<head>
|
||||
<title>Electron Updater Example</title>
|
||||
</head>
|
||||
<body>
|
||||
Current version: <span id="version">vX.Y.Z</span>
|
||||
<div id="messages"></div>
|
||||
<script>
|
||||
// Display the current version
|
||||
let version = window.location.hash.substring(1);
|
||||
document.getElementById("version").innerText = version;
|
||||
|
||||
// Listen for messages
|
||||
const {ipcRenderer} = require('electron');
|
||||
ipcRenderer.on('message', function(event, text) {
|
||||
var container = document.getElementById('messages');
|
||||
var message = document.createElement('div');
|
||||
message.innerHTML = text;
|
||||
container.appendChild(message);
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
// Listen for messages
|
||||
const { ipcRenderer } = require("electron");
|
||||
ipcRenderer.on("message", function (event, text) {
|
||||
var container = document.getElementById("messages");
|
||||
var message = document.createElement("div");
|
||||
message.innerHTML = text;
|
||||
container.appendChild(message);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,10 +1,67 @@
|
|||
{
|
||||
"name": "ente",
|
||||
"productName": "ente",
|
||||
"version": "1.6.63",
|
||||
"private": true,
|
||||
"description": "Desktop client for ente.io",
|
||||
"author": "ente <code@ente.io>",
|
||||
"main": "app/main.js",
|
||||
"scripts": {
|
||||
"build": "yarn build-renderer && yarn build-main",
|
||||
"build-main": "yarn install && tsc",
|
||||
"build-renderer": "cd ui && yarn install && yarn export:photos",
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"lint": "yarn prettier --check . && eslint \"src/**/*.{js,jsx,ts,tsx}\"",
|
||||
"lint-fix": "yarn prettier --write . && eslint --fix .",
|
||||
"start": "concurrently \"yarn start-main\" \"yarn start-renderer\"",
|
||||
"start-main": "yarn build-main && electron app/main.js",
|
||||
"start-renderer": "cd ui && yarn install && yarn dev:photos",
|
||||
"test-release": "cross-env IS_TEST_RELEASE=true yarn build && electron-builder --config.compression=store",
|
||||
"watch": "tsc -w"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sentry/electron": "^2.5.1",
|
||||
"any-shell-escape": "^0.1.1",
|
||||
"auto-launch": "^5.0.5",
|
||||
"chokidar": "^3.5.3",
|
||||
"compare-versions": "^6.1.0",
|
||||
"electron-log": "^4.3.5",
|
||||
"electron-reload": "^2.0.0-alpha.1",
|
||||
"electron-store": "^8.0.1",
|
||||
"electron-updater": "^4.3.8",
|
||||
"ffmpeg-static": "^5.1.0",
|
||||
"get-folder-size": "^2.0.1",
|
||||
"html-entities": "^2.4.0",
|
||||
"jpeg-js": "^0.4.4",
|
||||
"next-electron-server": "file:./thirdparty/next-electron-server",
|
||||
"node-fetch": "^2.6.7",
|
||||
"node-stream-zip": "^1.15.0",
|
||||
"onnxruntime-node": "^1.16.3",
|
||||
"promise-fs": "^2.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sentry/cli": "^1.68.0",
|
||||
"@types/auto-launch": "^5.0.2",
|
||||
"@types/ffmpeg-static": "^3.0.1",
|
||||
"@types/get-folder-size": "^2.0.0",
|
||||
"@types/node": "18.15.0",
|
||||
"@types/node-fetch": "^2.6.2",
|
||||
"@types/promise-fs": "^2.1.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.28.0",
|
||||
"@typescript-eslint/parser": "^5.28.0",
|
||||
"concurrently": "^7.0.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"electron": "^25.8.4",
|
||||
"electron-builder": "^24.6.4",
|
||||
"electron-builder-notarize": "^1.2.0",
|
||||
"electron-download": "^4.1.1",
|
||||
"eslint": "^7.23.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"prettier": "2.5.1",
|
||||
"prettier-plugin-organize-imports": "^3.2",
|
||||
"prettier-plugin-packagejson": "^2.4",
|
||||
"typescript": "^4.2.3"
|
||||
},
|
||||
"build": {
|
||||
"appId": "io.ente.bhari-frame",
|
||||
"artifactName": "${productName}-${version}-${arch}.${ext}",
|
||||
|
@ -83,63 +140,7 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"prebuild": "eslint \"src/**/*.{js,jsx,ts,tsx}\"",
|
||||
"prepare": "husky install",
|
||||
"lint": "eslint -c .eslintrc --ext .ts src",
|
||||
"watch": "tsc -w",
|
||||
"build-main": "yarn install && tsc",
|
||||
"start-main": "yarn build-main && electron app/main.js",
|
||||
"start-renderer": "cd ui && yarn install && yarn dev:photos",
|
||||
"start": "concurrently \"yarn start-main\" \"yarn start-renderer\"",
|
||||
"build-renderer": "cd ui && yarn install && yarn export:photos",
|
||||
"build": "yarn build-renderer && yarn build-main",
|
||||
"test-release": "cross-env IS_TEST_RELEASE=true yarn build && electron-builder --config.compression=store"
|
||||
},
|
||||
"author": "ente <code@ente.io>",
|
||||
"devDependencies": {
|
||||
"@sentry/cli": "^1.68.0",
|
||||
"@types/auto-launch": "^5.0.2",
|
||||
"@types/ffmpeg-static": "^3.0.1",
|
||||
"@types/get-folder-size": "^2.0.0",
|
||||
"@types/node": "18.15.0",
|
||||
"@types/node-fetch": "^2.6.2",
|
||||
"@types/promise-fs": "^2.1.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.28.0",
|
||||
"@typescript-eslint/parser": "^5.28.0",
|
||||
"concurrently": "^7.0.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"electron": "^25.8.4",
|
||||
"electron-builder": "^24.6.4",
|
||||
"electron-builder-notarize": "^1.2.0",
|
||||
"electron-download": "^4.1.1",
|
||||
"eslint": "^7.23.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"prettier": "2.5.1",
|
||||
"typescript": "^4.2.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sentry/electron": "^2.5.1",
|
||||
"any-shell-escape": "^0.1.1",
|
||||
"auto-launch": "^5.0.5",
|
||||
"chokidar": "^3.5.3",
|
||||
"compare-versions": "^6.1.0",
|
||||
"electron-log": "^4.3.5",
|
||||
"electron-reload": "^2.0.0-alpha.1",
|
||||
"electron-store": "^8.0.1",
|
||||
"electron-updater": "^4.3.8",
|
||||
"ffmpeg-static": "^5.1.0",
|
||||
"get-folder-size": "^2.0.1",
|
||||
"html-entities": "^2.4.0",
|
||||
"jpeg-js": "^0.4.4",
|
||||
"next-electron-server": "file:./thirdparty/next-electron-server",
|
||||
"node-fetch": "^2.6.7",
|
||||
"node-stream-zip": "^1.15.0",
|
||||
"onnxruntime-node": "^1.16.3",
|
||||
"promise-fs": "^2.1.1"
|
||||
},
|
||||
"productName": "ente",
|
||||
"standard": {
|
||||
"parser": "babel-eslint"
|
||||
}
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import { ipcRenderer } from 'electron/renderer';
|
||||
import path from 'path';
|
||||
import { existsSync, mkdir, rmSync } from 'promise-fs';
|
||||
import { DiskCache } from '../services/diskCache';
|
||||
import { ipcRenderer } from "electron/renderer";
|
||||
import path from "path";
|
||||
import { existsSync, mkdir, rmSync } from "promise-fs";
|
||||
import { DiskCache } from "../services/diskCache";
|
||||
|
||||
const ENTE_CACHE_DIR_NAME = 'ente';
|
||||
const ENTE_CACHE_DIR_NAME = "ente";
|
||||
|
||||
export const getCacheDirectory = async () => {
|
||||
const customCacheDir = await getCustomCacheDirectory();
|
||||
if (customCacheDir && existsSync(customCacheDir)) {
|
||||
return customCacheDir;
|
||||
}
|
||||
const defaultSystemCacheDir = await ipcRenderer.invoke('get-path', 'cache');
|
||||
const defaultSystemCacheDir = await ipcRenderer.invoke("get-path", "cache");
|
||||
return path.join(defaultSystemCacheDir, ENTE_CACHE_DIR_NAME);
|
||||
};
|
||||
|
||||
|
@ -44,9 +44,9 @@ export async function deleteDiskCache(cacheName: string) {
|
|||
export async function setCustomCacheDirectory(
|
||||
directory: string
|
||||
): Promise<void> {
|
||||
await ipcRenderer.invoke('set-custom-cache-directory', directory);
|
||||
await ipcRenderer.invoke("set-custom-cache-directory", directory);
|
||||
}
|
||||
|
||||
async function getCustomCacheDirectory(): Promise<string> {
|
||||
return await ipcRenderer.invoke('get-custom-cache-directory');
|
||||
return await ipcRenderer.invoke("get-custom-cache-directory");
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import { ipcRenderer } from 'electron';
|
||||
import { writeStream } from '../services/fs';
|
||||
import { isExecError } from '../utils/error';
|
||||
import { parseExecError } from '../utils/error';
|
||||
import { Model } from '../types';
|
||||
import { ipcRenderer } from "electron";
|
||||
import { writeStream } from "../services/fs";
|
||||
import { Model } from "../types";
|
||||
import { isExecError, parseExecError } from "../utils/error";
|
||||
|
||||
export async function computeImageEmbedding(
|
||||
model: Model,
|
||||
|
@ -10,11 +9,11 @@ export async function computeImageEmbedding(
|
|||
): Promise<Float32Array> {
|
||||
let tempInputFilePath = null;
|
||||
try {
|
||||
tempInputFilePath = await ipcRenderer.invoke('get-temp-file-path', '');
|
||||
tempInputFilePath = await ipcRenderer.invoke("get-temp-file-path", "");
|
||||
const imageStream = new Response(imageData.buffer).body;
|
||||
await writeStream(tempInputFilePath, imageStream);
|
||||
const embedding = await ipcRenderer.invoke(
|
||||
'compute-image-embedding',
|
||||
"compute-image-embedding",
|
||||
model,
|
||||
tempInputFilePath
|
||||
);
|
||||
|
@ -28,7 +27,7 @@ export async function computeImageEmbedding(
|
|||
}
|
||||
} finally {
|
||||
if (tempInputFilePath) {
|
||||
await ipcRenderer.invoke('remove-temp-file', tempInputFilePath);
|
||||
await ipcRenderer.invoke("remove-temp-file", tempInputFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +38,7 @@ export async function computeTextEmbedding(
|
|||
): Promise<Float32Array> {
|
||||
try {
|
||||
const embedding = await ipcRenderer.invoke(
|
||||
'compute-text-embedding',
|
||||
"compute-text-embedding",
|
||||
model,
|
||||
text
|
||||
);
|
||||
|
|
|
@ -1,44 +1,44 @@
|
|||
import { ipcRenderer } from 'electron/renderer';
|
||||
import { logError } from '../services/logging';
|
||||
import { ipcRenderer } from "electron/renderer";
|
||||
import { logError } from "../services/logging";
|
||||
|
||||
export const selectDirectory = async (): Promise<string> => {
|
||||
try {
|
||||
return await ipcRenderer.invoke('select-dir');
|
||||
return await ipcRenderer.invoke("select-dir");
|
||||
} catch (e) {
|
||||
logError(e, 'error while selecting root directory');
|
||||
logError(e, "error while selecting root directory");
|
||||
}
|
||||
};
|
||||
|
||||
export const getAppVersion = async (): Promise<string> => {
|
||||
try {
|
||||
return await ipcRenderer.invoke('get-app-version');
|
||||
return await ipcRenderer.invoke("get-app-version");
|
||||
} catch (e) {
|
||||
logError(e, 'failed to get release version');
|
||||
logError(e, "failed to get release version");
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
export const openDirectory = async (dirPath: string): Promise<void> => {
|
||||
try {
|
||||
await ipcRenderer.invoke('open-dir', dirPath);
|
||||
await ipcRenderer.invoke("open-dir", dirPath);
|
||||
} catch (e) {
|
||||
logError(e, 'error while opening directory');
|
||||
logError(e, "error while opening directory");
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
export const getPlatform = async (): Promise<'mac' | 'windows' | 'linux'> => {
|
||||
export const getPlatform = async (): Promise<"mac" | "windows" | "linux"> => {
|
||||
try {
|
||||
return await ipcRenderer.invoke('get-platform');
|
||||
return await ipcRenderer.invoke("get-platform");
|
||||
} catch (e) {
|
||||
logError(e, 'failed to get platform');
|
||||
logError(e, "failed to get platform");
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
getSentryUserID,
|
||||
logToDisk,
|
||||
openLogDirectory,
|
||||
getSentryUserID,
|
||||
updateOptOutOfCrashReports,
|
||||
} from '../services/logging';
|
||||
} from "../services/logging";
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { keysStore } from '../stores/keys.store';
|
||||
import { safeStorageStore } from '../stores/safeStorage.store';
|
||||
import { uploadStatusStore } from '../stores/upload.store';
|
||||
import { logError } from '../services/logging';
|
||||
import { userPreferencesStore } from '../stores/userPreferences.store';
|
||||
import { watchStore } from '../stores/watch.store';
|
||||
import { logError } from "../services/logging";
|
||||
import { keysStore } from "../stores/keys.store";
|
||||
import { safeStorageStore } from "../stores/safeStorage.store";
|
||||
import { uploadStatusStore } from "../stores/upload.store";
|
||||
import { userPreferencesStore } from "../stores/userPreferences.store";
|
||||
import { watchStore } from "../stores/watch.store";
|
||||
|
||||
export const clearElectronStore = () => {
|
||||
try {
|
||||
|
@ -11,9 +11,9 @@ export const clearElectronStore = () => {
|
|||
keysStore.clear();
|
||||
safeStorageStore.clear();
|
||||
watchStore.clear();
|
||||
userPreferencesStore.delete('optOutOfCrashReports');
|
||||
userPreferencesStore.delete("optOutOfCrashReports");
|
||||
} catch (e) {
|
||||
logError(e, 'error while clearing electron store');
|
||||
logError(e, "error while clearing electron store");
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { writeStream } from './../services/fs';
|
||||
import * as fs from 'promise-fs';
|
||||
import * as fs from "promise-fs";
|
||||
import { writeStream } from "./../services/fs";
|
||||
|
||||
export const exists = (path: string) => {
|
||||
return fs.existsSync(path);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { ipcRenderer } from 'electron';
|
||||
import { existsSync } from 'fs';
|
||||
import { writeStream } from '../services/fs';
|
||||
import { logError } from '../services/logging';
|
||||
import { ElectronFile } from '../types';
|
||||
import { ipcRenderer } from "electron";
|
||||
import { existsSync } from "fs";
|
||||
import { writeStream } from "../services/fs";
|
||||
import { logError } from "../services/logging";
|
||||
import { ElectronFile } from "../types";
|
||||
|
||||
export async function runFFmpegCmd(
|
||||
cmd: string[],
|
||||
|
@ -15,7 +15,7 @@ export async function runFFmpegCmd(
|
|||
try {
|
||||
if (!existsSync(inputFile.path)) {
|
||||
const tempFilePath = await ipcRenderer.invoke(
|
||||
'get-temp-file-path',
|
||||
"get-temp-file-path",
|
||||
inputFile.name
|
||||
);
|
||||
await writeStream(tempFilePath, await inputFile.stream());
|
||||
|
@ -25,7 +25,7 @@ export async function runFFmpegCmd(
|
|||
inputFilePath = inputFile.path;
|
||||
}
|
||||
const outputFileData = await ipcRenderer.invoke(
|
||||
'run-ffmpeg-cmd',
|
||||
"run-ffmpeg-cmd",
|
||||
cmd,
|
||||
inputFilePath,
|
||||
outputFileName,
|
||||
|
@ -35,9 +35,9 @@ export async function runFFmpegCmd(
|
|||
} finally {
|
||||
if (createdTempInputFile) {
|
||||
try {
|
||||
await ipcRenderer.invoke('remove-temp-file', inputFilePath);
|
||||
await ipcRenderer.invoke("remove-temp-file", inputFilePath);
|
||||
} catch (e) {
|
||||
logError(e, 'failed to deleteTempFile');
|
||||
logError(e, "failed to deleteTempFile");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { getElectronFile, getDirFilePaths } from '../services/fs';
|
||||
import { getDirFilePaths, getElectronFile } from "../services/fs";
|
||||
|
||||
export async function getDirFiles(dirPath: string) {
|
||||
const files = await getDirFilePaths(dirPath);
|
||||
|
@ -6,10 +6,10 @@ export async function getDirFiles(dirPath: string) {
|
|||
return electronFiles;
|
||||
}
|
||||
export {
|
||||
deleteFile,
|
||||
deleteFolder,
|
||||
isFolder,
|
||||
moveFile,
|
||||
deleteFolder,
|
||||
deleteFile,
|
||||
rename,
|
||||
readTextFile,
|
||||
} from '../services/fs';
|
||||
rename,
|
||||
} from "../services/fs";
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
import { CustomErrors } from '../constants/errors';
|
||||
import { ipcRenderer } from 'electron/renderer';
|
||||
import { existsSync } from 'fs';
|
||||
import { writeStream } from '../services/fs';
|
||||
import { logError } from '../services/logging';
|
||||
import { ElectronFile } from '../types';
|
||||
import { isPlatform } from '../utils/common/platform';
|
||||
import { ipcRenderer } from "electron/renderer";
|
||||
import { existsSync } from "fs";
|
||||
import { CustomErrors } from "../constants/errors";
|
||||
import { writeStream } from "../services/fs";
|
||||
import { logError } from "../services/logging";
|
||||
import { ElectronFile } from "../types";
|
||||
import { isPlatform } from "../utils/common/platform";
|
||||
|
||||
export async function convertToJPEG(
|
||||
fileData: Uint8Array,
|
||||
filename: string
|
||||
): Promise<Uint8Array> {
|
||||
if (isPlatform('windows')) {
|
||||
if (isPlatform("windows")) {
|
||||
throw Error(CustomErrors.WINDOWS_NATIVE_IMAGE_PROCESSING_NOT_SUPPORTED);
|
||||
}
|
||||
const convertedFileData = await ipcRenderer.invoke(
|
||||
'convert-to-jpeg',
|
||||
"convert-to-jpeg",
|
||||
fileData,
|
||||
filename
|
||||
);
|
||||
|
@ -29,14 +29,14 @@ export async function generateImageThumbnail(
|
|||
let inputFilePath = null;
|
||||
let createdTempInputFile = null;
|
||||
try {
|
||||
if (isPlatform('windows')) {
|
||||
if (isPlatform("windows")) {
|
||||
throw Error(
|
||||
CustomErrors.WINDOWS_NATIVE_IMAGE_PROCESSING_NOT_SUPPORTED
|
||||
);
|
||||
}
|
||||
if (!existsSync(inputFile.path)) {
|
||||
const tempFilePath = await ipcRenderer.invoke(
|
||||
'get-temp-file-path',
|
||||
"get-temp-file-path",
|
||||
inputFile.name
|
||||
);
|
||||
await writeStream(tempFilePath, await inputFile.stream());
|
||||
|
@ -46,7 +46,7 @@ export async function generateImageThumbnail(
|
|||
inputFilePath = inputFile.path;
|
||||
}
|
||||
const thumbnail = await ipcRenderer.invoke(
|
||||
'generate-image-thumbnail',
|
||||
"generate-image-thumbnail",
|
||||
inputFilePath,
|
||||
maxDimension,
|
||||
maxSize
|
||||
|
@ -55,9 +55,9 @@ export async function generateImageThumbnail(
|
|||
} finally {
|
||||
if (createdTempInputFile) {
|
||||
try {
|
||||
await ipcRenderer.invoke('remove-temp-file', inputFilePath);
|
||||
await ipcRenderer.invoke("remove-temp-file", inputFilePath);
|
||||
} catch (e) {
|
||||
logError(e, 'failed to deleteTempFile');
|
||||
logError(e, "failed to deleteTempFile");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
import { ipcRenderer } from 'electron';
|
||||
import { safeStorageStore } from '../stores/safeStorage.store';
|
||||
import { logError } from '../services/logging';
|
||||
import { ipcRenderer } from "electron";
|
||||
import { logError } from "../services/logging";
|
||||
import { safeStorageStore } from "../stores/safeStorage.store";
|
||||
|
||||
export async function setEncryptionKey(encryptionKey: string) {
|
||||
try {
|
||||
const encryptedKey: Buffer = await ipcRenderer.invoke(
|
||||
'safeStorage-encrypt',
|
||||
"safeStorage-encrypt",
|
||||
encryptionKey
|
||||
);
|
||||
const b64EncryptedKey = Buffer.from(encryptedKey).toString('base64');
|
||||
safeStorageStore.set('encryptionKey', b64EncryptedKey);
|
||||
const b64EncryptedKey = Buffer.from(encryptedKey).toString("base64");
|
||||
safeStorageStore.set("encryptionKey", b64EncryptedKey);
|
||||
} catch (e) {
|
||||
logError(e, 'setEncryptionKey failed');
|
||||
logError(e, "setEncryptionKey failed");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getEncryptionKey(): Promise<string> {
|
||||
try {
|
||||
const b64EncryptedKey = safeStorageStore.get('encryptionKey');
|
||||
const b64EncryptedKey = safeStorageStore.get("encryptionKey");
|
||||
if (b64EncryptedKey) {
|
||||
const keyBuffer = new Uint8Array(
|
||||
Buffer.from(b64EncryptedKey, 'base64')
|
||||
Buffer.from(b64EncryptedKey, "base64")
|
||||
);
|
||||
return await ipcRenderer.invoke('safeStorage-decrypt', keyBuffer);
|
||||
return await ipcRenderer.invoke("safeStorage-decrypt", keyBuffer);
|
||||
}
|
||||
} catch (e) {
|
||||
logError(e, 'getEncryptionKey failed');
|
||||
logError(e, "getEncryptionKey failed");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,37 +1,37 @@
|
|||
import { ipcRenderer } from 'electron';
|
||||
import { AppUpdateInfo } from '../types';
|
||||
import { ipcRenderer } from "electron";
|
||||
import { AppUpdateInfo } from "../types";
|
||||
|
||||
export const sendNotification = (content: string) => {
|
||||
ipcRenderer.send('send-notification', content);
|
||||
ipcRenderer.send("send-notification", content);
|
||||
};
|
||||
export const reloadWindow = () => {
|
||||
ipcRenderer.send('reload-window');
|
||||
ipcRenderer.send("reload-window");
|
||||
};
|
||||
|
||||
export const registerUpdateEventListener = (
|
||||
showUpdateDialog: (updateInfo: AppUpdateInfo) => void
|
||||
) => {
|
||||
ipcRenderer.removeAllListeners('show-update-dialog');
|
||||
ipcRenderer.on('show-update-dialog', (_, updateInfo: AppUpdateInfo) => {
|
||||
ipcRenderer.removeAllListeners("show-update-dialog");
|
||||
ipcRenderer.on("show-update-dialog", (_, updateInfo: AppUpdateInfo) => {
|
||||
showUpdateDialog(updateInfo);
|
||||
});
|
||||
};
|
||||
|
||||
export const registerForegroundEventListener = (onForeground: () => void) => {
|
||||
ipcRenderer.removeAllListeners('app-in-foreground');
|
||||
ipcRenderer.on('app-in-foreground', () => {
|
||||
ipcRenderer.removeAllListeners("app-in-foreground");
|
||||
ipcRenderer.on("app-in-foreground", () => {
|
||||
onForeground();
|
||||
});
|
||||
};
|
||||
|
||||
export const updateAndRestart = () => {
|
||||
ipcRenderer.send('update-and-restart');
|
||||
ipcRenderer.send("update-and-restart");
|
||||
};
|
||||
|
||||
export const skipAppUpdate = (version: string) => {
|
||||
ipcRenderer.send('skip-app-update', version);
|
||||
ipcRenderer.send("skip-app-update", version);
|
||||
};
|
||||
|
||||
export const muteUpdateNotification = (version: string) => {
|
||||
ipcRenderer.send('mute-update-notification', version);
|
||||
ipcRenderer.send("mute-update-notification", version);
|
||||
};
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import { getElectronFile } from './../services/fs';
|
||||
import { uploadStatusStore } from '../stores/upload.store';
|
||||
import { ElectronFile, FILE_PATH_TYPE } from '../types';
|
||||
import { logError } from '../services/logging';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { ipcRenderer } from "electron";
|
||||
import { logError } from "../services/logging";
|
||||
import {
|
||||
getElectronFilesFromGoogleZip,
|
||||
getSavedFilePaths,
|
||||
} from '../services/upload';
|
||||
} from "../services/upload";
|
||||
import { uploadStatusStore } from "../stores/upload.store";
|
||||
import { ElectronFile, FILE_PATH_TYPE } from "../types";
|
||||
import { getElectronFile } from "./../services/fs";
|
||||
|
||||
export const getPendingUploads = async () => {
|
||||
const filePaths = getSavedFilePaths(FILE_PATH_TYPE.FILES);
|
||||
const zipPaths = getSavedFilePaths(FILE_PATH_TYPE.ZIPS);
|
||||
const collectionName = uploadStatusStore.get('collectionName');
|
||||
const collectionName = uploadStatusStore.get("collectionName");
|
||||
|
||||
let files: ElectronFile[] = [];
|
||||
let type: FILE_PATH_TYPE;
|
||||
|
@ -39,31 +39,31 @@ export const getPendingUploads = async () => {
|
|||
export const showUploadDirsDialog = async () => {
|
||||
try {
|
||||
const filePaths: string[] = await ipcRenderer.invoke(
|
||||
'show-upload-dirs-dialog'
|
||||
"show-upload-dirs-dialog"
|
||||
);
|
||||
const files = await Promise.all(filePaths.map(getElectronFile));
|
||||
return files;
|
||||
} catch (e) {
|
||||
logError(e, 'error while selecting folders');
|
||||
logError(e, "error while selecting folders");
|
||||
}
|
||||
};
|
||||
|
||||
export const showUploadFilesDialog = async () => {
|
||||
try {
|
||||
const filePaths: string[] = await ipcRenderer.invoke(
|
||||
'show-upload-files-dialog'
|
||||
"show-upload-files-dialog"
|
||||
);
|
||||
const files = await Promise.all(filePaths.map(getElectronFile));
|
||||
return files;
|
||||
} catch (e) {
|
||||
logError(e, 'error while selecting files');
|
||||
logError(e, "error while selecting files");
|
||||
}
|
||||
};
|
||||
|
||||
export const showUploadZipDialog = async () => {
|
||||
try {
|
||||
const filePaths: string[] = await ipcRenderer.invoke(
|
||||
'show-upload-zip-dialog'
|
||||
"show-upload-zip-dialog"
|
||||
);
|
||||
let files: ElectronFile[] = [];
|
||||
|
||||
|
@ -79,12 +79,12 @@ export const showUploadZipDialog = async () => {
|
|||
files,
|
||||
};
|
||||
} catch (e) {
|
||||
logError(e, 'error while selecting zips');
|
||||
logError(e, "error while selecting zips");
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
setToUploadFiles,
|
||||
getElectronFilesFromGoogleZip,
|
||||
setToUploadCollection,
|
||||
} from '../services/upload';
|
||||
setToUploadFiles,
|
||||
} from "../services/upload";
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { isMappingPresent } from '../utils/watch';
|
||||
import path from 'path';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { ElectronFile, WatchMapping } from '../types';
|
||||
import { getElectronFile } from '../services/fs';
|
||||
import { getWatchMappings, setWatchMappings } from '../services/watch';
|
||||
import ElectronLog from 'electron-log';
|
||||
import { ipcRenderer } from "electron";
|
||||
import ElectronLog from "electron-log";
|
||||
import path from "path";
|
||||
import { getElectronFile } from "../services/fs";
|
||||
import { getWatchMappings, setWatchMappings } from "../services/watch";
|
||||
import { ElectronFile, WatchMapping } from "../types";
|
||||
import { isMappingPresent } from "../utils/watch";
|
||||
|
||||
export async function addWatchMapping(
|
||||
rootFolderName: string,
|
||||
|
@ -17,7 +17,7 @@ export async function addWatchMapping(
|
|||
throw new Error(`Watch mapping already exists`);
|
||||
}
|
||||
|
||||
await ipcRenderer.invoke('add-watcher', {
|
||||
await ipcRenderer.invoke("add-watcher", {
|
||||
dir: folderPath,
|
||||
});
|
||||
|
||||
|
@ -42,7 +42,7 @@ export async function removeWatchMapping(folderPath: string) {
|
|||
throw new Error(`Watch mapping does not exist`);
|
||||
}
|
||||
|
||||
await ipcRenderer.invoke('remove-watcher', {
|
||||
await ipcRenderer.invoke("remove-watcher", {
|
||||
dir: watchMapping.folderPath,
|
||||
});
|
||||
|
||||
|
@ -55,7 +55,7 @@ export async function removeWatchMapping(folderPath: string) {
|
|||
|
||||
export function updateWatchMappingSyncedFiles(
|
||||
folderPath: string,
|
||||
files: WatchMapping['syncedFiles']
|
||||
files: WatchMapping["syncedFiles"]
|
||||
): void {
|
||||
const watchMappings = getWatchMappings();
|
||||
const watchMapping = watchMappings.find(
|
||||
|
@ -72,7 +72,7 @@ export function updateWatchMappingSyncedFiles(
|
|||
|
||||
export function updateWatchMappingIgnoredFiles(
|
||||
folderPath: string,
|
||||
files: WatchMapping['ignoredFiles']
|
||||
files: WatchMapping["ignoredFiles"]
|
||||
): void {
|
||||
const watchMappings = getWatchMappings();
|
||||
const watchMapping = watchMappings.find(
|
||||
|
@ -92,23 +92,23 @@ export function registerWatcherFunctions(
|
|||
removeFile: (path: string) => Promise<void>,
|
||||
removeFolder: (folderPath: string) => Promise<void>
|
||||
) {
|
||||
ipcRenderer.removeAllListeners('watch-add');
|
||||
ipcRenderer.removeAllListeners('watch-change');
|
||||
ipcRenderer.removeAllListeners('watch-unlink-dir');
|
||||
ipcRenderer.on('watch-add', async (_, filePath: string) => {
|
||||
ipcRenderer.removeAllListeners("watch-add");
|
||||
ipcRenderer.removeAllListeners("watch-change");
|
||||
ipcRenderer.removeAllListeners("watch-unlink-dir");
|
||||
ipcRenderer.on("watch-add", async (_, filePath: string) => {
|
||||
filePath = filePath.split(path.sep).join(path.posix.sep);
|
||||
|
||||
await addFile(await getElectronFile(filePath));
|
||||
});
|
||||
ipcRenderer.on('watch-unlink', async (_, filePath: string) => {
|
||||
ipcRenderer.on("watch-unlink", async (_, filePath: string) => {
|
||||
filePath = filePath.split(path.sep).join(path.posix.sep);
|
||||
|
||||
await removeFile(filePath);
|
||||
});
|
||||
ipcRenderer.on('watch-unlink-dir', async (_, folderPath: string) => {
|
||||
ipcRenderer.on("watch-unlink-dir", async (_, folderPath: string) => {
|
||||
folderPath = folderPath.split(path.sep).join(path.posix.sep);
|
||||
await removeFolder(folderPath);
|
||||
});
|
||||
}
|
||||
|
||||
export { getWatchMappings } from '../services/watch';
|
||||
export { getWatchMappings } from "../services/watch";
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
const PROD_HOST_URL: string = 'ente://app';
|
||||
const RENDERER_OUTPUT_DIR: string = './ui/out';
|
||||
const LOG_FILENAME = 'ente.log';
|
||||
const PROD_HOST_URL: string = "ente://app";
|
||||
const RENDERER_OUTPUT_DIR: string = "./ui/out";
|
||||
const LOG_FILENAME = "ente.log";
|
||||
const MAX_LOG_SIZE = 50 * 1024 * 1024; // 50MB
|
||||
|
||||
const FILE_STREAM_CHUNK_SIZE: number = 4 * 1024 * 1024;
|
||||
|
||||
const SENTRY_DSN = 'https://759d8498487a81ac33a0c2efa2a42c4f@sentry.ente.io/9';
|
||||
const SENTRY_DSN = "https://759d8498487a81ac33a0c2efa2a42c4f@sentry.ente.io/9";
|
||||
|
||||
const RELEASE_VERSION = require('../../package.json').version;
|
||||
const RELEASE_VERSION = require("../../package.json").version;
|
||||
|
||||
export {
|
||||
PROD_HOST_URL,
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
export const CustomErrors = {
|
||||
WINDOWS_NATIVE_IMAGE_PROCESSING_NOT_SUPPORTED:
|
||||
'Windows native image processing is not supported',
|
||||
"Windows native image processing is not supported",
|
||||
INVALID_OS: (os: string) => `Invalid OS - ${os}`,
|
||||
WAIT_TIME_EXCEEDED: 'Wait time exceeded',
|
||||
WAIT_TIME_EXCEEDED: "Wait time exceeded",
|
||||
UNSUPPORTED_PLATFORM: (platform: string, arch: string) =>
|
||||
`Unsupported platform - ${platform} ${arch}`,
|
||||
MODEL_DOWNLOAD_PENDING:
|
||||
'Model download pending, skipping clip search request',
|
||||
INVALID_FILE_PATH: 'Invalid file path',
|
||||
"Model download pending, skipping clip search request",
|
||||
INVALID_FILE_PATH: "Invalid file path",
|
||||
INVALID_CLIP_MODEL: (model: string) => `Invalid Clip model - ${model}`,
|
||||
};
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
import { app, BrowserWindow } from 'electron';
|
||||
import { createWindow } from './utils/createWindow';
|
||||
import setupIpcComs from './utils/ipcComms';
|
||||
import { initWatcher } from './services/chokidar';
|
||||
import { addAllowOriginHeader } from './utils/cors';
|
||||
import { app, BrowserWindow } from "electron";
|
||||
import { initWatcher } from "./services/chokidar";
|
||||
import { initSentry } from "./services/sentry";
|
||||
import { getOptOutOfCrashReports } from "./services/userPreference";
|
||||
import { isDev } from "./utils/common";
|
||||
import { addAllowOriginHeader } from "./utils/cors";
|
||||
import { createWindow } from "./utils/createWindow";
|
||||
import { setupAppEventEmitter } from "./utils/events";
|
||||
import setupIpcComs from "./utils/ipcComms";
|
||||
import { setupLogging } from "./utils/logging";
|
||||
import {
|
||||
setupTrayItem,
|
||||
handleDownloads,
|
||||
setupMacWindowOnDockIconClick,
|
||||
setupMainMenu,
|
||||
setupMainHotReload,
|
||||
setupNextElectronServe,
|
||||
enableSharedArrayBufferSupport,
|
||||
handleDockIconHideOnAutoLaunch,
|
||||
handleDownloads,
|
||||
handleExternalLinks,
|
||||
handleUpdates,
|
||||
logSystemInfo,
|
||||
handleExternalLinks,
|
||||
} from './utils/main';
|
||||
import { initSentry } from './services/sentry';
|
||||
import { setupLogging } from './utils/logging';
|
||||
import { isDev } from './utils/common';
|
||||
import { setupMainProcessStatsLogger } from './utils/processStats';
|
||||
import { setupAppEventEmitter } from './utils/events';
|
||||
import { getOptOutOfCrashReports } from './services/userPreference';
|
||||
setupMacWindowOnDockIconClick,
|
||||
setupMainHotReload,
|
||||
setupMainMenu,
|
||||
setupNextElectronServe,
|
||||
setupTrayItem,
|
||||
} from "./utils/main";
|
||||
import { setupMainProcessStatsLogger } from "./utils/processStats";
|
||||
|
||||
let mainWindow: BrowserWindow;
|
||||
|
||||
|
@ -66,7 +66,7 @@ if (!gotTheLock) {
|
|||
} else {
|
||||
handleDockIconHideOnAutoLaunch();
|
||||
enableSharedArrayBufferSupport();
|
||||
app.on('second-instance', () => {
|
||||
app.on("second-instance", () => {
|
||||
// Someone tried to run a second instance, we should focus our window.
|
||||
if (mainWindow) {
|
||||
mainWindow.show();
|
||||
|
@ -80,7 +80,7 @@ if (!gotTheLock) {
|
|||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.on('ready', async () => {
|
||||
app.on("ready", async () => {
|
||||
logSystemInfo();
|
||||
setupMainProcessStatsLogger();
|
||||
const hasOptedOutOfCrashReports = getOptOutOfCrashReports();
|
||||
|
@ -101,5 +101,5 @@ if (!gotTheLock) {
|
|||
setupAppEventEmitter(mainWindow);
|
||||
});
|
||||
|
||||
app.on('before-quit', () => setIsAppQuitting(true));
|
||||
app.on("before-quit", () => setIsAppQuitting(true));
|
||||
}
|
||||
|
|
|
@ -1,71 +1,71 @@
|
|||
import {
|
||||
deleteDiskCache,
|
||||
getCacheDirectory,
|
||||
openDiskCache,
|
||||
setCustomCacheDirectory,
|
||||
} from "./api/cache";
|
||||
import { computeImageEmbedding, computeTextEmbedding } from "./api/clip";
|
||||
import {
|
||||
getAppVersion,
|
||||
getPlatform,
|
||||
getSentryUserID,
|
||||
logToDisk,
|
||||
openDirectory,
|
||||
openLogDirectory,
|
||||
selectDirectory,
|
||||
updateOptOutOfCrashReports,
|
||||
} from "./api/common";
|
||||
import { clearElectronStore } from "./api/electronStore";
|
||||
import {
|
||||
checkExistsAndCreateDir,
|
||||
exists,
|
||||
saveFileToDisk,
|
||||
saveStreamToDisk,
|
||||
} from "./api/export";
|
||||
import { runFFmpegCmd } from "./api/ffmpeg";
|
||||
import {
|
||||
deleteFile,
|
||||
deleteFolder,
|
||||
getDirFiles,
|
||||
isFolder,
|
||||
moveFile,
|
||||
readTextFile,
|
||||
rename,
|
||||
} from "./api/fs";
|
||||
import { convertToJPEG, generateImageThumbnail } from "./api/imageProcessor";
|
||||
import { getEncryptionKey, setEncryptionKey } from "./api/safeStorage";
|
||||
import {
|
||||
muteUpdateNotification,
|
||||
registerForegroundEventListener,
|
||||
registerUpdateEventListener,
|
||||
reloadWindow,
|
||||
sendNotification,
|
||||
updateAndRestart,
|
||||
skipAppUpdate,
|
||||
muteUpdateNotification,
|
||||
registerForegroundEventListener,
|
||||
} from './api/system';
|
||||
updateAndRestart,
|
||||
} from "./api/system";
|
||||
import {
|
||||
getElectronFilesFromGoogleZip,
|
||||
getPendingUploads,
|
||||
setToUploadCollection,
|
||||
setToUploadFiles,
|
||||
showUploadDirsDialog,
|
||||
showUploadFilesDialog,
|
||||
showUploadZipDialog,
|
||||
getPendingUploads,
|
||||
setToUploadFiles,
|
||||
getElectronFilesFromGoogleZip,
|
||||
setToUploadCollection,
|
||||
} from './api/upload';
|
||||
} from "./api/upload";
|
||||
import {
|
||||
registerWatcherFunctions,
|
||||
addWatchMapping,
|
||||
removeWatchMapping,
|
||||
updateWatchMappingSyncedFiles,
|
||||
updateWatchMappingIgnoredFiles,
|
||||
getWatchMappings,
|
||||
} from './api/watch';
|
||||
import { getEncryptionKey, setEncryptionKey } from './api/safeStorage';
|
||||
import { clearElectronStore } from './api/electronStore';
|
||||
registerWatcherFunctions,
|
||||
removeWatchMapping,
|
||||
updateWatchMappingIgnoredFiles,
|
||||
updateWatchMappingSyncedFiles,
|
||||
} from "./api/watch";
|
||||
import { setupLogging } from "./utils/logging";
|
||||
import { fixHotReloadNext12 } from "./utils/preload";
|
||||
import {
|
||||
openDiskCache,
|
||||
deleteDiskCache,
|
||||
getCacheDirectory,
|
||||
setCustomCacheDirectory,
|
||||
} from './api/cache';
|
||||
import {
|
||||
checkExistsAndCreateDir,
|
||||
saveStreamToDisk,
|
||||
saveFileToDisk,
|
||||
exists,
|
||||
} from './api/export';
|
||||
import {
|
||||
selectDirectory,
|
||||
logToDisk,
|
||||
openLogDirectory,
|
||||
getSentryUserID,
|
||||
getAppVersion,
|
||||
openDirectory,
|
||||
updateOptOutOfCrashReports,
|
||||
getPlatform,
|
||||
} from './api/common';
|
||||
import { fixHotReloadNext12 } from './utils/preload';
|
||||
import {
|
||||
isFolder,
|
||||
getDirFiles,
|
||||
moveFile,
|
||||
deleteFolder,
|
||||
rename,
|
||||
readTextFile,
|
||||
deleteFile,
|
||||
} from './api/fs';
|
||||
import { convertToJPEG, generateImageThumbnail } from './api/imageProcessor';
|
||||
import { setupLogging } from './utils/logging';
|
||||
import {
|
||||
setupRendererProcessStatsLogger,
|
||||
logRendererProcessMemoryUsage,
|
||||
} from './utils/processStats';
|
||||
import { runFFmpegCmd } from './api/ffmpeg';
|
||||
import { computeImageEmbedding, computeTextEmbedding } from './api/clip';
|
||||
setupRendererProcessStatsLogger,
|
||||
} from "./utils/processStats";
|
||||
|
||||
fixHotReloadNext12();
|
||||
setupLogging();
|
||||
|
@ -73,7 +73,7 @@ setupRendererProcessStatsLogger();
|
|||
|
||||
const windowObject: any = window;
|
||||
|
||||
windowObject['ElectronAPIs'] = {
|
||||
windowObject["ElectronAPIs"] = {
|
||||
exists,
|
||||
checkExistsAndCreateDir,
|
||||
saveStreamToDisk,
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import { app, BrowserWindow } from 'electron';
|
||||
import { autoUpdater } from 'electron-updater';
|
||||
import log from 'electron-log';
|
||||
import { setIsAppQuitting, setIsUpdateAvailable } from '../main';
|
||||
import { compareVersions } from 'compare-versions';
|
||||
import { AppUpdateInfo, GetFeatureFlagResponse } from '../types';
|
||||
import { compareVersions } from "compare-versions";
|
||||
import { app, BrowserWindow } from "electron";
|
||||
import { default as ElectronLog, default as log } from "electron-log";
|
||||
import { autoUpdater } from "electron-updater";
|
||||
import fetch from "node-fetch";
|
||||
import { setIsAppQuitting, setIsUpdateAvailable } from "../main";
|
||||
import { AppUpdateInfo, GetFeatureFlagResponse } from "../types";
|
||||
import { isPlatform } from "../utils/common/platform";
|
||||
import { logErrorSentry } from "./sentry";
|
||||
import {
|
||||
clearMuteUpdateNotificationVersion,
|
||||
clearSkipAppVersion,
|
||||
|
@ -11,11 +14,7 @@ import {
|
|||
getSkipAppVersion,
|
||||
setMuteUpdateNotificationVersion,
|
||||
setSkipAppVersion,
|
||||
} from './userPreference';
|
||||
import fetch from 'node-fetch';
|
||||
import { logErrorSentry } from './sentry';
|
||||
import ElectronLog from 'electron-log';
|
||||
import { isPlatform } from '../utils/common/platform';
|
||||
} from "./userPreference";
|
||||
|
||||
const FIVE_MIN_IN_MICROSECOND = 5 * 60 * 1000;
|
||||
const ONE_DAY_IN_MICROSECOND = 1 * 24 * 60 * 60 * 1000;
|
||||
|
@ -36,22 +35,22 @@ export function forceCheckForUpdateAndNotify(mainWindow: BrowserWindow) {
|
|||
clearMuteUpdateNotificationVersion();
|
||||
checkForUpdateAndNotify(mainWindow);
|
||||
} catch (e) {
|
||||
logErrorSentry(e, 'forceCheckForUpdateAndNotify failed');
|
||||
logErrorSentry(e, "forceCheckForUpdateAndNotify failed");
|
||||
}
|
||||
}
|
||||
|
||||
async function checkForUpdateAndNotify(mainWindow: BrowserWindow) {
|
||||
try {
|
||||
log.debug('checkForUpdateAndNotify called');
|
||||
log.debug("checkForUpdateAndNotify called");
|
||||
const updateCheckResult = await autoUpdater.checkForUpdates();
|
||||
log.debug('update version', updateCheckResult.updateInfo.version);
|
||||
log.debug("update version", updateCheckResult.updateInfo.version);
|
||||
if (
|
||||
compareVersions(
|
||||
updateCheckResult.updateInfo.version,
|
||||
app.getVersion()
|
||||
) <= 0
|
||||
) {
|
||||
log.debug('already at latest version');
|
||||
log.debug("already at latest version");
|
||||
return;
|
||||
}
|
||||
const skipAppVersion = getSkipAppVersion();
|
||||
|
@ -60,7 +59,7 @@ async function checkForUpdateAndNotify(mainWindow: BrowserWindow) {
|
|||
updateCheckResult.updateInfo.version === skipAppVersion
|
||||
) {
|
||||
log.info(
|
||||
'user chose to skip version ',
|
||||
"user chose to skip version ",
|
||||
updateCheckResult.updateInfo.version
|
||||
);
|
||||
return;
|
||||
|
@ -68,20 +67,20 @@ async function checkForUpdateAndNotify(mainWindow: BrowserWindow) {
|
|||
const desktopCutoffVersion = await getDesktopCutoffVersion();
|
||||
if (
|
||||
desktopCutoffVersion &&
|
||||
isPlatform('mac') &&
|
||||
isPlatform("mac") &&
|
||||
compareVersions(
|
||||
updateCheckResult.updateInfo.version,
|
||||
desktopCutoffVersion
|
||||
) > 0
|
||||
) {
|
||||
log.debug('auto update not possible due to key change');
|
||||
log.debug("auto update not possible due to key change");
|
||||
showUpdateDialog(mainWindow, {
|
||||
autoUpdatable: false,
|
||||
version: updateCheckResult.updateInfo.version,
|
||||
});
|
||||
} else {
|
||||
let timeout: NodeJS.Timeout;
|
||||
log.debug('attempting auto update');
|
||||
log.debug("attempting auto update");
|
||||
autoUpdater.downloadUpdate();
|
||||
const muteUpdateNotificationVersion =
|
||||
getMuteUpdateNotificationVersion();
|
||||
|
@ -91,12 +90,12 @@ async function checkForUpdateAndNotify(mainWindow: BrowserWindow) {
|
|||
muteUpdateNotificationVersion
|
||||
) {
|
||||
log.info(
|
||||
'user chose to mute update notification for version ',
|
||||
"user chose to mute update notification for version ",
|
||||
updateCheckResult.updateInfo.version
|
||||
);
|
||||
return;
|
||||
}
|
||||
autoUpdater.on('update-downloaded', () => {
|
||||
autoUpdater.on("update-downloaded", () => {
|
||||
timeout = setTimeout(
|
||||
() =>
|
||||
showUpdateDialog(mainWindow, {
|
||||
|
@ -106,9 +105,9 @@ async function checkForUpdateAndNotify(mainWindow: BrowserWindow) {
|
|||
FIVE_MIN_IN_MICROSECOND
|
||||
);
|
||||
});
|
||||
autoUpdater.on('error', (error) => {
|
||||
autoUpdater.on("error", (error) => {
|
||||
clearTimeout(timeout);
|
||||
logErrorSentry(error, 'auto update failed');
|
||||
logErrorSentry(error, "auto update failed");
|
||||
showUpdateDialog(mainWindow, {
|
||||
autoUpdatable: false,
|
||||
version: updateCheckResult.updateInfo.version,
|
||||
|
@ -117,12 +116,12 @@ async function checkForUpdateAndNotify(mainWindow: BrowserWindow) {
|
|||
}
|
||||
setIsUpdateAvailable(true);
|
||||
} catch (e) {
|
||||
logErrorSentry(e, 'checkForUpdateAndNotify failed');
|
||||
logErrorSentry(e, "checkForUpdateAndNotify failed");
|
||||
}
|
||||
}
|
||||
|
||||
export function updateAndRestart() {
|
||||
ElectronLog.log('user quit the app');
|
||||
ElectronLog.log("user quit the app");
|
||||
setIsAppQuitting(true);
|
||||
autoUpdater.quitAndInstall();
|
||||
}
|
||||
|
@ -142,11 +141,11 @@ export function muteUpdateNotification(version: string) {
|
|||
async function getDesktopCutoffVersion() {
|
||||
try {
|
||||
const featureFlags = (
|
||||
await fetch('https://static.ente.io/feature_flags.json')
|
||||
await fetch("https://static.ente.io/feature_flags.json")
|
||||
).json() as GetFeatureFlagResponse;
|
||||
return featureFlags.desktopCutoffVersion;
|
||||
} catch (e) {
|
||||
logErrorSentry(e, 'failed to get feature flags');
|
||||
logErrorSentry(e, "failed to get feature flags");
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
@ -155,5 +154,5 @@ function showUpdateDialog(
|
|||
mainWindow: BrowserWindow,
|
||||
updateInfo: AppUpdateInfo
|
||||
) {
|
||||
mainWindow.webContents.send('show-update-dialog', updateInfo);
|
||||
mainWindow.webContents.send("show-update-dialog", updateInfo);
|
||||
}
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
import { isPlatform } from '../utils/common/platform';
|
||||
import { AutoLauncherClient } from '../types/autoLauncher';
|
||||
import linuxAndWinAutoLauncher from './autoLauncherClients/linuxAndWinAutoLauncher';
|
||||
import macAutoLauncher from './autoLauncherClients/macAutoLauncher';
|
||||
import { AutoLauncherClient } from "../types/autoLauncher";
|
||||
import { isPlatform } from "../utils/common/platform";
|
||||
import linuxAndWinAutoLauncher from "./autoLauncherClients/linuxAndWinAutoLauncher";
|
||||
import macAutoLauncher from "./autoLauncherClients/macAutoLauncher";
|
||||
|
||||
class AutoLauncher {
|
||||
private client: AutoLauncherClient;
|
||||
async init() {
|
||||
if (isPlatform('linux') || isPlatform('windows')) {
|
||||
if (isPlatform("linux") || isPlatform("windows")) {
|
||||
this.client = linuxAndWinAutoLauncher;
|
||||
} else {
|
||||
this.client = macAutoLauncher;
|
||||
}
|
||||
// migrate old auto launch settings for windows from mac auto launcher to linux and windows auto launcher
|
||||
if (isPlatform('windows') && (await macAutoLauncher.isEnabled())) {
|
||||
if (isPlatform("windows") && (await macAutoLauncher.isEnabled())) {
|
||||
await macAutoLauncher.toggleAutoLaunch();
|
||||
await linuxAndWinAutoLauncher.toggleAutoLaunch();
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import AutoLaunch from 'auto-launch';
|
||||
import { AutoLauncherClient } from '../../types/autoLauncher';
|
||||
import { app } from 'electron';
|
||||
import AutoLaunch from "auto-launch";
|
||||
import { app } from "electron";
|
||||
import { AutoLauncherClient } from "../../types/autoLauncher";
|
||||
|
||||
const LAUNCHED_AS_HIDDEN_FLAG = 'hidden';
|
||||
const LAUNCHED_AS_HIDDEN_FLAG = "hidden";
|
||||
|
||||
class LinuxAndWinAutoLauncher implements AutoLauncherClient {
|
||||
private instance: AutoLaunch;
|
||||
constructor() {
|
||||
const autoLauncher = new AutoLaunch({
|
||||
name: 'ente',
|
||||
name: "ente",
|
||||
isHidden: true,
|
||||
});
|
||||
this.instance = autoLauncher;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { app } from 'electron';
|
||||
import { AutoLauncherClient } from '../../types/autoLauncher';
|
||||
import { app } from "electron";
|
||||
import { AutoLauncherClient } from "../../types/autoLauncher";
|
||||
|
||||
class MacAutoLauncher implements AutoLauncherClient {
|
||||
async isEnabled() {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import chokidar from 'chokidar';
|
||||
import { BrowserWindow } from 'electron';
|
||||
import { logError } from '../services/logging';
|
||||
import { getWatchMappings } from '../api/watch';
|
||||
import chokidar from "chokidar";
|
||||
import { BrowserWindow } from "electron";
|
||||
import { getWatchMappings } from "../api/watch";
|
||||
import { logError } from "../services/logging";
|
||||
|
||||
export function initWatcher(mainWindow: BrowserWindow) {
|
||||
const mappings = getWatchMappings();
|
||||
|
@ -13,20 +13,20 @@ export function initWatcher(mainWindow: BrowserWindow) {
|
|||
awaitWriteFinish: true,
|
||||
});
|
||||
watcher
|
||||
.on('add', (path) => {
|
||||
mainWindow.webContents.send('watch-add', path);
|
||||
.on("add", (path) => {
|
||||
mainWindow.webContents.send("watch-add", path);
|
||||
})
|
||||
.on('change', (path) => {
|
||||
mainWindow.webContents.send('watch-change', path);
|
||||
.on("change", (path) => {
|
||||
mainWindow.webContents.send("watch-change", path);
|
||||
})
|
||||
.on('unlink', (path) => {
|
||||
mainWindow.webContents.send('watch-unlink', path);
|
||||
.on("unlink", (path) => {
|
||||
mainWindow.webContents.send("watch-unlink", path);
|
||||
})
|
||||
.on('unlinkDir', (path) => {
|
||||
mainWindow.webContents.send('watch-unlink-dir', path);
|
||||
.on("unlinkDir", (path) => {
|
||||
mainWindow.webContents.send("watch-unlink-dir", path);
|
||||
})
|
||||
.on('error', (error) => {
|
||||
logError(error, 'error while watching files');
|
||||
.on("error", (error) => {
|
||||
logError(error, "error while watching files");
|
||||
});
|
||||
|
||||
return watcher;
|
||||
|
|
|
@ -1,59 +1,59 @@
|
|||
import * as log from 'electron-log';
|
||||
import util from 'util';
|
||||
import { logErrorSentry } from './sentry';
|
||||
import { isDev } from '../utils/common';
|
||||
import { app } from 'electron';
|
||||
import path from 'path';
|
||||
import { existsSync } from 'fs';
|
||||
import fs from 'fs/promises';
|
||||
const shellescape = require('any-shell-escape');
|
||||
const execAsync = util.promisify(require('child_process').exec);
|
||||
import fetch from 'node-fetch';
|
||||
import { writeNodeStream } from './fs';
|
||||
import { getPlatform } from '../utils/common/platform';
|
||||
import { CustomErrors } from '../constants/errors';
|
||||
const jpeg = require('jpeg-js');
|
||||
import { app } from "electron";
|
||||
import * as log from "electron-log";
|
||||
import { existsSync } from "fs";
|
||||
import fs from "fs/promises";
|
||||
import fetch from "node-fetch";
|
||||
import path from "path";
|
||||
import { readFile } from "promise-fs";
|
||||
import util from "util";
|
||||
import { CustomErrors } from "../constants/errors";
|
||||
import { Model } from "../types";
|
||||
import Tokenizer from "../utils/clip-bpe-ts/mod";
|
||||
import { isDev } from "../utils/common";
|
||||
import { getPlatform } from "../utils/common/platform";
|
||||
import { writeNodeStream } from "./fs";
|
||||
import { logErrorSentry } from "./sentry";
|
||||
const shellescape = require("any-shell-escape");
|
||||
const execAsync = util.promisify(require("child_process").exec);
|
||||
const jpeg = require("jpeg-js");
|
||||
|
||||
const CLIP_MODEL_PATH_PLACEHOLDER = 'CLIP_MODEL';
|
||||
const GGMLCLIP_PATH_PLACEHOLDER = 'GGML_PATH';
|
||||
const INPUT_PATH_PLACEHOLDER = 'INPUT';
|
||||
const CLIP_MODEL_PATH_PLACEHOLDER = "CLIP_MODEL";
|
||||
const GGMLCLIP_PATH_PLACEHOLDER = "GGML_PATH";
|
||||
const INPUT_PATH_PLACEHOLDER = "INPUT";
|
||||
|
||||
const IMAGE_EMBEDDING_EXTRACT_CMD: string[] = [
|
||||
GGMLCLIP_PATH_PLACEHOLDER,
|
||||
'-mv',
|
||||
"-mv",
|
||||
CLIP_MODEL_PATH_PLACEHOLDER,
|
||||
'--image',
|
||||
"--image",
|
||||
INPUT_PATH_PLACEHOLDER,
|
||||
];
|
||||
|
||||
const TEXT_EMBEDDING_EXTRACT_CMD: string[] = [
|
||||
GGMLCLIP_PATH_PLACEHOLDER,
|
||||
'-mt',
|
||||
"-mt",
|
||||
CLIP_MODEL_PATH_PLACEHOLDER,
|
||||
'--text',
|
||||
"--text",
|
||||
INPUT_PATH_PLACEHOLDER,
|
||||
];
|
||||
const ort = require('onnxruntime-node');
|
||||
import Tokenizer from '../utils/clip-bpe-ts/mod';
|
||||
import { readFile } from 'promise-fs';
|
||||
import { Model } from '../types';
|
||||
const ort = require("onnxruntime-node");
|
||||
|
||||
const TEXT_MODEL_DOWNLOAD_URL = {
|
||||
ggml: 'https://models.ente.io/clip-vit-base-patch32_ggml-text-model-f16.gguf',
|
||||
onnx: 'https://models.ente.io/clip-text-vit-32-uint8.onnx',
|
||||
ggml: "https://models.ente.io/clip-vit-base-patch32_ggml-text-model-f16.gguf",
|
||||
onnx: "https://models.ente.io/clip-text-vit-32-uint8.onnx",
|
||||
};
|
||||
const IMAGE_MODEL_DOWNLOAD_URL = {
|
||||
ggml: 'https://models.ente.io/clip-vit-base-patch32_ggml-vision-model-f16.gguf',
|
||||
onnx: 'https://models.ente.io/clip-image-vit-32-float32.onnx',
|
||||
ggml: "https://models.ente.io/clip-vit-base-patch32_ggml-vision-model-f16.gguf",
|
||||
onnx: "https://models.ente.io/clip-image-vit-32-float32.onnx",
|
||||
};
|
||||
|
||||
const TEXT_MODEL_NAME = {
|
||||
ggml: 'clip-vit-base-patch32_ggml-text-model-f16.gguf',
|
||||
onnx: 'clip-text-vit-32-uint8.onnx',
|
||||
ggml: "clip-vit-base-patch32_ggml-text-model-f16.gguf",
|
||||
onnx: "clip-text-vit-32-uint8.onnx",
|
||||
};
|
||||
const IMAGE_MODEL_NAME = {
|
||||
ggml: 'clip-vit-base-patch32_ggml-vision-model-f16.gguf',
|
||||
onnx: 'clip-image-vit-32-float32.onnx',
|
||||
ggml: "clip-vit-base-patch32_ggml-vision-model-f16.gguf",
|
||||
onnx: "clip-image-vit-32-float32.onnx",
|
||||
};
|
||||
|
||||
const IMAGE_MODEL_SIZE_IN_BYTES = {
|
||||
|
@ -65,14 +65,14 @@ const TEXT_MODEL_SIZE_IN_BYTES = {
|
|||
onnx: 64173509, // 61.2 MB
|
||||
};
|
||||
|
||||
const MODEL_SAVE_FOLDER = 'models';
|
||||
const MODEL_SAVE_FOLDER = "models";
|
||||
|
||||
function getModelSavePath(modelName: string) {
|
||||
let userDataDir: string;
|
||||
if (isDev) {
|
||||
userDataDir = '.';
|
||||
userDataDir = ".";
|
||||
} else {
|
||||
userDataDir = app.getPath('userData');
|
||||
userDataDir = app.getPath("userData");
|
||||
}
|
||||
return path.join(userDataDir, MODEL_SAVE_FOLDER, modelName);
|
||||
}
|
||||
|
@ -81,26 +81,26 @@ async function downloadModel(saveLocation: string, url: string) {
|
|||
// confirm that the save location exists
|
||||
const saveDir = path.dirname(saveLocation);
|
||||
if (!existsSync(saveDir)) {
|
||||
log.info('creating model save dir');
|
||||
log.info("creating model save dir");
|
||||
await fs.mkdir(saveDir, { recursive: true });
|
||||
}
|
||||
log.info('downloading clip model');
|
||||
log.info("downloading clip model");
|
||||
const resp = await fetch(url);
|
||||
await writeNodeStream(saveLocation, resp.body);
|
||||
log.info('clip model downloaded');
|
||||
log.info("clip model downloaded");
|
||||
}
|
||||
|
||||
let imageModelDownloadInProgress: Promise<void> = null;
|
||||
|
||||
export async function getClipImageModelPath(type: 'ggml' | 'onnx') {
|
||||
export async function getClipImageModelPath(type: "ggml" | "onnx") {
|
||||
try {
|
||||
const modelSavePath = getModelSavePath(IMAGE_MODEL_NAME[type]);
|
||||
if (imageModelDownloadInProgress) {
|
||||
log.info('waiting for image model download to finish');
|
||||
log.info("waiting for image model download to finish");
|
||||
await imageModelDownloadInProgress;
|
||||
} else {
|
||||
if (!existsSync(modelSavePath)) {
|
||||
log.info('clip image model not found, downloading');
|
||||
log.info("clip image model not found, downloading");
|
||||
imageModelDownloadInProgress = downloadModel(
|
||||
modelSavePath,
|
||||
IMAGE_MODEL_DOWNLOAD_URL[type]
|
||||
|
@ -110,7 +110,7 @@ export async function getClipImageModelPath(type: 'ggml' | 'onnx') {
|
|||
const localFileSize = (await fs.stat(modelSavePath)).size;
|
||||
if (localFileSize !== IMAGE_MODEL_SIZE_IN_BYTES[type]) {
|
||||
log.info(
|
||||
'clip image model size mismatch, downloading again got:',
|
||||
"clip image model size mismatch, downloading again got:",
|
||||
localFileSize
|
||||
);
|
||||
imageModelDownloadInProgress = downloadModel(
|
||||
|
@ -129,13 +129,13 @@ export async function getClipImageModelPath(type: 'ggml' | 'onnx') {
|
|||
|
||||
let textModelDownloadInProgress: boolean = false;
|
||||
|
||||
export async function getClipTextModelPath(type: 'ggml' | 'onnx') {
|
||||
export async function getClipTextModelPath(type: "ggml" | "onnx") {
|
||||
const modelSavePath = getModelSavePath(TEXT_MODEL_NAME[type]);
|
||||
if (textModelDownloadInProgress) {
|
||||
throw Error(CustomErrors.MODEL_DOWNLOAD_PENDING);
|
||||
} else {
|
||||
if (!existsSync(modelSavePath)) {
|
||||
log.info('clip text model not found, downloading');
|
||||
log.info("clip text model not found, downloading");
|
||||
textModelDownloadInProgress = true;
|
||||
downloadModel(modelSavePath, TEXT_MODEL_DOWNLOAD_URL[type])
|
||||
.catch(() => {
|
||||
|
@ -149,7 +149,7 @@ export async function getClipTextModelPath(type: 'ggml' | 'onnx') {
|
|||
const localFileSize = (await fs.stat(modelSavePath)).size;
|
||||
if (localFileSize !== TEXT_MODEL_SIZE_IN_BYTES[type]) {
|
||||
log.info(
|
||||
'clip text model size mismatch, downloading again got:',
|
||||
"clip text model size mismatch, downloading again got:",
|
||||
localFileSize
|
||||
);
|
||||
textModelDownloadInProgress = true;
|
||||
|
@ -169,7 +169,7 @@ export async function getClipTextModelPath(type: 'ggml' | 'onnx') {
|
|||
|
||||
function getGGMLClipPath() {
|
||||
return isDev
|
||||
? path.join('./build', `ggmlclip-${getPlatform()}`)
|
||||
? path.join("./build", `ggmlclip-${getPlatform()}`)
|
||||
: path.join(process.resourcesPath, `ggmlclip-${getPlatform()}`);
|
||||
}
|
||||
|
||||
|
@ -185,7 +185,7 @@ let onnxImageSessionPromise: Promise<any> = null;
|
|||
async function getOnnxImageSession() {
|
||||
if (!onnxImageSessionPromise) {
|
||||
onnxImageSessionPromise = (async () => {
|
||||
const clipModelPath = await getClipImageModelPath('onnx');
|
||||
const clipModelPath = await getClipImageModelPath("onnx");
|
||||
return createOnnxSession(clipModelPath);
|
||||
})();
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ let onnxTextSession: any = null;
|
|||
|
||||
async function getOnnxTextSession() {
|
||||
if (!onnxTextSession) {
|
||||
const clipModelPath = await getClipTextModelPath('onnx');
|
||||
const clipModelPath = await getClipTextModelPath("onnx");
|
||||
onnxTextSession = await createOnnxSession(clipModelPath);
|
||||
}
|
||||
return onnxTextSession;
|
||||
|
@ -230,7 +230,7 @@ export async function computeGGMLImageEmbedding(
|
|||
inputFilePath: string
|
||||
): Promise<Float32Array> {
|
||||
try {
|
||||
const clipModelPath = await getClipImageModelPath('ggml');
|
||||
const clipModelPath = await getClipImageModelPath("ggml");
|
||||
const ggmlclipPath = getGGMLClipPath();
|
||||
const cmd = IMAGE_EMBEDDING_EXTRACT_CMD.map((cmdPart) => {
|
||||
if (cmdPart === GGMLCLIP_PATH_PLACEHOLDER) {
|
||||
|
@ -245,19 +245,19 @@ export async function computeGGMLImageEmbedding(
|
|||
});
|
||||
|
||||
const escapedCmd = shellescape(cmd);
|
||||
log.info('running clip command', escapedCmd);
|
||||
log.info("running clip command", escapedCmd);
|
||||
const startTime = Date.now();
|
||||
const { stdout } = await execAsync(escapedCmd);
|
||||
log.info('clip command execution time ', Date.now() - startTime);
|
||||
log.info("clip command execution time ", Date.now() - startTime);
|
||||
// parse stdout and return embedding
|
||||
// get the last line of stdout
|
||||
const lines = stdout.split('\n');
|
||||
const lines = stdout.split("\n");
|
||||
const lastLine = lines[lines.length - 1];
|
||||
const embedding = JSON.parse(lastLine);
|
||||
const embeddingArray = new Float32Array(embedding);
|
||||
return embeddingArray;
|
||||
} catch (err) {
|
||||
logErrorSentry(err, 'Error in computeGGMLImageEmbedding');
|
||||
logErrorSentry(err, "Error in computeGGMLImageEmbedding");
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
@ -270,7 +270,7 @@ export async function computeONNXImageEmbedding(
|
|||
const t1 = Date.now();
|
||||
const rgbData = await getRGBData(inputFilePath);
|
||||
const feeds = {
|
||||
input: new ort.Tensor('float32', rgbData, [1, 3, 224, 224]),
|
||||
input: new ort.Tensor("float32", rgbData, [1, 3, 224, 224]),
|
||||
};
|
||||
const t2 = Date.now();
|
||||
const results = await imageSession.run(feeds);
|
||||
|
@ -279,10 +279,10 @@ export async function computeONNXImageEmbedding(
|
|||
t2 - t1
|
||||
} ms, extraction: ${Date.now() - t2} ms)`
|
||||
);
|
||||
const imageEmbedding = results['output'].data; // Float32Array
|
||||
const imageEmbedding = results["output"].data; // Float32Array
|
||||
return normalizeEmbedding(imageEmbedding);
|
||||
} catch (err) {
|
||||
logErrorSentry(err, 'Error in computeONNXImageEmbedding');
|
||||
logErrorSentry(err, "Error in computeONNXImageEmbedding");
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
@ -302,7 +302,7 @@ export async function computeGGMLTextEmbedding(
|
|||
text: string
|
||||
): Promise<Float32Array> {
|
||||
try {
|
||||
const clipModelPath = await getClipTextModelPath('ggml');
|
||||
const clipModelPath = await getClipTextModelPath("ggml");
|
||||
const ggmlclipPath = getGGMLClipPath();
|
||||
const cmd = TEXT_EMBEDDING_EXTRACT_CMD.map((cmdPart) => {
|
||||
if (cmdPart === GGMLCLIP_PATH_PLACEHOLDER) {
|
||||
|
@ -317,13 +317,13 @@ export async function computeGGMLTextEmbedding(
|
|||
});
|
||||
|
||||
const escapedCmd = shellescape(cmd);
|
||||
log.info('running clip command', escapedCmd);
|
||||
log.info("running clip command", escapedCmd);
|
||||
const startTime = Date.now();
|
||||
const { stdout } = await execAsync(escapedCmd);
|
||||
log.info('clip command execution time ', Date.now() - startTime);
|
||||
log.info("clip command execution time ", Date.now() - startTime);
|
||||
// parse stdout and return embedding
|
||||
// get the last line of stdout
|
||||
const lines = stdout.split('\n');
|
||||
const lines = stdout.split("\n");
|
||||
const lastLine = lines[lines.length - 1];
|
||||
const embedding = JSON.parse(lastLine);
|
||||
const embeddingArray = new Float32Array(embedding);
|
||||
|
@ -332,7 +332,7 @@ export async function computeGGMLTextEmbedding(
|
|||
if (err.message === CustomErrors.MODEL_DOWNLOAD_PENDING) {
|
||||
log.info(CustomErrors.MODEL_DOWNLOAD_PENDING);
|
||||
} else {
|
||||
logErrorSentry(err, 'Error in computeGGMLTextEmbedding');
|
||||
logErrorSentry(err, "Error in computeGGMLTextEmbedding");
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
|
@ -347,7 +347,7 @@ export async function computeONNXTextEmbedding(
|
|||
const tokenizer = getTokenizer();
|
||||
const tokenizedText = Int32Array.from(tokenizer.encodeForCLIP(text));
|
||||
const feeds = {
|
||||
input: new ort.Tensor('int32', tokenizedText, [1, 77]),
|
||||
input: new ort.Tensor("int32", tokenizedText, [1, 77]),
|
||||
};
|
||||
const t2 = Date.now();
|
||||
const results = await imageSession.run(feeds);
|
||||
|
@ -356,13 +356,13 @@ export async function computeONNXTextEmbedding(
|
|||
t2 - t1
|
||||
} ms, extraction: ${Date.now() - t2} ms)`
|
||||
);
|
||||
const textEmbedding = results['output'].data; // Float32Array
|
||||
const textEmbedding = results["output"].data; // Float32Array
|
||||
return normalizeEmbedding(textEmbedding);
|
||||
} catch (err) {
|
||||
if (err.message === CustomErrors.MODEL_DOWNLOAD_PENDING) {
|
||||
log.info(CustomErrors.MODEL_DOWNLOAD_PENDING);
|
||||
} else {
|
||||
logErrorSentry(err, 'Error in computeONNXTextEmbedding');
|
||||
logErrorSentry(err, "Error in computeONNXTextEmbedding");
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
|
@ -377,7 +377,7 @@ async function getRGBData(inputFilePath: string) {
|
|||
formatAsRGBA: false,
|
||||
});
|
||||
} catch (err) {
|
||||
logErrorSentry(err, 'JPEG decode error');
|
||||
logErrorSentry(err, "JPEG decode error");
|
||||
throw err;
|
||||
}
|
||||
|
||||
|
@ -447,7 +447,7 @@ export const computeClipMatchScore = async (
|
|||
textEmbedding: Float32Array
|
||||
) => {
|
||||
if (imageEmbedding.length !== textEmbedding.length) {
|
||||
throw Error('imageEmbedding and textEmbedding length mismatch');
|
||||
throw Error("imageEmbedding and textEmbedding length mismatch");
|
||||
}
|
||||
let score = 0;
|
||||
for (let index = 0; index < imageEmbedding.length; index++) {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import DiskLRUService from '../services/diskLRU';
|
||||
import crypto from 'crypto';
|
||||
import { existsSync, unlink, rename, stat } from 'promise-fs';
|
||||
import path from 'path';
|
||||
import { LimitedCache } from '../types/cache';
|
||||
import { logError } from './logging';
|
||||
import { getFileStream, writeStream } from './fs';
|
||||
import crypto from "crypto";
|
||||
import path from "path";
|
||||
import { existsSync, rename, stat, unlink } from "promise-fs";
|
||||
import DiskLRUService from "../services/diskLRU";
|
||||
import { LimitedCache } from "../types/cache";
|
||||
import { getFileStream, writeStream } from "./fs";
|
||||
import { logError } from "./logging";
|
||||
|
||||
const DEFAULT_CACHE_LIMIT = 1000 * 1000 * 1000; // 1GB
|
||||
|
||||
|
@ -33,11 +33,11 @@ export class DiskCache implements LimitedCache {
|
|||
if (sizeInBytes && fileStats.size !== sizeInBytes) {
|
||||
logError(
|
||||
Error(),
|
||||
'Cache key exists but size does not match. Deleting cache key.'
|
||||
"Cache key exists but size does not match. Deleting cache key."
|
||||
);
|
||||
unlink(cachePath).catch((e) => {
|
||||
if (e.code === 'ENOENT') return;
|
||||
logError(e, 'Failed to delete cache key');
|
||||
if (e.code === "ENOENT") return;
|
||||
logError(e, "Failed to delete cache key");
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
|
@ -54,11 +54,11 @@ export class DiskCache implements LimitedCache {
|
|||
if (sizeInBytes && fileStats.size !== sizeInBytes) {
|
||||
logError(
|
||||
Error(),
|
||||
'Old cache key exists but size does not match. Deleting cache key.'
|
||||
"Old cache key exists but size does not match. Deleting cache key."
|
||||
);
|
||||
unlink(oldCachePath).catch((e) => {
|
||||
if (e.code === 'ENOENT') return;
|
||||
logError(e, 'Failed to delete cache key');
|
||||
if (e.code === "ENOENT") return;
|
||||
logError(e, "Failed to delete cache key");
|
||||
});
|
||||
return undefined;
|
||||
}
|
||||
|
@ -83,9 +83,9 @@ export class DiskCache implements LimitedCache {
|
|||
function getOldAssetCachePath(cacheDir: string, cacheKey: string) {
|
||||
// hashing the key to prevent illegal filenames
|
||||
const cacheKeyHash = crypto
|
||||
.createHash('sha256')
|
||||
.createHash("sha256")
|
||||
.update(cacheKey)
|
||||
.digest('hex');
|
||||
.digest("hex");
|
||||
return path.join(cacheDir, cacheKeyHash);
|
||||
}
|
||||
|
||||
|
@ -93,6 +93,6 @@ async function migrateOldCacheKey(oldCacheKey: string, newCacheKey: string) {
|
|||
try {
|
||||
await rename(oldCacheKey, newCacheKey);
|
||||
} catch (e) {
|
||||
logError(e, 'Failed to move cache key to new cache key');
|
||||
logError(e, "Failed to move cache key to new cache key");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import path from 'path';
|
||||
import { readdir, stat, unlink } from 'promise-fs';
|
||||
import getFolderSize from 'get-folder-size';
|
||||
import { utimes, close, open } from 'promise-fs';
|
||||
import { logError } from '../services/logging';
|
||||
import getFolderSize from "get-folder-size";
|
||||
import path from "path";
|
||||
import { close, open, readdir, stat, unlink, utimes } from "promise-fs";
|
||||
import { logError } from "../services/logging";
|
||||
|
||||
export interface LeastRecentlyUsedResult {
|
||||
atime: Date;
|
||||
|
@ -18,11 +17,11 @@ class DiskLRUService {
|
|||
const time = new Date();
|
||||
await utimes(path, time, time);
|
||||
} catch (err) {
|
||||
logError(err, 'utimes method touch failed');
|
||||
logError(err, "utimes method touch failed");
|
||||
try {
|
||||
await close(await open(path, 'w'));
|
||||
await close(await open(path, "w"));
|
||||
} catch (e) {
|
||||
logError(e, 'open-close method touch failed');
|
||||
logError(e, "open-close method touch failed");
|
||||
}
|
||||
// log and ignore
|
||||
}
|
||||
|
@ -58,10 +57,10 @@ class DiskLRUService {
|
|||
} catch (e) {
|
||||
// ENOENT: File not found
|
||||
// which can be ignored as we are trying to delete the file anyway
|
||||
if (e.code !== 'ENOENT') {
|
||||
if (e.code !== "ENOENT") {
|
||||
logError(
|
||||
e,
|
||||
'Failed to evict least recently used'
|
||||
"Failed to evict least recently used"
|
||||
);
|
||||
}
|
||||
// ignoring the error, as it would get retried on the next run
|
||||
|
@ -72,7 +71,7 @@ class DiskLRUService {
|
|||
});
|
||||
});
|
||||
} catch (e) {
|
||||
logError(e, 'evictLeastRecentlyUsed failed');
|
||||
logError(e, "evictLeastRecentlyUsed failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,7 +79,7 @@ class DiskLRUService {
|
|||
dir: string,
|
||||
result?: LeastRecentlyUsedResult
|
||||
): Promise<LeastRecentlyUsedResult> {
|
||||
result = result || { atime: new Date(), path: '' };
|
||||
result = result || { atime: new Date(), path: "" };
|
||||
|
||||
const files = await readdir(dir);
|
||||
for (const file of files) {
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
import pathToFfmpeg from 'ffmpeg-static';
|
||||
const shellescape = require('any-shell-escape');
|
||||
import util from 'util';
|
||||
import log from 'electron-log';
|
||||
import { readFile, rmSync, writeFile } from 'promise-fs';
|
||||
import { logErrorSentry } from './sentry';
|
||||
import { generateTempFilePath, getTempDirPath } from '../utils/temp';
|
||||
import { existsSync } from 'fs';
|
||||
import { promiseWithTimeout } from '../utils/common';
|
||||
import log from "electron-log";
|
||||
import pathToFfmpeg from "ffmpeg-static";
|
||||
import { existsSync } from "fs";
|
||||
import { readFile, rmSync, writeFile } from "promise-fs";
|
||||
import util from "util";
|
||||
import { promiseWithTimeout } from "../utils/common";
|
||||
import { generateTempFilePath, getTempDirPath } from "../utils/temp";
|
||||
import { logErrorSentry } from "./sentry";
|
||||
const shellescape = require("any-shell-escape");
|
||||
|
||||
const execAsync = util.promisify(require('child_process').exec);
|
||||
const execAsync = util.promisify(require("child_process").exec);
|
||||
|
||||
const FFMPEG_EXECUTION_WAIT_TIME = 30 * 1000;
|
||||
|
||||
const INPUT_PATH_PLACEHOLDER = 'INPUT';
|
||||
const FFMPEG_PLACEHOLDER = 'FFMPEG';
|
||||
const OUTPUT_PATH_PLACEHOLDER = 'OUTPUT';
|
||||
const INPUT_PATH_PLACEHOLDER = "INPUT";
|
||||
const FFMPEG_PLACEHOLDER = "FFMPEG";
|
||||
const OUTPUT_PATH_PLACEHOLDER = "OUTPUT";
|
||||
|
||||
function getFFmpegStaticPath() {
|
||||
return pathToFfmpeg.replace('app.asar', 'app.asar.unpacked');
|
||||
return pathToFfmpeg.replace("app.asar", "app.asar.unpacked");
|
||||
}
|
||||
|
||||
export async function runFFmpegCmd(
|
||||
|
@ -42,7 +42,7 @@ export async function runFFmpegCmd(
|
|||
}
|
||||
});
|
||||
const escapedCmd = shellescape(cmd);
|
||||
log.info('running ffmpeg command', escapedCmd);
|
||||
log.info("running ffmpeg command", escapedCmd);
|
||||
const startTime = Date.now();
|
||||
if (dontTimeout) {
|
||||
await execAsync(escapedCmd);
|
||||
|
@ -53,25 +53,25 @@ export async function runFFmpegCmd(
|
|||
);
|
||||
}
|
||||
if (!existsSync(tempOutputFilePath)) {
|
||||
throw new Error('ffmpeg output file not found');
|
||||
throw new Error("ffmpeg output file not found");
|
||||
}
|
||||
log.info(
|
||||
'ffmpeg command execution time ',
|
||||
"ffmpeg command execution time ",
|
||||
escapedCmd,
|
||||
Date.now() - startTime,
|
||||
'ms'
|
||||
"ms"
|
||||
);
|
||||
|
||||
const outputFile = await readFile(tempOutputFilePath);
|
||||
return new Uint8Array(outputFile);
|
||||
} catch (e) {
|
||||
logErrorSentry(e, 'ffmpeg run command error');
|
||||
logErrorSentry(e, "ffmpeg run command error");
|
||||
throw e;
|
||||
} finally {
|
||||
try {
|
||||
rmSync(tempOutputFilePath, { force: true });
|
||||
} catch (e) {
|
||||
logErrorSentry(e, 'failed to remove tempOutputFile');
|
||||
logErrorSentry(e, "failed to remove tempOutputFile");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,8 +86,8 @@ export async function deleteTempFile(tempFilePath: string) {
|
|||
const tempDirPath = await getTempDirPath();
|
||||
if (!tempFilePath.startsWith(tempDirPath)) {
|
||||
logErrorSentry(
|
||||
Error('not a temp file'),
|
||||
'tried to delete a non temp file'
|
||||
Error("not a temp file"),
|
||||
"tried to delete a non temp file"
|
||||
);
|
||||
}
|
||||
rmSync(tempFilePath, { force: true });
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { FILE_STREAM_CHUNK_SIZE } from '../config';
|
||||
import path from 'path';
|
||||
import * as fs from 'promise-fs';
|
||||
import { ElectronFile } from '../types';
|
||||
import StreamZip from 'node-stream-zip';
|
||||
import { Readable } from 'stream';
|
||||
import { logError } from './logging';
|
||||
import { existsSync } from 'fs';
|
||||
import { existsSync } from "fs";
|
||||
import StreamZip from "node-stream-zip";
|
||||
import path from "path";
|
||||
import * as fs from "promise-fs";
|
||||
import { Readable } from "stream";
|
||||
import { FILE_STREAM_CHUNK_SIZE } from "../config";
|
||||
import { ElectronFile } from "../types";
|
||||
import { logError } from "./logging";
|
||||
|
||||
// https://stackoverflow.com/a/63111390
|
||||
export const getDirFilePaths = async (dirPath: string) => {
|
||||
|
@ -25,7 +25,7 @@ export const getDirFilePaths = async (dirPath: string) => {
|
|||
};
|
||||
|
||||
export const getFileStream = async (filePath: string) => {
|
||||
const file = await fs.open(filePath, 'r');
|
||||
const file = await fs.open(filePath, "r");
|
||||
let offset = 0;
|
||||
const readableStream = new ReadableStream<Uint8Array>({
|
||||
async pull(controller) {
|
||||
|
@ -66,20 +66,20 @@ export async function getElectronFile(filePath: string): Promise<ElectronFile> {
|
|||
lastModified: fileStats.mtime.valueOf(),
|
||||
stream: async () => {
|
||||
if (!existsSync(filePath)) {
|
||||
throw new Error('electronFile does not exist');
|
||||
throw new Error("electronFile does not exist");
|
||||
}
|
||||
return await getFileStream(filePath);
|
||||
},
|
||||
blob: async () => {
|
||||
if (!existsSync(filePath)) {
|
||||
throw new Error('electronFile does not exist');
|
||||
throw new Error("electronFile does not exist");
|
||||
}
|
||||
const blob = await fs.readFile(filePath);
|
||||
return new Blob([new Uint8Array(blob)]);
|
||||
},
|
||||
arrayBuffer: async () => {
|
||||
if (!existsSync(filePath)) {
|
||||
throw new Error('electronFile does not exist');
|
||||
throw new Error("electronFile does not exist");
|
||||
}
|
||||
const blob = await fs.readFile(filePath);
|
||||
return new Uint8Array(blob);
|
||||
|
@ -113,7 +113,7 @@ export const getZipFileStream = async (
|
|||
};
|
||||
let resolveObj: (value?: any) => void = null;
|
||||
let rejectObj: (reason?: any) => void = null;
|
||||
stream.on('readable', () => {
|
||||
stream.on("readable", () => {
|
||||
try {
|
||||
if (resolveObj) {
|
||||
inProgress.current = true;
|
||||
|
@ -128,7 +128,7 @@ export const getZipFileStream = async (
|
|||
rejectObj(e);
|
||||
}
|
||||
});
|
||||
stream.on('end', () => {
|
||||
stream.on("end", () => {
|
||||
try {
|
||||
done.current = true;
|
||||
if (resolveObj && !inProgress.current) {
|
||||
|
@ -139,7 +139,7 @@ export const getZipFileStream = async (
|
|||
rejectObj(e);
|
||||
}
|
||||
});
|
||||
stream.on('error', (e) => {
|
||||
stream.on("error", (e) => {
|
||||
try {
|
||||
done.current = true;
|
||||
if (rejectObj) {
|
||||
|
@ -175,7 +175,7 @@ export const getZipFileStream = async (
|
|||
controller.close();
|
||||
}
|
||||
} catch (e) {
|
||||
logError(e, 'readableStream pull failed');
|
||||
logError(e, "readableStream pull failed");
|
||||
controller.close();
|
||||
}
|
||||
},
|
||||
|
@ -190,14 +190,14 @@ export async function isFolder(dirPath: string) {
|
|||
} catch (e) {
|
||||
let err = e;
|
||||
// if code is defined, it's an error from fs.stat
|
||||
if (typeof e.code !== 'undefined') {
|
||||
if (typeof e.code !== "undefined") {
|
||||
// ENOENT means the file does not exist
|
||||
if (e.code === 'ENOENT') {
|
||||
if (e.code === "ENOENT") {
|
||||
return false;
|
||||
}
|
||||
err = Error(`fs error code: ${e.code}`);
|
||||
}
|
||||
logError(err, 'isFolder failed');
|
||||
logError(err, "isFolder failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ export const convertBrowserStreamToNode = (
|
|||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
rs.emit('error', e);
|
||||
rs.emit("error", e);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -232,15 +232,15 @@ export async function writeNodeStream(
|
|||
) {
|
||||
const writeable = fs.createWriteStream(filePath);
|
||||
|
||||
fileStream.on('error', (error) => {
|
||||
fileStream.on("error", (error) => {
|
||||
writeable.destroy(error); // Close the writable stream with an error
|
||||
});
|
||||
|
||||
fileStream.pipe(writeable);
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
writeable.on('finish', resolve);
|
||||
writeable.on('error', async (e) => {
|
||||
writeable.on("finish", resolve);
|
||||
writeable.on("error", async (e) => {
|
||||
if (existsSync(filePath)) {
|
||||
await fs.unlink(filePath);
|
||||
}
|
||||
|
@ -259,9 +259,9 @@ export async function writeStream(
|
|||
|
||||
export async function readTextFile(filePath: string) {
|
||||
if (!existsSync(filePath)) {
|
||||
throw new Error('File does not exist');
|
||||
throw new Error("File does not exist");
|
||||
}
|
||||
return await fs.readFile(filePath, 'utf-8');
|
||||
return await fs.readFile(filePath, "utf-8");
|
||||
}
|
||||
|
||||
export async function moveFile(
|
||||
|
@ -269,10 +269,10 @@ export async function moveFile(
|
|||
destinationPath: string
|
||||
): Promise<void> {
|
||||
if (!existsSync(sourcePath)) {
|
||||
throw new Error('File does not exist');
|
||||
throw new Error("File does not exist");
|
||||
}
|
||||
if (existsSync(destinationPath)) {
|
||||
throw new Error('Destination file already exists');
|
||||
throw new Error("Destination file already exists");
|
||||
}
|
||||
// check if destination folder exists
|
||||
const destinationFolder = path.dirname(destinationPath);
|
||||
|
@ -287,19 +287,19 @@ export async function deleteFolder(folderPath: string): Promise<void> {
|
|||
return;
|
||||
}
|
||||
if (!fs.statSync(folderPath).isDirectory()) {
|
||||
throw new Error('Path is not a folder');
|
||||
throw new Error("Path is not a folder");
|
||||
}
|
||||
// check if folder is empty
|
||||
const files = await fs.readdir(folderPath);
|
||||
if (files.length > 0) {
|
||||
throw new Error('Folder is not empty');
|
||||
throw new Error("Folder is not empty");
|
||||
}
|
||||
await fs.rmdir(folderPath);
|
||||
}
|
||||
|
||||
export async function rename(oldPath: string, newPath: string) {
|
||||
if (!existsSync(oldPath)) {
|
||||
throw new Error('Path does not exist');
|
||||
throw new Error("Path does not exist");
|
||||
}
|
||||
await fs.rename(oldPath, newPath);
|
||||
}
|
||||
|
@ -309,7 +309,7 @@ export function deleteFile(filePath: string): void {
|
|||
return;
|
||||
}
|
||||
if (!fs.statSync(filePath).isFile()) {
|
||||
throw new Error('Path is not a file');
|
||||
throw new Error("Path is not a file");
|
||||
}
|
||||
fs.rmSync(filePath);
|
||||
}
|
||||
|
|
|
@ -1,81 +1,81 @@
|
|||
import util from 'util';
|
||||
import { exec } from 'child_process';
|
||||
import { exec } from "child_process";
|
||||
import util from "util";
|
||||
|
||||
import { existsSync, rmSync } from 'fs';
|
||||
import { readFile, writeFile } from 'promise-fs';
|
||||
import { generateTempFilePath } from '../utils/temp';
|
||||
import { logErrorSentry } from './sentry';
|
||||
import { isPlatform } from '../utils/common/platform';
|
||||
import { isDev } from '../utils/common';
|
||||
import path from 'path';
|
||||
import log from 'electron-log';
|
||||
import { CustomErrors } from '../constants/errors';
|
||||
const shellescape = require('any-shell-escape');
|
||||
import log from "electron-log";
|
||||
import { existsSync, rmSync } from "fs";
|
||||
import path from "path";
|
||||
import { readFile, writeFile } from "promise-fs";
|
||||
import { CustomErrors } from "../constants/errors";
|
||||
import { isDev } from "../utils/common";
|
||||
import { isPlatform } from "../utils/common/platform";
|
||||
import { generateTempFilePath } from "../utils/temp";
|
||||
import { logErrorSentry } from "./sentry";
|
||||
const shellescape = require("any-shell-escape");
|
||||
|
||||
const asyncExec = util.promisify(exec);
|
||||
|
||||
const IMAGE_MAGICK_PLACEHOLDER = 'IMAGE_MAGICK';
|
||||
const MAX_DIMENSION_PLACEHOLDER = 'MAX_DIMENSION';
|
||||
const SAMPLE_SIZE_PLACEHOLDER = 'SAMPLE_SIZE';
|
||||
const INPUT_PATH_PLACEHOLDER = 'INPUT';
|
||||
const OUTPUT_PATH_PLACEHOLDER = 'OUTPUT';
|
||||
const QUALITY_PLACEHOLDER = 'QUALITY';
|
||||
const IMAGE_MAGICK_PLACEHOLDER = "IMAGE_MAGICK";
|
||||
const MAX_DIMENSION_PLACEHOLDER = "MAX_DIMENSION";
|
||||
const SAMPLE_SIZE_PLACEHOLDER = "SAMPLE_SIZE";
|
||||
const INPUT_PATH_PLACEHOLDER = "INPUT";
|
||||
const OUTPUT_PATH_PLACEHOLDER = "OUTPUT";
|
||||
const QUALITY_PLACEHOLDER = "QUALITY";
|
||||
|
||||
const MAX_QUALITY = 70;
|
||||
const MIN_QUALITY = 50;
|
||||
|
||||
const SIPS_HEIC_CONVERT_COMMAND_TEMPLATE = [
|
||||
'sips',
|
||||
'-s',
|
||||
'format',
|
||||
'jpeg',
|
||||
"sips",
|
||||
"-s",
|
||||
"format",
|
||||
"jpeg",
|
||||
INPUT_PATH_PLACEHOLDER,
|
||||
'--out',
|
||||
"--out",
|
||||
OUTPUT_PATH_PLACEHOLDER,
|
||||
];
|
||||
|
||||
const SIPS_THUMBNAIL_GENERATE_COMMAND_TEMPLATE = [
|
||||
'sips',
|
||||
'-s',
|
||||
'format',
|
||||
'jpeg',
|
||||
'-s',
|
||||
'formatOptions',
|
||||
"sips",
|
||||
"-s",
|
||||
"format",
|
||||
"jpeg",
|
||||
"-s",
|
||||
"formatOptions",
|
||||
QUALITY_PLACEHOLDER,
|
||||
'-Z',
|
||||
"-Z",
|
||||
MAX_DIMENSION_PLACEHOLDER,
|
||||
INPUT_PATH_PLACEHOLDER,
|
||||
'--out',
|
||||
"--out",
|
||||
OUTPUT_PATH_PLACEHOLDER,
|
||||
];
|
||||
|
||||
const IMAGEMAGICK_HEIC_CONVERT_COMMAND_TEMPLATE = [
|
||||
IMAGE_MAGICK_PLACEHOLDER,
|
||||
INPUT_PATH_PLACEHOLDER,
|
||||
'-quality',
|
||||
'100%',
|
||||
"-quality",
|
||||
"100%",
|
||||
OUTPUT_PATH_PLACEHOLDER,
|
||||
];
|
||||
|
||||
const IMAGE_MAGICK_THUMBNAIL_GENERATE_COMMAND_TEMPLATE = [
|
||||
IMAGE_MAGICK_PLACEHOLDER,
|
||||
'-auto-orient',
|
||||
'-define',
|
||||
"-auto-orient",
|
||||
"-define",
|
||||
`jpeg:size=${SAMPLE_SIZE_PLACEHOLDER}x${SAMPLE_SIZE_PLACEHOLDER}`,
|
||||
INPUT_PATH_PLACEHOLDER,
|
||||
'-thumbnail',
|
||||
"-thumbnail",
|
||||
`${MAX_DIMENSION_PLACEHOLDER}x${MAX_DIMENSION_PLACEHOLDER}>`,
|
||||
'-unsharp',
|
||||
'0x.5',
|
||||
'-quality',
|
||||
"-unsharp",
|
||||
"0x.5",
|
||||
"-quality",
|
||||
QUALITY_PLACEHOLDER,
|
||||
OUTPUT_PATH_PLACEHOLDER,
|
||||
];
|
||||
|
||||
function getImageMagickStaticPath() {
|
||||
return isDev
|
||||
? 'build/image-magick'
|
||||
: path.join(process.resourcesPath, 'image-magick');
|
||||
? "build/image-magick"
|
||||
: path.join(process.resourcesPath, "image-magick");
|
||||
}
|
||||
|
||||
export async function convertToJPEG(
|
||||
|
@ -86,32 +86,32 @@ export async function convertToJPEG(
|
|||
let tempOutputFilePath: string;
|
||||
try {
|
||||
tempInputFilePath = await generateTempFilePath(filename);
|
||||
tempOutputFilePath = await generateTempFilePath('output.jpeg');
|
||||
tempOutputFilePath = await generateTempFilePath("output.jpeg");
|
||||
|
||||
await writeFile(tempInputFilePath, fileData);
|
||||
|
||||
await runConvertCommand(tempInputFilePath, tempOutputFilePath);
|
||||
|
||||
if (!existsSync(tempOutputFilePath)) {
|
||||
throw new Error('heic convert output file not found');
|
||||
throw new Error("heic convert output file not found");
|
||||
}
|
||||
const convertedFileData = new Uint8Array(
|
||||
await readFile(tempOutputFilePath)
|
||||
);
|
||||
return convertedFileData;
|
||||
} catch (e) {
|
||||
logErrorSentry(e, 'failed to convert heic');
|
||||
logErrorSentry(e, "failed to convert heic");
|
||||
throw e;
|
||||
} finally {
|
||||
try {
|
||||
rmSync(tempInputFilePath, { force: true });
|
||||
} catch (e) {
|
||||
logErrorSentry(e, 'failed to remove tempInputFile');
|
||||
logErrorSentry(e, "failed to remove tempInputFile");
|
||||
}
|
||||
try {
|
||||
rmSync(tempOutputFilePath, { force: true });
|
||||
} catch (e) {
|
||||
logErrorSentry(e, 'failed to remove tempOutputFile');
|
||||
logErrorSentry(e, "failed to remove tempOutputFile");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ async function runConvertCommand(
|
|||
tempOutputFilePath
|
||||
);
|
||||
const escapedCmd = shellescape(convertCmd);
|
||||
log.info('running convert command: ' + escapedCmd);
|
||||
log.info("running convert command: " + escapedCmd);
|
||||
await asyncExec(escapedCmd);
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ function constructConvertCommand(
|
|||
tempOutputFilePath: string
|
||||
) {
|
||||
let convertCmd: string[];
|
||||
if (isPlatform('mac')) {
|
||||
if (isPlatform("mac")) {
|
||||
convertCmd = SIPS_HEIC_CONVERT_COMMAND_TEMPLATE.map((cmdPart) => {
|
||||
if (cmdPart === INPUT_PATH_PLACEHOLDER) {
|
||||
return tempInputFilePath;
|
||||
|
@ -144,7 +144,7 @@ function constructConvertCommand(
|
|||
}
|
||||
return cmdPart;
|
||||
});
|
||||
} else if (isPlatform('linux')) {
|
||||
} else if (isPlatform("linux")) {
|
||||
convertCmd = IMAGEMAGICK_HEIC_CONVERT_COMMAND_TEMPLATE.map(
|
||||
(cmdPart) => {
|
||||
if (cmdPart === IMAGE_MAGICK_PLACEHOLDER) {
|
||||
|
@ -173,7 +173,7 @@ export async function generateImageThumbnail(
|
|||
let tempOutputFilePath: string;
|
||||
let quality = MAX_QUALITY;
|
||||
try {
|
||||
tempOutputFilePath = await generateTempFilePath('thumb.jpeg');
|
||||
tempOutputFilePath = await generateTempFilePath("thumb.jpeg");
|
||||
let thumbnail: Uint8Array;
|
||||
do {
|
||||
await runThumbnailGenerationCommand(
|
||||
|
@ -184,20 +184,20 @@ export async function generateImageThumbnail(
|
|||
);
|
||||
|
||||
if (!existsSync(tempOutputFilePath)) {
|
||||
throw new Error('output thumbnail file not found');
|
||||
throw new Error("output thumbnail file not found");
|
||||
}
|
||||
thumbnail = new Uint8Array(await readFile(tempOutputFilePath));
|
||||
quality -= 10;
|
||||
} while (thumbnail.length > maxSize && quality > MIN_QUALITY);
|
||||
return thumbnail;
|
||||
} catch (e) {
|
||||
logErrorSentry(e, 'generate image thumbnail failed');
|
||||
logErrorSentry(e, "generate image thumbnail failed");
|
||||
throw e;
|
||||
} finally {
|
||||
try {
|
||||
rmSync(tempOutputFilePath, { force: true });
|
||||
} catch (e) {
|
||||
logErrorSentry(e, 'failed to remove tempOutputFile');
|
||||
logErrorSentry(e, "failed to remove tempOutputFile");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -216,7 +216,7 @@ async function runThumbnailGenerationCommand(
|
|||
quality
|
||||
);
|
||||
const escapedCmd = shellescape(thumbnailGenerationCmd);
|
||||
log.info('running thumbnail generation command: ' + escapedCmd);
|
||||
log.info("running thumbnail generation command: " + escapedCmd);
|
||||
await asyncExec(escapedCmd);
|
||||
}
|
||||
function constructThumbnailGenerationCommand(
|
||||
|
@ -226,7 +226,7 @@ function constructThumbnailGenerationCommand(
|
|||
quality: number
|
||||
) {
|
||||
let thumbnailGenerationCmd: string[];
|
||||
if (isPlatform('mac')) {
|
||||
if (isPlatform("mac")) {
|
||||
thumbnailGenerationCmd = SIPS_THUMBNAIL_GENERATE_COMMAND_TEMPLATE.map(
|
||||
(cmdPart) => {
|
||||
if (cmdPart === INPUT_PATH_PLACEHOLDER) {
|
||||
|
@ -244,7 +244,7 @@ function constructThumbnailGenerationCommand(
|
|||
return cmdPart;
|
||||
}
|
||||
);
|
||||
} else if (isPlatform('linux')) {
|
||||
} else if (isPlatform("linux")) {
|
||||
thumbnailGenerationCmd =
|
||||
IMAGE_MAGICK_THUMBNAIL_GENERATE_COMMAND_TEMPLATE.map((cmdPart) => {
|
||||
if (cmdPart === IMAGE_MAGICK_PLACEHOLDER) {
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
import log from 'electron-log';
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { ipcRenderer } from "electron";
|
||||
import log from "electron-log";
|
||||
|
||||
export function logToDisk(logLine: string) {
|
||||
log.info(logLine);
|
||||
}
|
||||
|
||||
export function openLogDirectory() {
|
||||
ipcRenderer.invoke('open-log-dir');
|
||||
ipcRenderer.invoke("open-log-dir");
|
||||
}
|
||||
|
||||
export function logError(error: Error, message: string, info?: string): void {
|
||||
ipcRenderer.invoke('log-error', error, message, info);
|
||||
ipcRenderer.invoke("log-error", error, message, info);
|
||||
}
|
||||
|
||||
export function getSentryUserID(): Promise<string> {
|
||||
return ipcRenderer.invoke('get-sentry-id');
|
||||
return ipcRenderer.invoke("get-sentry-id");
|
||||
}
|
||||
|
||||
export function updateOptOutOfCrashReports(optOut: boolean) {
|
||||
return ipcRenderer.invoke('update-opt-out-crash-reports', optOut);
|
||||
return ipcRenderer.invoke("update-opt-out-crash-reports", optOut);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import * as Sentry from '@sentry/electron/dist/main';
|
||||
import { makeID } from '../utils/logging';
|
||||
import { keysStore } from '../stores/keys.store';
|
||||
import { SENTRY_DSN, RELEASE_VERSION } from '../config';
|
||||
import { isDev } from '../utils/common';
|
||||
import { logToDisk } from './logging';
|
||||
import { hasOptedOutOfCrashReports } from '../main';
|
||||
import * as Sentry from "@sentry/electron/dist/main";
|
||||
import { RELEASE_VERSION, SENTRY_DSN } from "../config";
|
||||
import { hasOptedOutOfCrashReports } from "../main";
|
||||
import { keysStore } from "../stores/keys.store";
|
||||
import { isDev } from "../utils/common";
|
||||
import { makeID } from "../utils/logging";
|
||||
import { logToDisk } from "./logging";
|
||||
|
||||
const ENV_DEVELOPMENT = 'development';
|
||||
const ENV_DEVELOPMENT = "development";
|
||||
|
||||
const isDEVSentryENV = () =>
|
||||
process.env.NEXT_PUBLIC_SENTRY_ENV === ENV_DEVELOPMENT;
|
||||
|
@ -15,7 +15,7 @@ export function initSentry(): void {
|
|||
Sentry.init({
|
||||
dsn: SENTRY_DSN,
|
||||
release: RELEASE_VERSION,
|
||||
environment: isDev ? 'development' : 'production',
|
||||
environment: isDev ? "development" : "production",
|
||||
});
|
||||
Sentry.setUser({ id: getSentryUserID() });
|
||||
}
|
||||
|
@ -52,17 +52,17 @@ export function logErrorSentry(
|
|||
function errorWithContext(originalError: Error, context: string) {
|
||||
const errorWithContext = new Error(context);
|
||||
errorWithContext.stack =
|
||||
errorWithContext.stack.split('\n').slice(2, 4).join('\n') +
|
||||
'\n' +
|
||||
errorWithContext.stack.split("\n").slice(2, 4).join("\n") +
|
||||
"\n" +
|
||||
originalError.stack;
|
||||
return errorWithContext;
|
||||
}
|
||||
|
||||
export function getSentryUserID() {
|
||||
let anonymizeUserID = keysStore.get('AnonymizeUserID')?.id;
|
||||
let anonymizeUserID = keysStore.get("AnonymizeUserID")?.id;
|
||||
if (!anonymizeUserID) {
|
||||
anonymizeUserID = makeID(6);
|
||||
keysStore.set('AnonymizeUserID', { id: anonymizeUserID });
|
||||
keysStore.set("AnonymizeUserID", { id: anonymizeUserID });
|
||||
}
|
||||
return anonymizeUserID;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import StreamZip from 'node-stream-zip';
|
||||
import path from 'path';
|
||||
import { uploadStatusStore } from '../stores/upload.store';
|
||||
import { FILE_PATH_TYPE, FILE_PATH_KEYS, ElectronFile } from '../types';
|
||||
import { getValidPaths, getZipFileStream } from './fs';
|
||||
import StreamZip from "node-stream-zip";
|
||||
import path from "path";
|
||||
import { uploadStatusStore } from "../stores/upload.store";
|
||||
import { ElectronFile, FILE_PATH_KEYS, FILE_PATH_TYPE } from "../types";
|
||||
import { getValidPaths, getZipFileStream } from "./fs";
|
||||
|
||||
export const getSavedFilePaths = (type: FILE_PATH_TYPE) => {
|
||||
const paths =
|
||||
|
@ -52,9 +52,9 @@ export const setToUploadFiles = (type: FILE_PATH_TYPE, filePaths: string[]) => {
|
|||
|
||||
export const setToUploadCollection = (collectionName: string) => {
|
||||
if (collectionName) {
|
||||
uploadStatusStore.set('collectionName', collectionName);
|
||||
uploadStatusStore.set("collectionName", collectionName);
|
||||
} else {
|
||||
uploadStatusStore.delete('collectionName');
|
||||
uploadStatusStore.delete("collectionName");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -62,14 +62,14 @@ export const getElectronFilesFromGoogleZip = async (filePath: string) => {
|
|||
const zip = new StreamZip.async({
|
||||
file: filePath,
|
||||
});
|
||||
const zipName = path.basename(filePath, '.zip');
|
||||
const zipName = path.basename(filePath, ".zip");
|
||||
|
||||
const entries = await zip.entries();
|
||||
const files: ElectronFile[] = [];
|
||||
|
||||
for (const entry of Object.values(entries)) {
|
||||
const basename = path.basename(entry.name);
|
||||
if (entry.isFile && basename.length > 0 && basename[0] !== '.') {
|
||||
if (entry.isFile && basename.length > 0 && basename[0] !== ".") {
|
||||
files.push(await getZipEntryAsElectronFile(zipName, zip, entry));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,49 +1,49 @@
|
|||
import { userPreferencesStore } from '../stores/userPreferences.store';
|
||||
import { userPreferencesStore } from "../stores/userPreferences.store";
|
||||
|
||||
export function getHideDockIconPreference() {
|
||||
return userPreferencesStore.get('hideDockIcon');
|
||||
return userPreferencesStore.get("hideDockIcon");
|
||||
}
|
||||
|
||||
export function setHideDockIconPreference(shouldHideDockIcon: boolean) {
|
||||
userPreferencesStore.set('hideDockIcon', shouldHideDockIcon);
|
||||
userPreferencesStore.set("hideDockIcon", shouldHideDockIcon);
|
||||
}
|
||||
|
||||
export function getSkipAppVersion() {
|
||||
return userPreferencesStore.get('skipAppVersion');
|
||||
return userPreferencesStore.get("skipAppVersion");
|
||||
}
|
||||
|
||||
export function setSkipAppVersion(version: string) {
|
||||
userPreferencesStore.set('skipAppVersion', version);
|
||||
userPreferencesStore.set("skipAppVersion", version);
|
||||
}
|
||||
|
||||
export function getMuteUpdateNotificationVersion() {
|
||||
return userPreferencesStore.get('muteUpdateNotificationVersion');
|
||||
return userPreferencesStore.get("muteUpdateNotificationVersion");
|
||||
}
|
||||
|
||||
export function setMuteUpdateNotificationVersion(version: string) {
|
||||
userPreferencesStore.set('muteUpdateNotificationVersion', version);
|
||||
userPreferencesStore.set("muteUpdateNotificationVersion", version);
|
||||
}
|
||||
|
||||
export function getOptOutOfCrashReports() {
|
||||
return userPreferencesStore.get('optOutOfCrashReports') ?? false;
|
||||
return userPreferencesStore.get("optOutOfCrashReports") ?? false;
|
||||
}
|
||||
|
||||
export function setOptOutOfCrashReports(optOut: boolean) {
|
||||
userPreferencesStore.set('optOutOfCrashReports', optOut);
|
||||
userPreferencesStore.set("optOutOfCrashReports", optOut);
|
||||
}
|
||||
|
||||
export function clearSkipAppVersion() {
|
||||
userPreferencesStore.delete('skipAppVersion');
|
||||
userPreferencesStore.delete("skipAppVersion");
|
||||
}
|
||||
|
||||
export function clearMuteUpdateNotificationVersion() {
|
||||
userPreferencesStore.delete('muteUpdateNotificationVersion');
|
||||
userPreferencesStore.delete("muteUpdateNotificationVersion");
|
||||
}
|
||||
|
||||
export function setCustomCacheDirectory(directory: string) {
|
||||
userPreferencesStore.set('customCacheDirectory', directory);
|
||||
userPreferencesStore.set("customCacheDirectory", directory);
|
||||
}
|
||||
|
||||
export function getCustomCacheDirectory(): string {
|
||||
return userPreferencesStore.get('customCacheDirectory');
|
||||
return userPreferencesStore.get("customCacheDirectory");
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { WatchStoreType } from '../types';
|
||||
import { watchStore } from '../stores/watch.store';
|
||||
import { watchStore } from "../stores/watch.store";
|
||||
import { WatchStoreType } from "../types";
|
||||
|
||||
export function getWatchMappings() {
|
||||
const mappings = watchStore.get('mappings') ?? [];
|
||||
const mappings = watchStore.get("mappings") ?? [];
|
||||
return mappings;
|
||||
}
|
||||
|
||||
export function setWatchMappings(watchMappings: WatchStoreType['mappings']) {
|
||||
watchStore.set('mappings', watchMappings);
|
||||
export function setWatchMappings(watchMappings: WatchStoreType["mappings"]) {
|
||||
watchStore.set("mappings", watchMappings);
|
||||
}
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
import Store, { Schema } from 'electron-store';
|
||||
import { KeysStoreType } from '../types';
|
||||
import Store, { Schema } from "electron-store";
|
||||
import { KeysStoreType } from "../types";
|
||||
|
||||
const keysStoreSchema: Schema<KeysStoreType> = {
|
||||
AnonymizeUserID: {
|
||||
type: 'object',
|
||||
type: "object",
|
||||
properties: {
|
||||
id: {
|
||||
type: 'string',
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const keysStore = new Store({
|
||||
name: 'keys',
|
||||
name: "keys",
|
||||
schema: keysStoreSchema,
|
||||
});
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import Store, { Schema } from 'electron-store';
|
||||
import { SafeStorageStoreType } from '../types';
|
||||
import Store, { Schema } from "electron-store";
|
||||
import { SafeStorageStoreType } from "../types";
|
||||
|
||||
const safeStorageSchema: Schema<SafeStorageStoreType> = {
|
||||
encryptionKey: {
|
||||
type: 'string',
|
||||
type: "string",
|
||||
},
|
||||
};
|
||||
|
||||
export const safeStorageStore = new Store({
|
||||
name: 'safeStorage',
|
||||
name: "safeStorage",
|
||||
schema: safeStorageSchema,
|
||||
});
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
import Store, { Schema } from 'electron-store';
|
||||
import { UploadStoreType } from '../types';
|
||||
import Store, { Schema } from "electron-store";
|
||||
import { UploadStoreType } from "../types";
|
||||
|
||||
const uploadStoreSchema: Schema<UploadStoreType> = {
|
||||
filePaths: {
|
||||
type: 'array',
|
||||
type: "array",
|
||||
items: {
|
||||
type: 'string',
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
zipPaths: {
|
||||
type: 'array',
|
||||
type: "array",
|
||||
items: {
|
||||
type: 'string',
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
collectionName: {
|
||||
type: 'string',
|
||||
type: "string",
|
||||
},
|
||||
};
|
||||
|
||||
export const uploadStatusStore = new Store({
|
||||
name: 'upload-status',
|
||||
name: "upload-status",
|
||||
schema: uploadStoreSchema,
|
||||
});
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
import Store, { Schema } from 'electron-store';
|
||||
import { UserPreferencesType } from '../types';
|
||||
import Store, { Schema } from "electron-store";
|
||||
import { UserPreferencesType } from "../types";
|
||||
|
||||
const userPreferencesSchema: Schema<UserPreferencesType> = {
|
||||
hideDockIcon: {
|
||||
type: 'boolean',
|
||||
type: "boolean",
|
||||
},
|
||||
skipAppVersion: {
|
||||
type: 'string',
|
||||
type: "string",
|
||||
},
|
||||
muteUpdateNotificationVersion: {
|
||||
type: 'string',
|
||||
type: "string",
|
||||
},
|
||||
optOutOfCrashReports: {
|
||||
type: 'boolean',
|
||||
type: "boolean",
|
||||
},
|
||||
customCacheDirectory: {
|
||||
type: 'string',
|
||||
type: "string",
|
||||
},
|
||||
};
|
||||
|
||||
export const userPreferencesStore = new Store({
|
||||
name: 'userPreferences',
|
||||
name: "userPreferences",
|
||||
schema: userPreferencesSchema,
|
||||
});
|
||||
|
|
|
@ -1,39 +1,39 @@
|
|||
import Store, { Schema } from 'electron-store';
|
||||
import { WatchStoreType } from '../types';
|
||||
import Store, { Schema } from "electron-store";
|
||||
import { WatchStoreType } from "../types";
|
||||
|
||||
const watchStoreSchema: Schema<WatchStoreType> = {
|
||||
mappings: {
|
||||
type: 'array',
|
||||
type: "array",
|
||||
items: {
|
||||
type: 'object',
|
||||
type: "object",
|
||||
properties: {
|
||||
rootFolderName: {
|
||||
type: 'string',
|
||||
type: "string",
|
||||
},
|
||||
uploadStrategy: {
|
||||
type: 'number',
|
||||
type: "number",
|
||||
},
|
||||
folderPath: {
|
||||
type: 'string',
|
||||
type: "string",
|
||||
},
|
||||
syncedFiles: {
|
||||
type: 'array',
|
||||
type: "array",
|
||||
items: {
|
||||
type: 'object',
|
||||
type: "object",
|
||||
properties: {
|
||||
path: {
|
||||
type: 'string',
|
||||
type: "string",
|
||||
},
|
||||
id: {
|
||||
type: 'number',
|
||||
type: "number",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
ignoredFiles: {
|
||||
type: 'array',
|
||||
type: "array",
|
||||
items: {
|
||||
type: 'string',
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -42,6 +42,6 @@ const watchStoreSchema: Schema<WatchStoreType> = {
|
|||
};
|
||||
|
||||
export const watchStore = new Store({
|
||||
name: 'watch-status',
|
||||
name: "watch-status",
|
||||
schema: watchStoreSchema,
|
||||
});
|
||||
|
|
|
@ -39,15 +39,15 @@ export interface WatchStoreType {
|
|||
}
|
||||
|
||||
export enum FILE_PATH_TYPE {
|
||||
FILES = 'files',
|
||||
ZIPS = 'zips',
|
||||
FILES = "files",
|
||||
ZIPS = "zips",
|
||||
}
|
||||
|
||||
export const FILE_PATH_KEYS: {
|
||||
[k in FILE_PATH_TYPE]: keyof UploadStoreType;
|
||||
} = {
|
||||
[FILE_PATH_TYPE.ZIPS]: 'zipPaths',
|
||||
[FILE_PATH_TYPE.FILES]: 'filePaths',
|
||||
[FILE_PATH_TYPE.ZIPS]: "zipPaths",
|
||||
[FILE_PATH_TYPE.FILES]: "filePaths",
|
||||
};
|
||||
|
||||
export interface SafeStorageStoreType {
|
||||
|
@ -72,6 +72,6 @@ export interface GetFeatureFlagResponse {
|
|||
}
|
||||
|
||||
export enum Model {
|
||||
GGML_CLIP = 'ggml-clip',
|
||||
ONNX_CLIP = 'onnx-clip',
|
||||
GGML_CLIP = "ggml-clip",
|
||||
ONNX_CLIP = "onnx-clip",
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as htmlEntities from 'html-entities';
|
||||
import bpeVocabData from './bpe_simple_vocab_16e6';
|
||||
import * as htmlEntities from "html-entities";
|
||||
import bpeVocabData from "./bpe_simple_vocab_16e6";
|
||||
// import ftfy from "https://deno.land/x/ftfy_pyodide@v0.1.1/mod.js";
|
||||
|
||||
function ord(c: string) {
|
||||
|
@ -25,9 +25,9 @@ function range(start: number, stop?: number, step: number = 1) {
|
|||
|
||||
function bytesToUnicode() {
|
||||
const bs = [
|
||||
...range(ord('!'), ord('~') + 1),
|
||||
...range(ord('¡'), ord('¬') + 1),
|
||||
...range(ord('®'), ord('ÿ') + 1),
|
||||
...range(ord("!"), ord("~") + 1),
|
||||
...range(ord("¡"), ord("¬") + 1),
|
||||
...range(ord("®"), ord("ÿ") + 1),
|
||||
];
|
||||
const cs = bs.slice(0);
|
||||
let n = 0;
|
||||
|
@ -59,7 +59,7 @@ function basicClean(text: string) {
|
|||
}
|
||||
|
||||
function whitespaceClean(text: string) {
|
||||
return text.replace(/\s+/g, ' ').trim();
|
||||
return text.replace(/\s+/g, " ").trim();
|
||||
}
|
||||
|
||||
export default class {
|
||||
|
@ -77,283 +77,283 @@ export default class {
|
|||
this.byteDecoder = Object.fromEntries(
|
||||
Object.entries(this.byteEncoder).map(([k, v]) => [v, Number(k)])
|
||||
);
|
||||
let merges = bpeVocabData.text.split('\n');
|
||||
let merges = bpeVocabData.text.split("\n");
|
||||
merges = merges.slice(1, 49152 - 256 - 2 + 1);
|
||||
const mergedMerges = merges.map((merge) => merge.split(' '));
|
||||
const mergedMerges = merges.map((merge) => merge.split(" "));
|
||||
// There was a bug related to the ordering of Python's .values() output. I'm lazy do I've just copy-pasted the Python output:
|
||||
let vocab = [
|
||||
'!',
|
||||
"!",
|
||||
'"',
|
||||
'#',
|
||||
'$',
|
||||
'%',
|
||||
'&',
|
||||
"#",
|
||||
"$",
|
||||
"%",
|
||||
"&",
|
||||
"'",
|
||||
'(',
|
||||
')',
|
||||
'*',
|
||||
'+',
|
||||
',',
|
||||
'-',
|
||||
'.',
|
||||
'/',
|
||||
'0',
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
'4',
|
||||
'5',
|
||||
'6',
|
||||
'7',
|
||||
'8',
|
||||
'9',
|
||||
':',
|
||||
';',
|
||||
'<',
|
||||
'=',
|
||||
'>',
|
||||
'?',
|
||||
'@',
|
||||
'A',
|
||||
'B',
|
||||
'C',
|
||||
'D',
|
||||
'E',
|
||||
'F',
|
||||
'G',
|
||||
'H',
|
||||
'I',
|
||||
'J',
|
||||
'K',
|
||||
'L',
|
||||
'M',
|
||||
'N',
|
||||
'O',
|
||||
'P',
|
||||
'Q',
|
||||
'R',
|
||||
'S',
|
||||
'T',
|
||||
'U',
|
||||
'V',
|
||||
'W',
|
||||
'X',
|
||||
'Y',
|
||||
'Z',
|
||||
'[',
|
||||
'\\',
|
||||
']',
|
||||
'^',
|
||||
'_',
|
||||
'`',
|
||||
'a',
|
||||
'b',
|
||||
'c',
|
||||
'd',
|
||||
'e',
|
||||
'f',
|
||||
'g',
|
||||
'h',
|
||||
'i',
|
||||
'j',
|
||||
'k',
|
||||
'l',
|
||||
'm',
|
||||
'n',
|
||||
'o',
|
||||
'p',
|
||||
'q',
|
||||
'r',
|
||||
's',
|
||||
't',
|
||||
'u',
|
||||
'v',
|
||||
'w',
|
||||
'x',
|
||||
'y',
|
||||
'z',
|
||||
'{',
|
||||
'|',
|
||||
'}',
|
||||
'~',
|
||||
'¡',
|
||||
'¢',
|
||||
'£',
|
||||
'¤',
|
||||
'¥',
|
||||
'¦',
|
||||
'§',
|
||||
'¨',
|
||||
'©',
|
||||
'ª',
|
||||
'«',
|
||||
'¬',
|
||||
'®',
|
||||
'¯',
|
||||
'°',
|
||||
'±',
|
||||
'²',
|
||||
'³',
|
||||
'´',
|
||||
'µ',
|
||||
'¶',
|
||||
'·',
|
||||
'¸',
|
||||
'¹',
|
||||
'º',
|
||||
'»',
|
||||
'¼',
|
||||
'½',
|
||||
'¾',
|
||||
'¿',
|
||||
'À',
|
||||
'Á',
|
||||
'Â',
|
||||
'Ã',
|
||||
'Ä',
|
||||
'Å',
|
||||
'Æ',
|
||||
'Ç',
|
||||
'È',
|
||||
'É',
|
||||
'Ê',
|
||||
'Ë',
|
||||
'Ì',
|
||||
'Í',
|
||||
'Î',
|
||||
'Ï',
|
||||
'Ð',
|
||||
'Ñ',
|
||||
'Ò',
|
||||
'Ó',
|
||||
'Ô',
|
||||
'Õ',
|
||||
'Ö',
|
||||
'×',
|
||||
'Ø',
|
||||
'Ù',
|
||||
'Ú',
|
||||
'Û',
|
||||
'Ü',
|
||||
'Ý',
|
||||
'Þ',
|
||||
'ß',
|
||||
'à',
|
||||
'á',
|
||||
'â',
|
||||
'ã',
|
||||
'ä',
|
||||
'å',
|
||||
'æ',
|
||||
'ç',
|
||||
'è',
|
||||
'é',
|
||||
'ê',
|
||||
'ë',
|
||||
'ì',
|
||||
'í',
|
||||
'î',
|
||||
'ï',
|
||||
'ð',
|
||||
'ñ',
|
||||
'ò',
|
||||
'ó',
|
||||
'ô',
|
||||
'õ',
|
||||
'ö',
|
||||
'÷',
|
||||
'ø',
|
||||
'ù',
|
||||
'ú',
|
||||
'û',
|
||||
'ü',
|
||||
'ý',
|
||||
'þ',
|
||||
'ÿ',
|
||||
'Ā',
|
||||
'ā',
|
||||
'Ă',
|
||||
'ă',
|
||||
'Ą',
|
||||
'ą',
|
||||
'Ć',
|
||||
'ć',
|
||||
'Ĉ',
|
||||
'ĉ',
|
||||
'Ċ',
|
||||
'ċ',
|
||||
'Č',
|
||||
'č',
|
||||
'Ď',
|
||||
'ď',
|
||||
'Đ',
|
||||
'đ',
|
||||
'Ē',
|
||||
'ē',
|
||||
'Ĕ',
|
||||
'ĕ',
|
||||
'Ė',
|
||||
'ė',
|
||||
'Ę',
|
||||
'ę',
|
||||
'Ě',
|
||||
'ě',
|
||||
'Ĝ',
|
||||
'ĝ',
|
||||
'Ğ',
|
||||
'ğ',
|
||||
'Ġ',
|
||||
'ġ',
|
||||
'Ģ',
|
||||
'ģ',
|
||||
'Ĥ',
|
||||
'ĥ',
|
||||
'Ħ',
|
||||
'ħ',
|
||||
'Ĩ',
|
||||
'ĩ',
|
||||
'Ī',
|
||||
'ī',
|
||||
'Ĭ',
|
||||
'ĭ',
|
||||
'Į',
|
||||
'į',
|
||||
'İ',
|
||||
'ı',
|
||||
'IJ',
|
||||
'ij',
|
||||
'Ĵ',
|
||||
'ĵ',
|
||||
'Ķ',
|
||||
'ķ',
|
||||
'ĸ',
|
||||
'Ĺ',
|
||||
'ĺ',
|
||||
'Ļ',
|
||||
'ļ',
|
||||
'Ľ',
|
||||
'ľ',
|
||||
'Ŀ',
|
||||
'ŀ',
|
||||
'Ł',
|
||||
'ł',
|
||||
'Ń',
|
||||
"(",
|
||||
")",
|
||||
"*",
|
||||
"+",
|
||||
",",
|
||||
"-",
|
||||
".",
|
||||
"/",
|
||||
"0",
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9",
|
||||
":",
|
||||
";",
|
||||
"<",
|
||||
"=",
|
||||
">",
|
||||
"?",
|
||||
"@",
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F",
|
||||
"G",
|
||||
"H",
|
||||
"I",
|
||||
"J",
|
||||
"K",
|
||||
"L",
|
||||
"M",
|
||||
"N",
|
||||
"O",
|
||||
"P",
|
||||
"Q",
|
||||
"R",
|
||||
"S",
|
||||
"T",
|
||||
"U",
|
||||
"V",
|
||||
"W",
|
||||
"X",
|
||||
"Y",
|
||||
"Z",
|
||||
"[",
|
||||
"\\",
|
||||
"]",
|
||||
"^",
|
||||
"_",
|
||||
"`",
|
||||
"a",
|
||||
"b",
|
||||
"c",
|
||||
"d",
|
||||
"e",
|
||||
"f",
|
||||
"g",
|
||||
"h",
|
||||
"i",
|
||||
"j",
|
||||
"k",
|
||||
"l",
|
||||
"m",
|
||||
"n",
|
||||
"o",
|
||||
"p",
|
||||
"q",
|
||||
"r",
|
||||
"s",
|
||||
"t",
|
||||
"u",
|
||||
"v",
|
||||
"w",
|
||||
"x",
|
||||
"y",
|
||||
"z",
|
||||
"{",
|
||||
"|",
|
||||
"}",
|
||||
"~",
|
||||
"¡",
|
||||
"¢",
|
||||
"£",
|
||||
"¤",
|
||||
"¥",
|
||||
"¦",
|
||||
"§",
|
||||
"¨",
|
||||
"©",
|
||||
"ª",
|
||||
"«",
|
||||
"¬",
|
||||
"®",
|
||||
"¯",
|
||||
"°",
|
||||
"±",
|
||||
"²",
|
||||
"³",
|
||||
"´",
|
||||
"µ",
|
||||
"¶",
|
||||
"·",
|
||||
"¸",
|
||||
"¹",
|
||||
"º",
|
||||
"»",
|
||||
"¼",
|
||||
"½",
|
||||
"¾",
|
||||
"¿",
|
||||
"À",
|
||||
"Á",
|
||||
"Â",
|
||||
"Ã",
|
||||
"Ä",
|
||||
"Å",
|
||||
"Æ",
|
||||
"Ç",
|
||||
"È",
|
||||
"É",
|
||||
"Ê",
|
||||
"Ë",
|
||||
"Ì",
|
||||
"Í",
|
||||
"Î",
|
||||
"Ï",
|
||||
"Ð",
|
||||
"Ñ",
|
||||
"Ò",
|
||||
"Ó",
|
||||
"Ô",
|
||||
"Õ",
|
||||
"Ö",
|
||||
"×",
|
||||
"Ø",
|
||||
"Ù",
|
||||
"Ú",
|
||||
"Û",
|
||||
"Ü",
|
||||
"Ý",
|
||||
"Þ",
|
||||
"ß",
|
||||
"à",
|
||||
"á",
|
||||
"â",
|
||||
"ã",
|
||||
"ä",
|
||||
"å",
|
||||
"æ",
|
||||
"ç",
|
||||
"è",
|
||||
"é",
|
||||
"ê",
|
||||
"ë",
|
||||
"ì",
|
||||
"í",
|
||||
"î",
|
||||
"ï",
|
||||
"ð",
|
||||
"ñ",
|
||||
"ò",
|
||||
"ó",
|
||||
"ô",
|
||||
"õ",
|
||||
"ö",
|
||||
"÷",
|
||||
"ø",
|
||||
"ù",
|
||||
"ú",
|
||||
"û",
|
||||
"ü",
|
||||
"ý",
|
||||
"þ",
|
||||
"ÿ",
|
||||
"Ā",
|
||||
"ā",
|
||||
"Ă",
|
||||
"ă",
|
||||
"Ą",
|
||||
"ą",
|
||||
"Ć",
|
||||
"ć",
|
||||
"Ĉ",
|
||||
"ĉ",
|
||||
"Ċ",
|
||||
"ċ",
|
||||
"Č",
|
||||
"č",
|
||||
"Ď",
|
||||
"ď",
|
||||
"Đ",
|
||||
"đ",
|
||||
"Ē",
|
||||
"ē",
|
||||
"Ĕ",
|
||||
"ĕ",
|
||||
"Ė",
|
||||
"ė",
|
||||
"Ę",
|
||||
"ę",
|
||||
"Ě",
|
||||
"ě",
|
||||
"Ĝ",
|
||||
"ĝ",
|
||||
"Ğ",
|
||||
"ğ",
|
||||
"Ġ",
|
||||
"ġ",
|
||||
"Ģ",
|
||||
"ģ",
|
||||
"Ĥ",
|
||||
"ĥ",
|
||||
"Ħ",
|
||||
"ħ",
|
||||
"Ĩ",
|
||||
"ĩ",
|
||||
"Ī",
|
||||
"ī",
|
||||
"Ĭ",
|
||||
"ĭ",
|
||||
"Į",
|
||||
"į",
|
||||
"İ",
|
||||
"ı",
|
||||
"IJ",
|
||||
"ij",
|
||||
"Ĵ",
|
||||
"ĵ",
|
||||
"Ķ",
|
||||
"ķ",
|
||||
"ĸ",
|
||||
"Ĺ",
|
||||
"ĺ",
|
||||
"Ļ",
|
||||
"ļ",
|
||||
"Ľ",
|
||||
"ľ",
|
||||
"Ŀ",
|
||||
"ŀ",
|
||||
"Ł",
|
||||
"ł",
|
||||
"Ń",
|
||||
];
|
||||
vocab = [...vocab, ...vocab.map((v) => v + '</w>')];
|
||||
vocab = [...vocab, ...vocab.map((v) => v + "</w>")];
|
||||
for (const merge of mergedMerges) {
|
||||
vocab.push(merge.join(''));
|
||||
vocab.push(merge.join(""));
|
||||
}
|
||||
vocab.push('<|startoftext|>', '<|endoftext|>');
|
||||
vocab.push("<|startoftext|>", "<|endoftext|>");
|
||||
this.encoder = Object.fromEntries(vocab.map((v, i) => [v, i]));
|
||||
this.decoder = Object.fromEntries(
|
||||
Object.entries(this.encoder).map(([k, v]) => [v, k])
|
||||
);
|
||||
this.bpeRanks = Object.fromEntries(
|
||||
mergedMerges.map((v, i) => [v.join('·😎·'), i])
|
||||
mergedMerges.map((v, i) => [v.join("·😎·"), i])
|
||||
); // ·😎· because js doesn't yet have tuples
|
||||
this.cache = {
|
||||
'<|startoftext|>': '<|startoftext|>',
|
||||
'<|endoftext|>': '<|endoftext|>',
|
||||
"<|startoftext|>": "<|startoftext|>",
|
||||
"<|endoftext|>": "<|endoftext|>",
|
||||
};
|
||||
this.pat =
|
||||
/<\|startoftext\|>|<\|endoftext\|>|'s|'t|'re|'ve|'m|'ll|'d|[\p{L}]+|[\p{N}]|[^\s\p{L}\p{N}]+/giu;
|
||||
|
@ -364,11 +364,11 @@ export default class {
|
|||
return this.cache[token];
|
||||
}
|
||||
|
||||
let word = [...token.slice(0, -1), token.slice(-1) + '</w>'];
|
||||
let word = [...token.slice(0, -1), token.slice(-1) + "</w>"];
|
||||
let pairs = getPairs(word);
|
||||
|
||||
if (pairs.length === 0) {
|
||||
return token + '</w>';
|
||||
return token + "</w>";
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
|
@ -376,7 +376,7 @@ export default class {
|
|||
let bigram: [string, string] | null = null;
|
||||
let minRank = Infinity;
|
||||
for (const p of pairs) {
|
||||
const r = this.bpeRanks[p.join('·😎·')];
|
||||
const r = this.bpeRanks[p.join("·😎·")];
|
||||
if (r === undefined) continue;
|
||||
if (r < minRank) {
|
||||
minRank = r;
|
||||
|
@ -421,7 +421,7 @@ export default class {
|
|||
pairs = getPairs(word);
|
||||
}
|
||||
}
|
||||
const joinedWord = word.join(' ');
|
||||
const joinedWord = word.join(" ");
|
||||
this.cache[token] = joinedWord;
|
||||
return joinedWord;
|
||||
}
|
||||
|
@ -432,10 +432,10 @@ export default class {
|
|||
for (let token of [...text.matchAll(this.pat)].map((m) => m[0])) {
|
||||
token = [...token]
|
||||
.map((b) => this.byteEncoder[b.charCodeAt(0) as number])
|
||||
.join('');
|
||||
.join("");
|
||||
bpeTokens.push(
|
||||
...this.bpe(token)
|
||||
.split(' ')
|
||||
.split(" ")
|
||||
.map((bpeToken: string) => this.encoder[bpeToken])
|
||||
);
|
||||
}
|
||||
|
@ -455,12 +455,12 @@ export default class {
|
|||
decode(tokens: any[]) {
|
||||
let text = tokens
|
||||
.map((token: string | number) => this.decoder[token])
|
||||
.join('');
|
||||
.join("");
|
||||
text = [...text]
|
||||
.map((c) => this.byteDecoder[c])
|
||||
.map((v) => String.fromCharCode(v))
|
||||
.join('')
|
||||
.replace(/<\/w>/g, ' ');
|
||||
.join("")
|
||||
.replace(/<\/w>/g, " ");
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { CustomErrors } from '../../constants/errors';
|
||||
import { app } from 'electron';
|
||||
import { app } from "electron";
|
||||
import { CustomErrors } from "../../constants/errors";
|
||||
export const isDev = !app.isPackaged;
|
||||
|
||||
export const promiseWithTimeout = async <T>(
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
export function isPlatform(platform: 'mac' | 'windows' | 'linux') {
|
||||
export function isPlatform(platform: "mac" | "windows" | "linux") {
|
||||
return getPlatform() === platform;
|
||||
}
|
||||
|
||||
export function getPlatform(): 'mac' | 'windows' | 'linux' {
|
||||
export function getPlatform(): "mac" | "windows" | "linux" {
|
||||
switch (process.platform) {
|
||||
case 'aix':
|
||||
case 'freebsd':
|
||||
case 'linux':
|
||||
case 'openbsd':
|
||||
case 'android':
|
||||
return 'linux';
|
||||
case 'darwin':
|
||||
case 'sunos':
|
||||
return 'mac';
|
||||
case 'win32':
|
||||
return 'windows';
|
||||
case "aix":
|
||||
case "freebsd":
|
||||
case "linux":
|
||||
case "openbsd":
|
||||
case "android":
|
||||
return "linux";
|
||||
case "darwin":
|
||||
case "sunos":
|
||||
return "mac";
|
||||
case "win32":
|
||||
return "windows";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { BrowserWindow } from 'electron';
|
||||
import { BrowserWindow } from "electron";
|
||||
|
||||
function lowerCaseHeaders(responseHeaders: Record<string, string[]>) {
|
||||
const headers: Record<string, string[]> = {};
|
||||
|
@ -12,7 +12,7 @@ export function addAllowOriginHeader(mainWindow: BrowserWindow) {
|
|||
mainWindow.webContents.session.webRequest.onHeadersReceived(
|
||||
(details, callback) => {
|
||||
details.responseHeaders = lowerCaseHeaders(details.responseHeaders);
|
||||
details.responseHeaders['access-control-allow-origin'] = ['*'];
|
||||
details.responseHeaders["access-control-allow-origin"] = ["*"];
|
||||
callback({
|
||||
responseHeaders: details.responseHeaders,
|
||||
});
|
||||
|
|
|
@ -1,37 +1,37 @@
|
|||
import { app, BrowserWindow, nativeImage } from 'electron';
|
||||
import * as path from 'path';
|
||||
import { isDev } from './common';
|
||||
import { isAppQuitting } from '../main';
|
||||
import { PROD_HOST_URL } from '../config';
|
||||
import { isPlatform } from './common/platform';
|
||||
import { getHideDockIconPreference } from '../services/userPreference';
|
||||
import autoLauncher from '../services/autoLauncher';
|
||||
import ElectronLog from 'electron-log';
|
||||
import { logErrorSentry } from '../services/sentry';
|
||||
import { app, BrowserWindow, nativeImage } from "electron";
|
||||
import ElectronLog from "electron-log";
|
||||
import * as path from "path";
|
||||
import { PROD_HOST_URL } from "../config";
|
||||
import { isAppQuitting } from "../main";
|
||||
import autoLauncher from "../services/autoLauncher";
|
||||
import { logErrorSentry } from "../services/sentry";
|
||||
import { getHideDockIconPreference } from "../services/userPreference";
|
||||
import { isDev } from "./common";
|
||||
import { isPlatform } from "./common/platform";
|
||||
|
||||
export async function createWindow(): Promise<BrowserWindow> {
|
||||
const appImgPath = isDev
|
||||
? 'build/window-icon.png'
|
||||
: path.join(process.resourcesPath, 'window-icon.png');
|
||||
? "build/window-icon.png"
|
||||
: path.join(process.resourcesPath, "window-icon.png");
|
||||
const appIcon = nativeImage.createFromPath(appImgPath);
|
||||
// Create the browser window.
|
||||
const mainWindow = new BrowserWindow({
|
||||
webPreferences: {
|
||||
sandbox: false,
|
||||
preload: path.join(__dirname, '../preload.js'),
|
||||
preload: path.join(__dirname, "../preload.js"),
|
||||
contextIsolation: false,
|
||||
},
|
||||
icon: appIcon,
|
||||
show: false, // don't show the main window on load,
|
||||
});
|
||||
const wasAutoLaunched = await autoLauncher.wasAutoLaunched();
|
||||
ElectronLog.log('wasAutoLaunched', wasAutoLaunched);
|
||||
ElectronLog.log("wasAutoLaunched", wasAutoLaunched);
|
||||
|
||||
const splash = new BrowserWindow({
|
||||
transparent: true,
|
||||
show: false,
|
||||
});
|
||||
if (isPlatform('mac') && wasAutoLaunched) {
|
||||
if (isPlatform("mac") && wasAutoLaunched) {
|
||||
app.dock.hide();
|
||||
}
|
||||
if (!wasAutoLaunched) {
|
||||
|
@ -46,21 +46,21 @@ export async function createWindow(): Promise<BrowserWindow> {
|
|||
mainWindow.webContents.openDevTools();
|
||||
} else {
|
||||
splash.loadURL(
|
||||
`file://${path.join(process.resourcesPath, 'splash.html')}`
|
||||
`file://${path.join(process.resourcesPath, "splash.html")}`
|
||||
);
|
||||
mainWindow.loadURL(PROD_HOST_URL);
|
||||
}
|
||||
mainWindow.webContents.on('did-fail-load', () => {
|
||||
mainWindow.webContents.on("did-fail-load", () => {
|
||||
splash.close();
|
||||
isDev
|
||||
? mainWindow.loadFile(`../../build/error.html`)
|
||||
: splash.loadURL(
|
||||
`file://${path.join(process.resourcesPath, 'error.html')}`
|
||||
`file://${path.join(process.resourcesPath, "error.html")}`
|
||||
);
|
||||
mainWindow.maximize();
|
||||
mainWindow.show();
|
||||
});
|
||||
mainWindow.once('ready-to-show', async () => {
|
||||
mainWindow.once("ready-to-show", async () => {
|
||||
try {
|
||||
splash.destroy();
|
||||
if (!wasAutoLaunched) {
|
||||
|
@ -71,18 +71,18 @@ export async function createWindow(): Promise<BrowserWindow> {
|
|||
// ignore
|
||||
}
|
||||
});
|
||||
mainWindow.webContents.on('render-process-gone', (event, details) => {
|
||||
mainWindow.webContents.on("render-process-gone", (event, details) => {
|
||||
mainWindow.webContents.reload();
|
||||
logErrorSentry(
|
||||
Error('render-process-gone'),
|
||||
'webContents event render-process-gone',
|
||||
Error("render-process-gone"),
|
||||
"webContents event render-process-gone",
|
||||
{ details }
|
||||
);
|
||||
ElectronLog.log('webContents event render-process-gone', details);
|
||||
ElectronLog.log("webContents event render-process-gone", details);
|
||||
});
|
||||
mainWindow.webContents.on('unresponsive', () => {
|
||||
mainWindow.webContents.on("unresponsive", () => {
|
||||
mainWindow.webContents.forcefullyCrashRenderer();
|
||||
ElectronLog.log('webContents event unresponsive');
|
||||
ElectronLog.log("webContents event unresponsive");
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
|
@ -96,21 +96,21 @@ export async function createWindow(): Promise<BrowserWindow> {
|
|||
// ignore
|
||||
}
|
||||
}, 2000);
|
||||
mainWindow.on('close', function (event) {
|
||||
mainWindow.on("close", function (event) {
|
||||
if (!isAppQuitting()) {
|
||||
event.preventDefault();
|
||||
mainWindow.hide();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
mainWindow.on('hide', () => {
|
||||
mainWindow.on("hide", () => {
|
||||
const shouldHideDockIcon = getHideDockIconPreference();
|
||||
if (isPlatform('mac') && shouldHideDockIcon) {
|
||||
if (isPlatform("mac") && shouldHideDockIcon) {
|
||||
app.dock.hide();
|
||||
}
|
||||
});
|
||||
mainWindow.on('show', () => {
|
||||
if (isPlatform('mac')) {
|
||||
mainWindow.on("show", () => {
|
||||
if (isPlatform("mac")) {
|
||||
app.dock.show();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { CustomErrors } from '../constants/errors';
|
||||
import { CustomErrors } from "../constants/errors";
|
||||
|
||||
export const isExecError = (err: any) => {
|
||||
return err.message.includes('Command failed:');
|
||||
return err.message.includes("Command failed:");
|
||||
};
|
||||
|
||||
export const parseExecError = (err: any) => {
|
||||
const errMessage = err.message;
|
||||
if (errMessage.includes('Bad CPU type in executable')) {
|
||||
if (errMessage.includes("Bad CPU type in executable")) {
|
||||
return CustomErrors.UNSUPPORTED_PLATFORM(
|
||||
process.platform,
|
||||
process.arch
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { BrowserWindow } from 'electron';
|
||||
import { BrowserWindow } from "electron";
|
||||
|
||||
export function setupAppEventEmitter(mainWindow: BrowserWindow) {
|
||||
// fire event when mainWindow is in foreground
|
||||
mainWindow.on('focus', () => {
|
||||
mainWindow.webContents.send('app-in-foreground');
|
||||
mainWindow.on("focus", () => {
|
||||
mainWindow.webContents.send("app-in-foreground");
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,87 +1,87 @@
|
|||
import chokidar from "chokidar";
|
||||
import {
|
||||
app,
|
||||
BrowserWindow,
|
||||
dialog,
|
||||
ipcMain,
|
||||
Tray,
|
||||
Notification,
|
||||
safeStorage,
|
||||
app,
|
||||
shell,
|
||||
} from 'electron';
|
||||
import { createWindow } from './createWindow';
|
||||
import { getSentryUserID, logErrorSentry } from '../services/sentry';
|
||||
import chokidar from 'chokidar';
|
||||
import path from 'path';
|
||||
import { getDirFilePaths } from '../services/fs';
|
||||
import {
|
||||
convertToJPEG,
|
||||
generateImageThumbnail,
|
||||
} from '../services/imageProcessor';
|
||||
Tray,
|
||||
} from "electron";
|
||||
import path from "path";
|
||||
import { updateOptOutOfCrashReports } from "../main";
|
||||
import {
|
||||
getAppVersion,
|
||||
muteUpdateNotification,
|
||||
skipAppUpdate,
|
||||
updateAndRestart,
|
||||
} from '../services/appUpdater';
|
||||
import { deleteTempFile, runFFmpegCmd } from '../services/ffmpeg';
|
||||
import { generateTempFilePath } from './temp';
|
||||
} from "../services/appUpdater";
|
||||
import {
|
||||
computeImageEmbedding,
|
||||
computeTextEmbedding,
|
||||
} from "../services/clipService";
|
||||
import { deleteTempFile, runFFmpegCmd } from "../services/ffmpeg";
|
||||
import { getDirFilePaths } from "../services/fs";
|
||||
import {
|
||||
convertToJPEG,
|
||||
generateImageThumbnail,
|
||||
} from "../services/imageProcessor";
|
||||
import { getSentryUserID, logErrorSentry } from "../services/sentry";
|
||||
import {
|
||||
getCustomCacheDirectory,
|
||||
setCustomCacheDirectory,
|
||||
setOptOutOfCrashReports,
|
||||
} from '../services/userPreference';
|
||||
import { updateOptOutOfCrashReports } from '../main';
|
||||
import {
|
||||
computeImageEmbedding,
|
||||
computeTextEmbedding,
|
||||
} from '../services/clipService';
|
||||
import { getPlatform } from './common/platform';
|
||||
} from "../services/userPreference";
|
||||
import { getPlatform } from "./common/platform";
|
||||
import { createWindow } from "./createWindow";
|
||||
import { generateTempFilePath } from "./temp";
|
||||
|
||||
export default function setupIpcComs(
|
||||
tray: Tray,
|
||||
mainWindow: BrowserWindow,
|
||||
watcher: chokidar.FSWatcher
|
||||
): void {
|
||||
ipcMain.handle('select-dir', async () => {
|
||||
ipcMain.handle("select-dir", async () => {
|
||||
const result = await dialog.showOpenDialog({
|
||||
properties: ['openDirectory'],
|
||||
properties: ["openDirectory"],
|
||||
});
|
||||
if (result.filePaths && result.filePaths.length > 0) {
|
||||
return result.filePaths[0]?.split(path.sep)?.join(path.posix.sep);
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on('send-notification', (_, args) => {
|
||||
ipcMain.on("send-notification", (_, args) => {
|
||||
const notification = {
|
||||
title: 'ente',
|
||||
title: "ente",
|
||||
body: args,
|
||||
};
|
||||
new Notification(notification).show();
|
||||
});
|
||||
ipcMain.on('reload-window', async () => {
|
||||
ipcMain.on("reload-window", async () => {
|
||||
const secondWindow = await createWindow();
|
||||
mainWindow.destroy();
|
||||
mainWindow = secondWindow;
|
||||
});
|
||||
|
||||
ipcMain.handle('show-upload-files-dialog', async () => {
|
||||
ipcMain.handle("show-upload-files-dialog", async () => {
|
||||
const files = await dialog.showOpenDialog({
|
||||
properties: ['openFile', 'multiSelections'],
|
||||
properties: ["openFile", "multiSelections"],
|
||||
});
|
||||
return files.filePaths;
|
||||
});
|
||||
|
||||
ipcMain.handle('show-upload-zip-dialog', async () => {
|
||||
ipcMain.handle("show-upload-zip-dialog", async () => {
|
||||
const files = await dialog.showOpenDialog({
|
||||
properties: ['openFile', 'multiSelections'],
|
||||
filters: [{ name: 'Zip File', extensions: ['zip'] }],
|
||||
properties: ["openFile", "multiSelections"],
|
||||
filters: [{ name: "Zip File", extensions: ["zip"] }],
|
||||
});
|
||||
return files.filePaths;
|
||||
});
|
||||
|
||||
ipcMain.handle('show-upload-dirs-dialog', async () => {
|
||||
ipcMain.handle("show-upload-dirs-dialog", async () => {
|
||||
const dir = await dialog.showOpenDialog({
|
||||
properties: ['openDirectory', 'multiSelections'],
|
||||
properties: ["openDirectory", "multiSelections"],
|
||||
});
|
||||
|
||||
let files: string[] = [];
|
||||
|
@ -92,27 +92,27 @@ export default function setupIpcComs(
|
|||
return files;
|
||||
});
|
||||
|
||||
ipcMain.handle('add-watcher', async (_, args: { dir: string }) => {
|
||||
ipcMain.handle("add-watcher", async (_, args: { dir: string }) => {
|
||||
watcher.add(args.dir);
|
||||
});
|
||||
|
||||
ipcMain.handle('remove-watcher', async (_, args: { dir: string }) => {
|
||||
ipcMain.handle("remove-watcher", async (_, args: { dir: string }) => {
|
||||
watcher.unwatch(args.dir);
|
||||
});
|
||||
|
||||
ipcMain.handle('log-error', (_, err, msg, info?) => {
|
||||
ipcMain.handle("log-error", (_, err, msg, info?) => {
|
||||
logErrorSentry(err, msg, info);
|
||||
});
|
||||
|
||||
ipcMain.handle('safeStorage-encrypt', (_, message) => {
|
||||
ipcMain.handle("safeStorage-encrypt", (_, message) => {
|
||||
return safeStorage.encryptString(message);
|
||||
});
|
||||
|
||||
ipcMain.handle('safeStorage-decrypt', (_, message) => {
|
||||
ipcMain.handle("safeStorage-decrypt", (_, message) => {
|
||||
return safeStorage.decryptString(message);
|
||||
});
|
||||
|
||||
ipcMain.handle('get-path', (_, message) => {
|
||||
ipcMain.handle("get-path", (_, message) => {
|
||||
// By default, these paths are at the following locations:
|
||||
//
|
||||
// * macOS: `~/Library/Application Support/ente`
|
||||
|
@ -124,38 +124,38 @@ export default function setupIpcComs(
|
|||
return app.getPath(message);
|
||||
});
|
||||
|
||||
ipcMain.handle('convert-to-jpeg', (_, fileData, filename) => {
|
||||
ipcMain.handle("convert-to-jpeg", (_, fileData, filename) => {
|
||||
return convertToJPEG(fileData, filename);
|
||||
});
|
||||
|
||||
ipcMain.handle('open-log-dir', () => {
|
||||
shell.openPath(app.getPath('logs'));
|
||||
ipcMain.handle("open-log-dir", () => {
|
||||
shell.openPath(app.getPath("logs"));
|
||||
});
|
||||
|
||||
ipcMain.handle('open-dir', (_, dirPath) => {
|
||||
ipcMain.handle("open-dir", (_, dirPath) => {
|
||||
shell.openPath(path.normalize(dirPath));
|
||||
});
|
||||
|
||||
ipcMain.on('update-and-restart', () => {
|
||||
ipcMain.on("update-and-restart", () => {
|
||||
updateAndRestart();
|
||||
});
|
||||
ipcMain.on('skip-app-update', (_, version) => {
|
||||
ipcMain.on("skip-app-update", (_, version) => {
|
||||
skipAppUpdate(version);
|
||||
});
|
||||
|
||||
ipcMain.on('mute-update-notification', (_, version) => {
|
||||
ipcMain.on("mute-update-notification", (_, version) => {
|
||||
muteUpdateNotification(version);
|
||||
});
|
||||
ipcMain.handle('get-sentry-id', () => {
|
||||
ipcMain.handle("get-sentry-id", () => {
|
||||
return getSentryUserID();
|
||||
});
|
||||
|
||||
ipcMain.handle('get-app-version', () => {
|
||||
ipcMain.handle("get-app-version", () => {
|
||||
return getAppVersion();
|
||||
});
|
||||
|
||||
ipcMain.handle(
|
||||
'run-ffmpeg-cmd',
|
||||
"run-ffmpeg-cmd",
|
||||
(_, cmd, inputFilePath, outputFileName, dontTimeout) => {
|
||||
return runFFmpegCmd(
|
||||
cmd,
|
||||
|
@ -165,39 +165,39 @@ export default function setupIpcComs(
|
|||
);
|
||||
}
|
||||
);
|
||||
ipcMain.handle('get-temp-file-path', (_, formatSuffix) => {
|
||||
ipcMain.handle("get-temp-file-path", (_, formatSuffix) => {
|
||||
return generateTempFilePath(formatSuffix);
|
||||
});
|
||||
ipcMain.handle('remove-temp-file', (_, tempFilePath: string) => {
|
||||
ipcMain.handle("remove-temp-file", (_, tempFilePath: string) => {
|
||||
return deleteTempFile(tempFilePath);
|
||||
});
|
||||
|
||||
ipcMain.handle(
|
||||
'generate-image-thumbnail',
|
||||
"generate-image-thumbnail",
|
||||
(_, fileData, maxDimension, maxSize) => {
|
||||
return generateImageThumbnail(fileData, maxDimension, maxSize);
|
||||
}
|
||||
);
|
||||
|
||||
ipcMain.handle('update-opt-out-crash-reports', (_, optOut) => {
|
||||
ipcMain.handle("update-opt-out-crash-reports", (_, optOut) => {
|
||||
setOptOutOfCrashReports(optOut);
|
||||
updateOptOutOfCrashReports(optOut);
|
||||
});
|
||||
ipcMain.handle('compute-image-embedding', (_, model, inputFilePath) => {
|
||||
ipcMain.handle("compute-image-embedding", (_, model, inputFilePath) => {
|
||||
return computeImageEmbedding(model, inputFilePath);
|
||||
});
|
||||
ipcMain.handle('compute-text-embedding', (_, model, text) => {
|
||||
ipcMain.handle("compute-text-embedding", (_, model, text) => {
|
||||
return computeTextEmbedding(model, text);
|
||||
});
|
||||
ipcMain.handle('get-platform', () => {
|
||||
ipcMain.handle("get-platform", () => {
|
||||
return getPlatform();
|
||||
});
|
||||
|
||||
ipcMain.handle('set-custom-cache-directory', (_, directory: string) => {
|
||||
ipcMain.handle("set-custom-cache-directory", (_, directory: string) => {
|
||||
setCustomCacheDirectory(directory);
|
||||
});
|
||||
|
||||
ipcMain.handle('get-custom-cache-directory', async () => {
|
||||
ipcMain.handle("get-custom-cache-directory", async () => {
|
||||
return getCustomCacheDirectory();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import log from 'electron-log';
|
||||
import { LOG_FILENAME, MAX_LOG_SIZE } from '../config';
|
||||
import log from "electron-log";
|
||||
import { LOG_FILENAME, MAX_LOG_SIZE } from "../config";
|
||||
|
||||
export function setupLogging(isDev?: boolean) {
|
||||
log.transports.file.fileName = LOG_FILENAME;
|
||||
|
@ -8,13 +8,13 @@ export function setupLogging(isDev?: boolean) {
|
|||
log.transports.console.level = false;
|
||||
}
|
||||
log.transports.file.format =
|
||||
'[{y}-{m}-{d}T{h}:{i}:{s}{z}] [{level}]{scope} {text}';
|
||||
"[{y}-{m}-{d}T{h}:{i}:{s}{z}] [{level}]{scope} {text}";
|
||||
}
|
||||
|
||||
export function makeID(length: number) {
|
||||
let result = '';
|
||||
let result = "";
|
||||
const characters =
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
const charactersLength = characters.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += characters.charAt(
|
||||
|
@ -29,10 +29,10 @@ export function convertBytesToHumanReadable(
|
|||
precision = 2
|
||||
): string {
|
||||
if (bytes === 0 || isNaN(bytes)) {
|
||||
return '0 MB';
|
||||
return "0 MB";
|
||||
}
|
||||
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(1024));
|
||||
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
return (bytes / Math.pow(1024, i)).toFixed(precision) + ' ' + sizes[i];
|
||||
const sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||
return (bytes / Math.pow(1024, i)).toFixed(precision) + " " + sizes[i];
|
||||
}
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
import { PROD_HOST_URL, RENDERER_OUTPUT_DIR } from '../config';
|
||||
import { nativeImage, Tray, app, BrowserWindow, Menu } from 'electron';
|
||||
import electronReload from 'electron-reload';
|
||||
import serveNextAt from 'next-electron-server';
|
||||
import path from 'path';
|
||||
import { existsSync } from 'promise-fs';
|
||||
import { isDev } from './common';
|
||||
import { buildContextMenu, buildMenuBar } from './menu';
|
||||
import autoLauncher from '../services/autoLauncher';
|
||||
import { getHideDockIconPreference } from '../services/userPreference';
|
||||
import { setupAutoUpdater } from '../services/appUpdater';
|
||||
import ElectronLog from 'electron-log';
|
||||
import os from 'os';
|
||||
import util from 'util';
|
||||
import { isPlatform } from './common/platform';
|
||||
const execAsync = util.promisify(require('child_process').exec);
|
||||
import { app, BrowserWindow, Menu, nativeImage, Tray } from "electron";
|
||||
import ElectronLog from "electron-log";
|
||||
import electronReload from "electron-reload";
|
||||
import serveNextAt from "next-electron-server";
|
||||
import os from "os";
|
||||
import path from "path";
|
||||
import { existsSync } from "promise-fs";
|
||||
import util from "util";
|
||||
import { PROD_HOST_URL, RENDERER_OUTPUT_DIR } from "../config";
|
||||
import { setupAutoUpdater } from "../services/appUpdater";
|
||||
import autoLauncher from "../services/autoLauncher";
|
||||
import { getHideDockIconPreference } from "../services/userPreference";
|
||||
import { isDev } from "./common";
|
||||
import { isPlatform } from "./common/platform";
|
||||
import { buildContextMenu, buildMenuBar } from "./menu";
|
||||
const execAsync = util.promisify(require("child_process").exec);
|
||||
|
||||
export async function handleUpdates(mainWindow: BrowserWindow) {
|
||||
const isInstalledViaBrew = await checkIfInstalledViaBrew();
|
||||
|
@ -22,24 +22,24 @@ export async function handleUpdates(mainWindow: BrowserWindow) {
|
|||
}
|
||||
}
|
||||
export function setupTrayItem(mainWindow: BrowserWindow) {
|
||||
const iconName = isPlatform('mac')
|
||||
? 'taskbar-icon-Template.png'
|
||||
: 'taskbar-icon.png';
|
||||
const iconName = isPlatform("mac")
|
||||
? "taskbar-icon-Template.png"
|
||||
: "taskbar-icon.png";
|
||||
const trayImgPath = path.join(
|
||||
isDev ? 'build' : process.resourcesPath,
|
||||
isDev ? "build" : process.resourcesPath,
|
||||
iconName
|
||||
);
|
||||
const trayIcon = nativeImage.createFromPath(trayImgPath);
|
||||
const tray = new Tray(trayIcon);
|
||||
tray.setToolTip('ente');
|
||||
tray.setToolTip("ente");
|
||||
tray.setContextMenu(buildContextMenu(mainWindow));
|
||||
return tray;
|
||||
}
|
||||
|
||||
export function handleDownloads(mainWindow: BrowserWindow) {
|
||||
mainWindow.webContents.session.on('will-download', (_, item) => {
|
||||
mainWindow.webContents.session.on("will-download", (_, item) => {
|
||||
item.setSavePath(
|
||||
getUniqueSavePath(item.getFilename(), app.getPath('downloads'))
|
||||
getUniqueSavePath(item.getFilename(), app.getPath("downloads"))
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -58,14 +58,14 @@ export function getUniqueSavePath(filename: string, directory: string): string {
|
|||
extension,
|
||||
]
|
||||
.filter((x) => x) // filters out undefined/null values
|
||||
.join('');
|
||||
.join("");
|
||||
uniqueFileSavePath = path.join(directory, fileNameWithNumberedSuffix);
|
||||
}
|
||||
return uniqueFileSavePath;
|
||||
}
|
||||
|
||||
export function setupMacWindowOnDockIconClick() {
|
||||
app.on('activate', function () {
|
||||
app.on("activate", function () {
|
||||
const windows = BrowserWindow.getAllWindows();
|
||||
// we allow only one window
|
||||
windows[0].show();
|
||||
|
@ -92,13 +92,13 @@ export async function handleDockIconHideOnAutoLaunch() {
|
|||
const shouldHideDockIcon = getHideDockIconPreference();
|
||||
const wasAutoLaunched = await autoLauncher.wasAutoLaunched();
|
||||
|
||||
if (isPlatform('mac') && shouldHideDockIcon && wasAutoLaunched) {
|
||||
if (isPlatform("mac") && shouldHideDockIcon && wasAutoLaunched) {
|
||||
app.dock.hide();
|
||||
}
|
||||
}
|
||||
|
||||
export function enableSharedArrayBufferSupport() {
|
||||
app.commandLine.appendSwitch('enable-features', 'SharedArrayBuffer');
|
||||
app.commandLine.appendSwitch("enable-features", "SharedArrayBuffer");
|
||||
}
|
||||
|
||||
export function logSystemInfo() {
|
||||
|
@ -113,24 +113,24 @@ export function logSystemInfo() {
|
|||
export function handleExternalLinks(mainWindow: BrowserWindow) {
|
||||
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
|
||||
if (!url.startsWith(PROD_HOST_URL)) {
|
||||
require('electron').shell.openExternal(url);
|
||||
return { action: 'deny' };
|
||||
require("electron").shell.openExternal(url);
|
||||
return { action: "deny" };
|
||||
} else {
|
||||
return { action: 'allow' };
|
||||
return { action: "allow" };
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function checkIfInstalledViaBrew() {
|
||||
if (!isPlatform('mac')) {
|
||||
if (!isPlatform("mac")) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
await execAsync('brew list --cask ente');
|
||||
ElectronLog.info('ente installed via brew');
|
||||
await execAsync("brew list --cask ente");
|
||||
ElectronLog.info("ente installed via brew");
|
||||
return true;
|
||||
} catch (e) {
|
||||
ElectronLog.info('ente not installed via brew');
|
||||
ElectronLog.info("ente not installed via brew");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,34 +1,34 @@
|
|||
import {
|
||||
Menu,
|
||||
app,
|
||||
shell,
|
||||
BrowserWindow,
|
||||
Menu,
|
||||
MenuItemConstructorOptions,
|
||||
} from 'electron';
|
||||
shell,
|
||||
} from "electron";
|
||||
import ElectronLog from "electron-log";
|
||||
import { setIsAppQuitting } from "../main";
|
||||
import { forceCheckForUpdateAndNotify } from "../services/appUpdater";
|
||||
import autoLauncher from "../services/autoLauncher";
|
||||
import {
|
||||
getHideDockIconPreference,
|
||||
setHideDockIconPreference,
|
||||
} from '../services/userPreference';
|
||||
import { setIsAppQuitting } from '../main';
|
||||
import autoLauncher from '../services/autoLauncher';
|
||||
import { isPlatform } from './common/platform';
|
||||
import ElectronLog from 'electron-log';
|
||||
import { forceCheckForUpdateAndNotify } from '../services/appUpdater';
|
||||
} from "../services/userPreference";
|
||||
import { isPlatform } from "./common/platform";
|
||||
|
||||
export function buildContextMenu(mainWindow: BrowserWindow): Menu {
|
||||
// eslint-disable-next-line camelcase
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: 'Open ente',
|
||||
label: "Open ente",
|
||||
click: function () {
|
||||
mainWindow.maximize();
|
||||
mainWindow.show();
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Quit ente',
|
||||
label: "Quit ente",
|
||||
click: function () {
|
||||
ElectronLog.log('user quit the app');
|
||||
ElectronLog.log("user quit the app");
|
||||
setIsAppQuitting(true);
|
||||
app.quit();
|
||||
},
|
||||
|
@ -39,43 +39,43 @@ export function buildContextMenu(mainWindow: BrowserWindow): Menu {
|
|||
|
||||
export async function buildMenuBar(mainWindow: BrowserWindow): Promise<Menu> {
|
||||
let isAutoLaunchEnabled = await autoLauncher.isEnabled();
|
||||
const isMac = isPlatform('mac');
|
||||
const isMac = isPlatform("mac");
|
||||
let shouldHideDockIcon = getHideDockIconPreference();
|
||||
const template: MenuItemConstructorOptions[] = [
|
||||
{
|
||||
label: 'ente',
|
||||
label: "ente",
|
||||
submenu: [
|
||||
...((isMac
|
||||
? [
|
||||
{
|
||||
label: 'About ente',
|
||||
role: 'about',
|
||||
label: "About ente",
|
||||
role: "about",
|
||||
},
|
||||
]
|
||||
: []) as MenuItemConstructorOptions[]),
|
||||
{ type: 'separator' },
|
||||
{ type: "separator" },
|
||||
{
|
||||
label: 'Check for updates...',
|
||||
label: "Check for updates...",
|
||||
click: () => {
|
||||
forceCheckForUpdateAndNotify(mainWindow);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'View Changelog',
|
||||
label: "View Changelog",
|
||||
click: () => {
|
||||
shell.openExternal(
|
||||
'https://github.com/ente-io/ente/blob/main/desktop/CHANGELOG.md'
|
||||
"https://github.com/ente-io/ente/blob/main/desktop/CHANGELOG.md"
|
||||
);
|
||||
},
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{ type: "separator" },
|
||||
|
||||
{
|
||||
label: 'Preferences',
|
||||
label: "Preferences",
|
||||
submenu: [
|
||||
{
|
||||
label: 'Open ente on startup',
|
||||
type: 'checkbox',
|
||||
label: "Open ente on startup",
|
||||
type: "checkbox",
|
||||
checked: isAutoLaunchEnabled,
|
||||
click: () => {
|
||||
autoLauncher.toggleAutoLaunch();
|
||||
|
@ -83,8 +83,8 @@ export async function buildMenuBar(mainWindow: BrowserWindow): Promise<Menu> {
|
|||
},
|
||||
},
|
||||
{
|
||||
label: 'Hide dock icon',
|
||||
type: 'checkbox',
|
||||
label: "Hide dock icon",
|
||||
type: "checkbox",
|
||||
checked: shouldHideDockIcon,
|
||||
click: () => {
|
||||
setHideDockIconPreference(!shouldHideDockIcon);
|
||||
|
@ -94,121 +94,121 @@ export async function buildMenuBar(mainWindow: BrowserWindow): Promise<Menu> {
|
|||
],
|
||||
},
|
||||
|
||||
{ type: 'separator' },
|
||||
{ type: "separator" },
|
||||
...((isMac
|
||||
? [
|
||||
{
|
||||
label: 'Hide ente',
|
||||
role: 'hide',
|
||||
label: "Hide ente",
|
||||
role: "hide",
|
||||
},
|
||||
{
|
||||
label: 'Hide others',
|
||||
role: 'hideOthers',
|
||||
label: "Hide others",
|
||||
role: "hideOthers",
|
||||
},
|
||||
]
|
||||
: []) as MenuItemConstructorOptions[]),
|
||||
|
||||
{ type: 'separator' },
|
||||
{ type: "separator" },
|
||||
{
|
||||
label: 'Quit ente',
|
||||
role: 'quit',
|
||||
label: "Quit ente",
|
||||
role: "quit",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Edit',
|
||||
label: "Edit",
|
||||
submenu: [
|
||||
{ role: 'undo', label: 'Undo' },
|
||||
{ role: 'redo', label: 'Redo' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'cut', label: 'Cut' },
|
||||
{ role: 'copy', label: 'Copy' },
|
||||
{ role: 'paste', label: 'Paste' },
|
||||
{ role: "undo", label: "Undo" },
|
||||
{ role: "redo", label: "Redo" },
|
||||
{ type: "separator" },
|
||||
{ role: "cut", label: "Cut" },
|
||||
{ role: "copy", label: "Copy" },
|
||||
{ role: "paste", label: "Paste" },
|
||||
...((isMac
|
||||
? [
|
||||
{
|
||||
role: 'pasteAndMatchStyle',
|
||||
label: 'Paste and match style',
|
||||
role: "pasteAndMatchStyle",
|
||||
label: "Paste and match style",
|
||||
},
|
||||
{ role: 'delete', label: 'Delete' },
|
||||
{ role: 'selectAll', label: 'Select all' },
|
||||
{ type: 'separator' },
|
||||
{ role: "delete", label: "Delete" },
|
||||
{ role: "selectAll", label: "Select all" },
|
||||
{ type: "separator" },
|
||||
{
|
||||
label: 'Speech',
|
||||
label: "Speech",
|
||||
submenu: [
|
||||
{
|
||||
role: 'startSpeaking',
|
||||
label: 'start speaking',
|
||||
role: "startSpeaking",
|
||||
label: "start speaking",
|
||||
},
|
||||
{
|
||||
role: 'stopSpeaking',
|
||||
label: 'stop speaking',
|
||||
role: "stopSpeaking",
|
||||
label: "stop speaking",
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
: [
|
||||
{ type: 'separator' },
|
||||
{ role: 'selectAll', label: 'Select all' },
|
||||
{ type: "separator" },
|
||||
{ role: "selectAll", label: "Select all" },
|
||||
]) as MenuItemConstructorOptions[]),
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'View',
|
||||
label: "View",
|
||||
submenu: [
|
||||
{ role: 'reload', label: 'Reload' },
|
||||
{ role: 'forceReload', label: 'Force reload' },
|
||||
{ role: 'toggleDevTools', label: 'Toggle dev tools' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'resetZoom', label: 'Reset zoom' },
|
||||
{ role: 'zoomIn', label: 'Zoom in' },
|
||||
{ role: 'zoomOut', label: 'Zoom out' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'togglefullscreen', label: 'Toggle fullscreen' },
|
||||
{ role: "reload", label: "Reload" },
|
||||
{ role: "forceReload", label: "Force reload" },
|
||||
{ role: "toggleDevTools", label: "Toggle dev tools" },
|
||||
{ type: "separator" },
|
||||
{ role: "resetZoom", label: "Reset zoom" },
|
||||
{ role: "zoomIn", label: "Zoom in" },
|
||||
{ role: "zoomOut", label: "Zoom out" },
|
||||
{ type: "separator" },
|
||||
{ role: "togglefullscreen", label: "Toggle fullscreen" },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Window',
|
||||
label: "Window",
|
||||
submenu: [
|
||||
{ role: 'close', label: 'Close' },
|
||||
{ role: 'minimize', label: 'Minimize' },
|
||||
{ role: "close", label: "Close" },
|
||||
{ role: "minimize", label: "Minimize" },
|
||||
...((isMac
|
||||
? [
|
||||
{ type: 'separator' },
|
||||
{ role: 'front', label: 'Bring to front' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'window', label: 'ente' },
|
||||
{ type: "separator" },
|
||||
{ role: "front", label: "Bring to front" },
|
||||
{ type: "separator" },
|
||||
{ role: "window", label: "ente" },
|
||||
]
|
||||
: []) as MenuItemConstructorOptions[]),
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Help',
|
||||
label: "Help",
|
||||
submenu: [
|
||||
{
|
||||
label: 'FAQ',
|
||||
click: () => shell.openExternal('https://ente.io/faq/'),
|
||||
label: "FAQ",
|
||||
click: () => shell.openExternal("https://ente.io/faq/"),
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{ type: "separator" },
|
||||
{
|
||||
label: 'Support',
|
||||
click: () => shell.openExternal('mailto:support@ente.io'),
|
||||
label: "Support",
|
||||
click: () => shell.openExternal("mailto:support@ente.io"),
|
||||
},
|
||||
{
|
||||
label: 'Product updates',
|
||||
click: () => shell.openExternal('https://ente.io/blog/'),
|
||||
label: "Product updates",
|
||||
click: () => shell.openExternal("https://ente.io/blog/"),
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{ type: "separator" },
|
||||
{
|
||||
label: 'View crash reports',
|
||||
label: "View crash reports",
|
||||
click: () => {
|
||||
shell.openPath(app.getPath('crashDumps'));
|
||||
shell.openPath(app.getPath("crashDumps"));
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'View logs',
|
||||
label: "View logs",
|
||||
click: () => {
|
||||
shell.openPath(app.getPath('logs'));
|
||||
shell.openPath(app.getPath("logs"));
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { webFrame } from 'electron';
|
||||
import { webFrame } from "electron";
|
||||
|
||||
export const fixHotReloadNext12 = () => {
|
||||
webFrame.executeJavaScript(`Object.defineProperty(globalThis, 'WebSocket', {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import ElectronLog from 'electron-log';
|
||||
import { webFrame } from 'electron/renderer';
|
||||
import { convertBytesToHumanReadable } from './logging';
|
||||
import ElectronLog from "electron-log";
|
||||
import { webFrame } from "electron/renderer";
|
||||
import { convertBytesToHumanReadable } from "./logging";
|
||||
|
||||
const LOGGING_INTERVAL_IN_MICROSECONDS = 30 * 1000; // 30 seconds
|
||||
|
||||
|
@ -23,7 +23,7 @@ async function logMainProcessStats() {
|
|||
process.getHeapStatistics()
|
||||
);
|
||||
|
||||
ElectronLog.log('main process stats', {
|
||||
ElectronLog.log("main process stats", {
|
||||
processMemoryInfo,
|
||||
heapStatistics,
|
||||
cpuUsage,
|
||||
|
@ -69,7 +69,7 @@ async function logSpikeMainMemoryUsage() {
|
|||
process.getHeapStatistics()
|
||||
);
|
||||
|
||||
ElectronLog.log('reporting main memory usage spike', {
|
||||
ElectronLog.log("reporting main memory usage spike", {
|
||||
currentProcessMemoryInfo: normalizedCurrentProcessMemoryInfo,
|
||||
previousProcessMemoryInfo: normalizedPreviousProcessMemoryInfo,
|
||||
heapStatistics,
|
||||
|
@ -124,7 +124,7 @@ async function logSpikeRendererMemoryUsage() {
|
|||
process.getHeapStatistics()
|
||||
);
|
||||
|
||||
ElectronLog.log('reporting renderer memory usage spike', {
|
||||
ElectronLog.log("reporting renderer memory usage spike", {
|
||||
currentProcessMemoryInfo: normalizedCurrentProcessMemoryInfo,
|
||||
previousProcessMemoryInfo: normalizedPreviousProcessMemoryInfo,
|
||||
heapStatistics,
|
||||
|
@ -146,7 +146,7 @@ async function logRendererProcessStats() {
|
|||
const processMemoryInfo = await getNormalizedProcessMemoryInfo(
|
||||
await process.getProcessMemoryInfo()
|
||||
);
|
||||
ElectronLog.log('renderer process stats', {
|
||||
ElectronLog.log("renderer process stats", {
|
||||
blinkMemoryInfo,
|
||||
heapStatistics,
|
||||
processMemoryInfo,
|
||||
|
@ -177,7 +177,7 @@ export async function logRendererProcessMemoryUsage(message: string) {
|
|||
processMemoryInfo.residentSet ?? 0
|
||||
);
|
||||
ElectronLog.log(
|
||||
'renderer ProcessMemory',
|
||||
"renderer ProcessMemory",
|
||||
message,
|
||||
convertBytesToHumanReadable(processMemory * 1024)
|
||||
);
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import { app } from 'electron';
|
||||
import path from 'path';
|
||||
import { existsSync, mkdir } from 'promise-fs';
|
||||
import { app } from "electron";
|
||||
import path from "path";
|
||||
import { existsSync, mkdir } from "promise-fs";
|
||||
|
||||
const ENTE_TEMP_DIRECTORY = 'ente';
|
||||
const ENTE_TEMP_DIRECTORY = "ente";
|
||||
|
||||
const CHARACTERS =
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
|
||||
export async function getTempDirPath() {
|
||||
const tempDirPath = path.join(app.getPath('temp'), ENTE_TEMP_DIRECTORY);
|
||||
const tempDirPath = path.join(app.getPath("temp"), ENTE_TEMP_DIRECTORY);
|
||||
if (!existsSync(tempDirPath)) {
|
||||
await mkdir(tempDirPath);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ export async function getTempDirPath() {
|
|||
}
|
||||
|
||||
function generateTempName(length: number) {
|
||||
let result = '';
|
||||
let result = "";
|
||||
|
||||
const charactersLength = CHARACTERS.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
|
@ -32,7 +32,7 @@ export async function generateTempFilePath(formatSuffix: string) {
|
|||
do {
|
||||
const tempDirPath = await getTempDirPath();
|
||||
const namePrefix = generateTempName(10);
|
||||
tempFilePath = path.join(tempDirPath, namePrefix + '-' + formatSuffix);
|
||||
tempFilePath = path.join(tempDirPath, namePrefix + "-" + formatSuffix);
|
||||
} while (existsSync(tempFilePath));
|
||||
return tempFilePath;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { WatchMapping } from '../types';
|
||||
import { WatchMapping } from "../types";
|
||||
|
||||
export function isMappingPresent(
|
||||
watchMappings: WatchMapping[],
|
||||
|
|
|
@ -183,6 +183,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@octetstream/promisify/-/promisify-2.0.2.tgz#29ac3bd7aefba646db670227f895d812c1a19615"
|
||||
integrity sha512-7XHoRB61hxsz8lBQrjC1tq/3OEIgpvGWg6DKAdwi7WRzruwkmsdwmOoUXbU4Dtd4RSOMDwed0SkP3y8UlMt1Bg==
|
||||
|
||||
"@pkgr/core@^0.1.0":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31"
|
||||
integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==
|
||||
|
||||
"@sentry/browser@6.7.1":
|
||||
version "6.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-6.7.1.tgz#e01144a08984a486ecc91d7922cc457e9c9bd6b7"
|
||||
|
@ -1208,6 +1213,16 @@ delegates@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
|
||||
integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==
|
||||
|
||||
detect-indent@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-7.0.1.tgz#cbb060a12842b9c4d333f1cac4aa4da1bb66bc25"
|
||||
integrity sha512-Mc7QhQ8s+cLrnUfU/Ji94vG/r8M26m8f++vyres4ZoojaRDpZ1eSIh/EpzLNwlWuvzSZ3UbDFspjFvTDXe6e/g==
|
||||
|
||||
detect-newline@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-4.0.1.tgz#fcefdb5713e1fb8cb2839b8b6ee22e6716ab8f23"
|
||||
integrity sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==
|
||||
|
||||
detect-node@^2.0.4:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1"
|
||||
|
@ -1645,6 +1660,17 @@ fast-glob@^3.2.9:
|
|||
merge2 "^1.3.0"
|
||||
micromatch "^4.0.4"
|
||||
|
||||
fast-glob@^3.3.0:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
|
||||
integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
|
||||
dependencies:
|
||||
"@nodelib/fs.stat" "^2.0.2"
|
||||
"@nodelib/fs.walk" "^1.2.3"
|
||||
glob-parent "^5.1.2"
|
||||
merge2 "^1.3.0"
|
||||
micromatch "^4.0.4"
|
||||
|
||||
fast-json-stable-stringify@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
|
||||
|
@ -1865,6 +1891,11 @@ get-intrinsic@^1.1.1:
|
|||
has "^1.0.3"
|
||||
has-symbols "^1.0.3"
|
||||
|
||||
get-stdin@^9.0.0:
|
||||
version "9.0.0"
|
||||
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-9.0.0.tgz#3983ff82e03d56f1b2ea0d3e60325f39d703a575"
|
||||
integrity sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==
|
||||
|
||||
get-stream@^5.1.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
|
||||
|
@ -1879,6 +1910,11 @@ getpass@^0.1.1:
|
|||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
git-hooks-list@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/git-hooks-list/-/git-hooks-list-3.1.0.tgz#386dc531dcc17474cf094743ff30987a3d3e70fc"
|
||||
integrity sha512-LF8VeHeR7v+wAbXqfgRlTSX/1BJR9Q1vEMR8JAz1cEg6GX07+zyj3sAdDvYjj/xnlIfVuGgj4qBei1K3hKH+PA==
|
||||
|
||||
glob-parent@^5.1.2, glob-parent@~5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
|
||||
|
@ -1936,6 +1972,17 @@ globby@^11.1.0:
|
|||
merge2 "^1.4.1"
|
||||
slash "^3.0.0"
|
||||
|
||||
globby@^13.1.2:
|
||||
version "13.2.2"
|
||||
resolved "https://registry.yarnpkg.com/globby/-/globby-13.2.2.tgz#63b90b1bf68619c2135475cbd4e71e66aa090592"
|
||||
integrity sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==
|
||||
dependencies:
|
||||
dir-glob "^3.0.1"
|
||||
fast-glob "^3.3.0"
|
||||
ignore "^5.2.4"
|
||||
merge2 "^1.4.1"
|
||||
slash "^4.0.0"
|
||||
|
||||
got@^11.8.5:
|
||||
version "11.8.6"
|
||||
resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a"
|
||||
|
@ -2098,6 +2145,11 @@ ignore@^5.2.0:
|
|||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
|
||||
integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
|
||||
|
||||
ignore@^5.2.4:
|
||||
version "5.3.1"
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef"
|
||||
integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==
|
||||
|
||||
import-fresh@^3.0.0, import-fresh@^3.2.1:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
|
||||
|
@ -2189,6 +2241,11 @@ is-obj@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982"
|
||||
integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==
|
||||
|
||||
is-plain-obj@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0"
|
||||
integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==
|
||||
|
||||
is-typedarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
|
||||
|
@ -2810,6 +2867,19 @@ prelude-ls@^1.2.1:
|
|||
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
|
||||
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
|
||||
|
||||
prettier-plugin-organize-imports@^3.2:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.4.tgz#77967f69d335e9c8e6e5d224074609309c62845e"
|
||||
integrity sha512-6m8WBhIp0dfwu0SkgfOxJqh+HpdyfqSSLfKKRZSFbDuEQXDDndb8fTpRWkUrX/uBenkex3MgnVk0J3b3Y5byog==
|
||||
|
||||
prettier-plugin-packagejson@^2.4:
|
||||
version "2.4.12"
|
||||
resolved "https://registry.yarnpkg.com/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.4.12.tgz#eeb917dad83ae42d0caccc9f26d3728b5c4f2434"
|
||||
integrity sha512-hifuuOgw5rHHTdouw9VrhT8+Nd7UwxtL1qco8dUfd4XUFQL6ia3xyjSxhPQTsGnSYFraTWy5Omb+MZm/OWDTpQ==
|
||||
dependencies:
|
||||
sort-package-json "2.8.0"
|
||||
synckit "0.9.0"
|
||||
|
||||
prettier@2.5.1:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a"
|
||||
|
@ -3190,6 +3260,11 @@ slash@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
|
||||
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
|
||||
|
||||
slash@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7"
|
||||
integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==
|
||||
|
||||
slice-ansi@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787"
|
||||
|
@ -3213,6 +3288,24 @@ smart-buffer@^4.0.2:
|
|||
resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae"
|
||||
integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==
|
||||
|
||||
sort-object-keys@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.3.tgz#bff833fe85cab147b34742e45863453c1e190b45"
|
||||
integrity sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==
|
||||
|
||||
sort-package-json@2.8.0:
|
||||
version "2.8.0"
|
||||
resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-2.8.0.tgz#6a46439ad0fef77f091e678e103f03ecbea575c8"
|
||||
integrity sha512-PxeNg93bTJWmDGnu0HADDucoxfFiKkIr73Kv85EBThlI1YQPdc0XovBgg2llD0iABZbu2SlKo8ntGmOP9wOj/g==
|
||||
dependencies:
|
||||
detect-indent "^7.0.1"
|
||||
detect-newline "^4.0.0"
|
||||
get-stdin "^9.0.0"
|
||||
git-hooks-list "^3.0.0"
|
||||
globby "^13.1.2"
|
||||
is-plain-obj "^4.1.0"
|
||||
sort-object-keys "^1.1.3"
|
||||
|
||||
source-map-support@^0.5.19:
|
||||
version "0.5.21"
|
||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
|
||||
|
@ -3393,6 +3486,14 @@ supports-preserve-symlinks-flag@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
|
||||
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
|
||||
|
||||
synckit@0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.9.0.tgz#5b33b458b3775e4466a5b377fba69c63572ae449"
|
||||
integrity sha512-7RnqIMq572L8PeEzKeBINYEJDDxpcH8JEgLwUqBd3TkofhFRbkq4QLR0u+36avGAhCRbk2nnmjcW9SE531hPDg==
|
||||
dependencies:
|
||||
"@pkgr/core" "^0.1.0"
|
||||
tslib "^2.6.2"
|
||||
|
||||
table@^6.0.9:
|
||||
version "6.8.0"
|
||||
resolved "https://registry.yarnpkg.com/table/-/table-6.8.0.tgz#87e28f14fa4321c3377ba286f07b79b281a3b3ca"
|
||||
|
@ -3503,6 +3604,11 @@ tslib@^2.1.0, tslib@^2.2.0:
|
|||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
|
||||
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
|
||||
|
||||
tslib@^2.6.2:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
|
||||
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
|
||||
|
||||
tsutils@^3.21.0:
|
||||
version "3.21.0"
|
||||
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
|
||||
|
|
Loading…
Add table
Reference in a new issue