Skip to content

Commit

Permalink
新增:Linux 平台应用列表扫描支持
Browse files Browse the repository at this point in the history
  • Loading branch information
modstart committed Jan 15, 2025
1 parent 6bf867b commit bbed29a
Show file tree
Hide file tree
Showing 8 changed files with 136 additions and 21 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,20 @@ npm run dev
npm run build
```

### Ubuntu 开发环境

```shell
sudo apt install -y make gcc g++ python3
```

### Windows 开发环境

- 安装 `Visual Studio 2019`,并安装 `Desktop Development with C++` 相关组件

### MacOS 开发环境

- 安装 `Python3`

## 加入交流群

<table width="100%">
Expand Down
20 changes: 12 additions & 8 deletions electron/lib/env.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {resolve} from "node:path";
import os from "os";
import {execSync} from "child_process";
import {Log} from "../mapi/log";

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

Expand Down Expand Up @@ -52,14 +53,17 @@ export const platformArch = (): 'x86' | 'arm64' | null => {
let platformUUIDCache: string | null = null
export const platformUUID = () => {
if (null === platformUUIDCache) {
if (isWin) {
platformUUIDCache = execSync('wmic csproduct get UUID').toString().split('\n')[1].trim()
} else if (isMac) {
platformUUIDCache = execSync('system_profiler SPHardwareDataType | grep UUID').toString().split(': ')[1].trim()
} else if (isLinux) {
platformUUIDCache = execSync('cat /sys/class/dmi/id/product_uuid').toString().trim()
} else {
platformUUIDCache = ''
try {
if (isWin) {
platformUUIDCache = execSync('wmic csproduct get UUID').toString().split('\n')[1].trim()
} else if (isMac) {
platformUUIDCache = execSync('system_profiler SPHardwareDataType | grep UUID').toString().split(': ')[1].trim()
} else if (isLinux) {
platformUUIDCache = execSync('cat /var/lib/dbus/machine-id').toString().trim().toUpperCase()
}
} catch (e) {
Log.error('Env.platformUUID', e.message)
platformUUIDCache = '000000'
}
}
return platformUUIDCache
Expand Down
29 changes: 29 additions & 0 deletions electron/mapi/manager/system/plugin/app/linux/icon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import path from "node:path";
import fs from "node:fs";

export const getIcon = async (desktopInfo: Record<string, string>, pathname: string, name: string) => {
if (!desktopInfo.Icon) {
return null
}
const themes = [
'hicolor',
];
const sizes = ['scalable', '512x512', '256x256', '48x48', '32x32'];
const types = [
'apps',
];
const exts = ['.png', '.svg'];
for (const theme of themes) {
for (const size of sizes) {
for (const type of types) {
for (const ext of exts) {
let iconPath = path.join('/usr/share/icons', theme, size, type, desktopInfo.Icon + ext);
if (fs.existsSync(iconPath)) {
return 'file://' + iconPath;
}
}
}
}
}
return null
}
63 changes: 59 additions & 4 deletions electron/mapi/manager/system/plugin/app/linux/index.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,78 @@
import {listFiles} from "../util";
import path from "path";
import {ConfigLang} from "../../../../../../config/lang";
import {getIcon} from "./icon";
import {getAppTitle} from "./title";
import fs from "node:fs";

export const ManagerAppLinux = {
list: async () => {
return lists()
}
}

const appSet = new Set<string>();

const lists = async () => {
appSet.clear()
const files = await listFiles([
"/usr/share/applications",
"/var/lib/snapd/desktop/applications",
`${process.env.HOME}/.local/share/applications`,
])
for (const file of files) {
if (path.extname(file.pathname) !== ".desktop") {
const apps = []
const locale = ConfigLang.getLocale()
for (const f of files) {
if (appSet.has(f.pathname)) {
// console.log('appSet.has', f.pathname)
continue
}
const extname = path.extname(f.pathname);
if (extname !== '.desktop') {
continue
}
const app = {
name: f.name.replace(/\.(desktop)$/, ''),
title: f.name,
pathname: f.pathname,
icon: null,
command: null,
}
const desktopInfo = await parseDesktopFile(app.pathname)
app.icon = await getIcon(desktopInfo, app.pathname, app.name)
app.title = await getAppTitle(desktopInfo, locale, app.pathname, app.name);
if (!app.icon) {
continue
}
if (!desktopInfo.Exec) {
continue
}
//TODO
let command = desktopInfo.Exec
.replace(/ %[A-Za-z]/g, "")
.replace(/"/g, "")
.trim();
if (desktopInfo.Terminal === 'true') {
command = `gnome-terminal -x ${command}`
}
app.command = command
appSet.add(app.pathname)
apps.push(app)
}
return apps
}

const parseDesktopFile = async (pathname: string): Promise<Record<string, string>> => {
const content = fs.readFileSync(pathname, 'utf-8');
const desktop = {};
for (const line of content.split('\n')) {
if (line.startsWith('[')) {
continue;
}
const [key, value] = line.split('=');
if (!key || !value) {
continue;
}
desktop[key] = value;
}
return []
return desktop
}
19 changes: 19 additions & 0 deletions electron/mapi/manager/system/plugin/app/linux/title.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const langDirMap = {
'zh-CN': ['zh_CN'],
}

export const getAppTitle = async (desktopInfo: Record<string, string>, locale: string, pathname: string, name: string) => {
if (locale in langDirMap) {
for (const k of langDirMap[locale]) {
const infoKey = `Name[${k}]`
if (desktopInfo[infoKey]) {
return desktopInfo[infoKey]
}
}
}
if (desktopInfo.Name) {
return desktopInfo.Name
}
return name
}

7 changes: 1 addition & 6 deletions electron/mapi/manager/system/plugin/app/mac/icon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,7 @@ const getIconFile = (appFileInput) => {
const mat = plistContent.match(/<key>CFBundleIconFile<\/key>\s*<string>(.*?)<\/string>/)
if (mat) {
const CFBundleIconFile = mat[1]
const iconFile = path.join(
appFileInput,
'Contents',
'Resources',
CFBundleIconFile
);
const iconFile = path.join(appFileInput, 'Contents', 'Resources', CFBundleIconFile);
const iconFiles = [iconFile, iconFile + '.icns', iconFile + '.tiff']
const existedIcon = iconFiles.find((iconFile) => {
return fs.existsSync(iconFile);
Expand Down
1 change: 0 additions & 1 deletion electron/mapi/manager/system/plugin/app/mac/title.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {Files} from "../../../../../file/main";
import fs from "node:fs";
import {IconvUtil} from "../../../../../../lib/util";

const langDirMap = {
Expand Down
4 changes: 2 additions & 2 deletions src/types/Manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,8 @@ export type ActionRecord = {
// type = command
command?: string
// type = view
showFastPanel: boolean,
showMainPanel: boolean,
showFastPanel?: boolean,
showMainPanel?: boolean,
},

type?: ActionTypeEnum,
Expand Down

0 comments on commit bbed29a

Please sign in to comment.