Skip to content

Commit bbed29a

Browse files
committed
新增:Linux 平台应用列表扫描支持
1 parent 6bf867b commit bbed29a

8 files changed

Lines changed: 136 additions & 21 deletions

File tree

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,20 @@ npm run dev
139139
npm run build
140140
```
141141

142+
### Ubuntu 开发环境
143+
144+
```shell
145+
sudo apt install -y make gcc g++ python3
146+
```
147+
148+
### Windows 开发环境
149+
150+
- 安装 `Visual Studio 2019`,并安装 `Desktop Development with C++` 相关组件
151+
152+
### MacOS 开发环境
153+
154+
- 安装 `Python3`
155+
142156
## 加入交流群
143157

144158
<table width="100%">

electron/lib/env.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {resolve} from "node:path";
22
import os from "os";
33
import {execSync} from "child_process";
4+
import {Log} from "../mapi/log";
45

56
export const isPackaged = ['true'].includes(process.env.IS_PACKAGED)
67

@@ -52,14 +53,17 @@ export const platformArch = (): 'x86' | 'arm64' | null => {
5253
let platformUUIDCache: string | null = null
5354
export const platformUUID = () => {
5455
if (null === platformUUIDCache) {
55-
if (isWin) {
56-
platformUUIDCache = execSync('wmic csproduct get UUID').toString().split('\n')[1].trim()
57-
} else if (isMac) {
58-
platformUUIDCache = execSync('system_profiler SPHardwareDataType | grep UUID').toString().split(': ')[1].trim()
59-
} else if (isLinux) {
60-
platformUUIDCache = execSync('cat /sys/class/dmi/id/product_uuid').toString().trim()
61-
} else {
62-
platformUUIDCache = ''
56+
try {
57+
if (isWin) {
58+
platformUUIDCache = execSync('wmic csproduct get UUID').toString().split('\n')[1].trim()
59+
} else if (isMac) {
60+
platformUUIDCache = execSync('system_profiler SPHardwareDataType | grep UUID').toString().split(': ')[1].trim()
61+
} else if (isLinux) {
62+
platformUUIDCache = execSync('cat /var/lib/dbus/machine-id').toString().trim().toUpperCase()
63+
}
64+
} catch (e) {
65+
Log.error('Env.platformUUID', e.message)
66+
platformUUIDCache = '000000'
6367
}
6468
}
6569
return platformUUIDCache
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import path from "node:path";
2+
import fs from "node:fs";
3+
4+
export const getIcon = async (desktopInfo: Record<string, string>, pathname: string, name: string) => {
5+
if (!desktopInfo.Icon) {
6+
return null
7+
}
8+
const themes = [
9+
'hicolor',
10+
];
11+
const sizes = ['scalable', '512x512', '256x256', '48x48', '32x32'];
12+
const types = [
13+
'apps',
14+
];
15+
const exts = ['.png', '.svg'];
16+
for (const theme of themes) {
17+
for (const size of sizes) {
18+
for (const type of types) {
19+
for (const ext of exts) {
20+
let iconPath = path.join('/usr/share/icons', theme, size, type, desktopInfo.Icon + ext);
21+
if (fs.existsSync(iconPath)) {
22+
return 'file://' + iconPath;
23+
}
24+
}
25+
}
26+
}
27+
}
28+
return null
29+
}
Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,78 @@
11
import {listFiles} from "../util";
22
import path from "path";
3+
import {ConfigLang} from "../../../../../../config/lang";
4+
import {getIcon} from "./icon";
5+
import {getAppTitle} from "./title";
6+
import fs from "node:fs";
37

48
export const ManagerAppLinux = {
59
list: async () => {
610
return lists()
711
}
812
}
913

14+
const appSet = new Set<string>();
15+
1016
const lists = async () => {
17+
appSet.clear()
1118
const files = await listFiles([
1219
"/usr/share/applications",
1320
"/var/lib/snapd/desktop/applications",
1421
`${process.env.HOME}/.local/share/applications`,
1522
])
16-
for (const file of files) {
17-
if (path.extname(file.pathname) !== ".desktop") {
23+
const apps = []
24+
const locale = ConfigLang.getLocale()
25+
for (const f of files) {
26+
if (appSet.has(f.pathname)) {
27+
// console.log('appSet.has', f.pathname)
28+
continue
29+
}
30+
const extname = path.extname(f.pathname);
31+
if (extname !== '.desktop') {
32+
continue
33+
}
34+
const app = {
35+
name: f.name.replace(/\.(desktop)$/, ''),
36+
title: f.name,
37+
pathname: f.pathname,
38+
icon: null,
39+
command: null,
40+
}
41+
const desktopInfo = await parseDesktopFile(app.pathname)
42+
app.icon = await getIcon(desktopInfo, app.pathname, app.name)
43+
app.title = await getAppTitle(desktopInfo, locale, app.pathname, app.name);
44+
if (!app.icon) {
45+
continue
46+
}
47+
if (!desktopInfo.Exec) {
1848
continue
1949
}
20-
//TODO
50+
let command = desktopInfo.Exec
51+
.replace(/ %[A-Za-z]/g, "")
52+
.replace(/"/g, "")
53+
.trim();
54+
if (desktopInfo.Terminal === 'true') {
55+
command = `gnome-terminal -x ${command}`
56+
}
57+
app.command = command
58+
appSet.add(app.pathname)
59+
apps.push(app)
60+
}
61+
return apps
62+
}
63+
64+
const parseDesktopFile = async (pathname: string): Promise<Record<string, string>> => {
65+
const content = fs.readFileSync(pathname, 'utf-8');
66+
const desktop = {};
67+
for (const line of content.split('\n')) {
68+
if (line.startsWith('[')) {
69+
continue;
70+
}
71+
const [key, value] = line.split('=');
72+
if (!key || !value) {
73+
continue;
74+
}
75+
desktop[key] = value;
2176
}
22-
return []
77+
return desktop
2378
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const langDirMap = {
2+
'zh-CN': ['zh_CN'],
3+
}
4+
5+
export const getAppTitle = async (desktopInfo: Record<string, string>, locale: string, pathname: string, name: string) => {
6+
if (locale in langDirMap) {
7+
for (const k of langDirMap[locale]) {
8+
const infoKey = `Name[${k}]`
9+
if (desktopInfo[infoKey]) {
10+
return desktopInfo[infoKey]
11+
}
12+
}
13+
}
14+
if (desktopInfo.Name) {
15+
return desktopInfo.Name
16+
}
17+
return name
18+
}
19+

electron/mapi/manager/system/plugin/app/mac/icon.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,7 @@ const getIconFile = (appFileInput) => {
1919
const mat = plistContent.match(/<key>CFBundleIconFile<\/key>\s*<string>(.*?)<\/string>/)
2020
if (mat) {
2121
const CFBundleIconFile = mat[1]
22-
const iconFile = path.join(
23-
appFileInput,
24-
'Contents',
25-
'Resources',
26-
CFBundleIconFile
27-
);
22+
const iconFile = path.join(appFileInput, 'Contents', 'Resources', CFBundleIconFile);
2823
const iconFiles = [iconFile, iconFile + '.icns', iconFile + '.tiff']
2924
const existedIcon = iconFiles.find((iconFile) => {
3025
return fs.existsSync(iconFile);

electron/mapi/manager/system/plugin/app/mac/title.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import {Files} from "../../../../../file/main";
2-
import fs from "node:fs";
32
import {IconvUtil} from "../../../../../../lib/util";
43

54
const langDirMap = {

src/types/Manager.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,8 @@ export type ActionRecord = {
183183
// type = command
184184
command?: string
185185
// type = view
186-
showFastPanel: boolean,
187-
showMainPanel: boolean,
186+
showFastPanel?: boolean,
187+
showMainPanel?: boolean,
188188
},
189189

190190
type?: ActionTypeEnum,

0 commit comments

Comments
 (0)