Skip to content

Commit

Permalink
Merge pull request #36 from rolandbernard/devel
Browse files Browse the repository at this point in the history
v0.0.26
  • Loading branch information
rolandbernard committed May 8, 2021
2 parents 1a0bb5d + a2824ee commit 4372129
Show file tree
Hide file tree
Showing 28 changed files with 797 additions and 881 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "marvin",
"version": "0.0.25",
"version": "0.0.26",
"license": "MIT",
"scripts": {
"dev": "electron-webpack dev",
Expand Down Expand Up @@ -33,7 +33,7 @@
"babel-loader": "^8.1.0",
"css-loader": "^3.6.0",
"electron": "^12.0.2",
"electron-builder": "^22.4.1",
"electron-builder": "=22.10.4",
"electron-webpack": "^2.8.2",
"file-loader": "^6.0.0",
"style-loader": "^1.2.1",
Expand Down
18 changes: 8 additions & 10 deletions src/main/config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

import { existsSync, readFileSync, writeFileSync } from "fs";
import { readFile, writeFile } from "fs/promises";
import { app } from "electron";
import path from 'path';
import { mergeDeep, cloneDeep } from '../common/util';
Expand Down Expand Up @@ -175,19 +175,17 @@ export let config = CONFIG_DEFAULT;

const CONFIG_FILENAME = 'marvin.json';

export function loadConfig() {
export async function loadConfig() {
const config_path = path.join(app.getPath('userData'), CONFIG_FILENAME);
if (existsSync(config_path)) {
try {
config = mergeDeep(cloneDeep(config), JSON.parse(readFileSync(config_path, { encoding: 'utf8' })));
} catch (e) { }
}
try {
config = mergeDeep(cloneDeep(config), JSON.parse(await readFile(config_path, { encoding: 'utf8' })));
} catch (e) { /* Ignore errors? */ }
config.version = app.getVersion();
writeFileSync(config_path, JSON.stringify(config), { encoding: 'utf8' });
await writeFile(config_path, JSON.stringify(config), { encoding: 'utf8' });
}

export function updateConfig(new_config) {
export async function updateConfig(new_config) {
const config_path = path.join(app.getPath('userData'), CONFIG_FILENAME);
config = mergeDeep(cloneDeep(config), new_config);
writeFileSync(config_path, JSON.stringify(config), { encoding: 'utf8' });
await writeFile(config_path, JSON.stringify(config), { encoding: 'utf8' });
}
2 changes: 1 addition & 1 deletion src/main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ app.commandLine.appendSwitch("disable-gpu"); // Transparancy will not work witho
async function startApp() {
const got_single_instance_lock = app.requestSingleInstanceLock();
if (got_single_instance_lock) {
loadConfig();
await loadConfig();
await initModules();
} else {
console.error("Other instance is already running: quitting app.");
Expand Down
91 changes: 46 additions & 45 deletions src/main/modules/bookmarks.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { config } from "../config";
import { exec } from 'child_process';
import { getAllTranslation, getTranslation } from "../../common/local/locale";
import { Database, OPEN_READONLY } from 'sqlite3';
import { readFileSync, existsSync, readdirSync } from 'fs';
import { readFile, access, readdir } from 'fs/promises';
import { join } from 'path';
import { app } from 'electron';
import { decompressBlock } from 'lz4js';
Expand Down Expand Up @@ -38,67 +38,68 @@ async function getChromiumBookmarks() {
const files = [
join(app.getPath('home'), '.config/chromium/Default/Bookmarks'),
join(app.getPath('home'), '.config/google-chrome/Default/Bookmarks'),
].filter((file) => existsSync(file));
];
let ret = []
for (const file of files) {
const bookmarks = JSON.parse(readFileSync(file, { encoding: 'utf8' }));
ret = ret.concat(recursiveBookmarkSearch(bookmarks));
try {
const bookmarks = JSON.parse(await readFile(file, { encoding: 'utf8' }));
ret = ret.concat(recursiveBookmarkSearch(bookmarks));
} catch (e) { /* Ignore errors */ }
}
return ret;
}

async function getMidoriBookmarks() {
const files = [
join(app.getPath('home'), '.config/midori/bookmarks.db'),
].filter((file) => existsSync(file));
return (await Promise.all(files.map((file) => {
return new Promise((res) => {
const db = new Database(file, OPEN_READONLY, (err) => {
if (err) {
res([]);
} else {
db.all(`
Select title, uri url
From bookmarks;
`, (err, rows) => {
if (err) {
return res([]);
} else {
return res(rows);
}
});
}
db.close();
];
return (await Promise.all(files.map(async file => {
try {
await access(file);
return await new Promise((res) => {
const db = new Database(file, OPEN_READONLY, (err) => {
if (err) {
res([]);
} else {
db.all(`
Select title, uri url
From bookmarks;
`, (err, rows) => {
if (err) {
return res([]);
} else {
return res(rows);
}
});
}
db.close();
});
});
});
} catch (e) {
return [];
}
}))).flat();
}

async function getFirefoxBookmarks() {
const firefox_dir = join(app.getPath('home'), '.mozilla/firefox');
if (existsSync(firefox_dir)) {
const files = readdirSync(firefox_dir)
try {
access(firefox_dir);
const folders = (await readdir(firefox_dir))
.filter((file) => file.endsWith('.default'))
.map((file) => join(firefox_dir, file, 'bookmarkbackups'))
.filter((file) => existsSync(file))
.flatMap((folder) => {
const files = readdirSync(folder);
if (files.length > 0) {
return join(folder, files.sort().pop())
} else {
return null;
}
}).filter((file) => file);
return (await Promise.all(files.map((file) => {
return new Promise((res) => {
const data = readFileSync(file);
const decompressed = Buffer.alloc(data.readUInt32LE(8));
decompressBlock(data, decompressed, 12, data.length - 12, 0);
const bookmarks = JSON.parse(decompressed.toString());
res(recursiveBookmarkSearch(bookmarks));
});
.map((file) => join(firefox_dir, file, 'bookmarkbackups'));
const files = await Promise.all(folders.map(async folder => {
const files = await readdir(folder);
return join(folder, files.sort().pop())
}))
return (await Promise.all(files.map(async file => {
const data = await readFile(file);
const decompressed = Buffer.alloc(data.readUInt32LE(8));
decompressBlock(data, decompressed, 12, data.length - 12, 0);
const bookmarks = JSON.parse(decompressed.toString());
return recursiveBookmarkSearch(bookmarks);
}))).flat();
} else {
} catch (e) {
return [];
}
}
Expand Down
30 changes: 14 additions & 16 deletions src/main/modules/clipboard.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

import { existsSync, readFileSync, writeFileSync } from "fs";
import { readFile, writeFile } from "fs/promises";
import { clipboard, app, ipcMain } from 'electron';
import { config } from '../config';
import { stringMatchQuality } from "../search";
Expand All @@ -10,37 +10,35 @@ let clipboard_history = [];

const CLIPBOARD_FILENAME = 'clipboard.json';

function loadClipboard() {
async function loadClipboard() {
const clipboard_path = path.join(app.getPath('userData'), CLIPBOARD_FILENAME);
if (existsSync(clipboard_path)) {
try {
clipboard_history = JSON.parse(readFileSync(clipboard_path, { encoding: 'utf8' }));
} catch (e) { }
}
writeFileSync(clipboard_path, JSON.stringify(clipboard_history), { encoding: 'utf8' });
try {
clipboard_history = JSON.parse(await readFile(clipboard_path, { encoding: 'utf8' }));
} catch (e) { }
await writeFile(clipboard_path, JSON.stringify(clipboard_history), { encoding: 'utf8' });
}

function updateClipboard() {
async function updateClipboard() {
const clipboard_path = path.join(app.getPath('userData'), CLIPBOARD_FILENAME);
writeFileSync(clipboard_path, JSON.stringify(clipboard_history), { encoding: 'utf8' });
await writeFile(clipboard_path, JSON.stringify(clipboard_history), { encoding: 'utf8' });
}
ipcMain.on('reset-clipboard', (_) => {

ipcMain.on('reset-clipboard', async _ => {
clipboard_history = [];
updateClipboard();
await updateClipboard();
});

let interval = null;

const ClipboardModule = {
init: async () => {
if (config.modules.clipboard.active) {
loadClipboard();
interval = setInterval(() => {
await loadClipboard();
interval = setInterval(async () => {
const text = clipboard.readText();
if (text && clipboard_history[0] !== text) {
clipboard_history = Array.from(new Set([text].concat(clipboard_history))).slice(0, config.modules.clipboard.maximum_history);
updateClipboard();
await updateClipboard();
}
}, config.modules.clipboard.refresh_time);
}
Expand Down
4 changes: 2 additions & 2 deletions src/main/modules/duckduckgo.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ const DuckduckgoModule = {
url: data.FirstURL,
},
}))).filter((el) => el.text?.length >= 1 || (el.primary?.length >= 1 && el.secondary?.length >= 1)));
}).catch((e) => { resolve([]) });
}).catch((e) => { resolve([]) });
}).catch(() => { resolve([]) });
}).catch(() => { resolve([]) });
}, config.modules.duckduckgo.debounce_time)
});
},
Expand Down
105 changes: 37 additions & 68 deletions src/main/modules/folders.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,31 @@

import { generateSearchRegex, stringMatchQuality } from "../search";
import { config } from "../config";
import { stat, exists, readdir } from "fs";
import path, { extname } from 'path';
import { format } from 'url';
import { access, stat, readdir } from "fs/promises";
import { extname, basename, dirname, join } from 'path';
import { app } from "electron";
import { exec } from "child_process";

function generateFilePreview(path) {
if (extname(path).match(/\.(pdf)/i)) {
function generateFilePreview(filename) {
if (extname(filename).match(/\.(pdf)/i)) {
return {
type: 'embed',
url: format({
pathname: path,
protocol: 'file',
slashes: true,
}),
url: `file://${filename}`,
};
} else if (extname(path).match(/\.(a?png|avif|gif|jpe?g|jfif|pjp(eg)?|svg|webp|bmp|ico|cur)/i)) {
} else if (extname(filename).match(/\.(a?png|avif|gif|jpe?g|jfif|pjp(eg)?|svg|webp|bmp|ico|cur)/i)) {
return {
type: 'image',
url: format({
pathname: path,
protocol: 'file',
slashes: true,
}),
url: `file://${filename}`,
};
} else if (extname(path).match(/\.(mp4|webm|avi|ogv|ogm|ogg)/i)) {
} else if (extname(filename).match(/\.(mp4|webm|avi|ogv|ogm|ogg)/i)) {
return {
type: 'video',
url: format({
pathname: path,
protocol: 'file',
slashes: true,
}),
url: `file://${filename}`,
};
} else if (extname(path).match(/\.(mp3|wav|mpeg)/i)) {
} else if (extname(filename).match(/\.(mp3|wav|mpeg)/i)) {
return {
type: 'audio',
url: format({
pathname: path,
protocol: 'file',
slashes: true,
}),
url: `file://${filename}`,
};
} else {
return null;
Expand All @@ -54,48 +37,34 @@ const FoldersModule = {
return query.trim().length >= 1;
},
search: async (query) => {
const base_query = query[query.length - 1] === '/' ? '' : basename(query);
const query_dir = query[query.length - 1] === '/' ? query : dirname(query);
const regex = generateSearchRegex(base_query);
return (await Promise.all(config.modules.folders.directories.map(async (directory) => {
const base_query = path.basename(query);
const regex = generateSearchRegex(base_query);
try {
return await new Promise((resolve) => {
exists(directory, (exist) => {
if (exist) {
let query_dir = query[query.length - 1] === '/' ? query : path.dirname(query);
let dir = query[query.length - 1] === '/' ? path.join(directory, query) : path.dirname(path.join(directory, query));
exists(dir, (exist) => {
if (exist) {
readdir(dir, async (_, files) => {
resolve(await Promise.all(files.map((file) => new Promise((resolve) => {
stat(path.join(dir, file), async (_, stats) => {
let option = stats && {
type: 'icon_list_item',
uri_icon: stats.isDirectory() ? null
: (await app.getFileIcon(path.join(dir, file))).toDataURL(),
material_icon: stats.isDirectory() ? 'folder' : null,
primary: file,
secondary: path.join(dir, file),
executable: true,
complete: path.join(query_dir, file) + (stats.isDirectory() ? '/' : ''),
quality: stringMatchQuality(base_query, file, regex),
file: path.join(dir, file),
preview: config.modules.folders.file_preview && generateFilePreview(path.join(dir, file)),
};
resolve(option);
});
}))));
});
} else {
resolve([]);
}
});
} else {
resolve([]);
}
});
});
} catch (e) { resolve([]) }
}))).filter((a) => a).flat();
await access(directory);
const dir = join(directory, query_dir);
const files = await readdir(dir);
return (await Promise.all(files.map(async file => {
const filepath = join(dir, file);
const stats = await stat(filepath);
return {
type: 'icon_list_item',
uri_icon: stats.isDirectory() ? null : (await app.getFileIcon(filepath)).toDataURL(),
material_icon: stats.isDirectory() ? 'folder' : null,
primary: file,
secondary: filepath,
executable: true,
complete: join(query_dir, file) + (stats.isDirectory() ? '/' : ''),
quality: base_query ? stringMatchQuality(base_query, file, regex) : 0.01,
file: join(dir, file),
preview: config.modules.folders.file_preview && generateFilePreview(filepath),
};
})));
} catch (e) {
return [];
}
}))).filter(a => a).flat();
},
execute: async (option) => {
exec(`xdg-open '${option.file.replace(/\'/g, "'\\''")}'`);
Expand Down
Loading

0 comments on commit 4372129

Please sign in to comment.