aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar Vijay Raghavan Aravamudhan <vraravam@users.noreply.github.com>2021-08-08 00:01:37 +0000
committerLibravatar GitHub <noreply@github.com>2021-08-08 05:31:37 +0530
commit97d51a7763b14c92ee71ff9a012311dd9498d803 (patch)
treebd36005031ecb1148f27aa541e7a92a5e3aa4c0c /src
parent5.6.1-nightly.17 [skip ci] (diff)
downloadferdium-app-97d51a7763b14c92ee71ff9a012311dd9498d803.tar.gz
ferdium-app-97d51a7763b14c92ee71ff9a012311dd9498d803.tar.zst
ferdium-app-97d51a7763b14c92ee71ff9a012311dd9498d803.zip
refactor: path-references refactoring and using 'import' instead of 'require' (#1752)
* refactor references to 'userData' and 'appData' directories to move hardcoding into single location * convert to es6 for lower memory usage as per https://codesource.io/the-difference-between-import-and-require-in-javascript/
Diffstat (limited to 'src')
-rw-r--r--src/api/server/ServerApi.js50
-rw-r--r--src/components/services/content/ServiceWebview.js4
-rw-r--r--src/components/services/tabs/TabBarSortableList.js9
-rw-r--r--src/containers/settings/RecipesScreen.js12
-rw-r--r--src/electron/Settings.js6
-rw-r--r--src/electron/ipc-api/appIndicator.js4
-rw-r--r--src/electron/ipc-api/download.js4
-rw-r--r--src/electron/ipc-api/localServer.js5
-rw-r--r--src/electron/macOSPermissions.js46
-rw-r--r--src/electron/webview-ime-focus.js4
-rw-r--r--src/environment.js25
-rw-r--r--src/helpers/recipe-helpers.js11
-rw-r--r--src/helpers/service-helpers.js16
-rw-r--r--src/helpers/userAgent-helpers.js5
-rw-r--r--src/index.js14
-rw-r--r--src/internal-server/start.js4
-rw-r--r--src/lib/Tray.js4
-rw-r--r--src/models/Recipe.js6
-rw-r--r--src/models/Service.js4
-rw-r--r--src/scripts/add-crowdin-contributors.js2
-rw-r--r--src/scripts/build-theme-info.js4
-rw-r--r--src/scripts/link-readme.js2
-rw-r--r--src/stores/AppStore.js6
-rw-r--r--src/stores/RecipesStore.js9
-rw-r--r--src/stores/ServicesStore.js21
-rw-r--r--src/webview/darkmode.js10
-rw-r--r--src/webview/lib/RecipeWebview.js8
-rw-r--r--src/webview/recipe.js20
28 files changed, 149 insertions, 166 deletions
diff --git a/src/api/server/ServerApi.js b/src/api/server/ServerApi.js
index f91aeb23a..2111eb80b 100644
--- a/src/api/server/ServerApi.js
+++ b/src/api/server/ServerApi.js
@@ -1,6 +1,6 @@
1import path from 'path'; 1import { join } from 'path';
2import tar from 'tar'; 2import tar from 'tar';
3import fs from 'fs-extra'; 3import { readdirSync, statSync, writeFileSync, copySync, ensureDirSync, pathExistsSync, readJsonSync, removeSync } from 'fs-extra';
4import { app, require as remoteRequire } from '@electron/remote'; 4import { app, require as remoteRequire } from '@electron/remote';
5 5
6import ServiceModel from '../../models/Service'; 6import ServiceModel from '../../models/Service';
@@ -13,7 +13,7 @@ import OrderModel from '../../models/Order';
13import { sleep } from '../../helpers/async-helpers'; 13import { sleep } from '../../helpers/async-helpers';
14 14
15import { SERVER_NOT_LOADED } from '../../config'; 15import { SERVER_NOT_LOADED } from '../../config';
16import { osArch, osPlatform, RECIPES_PATH } from '../../environment'; 16import { osArch, osPlatform, asarRecipesPath, userDataRecipesPath, userDataPath } from '../../environment';
17import apiBase from '../apiBase'; 17import apiBase from '../apiBase';
18import { prepareAuthRequest, sendAuthRequest } from '../utils/auth'; 18import { prepareAuthRequest, sendAuthRequest } from '../utils/auth';
19 19
@@ -311,11 +311,10 @@ export default class ServerApi {
311 // Recipes 311 // Recipes
312 async getInstalledRecipes() { 312 async getInstalledRecipes() {
313 const recipesDirectory = getRecipeDirectory(); 313 const recipesDirectory = getRecipeDirectory();
314 const paths = fs 314 const paths = readdirSync(recipesDirectory)
315 .readdirSync(recipesDirectory)
316 .filter( 315 .filter(
317 file => 316 file =>
318 fs.statSync(path.join(recipesDirectory, file)).isDirectory() && 317 statSync(join(recipesDirectory, file)).isDirectory() &&
319 file !== 'temp' && 318 file !== 'temp' &&
320 file !== 'dev', 319 file !== 'dev',
321 ); 320 );
@@ -381,17 +380,17 @@ export default class ServerApi {
381 380
382 async getRecipePackage(recipeId) { 381 async getRecipePackage(recipeId) {
383 try { 382 try {
384 const recipesDirectory = path.join(app.getPath('userData'), 'recipes'); 383 const recipesDirectory = userDataRecipesPath();
385 const recipeTempDirectory = path.join(recipesDirectory, 'temp', recipeId); 384 const recipeTempDirectory = join(recipesDirectory, 'temp', recipeId);
386 const tempArchivePath = path.join(recipeTempDirectory, 'recipe.tar.gz'); 385 const tempArchivePath = join(recipeTempDirectory, 'recipe.tar.gz');
387 386
388 const internalRecipeFile = path.join(RECIPES_PATH, `${recipeId}.tar.gz`); 387 const internalRecipeFile = asarRecipesPath(`${recipeId}.tar.gz`);
389 388
390 fs.ensureDirSync(recipeTempDirectory); 389 ensureDirSync(recipeTempDirectory);
391 390
392 let archivePath; 391 let archivePath;
393 392
394 if (fs.existsSync(internalRecipeFile)) { 393 if (pathExistsSync(internalRecipeFile)) {
395 debug('[ServerApi::getRecipePackage] Using internal recipe file'); 394 debug('[ServerApi::getRecipePackage] Using internal recipe file');
396 archivePath = internalRecipeFile; 395 archivePath = internalRecipeFile;
397 } else { 396 } else {
@@ -403,7 +402,7 @@ export default class ServerApi {
403 const res = await fetch(packageUrl); 402 const res = await fetch(packageUrl);
404 debug('Recipe downloaded', recipeId); 403 debug('Recipe downloaded', recipeId);
405 const buffer = await res.buffer(); 404 const buffer = await res.buffer();
406 fs.writeFileSync(archivePath, buffer); 405 writeFileSync(archivePath, buffer);
407 } 406 }
408 debug(archivePath); 407 debug(archivePath);
409 408
@@ -420,13 +419,11 @@ export default class ServerApi {
420 419
421 await sleep(10); 420 await sleep(10);
422 421
423 const { id } = fs.readJsonSync( 422 const { id } = readJsonSync(join(recipeTempDirectory, 'package.json'));
424 path.join(recipeTempDirectory, 'package.json'), 423 const recipeDirectory = join(recipesDirectory, id);
425 ); 424 copySync(recipeTempDirectory, recipeDirectory);
426 const recipeDirectory = path.join(recipesDirectory, id); 425 removeSync(recipeTempDirectory);
427 fs.copySync(recipeTempDirectory, recipeDirectory); 426 removeSync(join(recipesDirectory, recipeId, 'recipe.tar.gz'));
428 fs.remove(recipeTempDirectory);
429 fs.remove(path.join(recipesDirectory, recipeId, 'recipe.tar.gz'));
430 427
431 return id; 428 return id;
432 } catch (err) { 429 } catch (err) {
@@ -475,14 +472,10 @@ export default class ServerApi {
475 } 472 }
476 473
477 async getLegacyServices() { 474 async getLegacyServices() {
478 const file = path.join( 475 const file = userDataPath('settings', 'services.json');
479 app.getPath('userData'),
480 'settings',
481 'services.json',
482 );
483 476
484 try { 477 try {
485 const config = fs.readJsonSync(file); 478 const config = readJsonSync(file);
486 479
487 if (Object.prototype.hasOwnProperty.call(config, 'services')) { 480 if (Object.prototype.hasOwnProperty.call(config, 'services')) {
488 const services = await Promise.all( 481 const services = await Promise.all(
@@ -614,11 +607,10 @@ export default class ServerApi {
614 _getDevRecipes() { 607 _getDevRecipes() {
615 const recipesDirectory = getDevRecipeDirectory(); 608 const recipesDirectory = getDevRecipeDirectory();
616 try { 609 try {
617 const paths = fs 610 const paths = readdirSync(recipesDirectory)
618 .readdirSync(recipesDirectory)
619 .filter( 611 .filter(
620 file => 612 file =>
621 fs.statSync(path.join(recipesDirectory, file)).isDirectory() && 613 statSync(join(recipesDirectory, file)).isDirectory() &&
622 file !== 'temp', 614 file !== 'temp',
623 ); 615 );
624 616
diff --git a/src/components/services/content/ServiceWebview.js b/src/components/services/content/ServiceWebview.js
index 4edbde5e2..3b499a5db 100644
--- a/src/components/services/content/ServiceWebview.js
+++ b/src/components/services/content/ServiceWebview.js
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { observable, reaction } from 'mobx'; 4import { observable, reaction } from 'mobx';
5import ElectronWebView from 'react-electron-web-view'; 5import ElectronWebView from 'react-electron-web-view';
6import path from 'path'; 6import { join } from 'path';
7 7
8import ServiceModel from '../../../models/Service'; 8import ServiceModel from '../../../models/Service';
9 9
@@ -59,7 +59,7 @@ class ServiceWebview extends Component {
59 isSpellcheckerEnabled, 59 isSpellcheckerEnabled,
60 } = this.props; 60 } = this.props;
61 61
62 const preloadScript = path.join(__dirname, '../../../', 'webview', 'recipe.js'); 62 const preloadScript = join(__dirname, '..', '..', '..', 'webview', 'recipe.js');
63 63
64 return ( 64 return (
65 <ElectronWebView 65 <ElectronWebView
diff --git a/src/components/services/tabs/TabBarSortableList.js b/src/components/services/tabs/TabBarSortableList.js
index f12d90602..117d799d7 100644
--- a/src/components/services/tabs/TabBarSortableList.js
+++ b/src/components/services/tabs/TabBarSortableList.js
@@ -64,15 +64,6 @@ class TabBarSortableList extends Component {
64 showMessageBadgesEvenWhenMuted={showMessageBadgesEvenWhenMuted} 64 showMessageBadgesEvenWhenMuted={showMessageBadgesEvenWhenMuted}
65 /> 65 />
66 ))} 66 ))}
67 {/* <li>
68 <button
69 className="sidebar__add-service"
70 onClick={() => openSettings({ path: 'recipes' })}
71 data-tip={`${intl.formatMessage(messages.addNewService)} (${ctrlKey}+N)`}
72 >
73 <span className="mdi mdi-plus" />
74 </button>
75 </li> */}
76 </ul> 67 </ul>
77 ); 68 );
78 } 69 }
diff --git a/src/containers/settings/RecipesScreen.js b/src/containers/settings/RecipesScreen.js
index 93503fb0e..ff3c688fa 100644
--- a/src/containers/settings/RecipesScreen.js
+++ b/src/containers/settings/RecipesScreen.js
@@ -1,11 +1,9 @@
1import { shell } from 'electron'; 1import { shell } from 'electron';
2import { app } from '@electron/remote'; 2import { ensureDirSync, readJsonSync } from 'fs-extra';
3import fs from 'fs-extra';
4import React, { Component } from 'react'; 3import React, { Component } from 'react';
5import PropTypes from 'prop-types'; 4import PropTypes from 'prop-types';
6import { autorun } from 'mobx'; 5import { autorun } from 'mobx';
7import { inject, observer } from 'mobx-react'; 6import { inject, observer } from 'mobx-react';
8import path from 'path';
9 7
10import RecipePreviewsStore from '../../stores/RecipePreviewsStore'; 8import RecipePreviewsStore from '../../stores/RecipePreviewsStore';
11import RecipeStore from '../../stores/RecipesStore'; 9import RecipeStore from '../../stores/RecipesStore';
@@ -15,7 +13,7 @@ import UserStore from '../../stores/UserStore';
15import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard'; 13import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard';
16import ErrorBoundary from '../../components/util/ErrorBoundary'; 14import ErrorBoundary from '../../components/util/ErrorBoundary';
17import { CUSTOM_WEBSITE_RECIPE_ID, FRANZ_DEV_DOCS } from '../../config'; 15import { CUSTOM_WEBSITE_RECIPE_ID, FRANZ_DEV_DOCS } from '../../config';
18import { RECIPES_PATH } from '../../environment'; 16import { asarRecipesPath, userDataRecipesPath } from '../../environment';
19import { communityRecipesStore } from '../../features/communityRecipes'; 17import { communityRecipesStore } from '../../features/communityRecipes';
20import RecipePreview from '../../models/RecipePreview'; 18import RecipePreview from '../../models/RecipePreview';
21import AppStore from '../../stores/AppStore'; 19import AppStore from '../../stores/AppStore';
@@ -45,7 +43,7 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend
45 constructor(props) { 43 constructor(props) {
46 super(props); 44 super(props);
47 45
48 this.customRecipes = fs.readJsonSync(path.join(RECIPES_PATH, 'all.json')); 46 this.customRecipes = readJsonSync(asarRecipesPath('all.json'));
49 } 47 }
50 48
51 componentDidMount() { 49 componentDidMount() {
@@ -140,7 +138,7 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend
140 || recipes.installRecipeRequest.isExecuting 138 || recipes.installRecipeRequest.isExecuting
141 || recipePreviews.searchRecipePreviewsRequest.isExecuting; 139 || recipePreviews.searchRecipePreviewsRequest.isExecuting;
142 140
143 const recipeDirectory = path.join(app.getPath('userData'), 'recipes', 'dev'); 141 const recipeDirectory = userDataRecipesPath('dev');
144 142
145 return ( 143 return (
146 <ErrorBoundary> 144 <ErrorBoundary>
@@ -157,7 +155,7 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend
157 recipeFilter={filter} 155 recipeFilter={filter}
158 recipeDirectory={recipeDirectory} 156 recipeDirectory={recipeDirectory}
159 openRecipeDirectory={async () => { 157 openRecipeDirectory={async () => {
160 await fs.ensureDir(recipeDirectory); 158 ensureDirSync(recipeDirectory);
161 shell.openExternal(`file://${recipeDirectory}`); 159 shell.openExternal(`file://${recipeDirectory}`);
162 }} 160 }}
163 openDevDocs={() => { 161 openDevDocs={() => {
diff --git a/src/electron/Settings.js b/src/electron/Settings.js
index 2f3f8261a..4dd9f8245 100644
--- a/src/electron/Settings.js
+++ b/src/electron/Settings.js
@@ -1,8 +1,6 @@
1import { observable, toJS } from 'mobx'; 1import { observable, toJS } from 'mobx';
2import { pathExistsSync, outputJsonSync, readJsonSync } from 'fs-extra'; 2import { pathExistsSync, outputJsonSync, readJsonSync } from 'fs-extra';
3import path from 'path'; 3import { userDataPath } from '../environment';
4
5import { SETTINGS_PATH } from '../environment';
6 4
7const debug = require('debug')('Ferdi:Settings'); 5const debug = require('debug')('Ferdi:Settings');
8 6
@@ -58,6 +56,6 @@ export default class Settings {
58 } 56 }
59 57
60 get settingsFile() { 58 get settingsFile() {
61 return path.join(SETTINGS_PATH, `${this.type === 'app' ? 'settings' : this.type}.json`); 59 return userDataPath('config', `${this.type === 'app' ? 'settings' : this.type}.json`);
62 } 60 }
63} 61}
diff --git a/src/electron/ipc-api/appIndicator.js b/src/electron/ipc-api/appIndicator.js
index 0691e5170..c6c261d0f 100644
--- a/src/electron/ipc-api/appIndicator.js
+++ b/src/electron/ipc-api/appIndicator.js
@@ -1,5 +1,5 @@
1import { app, ipcMain } from 'electron'; 1import { app, ipcMain } from 'electron';
2import path from 'path'; 2import { join } from 'path';
3import { autorun } from 'mobx'; 3import { autorun } from 'mobx';
4import { isMac, isWindows, isLinux } from '../../environment'; 4import { isMac, isWindows, isLinux } from '../../environment';
5 5
@@ -9,7 +9,7 @@ const FILE_EXTENSION = isWindows ? 'ico' : 'png';
9let isTrayIconEnabled; 9let isTrayIconEnabled;
10 10
11function getAsset(type, asset) { 11function getAsset(type, asset) {
12 return path.join( 12 return join(
13 __dirname, '..', '..', 'assets', 'images', type, process.platform, `${asset}.${FILE_EXTENSION}`, 13 __dirname, '..', '..', 'assets', 'images', type, process.platform, `${asset}.${FILE_EXTENSION}`,
14 ); 14 );
15} 15}
diff --git a/src/electron/ipc-api/download.js b/src/electron/ipc-api/download.js
index 7f8718924..ba261ba1e 100644
--- a/src/electron/ipc-api/download.js
+++ b/src/electron/ipc-api/download.js
@@ -1,7 +1,7 @@
1import { ipcMain, dialog, BrowserWindow } from 'electron'; 1import { ipcMain, dialog, BrowserWindow } from 'electron';
2import { download } from 'electron-dl'; 2import { download } from 'electron-dl';
3import mime from 'mime-types'; 3import mime from 'mime-types';
4import fs from 'fs-extra'; 4import { writeFileSync } from 'fs-extra';
5 5
6const debug = require('debug')('Ferdi:ipcApi:download'); 6const debug = require('debug')('Ferdi:ipcApi:download');
7 7
@@ -37,7 +37,7 @@ export default (params) => {
37 if (saveDialog.canceled) return; 37 if (saveDialog.canceled) return;
38 38
39 const binaryImage = decodeBase64Image(content); 39 const binaryImage = decodeBase64Image(content);
40 fs.writeFileSync(saveDialog.filePath, binaryImage, 'binary'); 40 writeFileSync(saveDialog.filePath, binaryImage, 'binary');
41 41
42 debug('File blob saved to', saveDialog.filePath); 42 debug('File blob saved to', saveDialog.filePath);
43 } catch (err) { 43 } catch (err) {
diff --git a/src/electron/ipc-api/localServer.js b/src/electron/ipc-api/localServer.js
index 493253e17..1ed4b7167 100644
--- a/src/electron/ipc-api/localServer.js
+++ b/src/electron/ipc-api/localServer.js
@@ -1,6 +1,7 @@
1import { ipcMain, app } from 'electron'; 1import { ipcMain } from 'electron';
2import net from 'net'; 2import net from 'net';
3import { LOCAL_HOSTNAME } from '../../config'; 3import { LOCAL_HOSTNAME } from '../../config';
4import { userDataPath } from '../../environment';
4import startServer from '../../internal-server/start'; 5import startServer from '../../internal-server/start';
5 6
6const DEFAULT_PORT = 45569; 7const DEFAULT_PORT = 45569;
@@ -37,7 +38,7 @@ export default (params) => {
37 } 38 }
38 console.log('Starting local server on port', port); 39 console.log('Starting local server on port', port);
39 40
40 startServer(app.getPath('userData'), port); 41 startServer(userDataPath(), port);
41 42
42 params.mainWindow.webContents.send('localServerPort', { 43 params.mainWindow.webContents.send('localServerPort', {
43 port, 44 port,
diff --git a/src/electron/macOSPermissions.js b/src/electron/macOSPermissions.js
index c114f4843..887af2903 100644
--- a/src/electron/macOSPermissions.js
+++ b/src/electron/macOSPermissions.js
@@ -1,45 +1,43 @@
1import { app, systemPreferences, dialog } from 'electron'; 1import { systemPreferences, dialog } from 'electron';
2import fs from 'fs'; 2import { pathExistsSync, mkdirSync, writeFileSync } from 'fs-extra';
3import macosVersion from 'macos-version'; 3import macosVersion from 'macos-version';
4import path from 'path'; 4import { dirname } from 'path';
5import { askForScreenCaptureAccess } from 'node-mac-permissions'; 5import { askForScreenCaptureAccess } from 'node-mac-permissions';
6import { userDataPath } from '../environment';
6 7
7const debug = require('debug')('Ferdi:macOSPermissions'); 8const debug = require('debug')('Ferdi:macOSPermissions');
8 9
9const permissionExists = macosVersion.isGreaterThanOrEqualTo('10.15'); 10const isExplicitScreenCapturePermissionReqd = macosVersion.isGreaterThanOrEqualTo('10.15');
10const filePath = path.join( 11debug(`Should check explicitly for screen-capture permissions: ${isExplicitScreenCapturePermissionReqd}`);
11 app.getPath('userData'),
12 '.has-app-requested-screen-capture-permissions',
13);
14 12
15function hasPromptedForPermission() { 13const filePath = userDataPath('.has-app-requested-screen-capture-permissions');
16 if (!permissionExists) {
17 return false;
18 }
19 14
20 if (filePath && fs.existsSync(filePath)) { 15function hasPromptedForScreenCapturePermission() {
21 return true; 16 if (!isExplicitScreenCapturePermissionReqd) {
17 return false;
22 } 18 }
23 19
24 return false; 20 debug('Checking if status file exists');
21 return filePath && pathExistsSync(filePath);
25} 22}
26 23
27function hasScreenCapturePermission() { 24function hasScreenCapturePermissionAlreadyBeenGranted() {
28 if (!permissionExists) { 25 if (!isExplicitScreenCapturePermissionReqd) {
29 return true; 26 return true;
30 } 27 }
31 28
32 const screenCaptureStatus = systemPreferences.getMediaAccessStatus('screen'); 29 const screenCaptureStatus = systemPreferences.getMediaAccessStatus('screen');
30 debug(`screen-capture permissions status: ${screenCaptureStatus}`);
33 return screenCaptureStatus === 'granted'; 31 return screenCaptureStatus === 'granted';
34} 32}
35 33
36function createStatusFile() { 34function createStatusFile() {
37 try { 35 try {
38 fs.writeFileSync(filePath, ''); 36 writeFileSync(filePath, '');
39 } catch (error) { 37 } catch (error) {
40 if (error.code === 'ENOENT') { 38 if (error.code === 'ENOENT') {
41 fs.mkdirSync(path.dirname(filePath)); 39 mkdirSync(dirname(filePath));
42 fs.writeFileSync(filePath, ''); 40 writeFileSync(filePath, '');
43 } 41 }
44 42
45 throw error; 43 throw error;
@@ -51,7 +49,13 @@ export const askFormacOSPermissions = async mainWindow => {
51 systemPreferences.askForMediaAccess('camera'); 49 systemPreferences.askForMediaAccess('camera');
52 systemPreferences.askForMediaAccess('microphone'); 50 systemPreferences.askForMediaAccess('microphone');
53 51
54 if (!hasPromptedForPermission() && !hasScreenCapturePermission()) { 52 if (hasScreenCapturePermissionAlreadyBeenGranted()) {
53 debug('Already obtained screen-capture permissions - writing status file');
54 createStatusFile();
55 return;
56 }
57
58 if (!hasPromptedForScreenCapturePermission()) {
55 debug('Checking screen capture permissions'); 59 debug('Checking screen capture permissions');
56 60
57 const { response } = await dialog.showMessageBox(mainWindow, { 61 const { response } = await dialog.showMessageBox(mainWindow, {
diff --git a/src/electron/webview-ime-focus.js b/src/electron/webview-ime-focus.js
index b9421eb06..e187ee0b4 100644
--- a/src/electron/webview-ime-focus.js
+++ b/src/electron/webview-ime-focus.js
@@ -1,5 +1,5 @@
1const { webContents } = require('@electron/remote'); 1import { webContents } from '@electron/remote';
2const { releaseDocumentFocus } = require('./webview-ime-focus-helpers'); 2import { releaseDocumentFocus } from './webview-ime-focus-helpers';
3 3
4function giveWebviewDocumentFocus(element) { 4function giveWebviewDocumentFocus(element) {
5 releaseDocumentFocus(); 5 releaseDocumentFocus();
diff --git a/src/environment.js b/src/environment.js
index 7b560acb6..7267f93a6 100644
--- a/src/environment.js
+++ b/src/environment.js
@@ -1,10 +1,11 @@
1import os from 'os'; 1import os from 'os';
2import path from 'path'; 2import { join } from 'path';
3 3
4import { is, api as electronApi } from 'electron-util'; 4import { is, api as electronApi } from 'electron-util';
5 5
6import { DEFAULT_ACCENT_COLOR } from '@meetfranz/theme'; 6import { DEFAULT_ACCENT_COLOR } from '@meetfranz/theme';
7 7
8import osName from 'os-name';
8import { 9import {
9 LIVE_FERDI_API, 10 LIVE_FERDI_API,
10 DEV_FRANZ_API, 11 DEV_FRANZ_API,
@@ -25,8 +26,6 @@ import {
25import { asarPath } from './helpers/asar-helpers'; 26import { asarPath } from './helpers/asar-helpers';
26import * as buildInfo from './buildInfo.json'; // eslint-disable-line import/no-unresolved 27import * as buildInfo from './buildInfo.json'; // eslint-disable-line import/no-unresolved
27 28
28const osName = require('os-name');
29
30export const { app } = electronApi; 29export const { app } = electronApi;
31export const ferdiVersion = app.getVersion(); 30export const ferdiVersion = app.getVersion();
32export const electronVersion = process.versions.electron; 31export const electronVersion = process.versions.electron;
@@ -36,24 +35,32 @@ export const nodeVersion = process.versions.node;
36// Set app directory before loading user modules 35// Set app directory before loading user modules
37if (process.env.FERDI_APPDATA_DIR != null) { 36if (process.env.FERDI_APPDATA_DIR != null) {
38 app.setPath('appData', process.env.FERDI_APPDATA_DIR); 37 app.setPath('appData', process.env.FERDI_APPDATA_DIR);
39 app.setPath('userData', path.join(app.getPath('appData'))); 38 app.setPath('userData', join(app.getPath('appData')));
40} else if (process.env.PORTABLE_EXECUTABLE_DIR != null) { 39} else if (process.env.PORTABLE_EXECUTABLE_DIR != null) {
41 app.setPath('appData', process.env.PORTABLE_EXECUTABLE_DIR, `${app.name}AppData`); 40 app.setPath('appData', process.env.PORTABLE_EXECUTABLE_DIR, `${app.name}AppData`);
42 app.setPath('userData', path.join(app.getPath('appData'), `${app.name}AppData`)); 41 app.setPath('userData', join(app.getPath('appData'), `${app.name}AppData`));
43} else if (is.windows) { 42} else if (is.windows) {
44 app.setPath('appData', process.env.APPDATA); 43 app.setPath('appData', process.env.APPDATA);
45 app.setPath('userData', path.join(app.getPath('appData'), app.name)); 44 app.setPath('userData', join(app.getPath('appData'), app.name));
46} 45}
47 46
48export const isDevMode = is.development; 47export const isDevMode = is.development;
49if (isDevMode) { 48if (isDevMode) {
50 app.setPath('userData', path.join(app.getPath('appData'), `${app.name}Dev`)); 49 app.setPath('userData', join(app.getPath('appData'), `${app.name}Dev`));
51} 50}
52 51
53export const SETTINGS_PATH = path.join(app.getPath('userData'), 'config'); 52export function userDataPath(...segments) {
53 return join(app.getPath('userData'), ...([segments].flat()));
54}
55
56export function userDataRecipesPath(...segments) {
57 return userDataPath('recipes', ...([segments].flat()));
58}
54 59
55// Replacing app.asar is not beautiful but unfortunately necessary 60// Replacing app.asar is not beautiful but unfortunately necessary
56export const RECIPES_PATH = asarPath(path.join(__dirname, 'recipes')); 61export function asarRecipesPath(...segments) {
62 return join(asarPath(join(__dirname, 'recipes')), ...([segments].flat()));
63}
57 64
58export const useLiveAPI = process.env.USE_LIVE_API; 65export const useLiveAPI = process.env.USE_LIVE_API;
59const useLocalAPI = process.env.USE_LOCAL_API; 66const useLocalAPI = process.env.USE_LOCAL_API;
diff --git a/src/helpers/recipe-helpers.js b/src/helpers/recipe-helpers.js
index 7daa0aaab..7e4bfa85a 100644
--- a/src/helpers/recipe-helpers.js
+++ b/src/helpers/recipe-helpers.js
@@ -1,12 +1,12 @@
1import path from 'path'; 1import { parse } from 'path';
2import { app } from '@electron/remote'; 2import { userDataRecipesPath } from '../environment';
3 3
4export function getRecipeDirectory(id = '') { 4export function getRecipeDirectory(id = '') {
5 return path.join(app.getPath('userData'), 'recipes', id); 5 return userDataRecipesPath(id);
6} 6}
7 7
8export function getDevRecipeDirectory(id = '') { 8export function getDevRecipeDirectory(id = '') {
9 return path.join(app.getPath('userData'), 'recipes', 'dev', id); 9 return userDataRecipesPath('dev', id);
10} 10}
11 11
12export function loadRecipeConfig(recipeId) { 12export function loadRecipeConfig(recipeId) {
@@ -19,8 +19,7 @@ export function loadRecipeConfig(recipeId) {
19 let config = require(configPath); 19 let config = require(configPath);
20 20
21 const moduleConfigPath = require.resolve(configPath); 21 const moduleConfigPath = require.resolve(configPath);
22 const paths = path.parse(moduleConfigPath); 22 config.path = parse(moduleConfigPath).dir;
23 config.path = paths.dir;
24 23
25 return config; 24 return config;
26 } catch (e) { 25 } catch (e) {
diff --git a/src/helpers/service-helpers.js b/src/helpers/service-helpers.js
index 28d483182..745f40dd9 100644
--- a/src/helpers/service-helpers.js
+++ b/src/helpers/service-helpers.js
@@ -1,18 +1,16 @@
1import path from 'path'; 1import { readdirSync, removeSync } from 'fs-extra';
2import { app } from '@electron/remote'; 2import { userDataPath } from '../environment';
3import fs from 'fs-extra';
4 3
5export function getServicePartitionsDirectory() { 4export function getServicePartitionsDirectory(...segments) {
6 return path.join(app.getPath('userData'), 'Partitions'); 5 return userDataPath('Partitions', ...([segments].flat()));
7} 6}
8 7
9export function removeServicePartitionDirectory(id = '', addServicePrefix = false) { 8export function removeServicePartitionDirectory(id = '', addServicePrefix = false) {
10 const servicePartition = path.join(getServicePartitionsDirectory(), `${addServicePrefix ? 'service-' : ''}${id}`); 9 const servicePartition = getServicePartitionsDirectory(`${addServicePrefix ? 'service-' : ''}${id}`);
11 10 return removeSync(servicePartition);
12 return fs.remove(servicePartition);
13} 11}
14 12
15export async function getServiceIdsFromPartitions() { 13export async function getServiceIdsFromPartitions() {
16 const files = await fs.readdir(getServicePartitionsDirectory()); 14 const files = readdirSync(getServicePartitionsDirectory());
17 return files.filter((n) => n !== '__chrome_extension'); 15 return files.filter((n) => n !== '__chrome_extension');
18} 16}
diff --git a/src/helpers/userAgent-helpers.js b/src/helpers/userAgent-helpers.js
index 9c9c8f132..ede5e6dc4 100644
--- a/src/helpers/userAgent-helpers.js
+++ b/src/helpers/userAgent-helpers.js
@@ -1,11 +1,10 @@
1import os from 'os'; 1import os from 'os';
2import macosVersion from 'macos-version'; 2import macosVersion from 'macos-version';
3import { chrome } from 'useragent-generator';
3import { 4import {
4 chromeVersion, isMac, isWindows, is64Bit, osArch, osRelease, 5 chromeVersion, isMac, isWindows, is64Bit, osArch, osRelease,
5} from '../environment'; 6} from '../environment';
6 7
7const uaGenerator = require('useragent-generator');
8
9function macOS() { 8function macOS() {
10 const version = macosVersion(); 9 const version = macosVersion();
11 let cpuName = os.cpus()[0].model.split(' ')[0]; 10 let cpuName = os.cpus()[0].model.split(' ')[0];
@@ -38,5 +37,5 @@ export default function userAgent() {
38 platformString = linux(); 37 platformString = linux();
39 } 38 }
40 39
41 return uaGenerator.chrome({ os: platformString, version: chromeVersion }); 40 return chrome({ os: platformString, version: chromeVersion });
42} 41}
diff --git a/src/index.js b/src/index.js
index 78ab9bef2..3264fdc63 100644
--- a/src/index.js
+++ b/src/index.js
@@ -2,8 +2,8 @@
2 2
3import { app, BrowserWindow, shell, ipcMain, session } from 'electron'; 3import { app, BrowserWindow, shell, ipcMain, session } from 'electron';
4 4
5import fs from 'fs-extra'; 5import { emptyDirSync, ensureFileSync } from 'fs-extra';
6import path from 'path'; 6import { join } from 'path';
7import windowStateKeeper from 'electron-window-state'; 7import windowStateKeeper from 'electron-window-state';
8import { enforceMacOSAppLocation } from 'electron-util'; 8import { enforceMacOSAppLocation } from 'electron-util';
9import ms from 'ms'; 9import ms from 'ms';
@@ -19,6 +19,8 @@ import {
19 isWindows, 19 isWindows,
20 isLinux, 20 isLinux,
21 aboutAppDetails, 21 aboutAppDetails,
22 userDataRecipesPath,
23 userDataPath,
22} from './environment'; 24} from './environment';
23 25
24import { mainIpcHandler as basicAuthHandler } from './features/basicAuth'; 26import { mainIpcHandler as basicAuthHandler } from './features/basicAuth';
@@ -63,8 +65,8 @@ function onDidLoad(fn) {
63} 65}
64 66
65// Ensure that the recipe directory exists 67// Ensure that the recipe directory exists
66fs.emptyDirSync(path.join(app.getPath('userData'), 'recipes', 'temp')); 68emptyDirSync(userDataRecipesPath('temp'));
67fs.ensureFileSync(path.join(app.getPath('userData'), 'window-state.json')); 69ensureFileSync(userDataPath('window-state.json'));
68 70
69// Set App ID for Windows 71// Set App ID for Windows
70if (isWindows) { 72if (isWindows) {
@@ -193,7 +195,7 @@ const createWindow = () => {
193 nodeIntegration: true, 195 nodeIntegration: true,
194 contextIsolation: false, 196 contextIsolation: false,
195 webviewTag: true, 197 webviewTag: true,
196 preload: path.join(__dirname, 'sentry.js'), 198 preload: join(__dirname, 'sentry.js'),
197 enableRemoteModule: true, 199 enableRemoteModule: true,
198 }, 200 },
199 }); 201 });
@@ -401,7 +403,7 @@ app.on('ready', () => {
401 program: process.execPath, 403 program: process.execPath,
402 arguments: `${isDevMode ? `${__dirname} ` : ''}--reset-window`, 404 arguments: `${isDevMode ? `${__dirname} ` : ''}--reset-window`,
403 iconPath: asarPath( 405 iconPath: asarPath(
404 path.join( 406 join(
405 isDevMode ? `${__dirname}../src/` : __dirname, 407 isDevMode ? `${__dirname}../src/` : __dirname,
406 'assets/images/taskbar/win32/display.ico', 408 'assets/images/taskbar/win32/display.ico',
407 ), 409 ),
diff --git a/src/internal-server/start.js b/src/internal-server/start.js
index cb8ef56c8..5ccc1330e 100644
--- a/src/internal-server/start.js
+++ b/src/internal-server/start.js
@@ -18,9 +18,9 @@
18const fold = require('@adonisjs/fold'); 18const fold = require('@adonisjs/fold');
19const { Ignitor } = require('@adonisjs/ignitor'); 19const { Ignitor } = require('@adonisjs/ignitor');
20const fs = require('fs-extra'); 20const fs = require('fs-extra');
21const os = require('os');
22const path = require('path'); 21const path = require('path');
23const { LOCAL_HOSTNAME } = require('../config'); 22const { LOCAL_HOSTNAME } = require('../config');
23const { isWindows } = require('../environment');
24 24
25process.env.ENV_PATH = path.join(__dirname, 'env.ini'); 25process.env.ENV_PATH = path.join(__dirname, 'env.ini');
26 26
@@ -35,7 +35,7 @@ module.exports = async (userPath, port) => {
35 await fs.writeFile(dbPath, dbTemplate); 35 await fs.writeFile(dbPath, dbTemplate);
36 36
37 // Change permissions to ensure to file is not read-only 37 // Change permissions to ensure to file is not read-only
38 if (os.platform() === 'win32') { 38 if (isWindows) {
39 // eslint-disable-next-line no-bitwise 39 // eslint-disable-next-line no-bitwise
40 fs.chmodSync(dbPath, fs.statSync(dbPath).mode | 146); 40 fs.chmodSync(dbPath, fs.statSync(dbPath).mode | 146);
41 } 41 }
diff --git a/src/lib/Tray.js b/src/lib/Tray.js
index f37b4eb7b..f5970f7e7 100644
--- a/src/lib/Tray.js
+++ b/src/lib/Tray.js
@@ -1,7 +1,7 @@
1import { 1import {
2 app, Menu, nativeImage, nativeTheme, systemPreferences, Tray, ipcMain, 2 app, Menu, nativeImage, nativeTheme, systemPreferences, Tray, ipcMain,
3} from 'electron'; 3} from 'electron';
4import path from 'path'; 4import { join } from 'path';
5import macosVersion from 'macos-version'; 5import macosVersion from 'macos-version';
6import { isMac, isWindows, isLinux } from '../environment'; 6import { isMac, isWindows, isLinux } from '../environment';
7 7
@@ -174,7 +174,7 @@ export default class TrayIcon {
174 platform = `${platform}-dark`; 174 platform = `${platform}-dark`;
175 } 175 }
176 176
177 return nativeImage.createFromPath(path.join( 177 return nativeImage.createFromPath(join(
178 __dirname, '..', 'assets', 'images', type, platform, `${asset}.${FILE_EXTENSION}`, 178 __dirname, '..', 'assets', 'images', type, platform, `${asset}.${FILE_EXTENSION}`,
179 )); 179 ));
180 } 180 }
diff --git a/src/models/Recipe.js b/src/models/Recipe.js
index 106b4a56a..92ff0d67d 100644
--- a/src/models/Recipe.js
+++ b/src/models/Recipe.js
@@ -1,7 +1,7 @@
1import emailParser from 'address-rfc2822'; 1import emailParser from 'address-rfc2822';
2import semver from 'semver'; 2import semver from 'semver';
3import fs from 'fs-extra'; 3import { pathExistsSync } from 'fs-extra';
4import path from 'path'; 4import { join } from 'path';
5 5
6export default class Recipe { 6export default class Recipe {
7 id = ''; 7 id = '';
@@ -98,6 +98,6 @@ export default class Recipe {
98 } 98 }
99 99
100 get hasDarkMode() { 100 get hasDarkMode() {
101 return fs.pathExistsSync(path.join(this.path, 'darkmode.css')); 101 return pathExistsSync(join(this.path, 'darkmode.css'));
102 } 102 }
103} 103}
diff --git a/src/models/Service.js b/src/models/Service.js
index 79181186a..fe56e5a76 100644
--- a/src/models/Service.js
+++ b/src/models/Service.js
@@ -2,7 +2,7 @@ import { autorun, computed, observable } from 'mobx';
2import { ipcRenderer } from 'electron'; 2import { ipcRenderer } from 'electron';
3import { webContents } from '@electron/remote'; 3import { webContents } from '@electron/remote';
4import normalizeUrl from 'normalize-url'; 4import normalizeUrl from 'normalize-url';
5import path from 'path'; 5import { join } from 'path';
6 6
7import { todosStore } from '../features/todos'; 7import { todosStore } from '../features/todos';
8import { isValidExternalURL } from '../helpers/url-helpers'; 8import { isValidExternalURL } from '../helpers/url-helpers';
@@ -230,7 +230,7 @@ export default class Service {
230 return this.iconUrl; 230 return this.iconUrl;
231 } 231 }
232 232
233 return path.join(this.recipe.path, 'icon.svg'); 233 return join(this.recipe.path, 'icon.svg');
234 } 234 }
235 235
236 @computed get hasCustomIcon() { 236 @computed get hasCustomIcon() {
diff --git a/src/scripts/add-crowdin-contributors.js b/src/scripts/add-crowdin-contributors.js
index efe981b6e..ed29a0daf 100644
--- a/src/scripts/add-crowdin-contributors.js
+++ b/src/scripts/add-crowdin-contributors.js
@@ -58,7 +58,7 @@ const fs = require('fs-extra');
58const path = require('path'); 58const path = require('path');
59const allContributors = require('all-contributors-cli'); 59const allContributors = require('all-contributors-cli');
60 60
61const infoPath = path.join(__dirname, '../../.all-contributorsrc'); 61const infoPath = path.join(__dirname, '..', '..', '.all-contributorsrc');
62 62
63(async () => { 63(async () => {
64 const info = await fs.readJSON(infoPath); 64 const info = await fs.readJSON(infoPath);
diff --git a/src/scripts/build-theme-info.js b/src/scripts/build-theme-info.js
index cff33e3c4..4058be942 100644
--- a/src/scripts/build-theme-info.js
+++ b/src/scripts/build-theme-info.js
@@ -15,8 +15,8 @@ const accentColors = [
15 '#5e50ee', 15 '#5e50ee',
16]; 16];
17 17
18const cssFile = path.join(__dirname, '../../', 'build', 'styles', 'main.css'); 18const cssFile = path.join(__dirname, '..', '..', 'build', 'styles', 'main.css');
19const outputFile = path.join(__dirname, '../', 'assets', 'themeInfo.json'); 19const outputFile = path.join(__dirname, '..', 'assets', 'themeInfo.json');
20 20
21// Parse and extract the rules from a CSS stylesheet file 21// Parse and extract the rules from a CSS stylesheet file
22async function getRulesFromCssFile(file) { 22async function getRulesFromCssFile(file) {
diff --git a/src/scripts/link-readme.js b/src/scripts/link-readme.js
index 694b89700..1e47cddf8 100644
--- a/src/scripts/link-readme.js
+++ b/src/scripts/link-readme.js
@@ -11,7 +11,7 @@ const path = require('path');
11 11
12console.log('Linking issues and PRs in README.md'); 12console.log('Linking issues and PRs in README.md');
13 13
14const readmepath = path.join(__dirname, '../../', 'README.md'); 14const readmepath = path.join(__dirname, '..', '..', 'README.md');
15 15
16// Read README.md 16// Read README.md
17let readme = fs.readFileSync(readmepath, 'utf-8'); 17let readme = fs.readFileSync(readmepath, 'utf-8');
diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js
index 6b5ca7c9a..1d706f1ef 100644
--- a/src/stores/AppStore.js
+++ b/src/stores/AppStore.js
@@ -12,7 +12,6 @@ import moment from 'moment';
12import AutoLaunch from 'auto-launch'; 12import AutoLaunch from 'auto-launch';
13import ms from 'ms'; 13import ms from 'ms';
14import { URL } from 'url'; 14import { URL } from 'url';
15import path from 'path';
16import { readJsonSync } from 'fs-extra'; 15import { readJsonSync } from 'fs-extra';
17 16
18import Store from './lib/Store'; 17import Store from './lib/Store';
@@ -24,6 +23,7 @@ import {
24 ferdiVersion, 23 ferdiVersion,
25 electronVersion, 24 electronVersion,
26 osRelease, 25 osRelease,
26 userDataPath,
27} from '../environment'; 27} from '../environment';
28import locales from '../i18n/translations'; 28import locales from '../i18n/translations';
29import { onVisibilityChange } from '../helpers/visibility-helper'; 29import { onVisibilityChange } from '../helpers/visibility-helper';
@@ -307,9 +307,7 @@ export default class AppStore extends Store {
307 id: workspace.id, 307 id: workspace.id,
308 services: workspace.services, 308 services: workspace.services,
309 })), 309 })),
310 windowSettings: readJsonSync( 310 windowSettings: readJsonSync(userDataPath('window-state.json')),
311 path.join(app.getPath('userData'), 'window-state.json'),
312 ),
313 settings, 311 settings,
314 features: this.stores.features.features, 312 features: this.stores.features.features,
315 user: this.stores.user.data.id, 313 user: this.stores.user.data.id,
diff --git a/src/stores/RecipesStore.js b/src/stores/RecipesStore.js
index c7c4c1deb..d2acebb75 100644
--- a/src/stores/RecipesStore.js
+++ b/src/stores/RecipesStore.js
@@ -1,13 +1,12 @@
1import { action, computed, observable } from 'mobx'; 1import { action, computed, observable } from 'mobx';
2import fs from 'fs-extra'; 2import { readJSONSync } from 'fs-extra';
3import path from 'path';
4import semver from 'semver'; 3import semver from 'semver';
5 4
6import Store from './lib/Store'; 5import Store from './lib/Store';
7import CachedRequest from './lib/CachedRequest'; 6import CachedRequest from './lib/CachedRequest';
8import Request from './lib/Request'; 7import Request from './lib/Request';
9import { matchRoute } from '../helpers/routing-helpers'; 8import { matchRoute } from '../helpers/routing-helpers';
10import { RECIPES_PATH } from '../environment'; 9import { asarRecipesPath } from '../environment';
11 10
12const debug = require('debug')('Ferdi:RecipeStore'); 11const debug = require('debug')('Ferdi:RecipeStore');
13 12
@@ -90,8 +89,8 @@ export default class RecipesStore extends Store {
90 const remoteUpdates = await this.getRecipeUpdatesRequest.execute(recipes)._promise; 89 const remoteUpdates = await this.getRecipeUpdatesRequest.execute(recipes)._promise;
91 90
92 // Check for local updates 91 // Check for local updates
93 const allJsonFile = path.join(RECIPES_PATH, 'all.json'); 92 const allJsonFile = asarRecipesPath('all.json');
94 const allJson = await fs.readJSON(allJsonFile); 93 const allJson = readJSONSync(allJsonFile);
95 const localUpdates = []; 94 const localUpdates = [];
96 95
97 Object.keys(recipes).forEach((recipe) => { 96 Object.keys(recipes).forEach((recipe) => {
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js
index 829797930..499495d08 100644
--- a/src/stores/ServicesStore.js
+++ b/src/stores/ServicesStore.js
@@ -3,8 +3,8 @@ import { action, reaction, computed, observable } from 'mobx';
3import { debounce, remove } from 'lodash'; 3import { debounce, remove } from 'lodash';
4import ms from 'ms'; 4import ms from 'ms';
5import { app } from '@electron/remote'; 5import { app } from '@electron/remote';
6import fs from 'fs-extra'; 6import { ensureFileSync, pathExistsSync, writeFileSync } from 'fs-extra';
7import path from 'path'; 7import { join } from 'path';
8 8
9import Store from './lib/Store'; 9import Store from './lib/Store';
10import Request from './lib/Request'; 10import Request from './lib/Request';
@@ -524,9 +524,9 @@ export default class ServicesStore extends Store {
524 const devDirectory = getDevRecipeDirectory(recipe); 524 const devDirectory = getDevRecipeDirectory(recipe);
525 let directory; 525 let directory;
526 526
527 if (await fs.pathExists(normalDirectory)) { 527 if (pathExistsSync(normalDirectory)) {
528 directory = normalDirectory; 528 directory = normalDirectory;
529 } else if (await fs.pathExists(devDirectory)) { 529 } else if (pathExistsSync(devDirectory)) {
530 directory = devDirectory; 530 directory = devDirectory;
531 } else { 531 } else {
532 // Recipe cannot be found on drive 532 // Recipe cannot be found on drive
@@ -534,20 +534,19 @@ export default class ServicesStore extends Store {
534 } 534 }
535 535
536 // Create and open file 536 // Create and open file
537 const filePath = path.join(directory, file); 537 const filePath = join(directory, file);
538 if (file === 'user.js') { 538 if (file === 'user.js') {
539 if (!fs.existsSync(filePath)) { 539 if (!pathExistsSync(filePath)) {
540 await fs.writeFile( 540 writeFileSync(
541 filePath, 541 filePath,
542 `module.exports = (config, Ferdi) => { 542 `module.exports = (config, Ferdi) => {
543 // Write your scripts here 543 // Write your scripts here
544 console.log("Hello, World!", config); 544 console.log("Hello, World!", config);
545} 545};
546`, 546`);
547 );
548 } 547 }
549 } else { 548 } else {
550 await fs.ensureFile(filePath); 549 ensureFileSync(filePath);
551 } 550 }
552 shell.showItemInFolder(filePath); 551 shell.showItemInFolder(filePath);
553 } 552 }
diff --git a/src/webview/darkmode.js b/src/webview/darkmode.js
index ab629435c..7435d6404 100644
--- a/src/webview/darkmode.js
+++ b/src/webview/darkmode.js
@@ -1,7 +1,7 @@
1/* eslint no-bitwise: ["error", { "int32Hint": true }] */ 1/* eslint no-bitwise: ["error", { "int32Hint": true }] */
2 2
3import path from 'path'; 3import { join } from 'path';
4import fs from 'fs-extra'; 4import { pathExistsSync, readFileSync } from 'fs-extra';
5 5
6const debug = require('debug')('Ferdi:DarkMode'); 6const debug = require('debug')('Ferdi:DarkMode');
7 7
@@ -10,9 +10,9 @@ const chars = [...'abcdefghijklmnopqrstuvwxyz'];
10const ID = [...Array(20)].map(() => chars[Math.random() * chars.length | 0]).join``; 10const ID = [...Array(20)].map(() => chars[Math.random() * chars.length | 0]).join``;
11 11
12export function injectDarkModeStyle(recipePath) { 12export function injectDarkModeStyle(recipePath) {
13 const darkModeStyle = path.join(recipePath, 'darkmode.css'); 13 const darkModeStyle = join(recipePath, 'darkmode.css');
14 if (fs.pathExistsSync(darkModeStyle)) { 14 if (pathExistsSync(darkModeStyle)) {
15 const data = fs.readFileSync(darkModeStyle); 15 const data = readFileSync(darkModeStyle);
16 const styles = document.createElement('style'); 16 const styles = document.createElement('style');
17 styles.id = ID; 17 styles.id = ID;
18 styles.innerHTML = data.toString(); 18 styles.innerHTML = data.toString();
diff --git a/src/webview/lib/RecipeWebview.js b/src/webview/lib/RecipeWebview.js
index 305e79882..96caa125e 100644
--- a/src/webview/lib/RecipeWebview.js
+++ b/src/webview/lib/RecipeWebview.js
@@ -1,5 +1,5 @@
1import { ipcRenderer } from 'electron'; 1import { ipcRenderer } from 'electron';
2import { exists, pathExistsSync, readFile } from 'fs-extra'; 2import { exists, pathExistsSync, readFileSync } from 'fs-extra';
3 3
4const debug = require('debug')('Ferdi:Plugin:RecipeWebview'); 4const debug = require('debug')('Ferdi:Plugin:RecipeWebview');
5 5
@@ -55,9 +55,8 @@ class RecipeWebview {
55 injectCSS(...files) { 55 injectCSS(...files) {
56 files.forEach(async (file) => { 56 files.forEach(async (file) => {
57 if (pathExistsSync(file)) { 57 if (pathExistsSync(file)) {
58 const data = await readFile(file, 'utf8');
59 const styles = document.createElement('style'); 58 const styles = document.createElement('style');
60 styles.innerHTML = data; 59 styles.innerHTML = readFileSync(file, 'utf8');
61 60
62 document.querySelector('head').appendChild(styles); 61 document.querySelector('head').appendChild(styles);
63 62
@@ -69,8 +68,7 @@ class RecipeWebview {
69 injectJSUnsafe(...files) { 68 injectJSUnsafe(...files) {
70 Promise.all(files.map(async (file) => { 69 Promise.all(files.map(async (file) => {
71 if (await exists(file)) { 70 if (await exists(file)) {
72 const data = await readFile(file, 'utf8'); 71 return readFileSync(file, 'utf8');
73 return data;
74 } 72 }
75 debug('Script not found', file); 73 debug('Script not found', file);
76 return null; 74 return null;
diff --git a/src/webview/recipe.js b/src/webview/recipe.js
index 598c3eb9a..a45c34002 100644
--- a/src/webview/recipe.js
+++ b/src/webview/recipe.js
@@ -1,8 +1,8 @@
1/* eslint-disable import/first */ 1/* eslint-disable import/first */
2import { contextBridge, ipcRenderer } from 'electron'; 2import { contextBridge, ipcRenderer } from 'electron';
3import path from 'path'; 3import { join } from 'path';
4import { autorun, computed, observable } from 'mobx'; 4import { autorun, computed, observable } from 'mobx';
5import fs from 'fs-extra'; 5import { pathExistsSync, readFileSync } from 'fs-extra';
6import { debounce } from 'lodash'; 6import { debounce } from 'lodash';
7 7
8// For some services darkreader tries to use the chrome extension message API 8// For some services darkreader tries to use the chrome extension message API
@@ -189,7 +189,7 @@ class RecipeController {
189 189
190 loadRecipeModule(event, config, recipe) { 190 loadRecipeModule(event, config, recipe) {
191 debug('loadRecipeModule'); 191 debug('loadRecipeModule');
192 const modulePath = path.join(recipe.path, 'webview.js'); 192 const modulePath = join(recipe.path, 'webview.js');
193 debug('module path', modulePath); 193 debug('module path', modulePath);
194 // Delete module from cache 194 // Delete module from cache
195 delete require.cache[require.resolve(modulePath)]; 195 delete require.cache[require.resolve(modulePath)];
@@ -214,15 +214,15 @@ class RecipeController {
214 const styles = document.createElement('style'); 214 const styles = document.createElement('style');
215 styles.innerHTML = screenShareCss; 215 styles.innerHTML = screenShareCss;
216 216
217 const userCss = path.join(recipe.path, 'user.css'); 217 const userCss = join(recipe.path, 'user.css');
218 if (fs.existsSync(userCss)) { 218 if (pathExistsSync(userCss)) {
219 const data = await fs.readFile(userCss); 219 const data = readFileSync(userCss);
220 styles.innerHTML += data.toString(); 220 styles.innerHTML += data.toString();
221 } 221 }
222 document.querySelector('head').appendChild(styles); 222 document.querySelector('head').appendChild(styles);
223 223
224 const userJs = path.join(recipe.path, 'user.js'); 224 const userJs = join(recipe.path, 'user.js');
225 if (fs.existsSync(userJs)) { 225 if (pathExistsSync(userJs)) {
226 const loadUserJs = () => { 226 const loadUserJs = () => {
227 // eslint-disable-next-line 227 // eslint-disable-next-line
228 const userJsModule = require(userJs); 228 const userJsModule = require(userJs);
@@ -308,11 +308,11 @@ class RecipeController {
308 debug('Enable dark mode'); 308 debug('Enable dark mode');
309 309
310 // Check if recipe has a darkmode.css 310 // Check if recipe has a darkmode.css
311 const darkModeStyle = path.join( 311 const darkModeStyle = join(
312 this.settings.service.recipe.path, 312 this.settings.service.recipe.path,
313 'darkmode.css', 313 'darkmode.css',
314 ); 314 );
315 const darkModeExists = fs.pathExistsSync(darkModeStyle); 315 const darkModeExists = pathExistsSync(darkModeStyle);
316 316
317 debug('darkmode.css exists? ', darkModeExists ? 'Yes' : 'No'); 317 debug('darkmode.css exists? ', darkModeExists ? 'Yes' : 'No');
318 318