1898 lines
63 KiB
JavaScript
1898 lines
63 KiB
JavaScript
import { ipcMain, dialog, Menu, clipboard, shell } from "electron";
|
|
import * as cheerio from "cheerio";
|
|
import url from "url";
|
|
import fs from "fs";
|
|
import path from "path";
|
|
import mime from "mime";
|
|
import index from "./index";
|
|
import util from "../util";
|
|
import xml2js from "xml2js";
|
|
import os from "os";
|
|
import request from "request";
|
|
import URI from "urijs";
|
|
import retry from "retry";
|
|
import cacheData from "../cache/data";
|
|
import ItemJS from "@/main/item/index";
|
|
import ClassificationJS from "@/main/classification/index";
|
|
const { execSync } = require("child_process");
|
|
|
|
/**
|
|
* 随机user-agent
|
|
* @returns {string}
|
|
*/
|
|
function getRandomUserAgent() {
|
|
const userAgents = [
|
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
|
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
|
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0",
|
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Firefox/89.0",
|
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36",
|
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36",
|
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.59",
|
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.59",
|
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0",
|
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Firefox/89.0",
|
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 OPR/76.0.4017.123",
|
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 OPR/76.0.4017.123",
|
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0",
|
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Firefox/89.0",
|
|
];
|
|
const randomIndex = Math.floor(Math.random() * userAgents.length);
|
|
return userAgents[randomIndex];
|
|
}
|
|
|
|
/**
|
|
* 发送网址信息
|
|
* @param item
|
|
*/
|
|
function sendUrlInfo(item) {
|
|
global.mainWindow.webContents.send("getUrlInfo", JSON.stringify(item));
|
|
}
|
|
|
|
/**
|
|
* 获取代理
|
|
*/
|
|
function getProxy() {
|
|
if (global.setting.network.useProxy && !util.strIsEmpty(global.setting.network.proxy.address)) {
|
|
let uri = new URI(global.setting.network.proxy.address);
|
|
if (!util.strIsEmpty(uri.protocol())) {
|
|
let address = uri.protocol().toLowerCase() + "://";
|
|
if (!util.strIsEmpty(global.setting.network.proxy.username) && !util.strIsEmpty(global.setting.network.proxy.password)) {
|
|
address += global.setting.network.proxy.username + ":" + global.setting.network.proxy.password + "@";
|
|
}
|
|
address += uri.hostname() + ":" + uri.port();
|
|
return address;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* 获取网址信息
|
|
* @param u 网址
|
|
* @param r 是否支持跳转获取
|
|
*/
|
|
function getUrlInfo(u, r) {
|
|
let result = {
|
|
status: false,
|
|
message: null,
|
|
name: null,
|
|
icon: null,
|
|
};
|
|
// 重试
|
|
const operation = retry.operation({
|
|
retries: 5, // 最多重试 5 次
|
|
factor: 1, // 每次重试之间的时间间隔加倍
|
|
minTimeout: 1000, // 第一次重试之前等待的时间
|
|
maxTimeout: 5000, // 最长等待时间
|
|
});
|
|
try {
|
|
// 发起请求
|
|
operation.attempt((currentAttempt) => {
|
|
request(
|
|
{
|
|
uri: u,
|
|
proxy: getProxy(),
|
|
timeout: 5000,
|
|
headers: {
|
|
"User-Agent": getRandomUserAgent(),
|
|
},
|
|
},
|
|
function (error, response, body) {
|
|
if (operation.retry(error)) {
|
|
return;
|
|
}
|
|
if (!error && response.statusCode >= 200 && response.statusCode <= 299) {
|
|
// 解析HTML
|
|
let $ = cheerio.load(body);
|
|
// 是否有跳转标签
|
|
let refresh = $("meta[http-equiv='refresh']");
|
|
if (refresh != null && !util.strIsEmpty(refresh.attr("content")) && r) {
|
|
// 如果有跳转标签的话,就请求新网址并获取网址信息
|
|
let content = refresh.attr("content");
|
|
let contentSplit = content.split(";");
|
|
let urlProperty = contentSplit[contentSplit.length - 1];
|
|
let urlPropertySplit = urlProperty.split("=");
|
|
let newUrl = urlPropertySplit[urlPropertySplit.length - 1];
|
|
// 重新获取新网址信息
|
|
getUrlInfo(newUrl, false);
|
|
} else {
|
|
// 解析HTML并返回信息
|
|
analysisHTML(u, body);
|
|
}
|
|
} else {
|
|
sendUrlInfo(result);
|
|
}
|
|
}
|
|
);
|
|
});
|
|
} catch (e) {
|
|
sendUrlInfo(result);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 解析HTML并返回信息
|
|
* @param u url
|
|
* @param data HTML
|
|
*/
|
|
function analysisHTML(u, data) {
|
|
let result = {
|
|
status: false,
|
|
message: null,
|
|
name: null,
|
|
icon: null,
|
|
};
|
|
try {
|
|
// 解析HTML
|
|
let $ = cheerio.load(data);
|
|
// 获取标题
|
|
result.name = $("head").find("title").text();
|
|
// 获取图标URL
|
|
let iconUrl;
|
|
let icon = $("link[rel='icon']");
|
|
if (icon != null && !util.strIsEmpty(icon.attr("href"))) {
|
|
iconUrl = icon.attr("href");
|
|
} else {
|
|
let shortcutIcon = $("link[rel='shortcut icon']");
|
|
if (shortcutIcon != null && !util.strIsEmpty(shortcutIcon.attr("href"))) {
|
|
iconUrl = shortcutIcon.attr("href");
|
|
} else {
|
|
iconUrl = "/favicon.ico";
|
|
}
|
|
}
|
|
if (!util.strIsEmpty(iconUrl)) {
|
|
// 解析URL
|
|
let urlParse = url.parse(u);
|
|
// 新图标URL
|
|
let newIconUrl = "";
|
|
// 去掉类似//www.baidu.com/favicon.ico这样域名的”//“字符
|
|
if (iconUrl.indexOf("//") == 0) {
|
|
iconUrl = "http:" + iconUrl;
|
|
}
|
|
// 如果url包含https://或者http://就是正常的链接
|
|
if (iconUrl.indexOf("http://") >= 0 || iconUrl.indexOf("https://") >= 0) {
|
|
newIconUrl = iconUrl;
|
|
} else {
|
|
// 无协议头,使用当前网址域名
|
|
newIconUrl = url.resolve("http://" + urlParse.host + (urlParse.port != null ? ":" + urlParse.port : ""), iconUrl);
|
|
}
|
|
// 重试
|
|
const operation = retry.operation({
|
|
retries: 5, // 最多重试 5 次
|
|
factor: 1, // 每次重试之间的时间间隔加倍
|
|
minTimeout: 1000, // 第一次重试之前等待的时间
|
|
maxTimeout: 5000, // 最长等待时间
|
|
});
|
|
operation.attempt((currentAttempt) => {
|
|
// 下载图标
|
|
request(
|
|
{
|
|
uri: newIconUrl,
|
|
proxy: getProxy(),
|
|
encoding: null,
|
|
timeout: 5000,
|
|
headers: {
|
|
"User-Agent": getRandomUserAgent(),
|
|
},
|
|
},
|
|
function (error, response, body) {
|
|
if (operation.retry(error)) {
|
|
return;
|
|
}
|
|
if (!error && response.statusCode >= 200 && response.statusCode <= 299) {
|
|
let buffer = Buffer.from(body);
|
|
result.icon = "data:" + mime.getType(newIconUrl) + ";base64," + buffer.toString("base64");
|
|
result.status = true;
|
|
sendUrlInfo(result);
|
|
} else {
|
|
sendUrlInfo(result);
|
|
}
|
|
}
|
|
);
|
|
});
|
|
} else {
|
|
sendUrlInfo(result);
|
|
}
|
|
} catch (e) {
|
|
sendUrlInfo(result);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取文件图标
|
|
* @param target
|
|
* @param message
|
|
*/
|
|
async function getFileIcon(target, message) {
|
|
return await index.getFileIcon(target, message);
|
|
}
|
|
|
|
/**
|
|
* 转换为菜单
|
|
*
|
|
* @param classificationParentId
|
|
* @param classificationChildId
|
|
* @param id
|
|
* @param list
|
|
* @param del
|
|
*/
|
|
function convertMenu(classificationParentId, classificationChildId, id, list, del) {
|
|
let menuList = [];
|
|
for (let i = 0; i < list.length; i++) {
|
|
let classification = list[i];
|
|
let menu = {
|
|
label: classification.name,
|
|
};
|
|
let submenu = [];
|
|
if (!util.arrayIsEmpty(classification.childList)) {
|
|
for (let j = 0; j < classification.childList.length; j++) {
|
|
if (util.strIsEmpty(classification.childList[j].mapDirectory) && (classification.childList[j].type == null || classification.childList[j].type != 1)) {
|
|
submenu.push({
|
|
label: classification.childList[j].name,
|
|
click: () => {
|
|
let params = {
|
|
from: {
|
|
classificationParentId: classificationParentId,
|
|
classificationChildId: classificationChildId,
|
|
id: id,
|
|
},
|
|
to: {
|
|
classificationParentId: classification.id,
|
|
classificationChildId: classification.childList[j].id,
|
|
},
|
|
del: del,
|
|
};
|
|
global.mainWindow.webContents.send("moveItem", JSON.stringify(params));
|
|
},
|
|
});
|
|
}
|
|
}
|
|
}
|
|
if (!util.arrayIsEmpty(submenu)) {
|
|
menu.submenu = submenu;
|
|
menu.type = "submenu";
|
|
} else {
|
|
menu.type = "normal";
|
|
menu.click = () => {
|
|
let params = {
|
|
from: {
|
|
classificationParentId: classificationParentId,
|
|
classificationChildId: classificationChildId,
|
|
id: id,
|
|
},
|
|
to: {
|
|
classificationParentId: classification.id,
|
|
classificationChildId: null,
|
|
},
|
|
del: del,
|
|
};
|
|
global.mainWindow.webContents.send("moveItem", JSON.stringify(params));
|
|
};
|
|
}
|
|
if (util.strIsEmpty(classification.mapDirectory) && (classification.type == null || classification.type != 1)) {
|
|
menuList.push(menu);
|
|
}
|
|
}
|
|
return menuList;
|
|
}
|
|
|
|
/**
|
|
* 批量操作转换为菜单
|
|
*
|
|
* @param list
|
|
* @param del
|
|
*/
|
|
function batchOperationConvertMenu(list, del) {
|
|
let menuList = [];
|
|
for (let i = 0; i < list.length; i++) {
|
|
let classification = list[i];
|
|
let menu = {
|
|
label: classification.name,
|
|
};
|
|
let submenu = [];
|
|
if (!util.arrayIsEmpty(classification.childList)) {
|
|
for (let j = 0; j < classification.childList.length; j++) {
|
|
if (util.strIsEmpty(classification.childList[j].mapDirectory) && (classification.childList[j].type == null || classification.childList[j].type != 1)) {
|
|
submenu.push({
|
|
label: classification.childList[j].name,
|
|
click: () => {
|
|
dialog
|
|
.showMessageBox(global.mainWindow, {
|
|
message: del ? global.currentLanguage.batchMoveItemMessage : global.currentLanguage.batchCopyItemMessage,
|
|
buttons: [global.currentLanguage.ok, global.currentLanguage.cancel],
|
|
type: "question",
|
|
noLink: true,
|
|
cancelId: 1,
|
|
})
|
|
.then((r) => {
|
|
if (r.response == 0) {
|
|
let params = {
|
|
to: {
|
|
classificationParentId: classification.id,
|
|
classificationChildId: classification.childList[j].id,
|
|
},
|
|
del: del,
|
|
};
|
|
global.mainWindow.webContents.send("batchMoveItem", JSON.stringify(params));
|
|
}
|
|
});
|
|
},
|
|
});
|
|
}
|
|
}
|
|
}
|
|
if (!util.arrayIsEmpty(submenu)) {
|
|
menu.submenu = submenu;
|
|
menu.type = "submenu";
|
|
} else {
|
|
menu.type = "normal";
|
|
menu.click = () => {
|
|
dialog
|
|
.showMessageBox(global.mainWindow, {
|
|
message: del ? global.currentLanguage.batchMoveItemMessage : global.currentLanguage.batchCopyItemMessage,
|
|
buttons: [global.currentLanguage.ok, global.currentLanguage.cancel],
|
|
type: "question",
|
|
noLink: true,
|
|
cancelId: 1,
|
|
})
|
|
.then((r) => {
|
|
if (r.response == 0) {
|
|
let params = {
|
|
to: {
|
|
classificationParentId: classification.id,
|
|
classificationChildId: null,
|
|
},
|
|
del: del,
|
|
};
|
|
global.mainWindow.webContents.send("batchMoveItem", JSON.stringify(params));
|
|
}
|
|
});
|
|
};
|
|
}
|
|
if (util.strIsEmpty(classification.mapDirectory) && (classification.type == null || classification.type != 1)) {
|
|
menuList.push(menu);
|
|
}
|
|
}
|
|
return menuList;
|
|
}
|
|
|
|
/**
|
|
* 读取路径下的文件
|
|
* @param path
|
|
* @returns {*[]}
|
|
*/
|
|
function getPathProgramList(path) {
|
|
let resultList = [];
|
|
try {
|
|
// 读取开始菜单下所有内容
|
|
let pathList = fs.readdirSync(path);
|
|
// 循环判断文件类型
|
|
for (let p of pathList) {
|
|
// 完整路径
|
|
let fullPath = path + "\\" + p;
|
|
// 判断文件类型
|
|
let stats;
|
|
try {
|
|
// 文件类型
|
|
stats = fs.statSync(fullPath);
|
|
// 如果是文件夹继续向下读取,如果是文件则添加到返回列表
|
|
if (stats.isDirectory()) {
|
|
// 文件夹
|
|
resultList.push(...getPathProgramList(fullPath));
|
|
} else {
|
|
// 文件
|
|
resultList.push(fullPath);
|
|
}
|
|
} catch (e) {
|
|
if (process.env.NODE_ENV !== "production") {
|
|
console.log(e);
|
|
}
|
|
}
|
|
}
|
|
} catch (e) {
|
|
if (process.env.NODE_ENV !== "production") {
|
|
console.log(e);
|
|
}
|
|
}
|
|
return resultList;
|
|
}
|
|
|
|
/**
|
|
* 获取最大图标尺寸
|
|
*/
|
|
function getMaxIconSize(list, name, type) {
|
|
// 获取最大图标尺寸
|
|
let max = null;
|
|
for (let targetSize of list) {
|
|
let s = targetSize.replace(name + "." + type + "-", "").split("_");
|
|
let size = Number(s[0].replace(".png", ""));
|
|
if (max == null) {
|
|
max = size;
|
|
} else {
|
|
if (size > max) {
|
|
max = size;
|
|
}
|
|
}
|
|
}
|
|
return max;
|
|
}
|
|
|
|
/**
|
|
* 接续XML同步
|
|
* @param xml
|
|
* @returns {Promise<unknown>}
|
|
*/
|
|
async function xml2jsSync(xml) {
|
|
let parser = new xml2js.Parser();
|
|
return new Promise((resolve, reject) => {
|
|
parser.parseString(xml, function (err, json) {
|
|
if (err) reject(err);
|
|
else resolve(json);
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 获取AppxPropertiesLogo
|
|
* @param installLocation
|
|
* @param result
|
|
* @returns {string|null}
|
|
*/
|
|
function getPropertiesIcon(installLocation, result) {
|
|
if (result.Package.Properties != null) {
|
|
if (result.Package.Properties[0].Logo != null) {
|
|
let logo = result.Package.Properties[0].Logo[0];
|
|
return installLocation + "\\" + logo;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* 获取Appx信息
|
|
*/
|
|
async function getAppxInfo(installLocation) {
|
|
let appxInfo = {};
|
|
let buffer, result;
|
|
try {
|
|
buffer = fs.readFileSync(installLocation + "\\AppxManifest.xml");
|
|
result = await xml2jsSync(buffer);
|
|
// 备用,如果没有名称的话
|
|
let executable = null;
|
|
// targetsize图标
|
|
let targetSizeIcon = null;
|
|
let targetSizeIconMax = null;
|
|
// scale图标
|
|
let scaleIcon = null;
|
|
let scaleIconMax = null;
|
|
// 图标 APPID
|
|
if (result.Package.Applications != null && result.Package.Applications[0] != null) {
|
|
if (result.Package.Applications[0].Application[0] != null) {
|
|
// APPID
|
|
appxInfo.appId = result.Package.Applications[0].Application[0].$.Id;
|
|
// Executable
|
|
executable = result.Package.Applications[0].Application[0].$.Executable;
|
|
// 图标
|
|
if (result.Package.Applications[0].Application[0]["uap:VisualElements"] != null) {
|
|
// logo地址
|
|
let logo = result.Package.Applications[0].Application[0]["uap:VisualElements"][0].$.Square44x44Logo;
|
|
// 解析路径
|
|
let parsedPath = path.parse(logo);
|
|
// 获取文件夹下所有文件
|
|
let fileNameList = fs.readdirSync(installLocation + "\\" + parsedPath.dir);
|
|
// 筛选出和包含logo名称的文件名
|
|
let filterList = fileNameList.filter((f) => f.indexOf(parsedPath.name) >= 0);
|
|
if (filterList.length > 1) {
|
|
// 获取targetsize图片
|
|
let targetSizeList = filterList.filter((f) => f.indexOf(parsedPath.name + ".targetsize") >= 0);
|
|
if (targetSizeList.length > 0) {
|
|
// 获取最大图标尺寸
|
|
let max = getMaxIconSize(targetSizeList, parsedPath.name, "targetsize");
|
|
if (max != null) {
|
|
// 记录max
|
|
targetSizeIconMax = max;
|
|
// 先获取最终图标
|
|
let defaultList = targetSizeList.filter(
|
|
(f) => f == parsedPath.name + ".targetsize-" + max + "_altform-unplated_devicefamily-colorfulunplated.png"
|
|
);
|
|
targetSizeIcon =
|
|
defaultList.length > 0
|
|
? installLocation +
|
|
"\\" +
|
|
parsedPath.dir +
|
|
"\\" +
|
|
parsedPath.name +
|
|
".targetsize-" +
|
|
max +
|
|
"_altform-unplated_devicefamily-colorfulunplated.png"
|
|
: null;
|
|
if (targetSizeIcon == null) {
|
|
// 获取 名称.targetsize-{max}_altform-unplated.png
|
|
let defaultUnplatedList = targetSizeList.filter((f) => f == parsedPath.name + ".targetsize-" + max + "_altform-unplated.png");
|
|
if (defaultUnplatedList.length > 0) {
|
|
targetSizeIcon = installLocation + "\\" + parsedPath.dir + "\\" + parsedPath.name + ".targetsize-" + max + "_altform-unplated.png";
|
|
} else {
|
|
// 获取 名称.targetsize-{max}_altform.png
|
|
let defaultAltFormList = targetSizeList.filter((f) => f == parsedPath.name + ".targetsize-" + max + "_altform.png");
|
|
if (defaultAltFormList.length > 0) {
|
|
targetSizeIcon = installLocation + "\\" + parsedPath.dir + "\\" + parsedPath.name + ".targetsize-" + max + "_altform.png";
|
|
} else {
|
|
// 获取 名称.targetsize-{max}.png
|
|
let defaultTargetSizeList = targetSizeList.filter((f) => f == parsedPath.name + ".targetsize-" + max + ".png");
|
|
if (defaultTargetSizeList.length > 0) {
|
|
targetSizeIcon = installLocation + "\\" + parsedPath.dir + "\\" + defaultTargetSizeList[0];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// 获取scale图片
|
|
let scaleList = filterList.filter((f) => f.indexOf(parsedPath.name + ".scale") >= 0);
|
|
if (scaleList.length > 0) {
|
|
// 获取最大图标尺寸
|
|
let max = getMaxIconSize(scaleList, parsedPath.name, "scale");
|
|
if (max != null) {
|
|
// 记录max
|
|
scaleIconMax = max;
|
|
// 获取 名称.scale-{max}.png
|
|
let defaultList = scaleList.filter((f) => f == parsedPath.name + ".scale-" + max + ".png");
|
|
if (defaultList.length > 0) {
|
|
scaleIcon = installLocation + "\\" + parsedPath.dir + "\\" + defaultList[0];
|
|
}
|
|
}
|
|
} else {
|
|
scaleList = filterList.filter((f) => f.indexOf(parsedPath.name + ".Theme-Dark_Scale") >= 0);
|
|
if (scaleList.length > 0) {
|
|
let max = getMaxIconSize(scaleList, parsedPath.name, "Theme-Dark_Scale");
|
|
if (max != null) {
|
|
// 记录max
|
|
scaleIconMax = max;
|
|
// 获取 名称.Theme-Dark_Scale{max}.png
|
|
let defaultList = scaleList.filter((f) => f == parsedPath.name + ".Theme-Dark_Scale-" + max + ".png");
|
|
if (defaultList.length > 0) {
|
|
scaleIcon = installLocation + "\\" + parsedPath.dir + "\\" + defaultList[0];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (filterList.length == 1) {
|
|
// 只有一张图片
|
|
appxInfo.icon = installLocation + "\\" + parsedPath.dir + "\\" + filterList[0];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (appxInfo.icon == null) {
|
|
// 判断图标大小
|
|
if (targetSizeIcon != null && scaleIcon == null) {
|
|
appxInfo.icon = targetSizeIcon;
|
|
} else if (targetSizeIcon == null && scaleIcon != null) {
|
|
appxInfo.icon = scaleIcon;
|
|
} else if (targetSizeIcon != null && scaleIcon != null) {
|
|
if (targetSizeIconMax == 256 || targetSizeIconMax > scaleIconMax) {
|
|
appxInfo.icon = targetSizeIcon;
|
|
} else if (targetSizeIconMax < scaleIconMax) {
|
|
appxInfo.icon = scaleIcon;
|
|
} else {
|
|
appxInfo.icon = targetSizeIcon;
|
|
}
|
|
} else if (targetSizeIcon == null && scaleIcon == null) {
|
|
let propertiesIcon = getPropertiesIcon(installLocation, result);
|
|
if (propertiesIcon != null) {
|
|
appxInfo.icon = propertiesIcon;
|
|
}
|
|
}
|
|
}
|
|
// 名称
|
|
if (result.Package.Properties != null) {
|
|
if (result.Package.Properties[0].DisplayName != null) {
|
|
appxInfo.name = result.Package.Properties[0].DisplayName[0];
|
|
}
|
|
}
|
|
if (appxInfo.name == null || (appxInfo.name != null && appxInfo.name.indexOf("ms-resource:") >= 0)) {
|
|
if (executable != null && executable.indexOf("ms-resource:") < 0) {
|
|
appxInfo.name = path.parse(executable).name;
|
|
} else {
|
|
appxInfo.name = null;
|
|
}
|
|
}
|
|
if (appxInfo.name == null) {
|
|
if (result.Package.Identity != null && result.Package.Identity[0] != null) {
|
|
let name = result.Package.Identity[0].$.Name;
|
|
if (name != null && name.indexOf("ms-resource:") < 0) {
|
|
appxInfo.name = name;
|
|
}
|
|
}
|
|
}
|
|
} catch (ex) {
|
|
if (result != null) {
|
|
let propertiesIcon = getPropertiesIcon(installLocation, result);
|
|
if (propertiesIcon != null) {
|
|
appxInfo.icon = propertiesIcon;
|
|
}
|
|
}
|
|
if (process.env.NODE_ENV !== "production") {
|
|
console.log(ex);
|
|
}
|
|
}
|
|
return appxInfo;
|
|
}
|
|
|
|
/**
|
|
* 刷新图标缓存
|
|
* @param item
|
|
*/
|
|
async function refreshIconCache(item) {
|
|
let info = {};
|
|
if (item.type == 0 || item.type == 1) {
|
|
info.icon = await getFileIcon(item.path, false);
|
|
} else {
|
|
let appxInfo = await getAppxInfo(item.installLocation);
|
|
if (appxInfo.icon != null) {
|
|
try {
|
|
let buffer = fs.readFileSync(appxInfo.icon);
|
|
info.icon = "data:" + mime.getType(appxInfo.icon) + ";base64," + buffer.toString("base64");
|
|
info.iconPath = appxInfo.icon;
|
|
} catch (ex) {
|
|
if (process.env.NODE_ENV !== "production") {
|
|
console.log(ex);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return info;
|
|
}
|
|
|
|
/**
|
|
* 刷新图标缓存
|
|
* @param item
|
|
*/
|
|
async function refreshIconCacheList(classificationParentId, classificationChildId) {
|
|
// 获取分类下所有项目
|
|
let classification;
|
|
if (classificationParentId != null) {
|
|
let classificationParent;
|
|
for (let c of global.list) {
|
|
if (c.id == classificationParentId) {
|
|
classificationParent = c;
|
|
break;
|
|
}
|
|
}
|
|
if (classificationChildId != null) {
|
|
if (!util.arrayIsEmpty(classificationParent.childList)) {
|
|
let classificationChild;
|
|
for (let c of classificationParent.childList) {
|
|
if (c.id == classificationChildId) {
|
|
classificationChild = c;
|
|
break;
|
|
}
|
|
}
|
|
classification = classificationChild;
|
|
} else {
|
|
classification = classificationParent;
|
|
}
|
|
} else {
|
|
classification = classificationParent;
|
|
}
|
|
}
|
|
let resultList = [];
|
|
if (classification != null && !util.arrayIsEmpty(classification.itemList)) {
|
|
// 刷新所有项目图标
|
|
for (let item of classification.itemList) {
|
|
if ((item.type == 0 || item.type == 1 || item.type == 5) && (item.notRefreshIcon == null || !item.notRefreshIcon)) {
|
|
let info = await refreshIconCache(item);
|
|
info.itemId = item.id;
|
|
resultList.push(info);
|
|
}
|
|
}
|
|
}
|
|
return resultList;
|
|
}
|
|
|
|
/**
|
|
* 读取文件
|
|
* @param pathArr
|
|
*/
|
|
async function readFiles(pathArr) {
|
|
let itemList = [];
|
|
for (let filePath of pathArr) {
|
|
try {
|
|
let item = {
|
|
// id
|
|
id: null,
|
|
// 路径
|
|
path: null,
|
|
// url
|
|
url: null,
|
|
// 名称
|
|
name: null,
|
|
// 图标
|
|
icon: null,
|
|
// 参数
|
|
params: null,
|
|
// 以管理员身份运行
|
|
admin: false,
|
|
// 类型 0:文件 1:文件夹 2:网址
|
|
type: 0,
|
|
// 排序
|
|
order: 0,
|
|
};
|
|
// path
|
|
let target = filePath;
|
|
// 文件名
|
|
item.name = path.basename(target);
|
|
// 判断是否是快捷方式,如果是的话,需要获取真实路径
|
|
if (mime.getType(filePath) == "application/x-ms-shortcut") {
|
|
// 快捷方式
|
|
// 获取真实文件路径和参数
|
|
let shortcutDetail = global.api.GetShortcutFile(filePath);
|
|
if (util.strIsEmpty(shortcutDetail.target)) {
|
|
// 路径
|
|
target = filePath;
|
|
} else {
|
|
// 路径
|
|
target = shortcutDetail.target;
|
|
}
|
|
// 参数
|
|
item.params = !util.strIsEmpty(shortcutDetail.arguments) ? shortcutDetail.arguments : null;
|
|
}
|
|
// 文件类型
|
|
let stats = fs.statSync(target);
|
|
// 路径
|
|
item.path = target;
|
|
item.type = stats.isFile() ? 0 : 1;
|
|
// 获取图标
|
|
item.icon = await getFileIcon(target, true);
|
|
// 去掉后缀
|
|
if (item.type == 0) {
|
|
item.name = util.removeSuffix(item.name);
|
|
}
|
|
// add
|
|
itemList.push(item);
|
|
} catch (e) {
|
|
if (process.env.NODE_ENV !== "production") {
|
|
console.log(e);
|
|
}
|
|
}
|
|
}
|
|
return itemList;
|
|
}
|
|
|
|
/**
|
|
* 获取开始菜单程序
|
|
*/
|
|
async function getStartMenuProgramList() {
|
|
// 返回列表
|
|
let resultList = [];
|
|
// appData
|
|
let appDataPathList = getPathProgramList(process.env["AppData"] + "\\Microsoft\\Windows\\Start Menu\\Programs");
|
|
// programData
|
|
let programDataPathList = getPathProgramList(process.env["ProgramData"] + "\\Microsoft\\Windows\\Start Menu\\Programs");
|
|
// list
|
|
let pathList = [];
|
|
pathList.push(...appDataPathList);
|
|
pathList.push(...programDataPathList);
|
|
// 查询缓存
|
|
let cacheStartMenuProgramList = cacheData.cacheStore.get("startMenuProgramList");
|
|
// 循环组装数据
|
|
for (let p of pathList) {
|
|
// 获取后缀,必须是快捷方式
|
|
if (mime.getType(p) == "application/x-ms-shortcut") {
|
|
// 获取名称去掉后缀
|
|
let name = util.removeSuffix(path.basename(p));
|
|
// 查重
|
|
let flag = false;
|
|
for (let e of resultList) {
|
|
if (e.name == name) {
|
|
flag = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!flag) {
|
|
let exist = false;
|
|
// 是否存在如果存在的话不需要重新获取图标
|
|
if (!util.arrayIsEmpty(cacheStartMenuProgramList)) {
|
|
for (let pro of cacheStartMenuProgramList) {
|
|
if (name == pro.name && p == pro.path) {
|
|
resultList.push(pro);
|
|
exist = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!exist) {
|
|
// data
|
|
let data = {
|
|
name: name,
|
|
path: p,
|
|
icon: await getFileIcon(p, true),
|
|
};
|
|
// push
|
|
resultList.push(data);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// 排序
|
|
resultList.sort((a, b) => a.name.localeCompare(b.name));
|
|
// 写入缓存
|
|
cacheData.cacheStore.set("startMenuProgramList", resultList);
|
|
// 返回
|
|
return resultList;
|
|
}
|
|
|
|
/**
|
|
* 获取Appx列表
|
|
*/
|
|
async function getAppxList() {
|
|
let resultList = [];
|
|
try {
|
|
let release = os.release();
|
|
let releaseSplit = release.split(".");
|
|
if (Number(releaseSplit[0]) >= 10) {
|
|
let stdout = execSync('powershell -Command "Get-AppxPackage | Select-Object PackageFamilyName, InstallLocation | Format-list"');
|
|
stdout = stdout.toString("UTF8");
|
|
let split = stdout.trim().split("\r\n");
|
|
split = split.filter((str) => str.trim() != "");
|
|
let list = [];
|
|
let packageFamilyName = null;
|
|
let installLocation = null;
|
|
let prev = null;
|
|
for (let i = 0; i < split.length; i++) {
|
|
let t = split[i].trim();
|
|
let s = t.split(" : ");
|
|
if (s.length > 1) {
|
|
if (s[0].trim() == "PackageFamilyName") {
|
|
if (packageFamilyName != null && installLocation != null) {
|
|
list.push({
|
|
packageFamilyName: packageFamilyName,
|
|
installLocation: installLocation,
|
|
});
|
|
packageFamilyName = s[1].trim();
|
|
installLocation = null;
|
|
prev = "PackageFamilyName";
|
|
} else {
|
|
packageFamilyName = s[1].trim();
|
|
prev = "PackageFamilyName";
|
|
}
|
|
} else if (s[0].trim() == "InstallLocation") {
|
|
installLocation = s[1].trim();
|
|
prev = "InstallLocation";
|
|
}
|
|
} else {
|
|
if (prev == "PackageFamilyName") {
|
|
packageFamilyName += t;
|
|
} else if (prev == "InstallLocation") {
|
|
installLocation += t;
|
|
}
|
|
}
|
|
}
|
|
if (packageFamilyName != null && installLocation != null) {
|
|
list.push({
|
|
packageFamilyName: packageFamilyName,
|
|
installLocation: installLocation,
|
|
});
|
|
}
|
|
// 读取XML获取图标路径和名称
|
|
for (let e of list) {
|
|
let appxInfo = await getAppxInfo(e.installLocation);
|
|
e.appId = appxInfo.appId;
|
|
e.icon = appxInfo.icon;
|
|
e.name = appxInfo.name;
|
|
}
|
|
// 过滤
|
|
let filterList = list.filter((e) => e.icon != null && e.appId != null && e.name != null);
|
|
// 图标转BASE64
|
|
for (let e of filterList) {
|
|
try {
|
|
let buffer = fs.readFileSync(e.icon);
|
|
let icon = "data:" + mime.getType(e.icon) + ";base64," + buffer.toString("base64");
|
|
e.originalIcon = e.icon;
|
|
e.icon = icon;
|
|
} catch (ex) {
|
|
if (process.env.NODE_ENV !== "production") {
|
|
console.log(ex);
|
|
}
|
|
e.icon = null;
|
|
}
|
|
}
|
|
// 返回列表
|
|
resultList = filterList.filter((e) => e.icon != null);
|
|
// 排序
|
|
resultList.sort((a, b) => a.name.localeCompare(b.name));
|
|
}
|
|
} catch (e) {
|
|
if (process.env.NODE_ENV !== "production") {
|
|
console.log(e);
|
|
}
|
|
}
|
|
return resultList;
|
|
}
|
|
|
|
/**
|
|
* 图片转BASE64
|
|
*/
|
|
function imageToBase64(path) {
|
|
fs.readFile(path, (err, data) => {
|
|
let buffer = Buffer.from(data);
|
|
let icon = "data:" + mime.getType(path) + ";base64," + buffer.toString("base64");
|
|
global.mainWindow.webContents.send("imageToBase64", icon);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 下载图片
|
|
* @param url
|
|
*/
|
|
function downloadImage(url) {
|
|
let result = {
|
|
status: false,
|
|
message: global.currentLanguage.downloadImageFailedMessage,
|
|
name: null,
|
|
icon: null,
|
|
};
|
|
// 重试
|
|
const operation = retry.operation({
|
|
retries: 5, // 最多重试 5 次
|
|
factor: 1, // 每次重试之间的时间间隔加倍
|
|
minTimeout: 1000, // 第一次重试之前等待的时间
|
|
maxTimeout: 5000, // 最长等待时间
|
|
});
|
|
operation.attempt((currentAttempt) => {
|
|
// 下载图片
|
|
request(
|
|
{
|
|
uri: url,
|
|
proxy: getProxy(),
|
|
encoding: null,
|
|
timeout: 5000,
|
|
headers: {
|
|
"User-Agent": getRandomUserAgent(),
|
|
},
|
|
},
|
|
function (error, response, body) {
|
|
if (operation.retry(error)) {
|
|
return;
|
|
}
|
|
if (!error && response.statusCode >= 200 && response.statusCode <= 299) {
|
|
if (response.headers != null && response.headers["content-type"] != null) {
|
|
let ext = mime.getExtension(response.headers["content-type"]);
|
|
if (ext == "jpg" || ext == "jpeg" || ext == "png" || ext == "gif" || ext == "ico" || ext == "svg") {
|
|
let buffer = Buffer.from(body);
|
|
result.icon = "data:" + mime.getType(response.headers["content-type"]) + ";base64," + buffer.toString("base64");
|
|
result.status = true;
|
|
result.message = null;
|
|
} else {
|
|
result.icon = null;
|
|
result.status = false;
|
|
result.message = global.currentLanguage.downloadImageNotImageFormatMessage;
|
|
}
|
|
}
|
|
}
|
|
returnDownloadImage(result);
|
|
}
|
|
);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 返回下载图片信息
|
|
* @param result
|
|
*/
|
|
function returnDownloadImage(result) {
|
|
global.mainWindow.webContents.send("returnDownloadImage", JSON.stringify(result));
|
|
}
|
|
|
|
/**
|
|
* 添加/修改项目菜单项
|
|
* @param type
|
|
* @param classificationParentId
|
|
* @param classificationChildId
|
|
* @param id
|
|
* @param itemType
|
|
*/
|
|
function addEditItemMenu(type, classificationParentId, classificationChildId, id, itemType) {
|
|
let params = {
|
|
type: type,
|
|
classificationParentId: classificationParentId,
|
|
classificationChildId: classificationChildId,
|
|
id: id,
|
|
itemType: itemType,
|
|
};
|
|
global.mainWindow.webContents.send("showItemAddEditWindow", JSON.stringify(params));
|
|
}
|
|
|
|
/**
|
|
* 清空项目菜单
|
|
* @param classificationParentId
|
|
* @param classificationChildId
|
|
* @param confirm
|
|
*/
|
|
function clearItemMenu(classificationParentId, classificationChildId, confirm) {
|
|
let params = {
|
|
classificationParentId: classificationParentId,
|
|
classificationChildId: classificationChildId,
|
|
confirm: confirm,
|
|
};
|
|
global.mainWindow.webContents.send("clearItem", JSON.stringify(params));
|
|
}
|
|
|
|
/**
|
|
* 项目刷新图标缓存列表菜单
|
|
* @param classificationParentId
|
|
* @param classificationChildId
|
|
*/
|
|
function refreshIconCacheListItemMenu(classificationParentId, classificationChildId) {
|
|
dialog
|
|
.showMessageBox(global.mainWindow, {
|
|
message: global.currentLanguage.refreshIconCurrentClassificationMessage,
|
|
buttons: [global.currentLanguage.ok, global.currentLanguage.cancel],
|
|
type: "question",
|
|
noLink: true,
|
|
cancelId: 1,
|
|
})
|
|
.then((r) => {
|
|
if (r.response == 0) {
|
|
refreshIconCacheList(classificationParentId, classificationChildId).then((res) => {
|
|
let params = {
|
|
classificationParentId: classificationParentId,
|
|
classificationChildId: classificationChildId,
|
|
list: res,
|
|
};
|
|
global.mainWindow.webContents.send("refreshIconCacheList", JSON.stringify(params));
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 项目转换路径菜单
|
|
* @param classificationParentId
|
|
* @param classificationChildId
|
|
* @param type
|
|
*/
|
|
function convertPathListItemMenu(classificationParentId, classificationChildId, type) {
|
|
dialog
|
|
.showMessageBox(global.mainWindow, {
|
|
message: type == "relative" ? global.currentLanguage.relativeCurrentClassificationMessage : global.currentLanguage.absoluteCurrentClassificationMessage,
|
|
buttons: [global.currentLanguage.ok, global.currentLanguage.cancel],
|
|
type: "question",
|
|
noLink: true,
|
|
cancelId: 1,
|
|
})
|
|
.then((r) => {
|
|
if (r.response == 0) {
|
|
let params = {
|
|
classificationParentId: classificationParentId,
|
|
classificationChildId: classificationChildId,
|
|
type: type,
|
|
};
|
|
global.mainWindow.webContents.send("convertPathList", JSON.stringify(params));
|
|
}
|
|
});
|
|
}
|
|
|
|
export default function () {
|
|
// 项目空白处右键菜单
|
|
ipcMain.on("itemContentRightMenu", (event, args) => {
|
|
// 参数
|
|
let p = JSON.parse(args);
|
|
// 在拥有子级分类的父级分类下右键
|
|
let addSubmenu = [];
|
|
let clearSubmenu = [];
|
|
let refreshIconCacheSubmenu = [];
|
|
let convertRelativePathSubmenu = [];
|
|
let convertAbsolutePathSubmenu = [];
|
|
if (p.haveClassificationChild && p.classificationChildId == null) {
|
|
for (let i = 0; i < global.list.length; i++) {
|
|
if (global.list[i].id == p.classificationParentId) {
|
|
for (let j = 0; j < global.list[i].childList.length; j++) {
|
|
if (
|
|
util.strIsEmpty(global.list[i].childList[j].mapDirectory) &&
|
|
(global.list[i].childList[j].type == null || global.list[i].childList[j].type != 1)
|
|
) {
|
|
addSubmenu.push({
|
|
label: global.list[i].childList[j].name,
|
|
click: () => {
|
|
addEditItemMenu(0, p.classificationParentId, global.list[i].childList[j].id);
|
|
},
|
|
});
|
|
clearSubmenu.push({
|
|
label: global.list[i].childList[j].name,
|
|
click: () => {
|
|
clearItemMenu(p.classificationParentId, global.list[i].childList[j].id, true);
|
|
},
|
|
});
|
|
convertRelativePathSubmenu.push({
|
|
label: global.list[i].childList[j].name,
|
|
click: () => {
|
|
convertPathListItemMenu(p.classificationParentId, global.list[i].childList[j].id, "relative");
|
|
},
|
|
});
|
|
convertAbsolutePathSubmenu.push({
|
|
label: global.list[i].childList[j].name,
|
|
click: () => {
|
|
convertPathListItemMenu(p.classificationParentId, global.list[i].childList[j].id, "absolute");
|
|
},
|
|
});
|
|
}
|
|
if (global.list[i].childList[j].type == null || global.list[i].childList[j].type != 1) {
|
|
refreshIconCacheSubmenu.push({
|
|
label: global.list[i].childList[j].name,
|
|
click: () => {
|
|
refreshIconCacheListItemMenu(p.classificationParentId, global.list[i].childList[j].id);
|
|
},
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// 菜单
|
|
let menuList = [];
|
|
if (p.haveClassificationChild && p.classificationChildId == null) {
|
|
if (!util.arrayIsEmpty(addSubmenu)) {
|
|
menuList.push({
|
|
label: global.currentLanguage.newItem,
|
|
type: "submenu",
|
|
submenu: addSubmenu,
|
|
});
|
|
}
|
|
} else {
|
|
if (!p.isMapDirectory && !p.aggregate) {
|
|
menuList.push({
|
|
label: global.currentLanguage.newItem,
|
|
click: () => {
|
|
addEditItemMenu(0, p.classificationParentId, p.classificationChildId);
|
|
},
|
|
});
|
|
}
|
|
}
|
|
if (!p.aggregate) {
|
|
menuList.push(index.itemSortMenu(p.classificationParentId, p.classificationChildId, p.haveClassificationChild, p.sort));
|
|
}
|
|
menuList.push(...index.itemLayoutIconSize(p.classificationParentId, p.classificationChildId, p.haveClassificationChild, p.layout, p.iconSize));
|
|
menuList.push(ItemJS.itemShowOnly(p.classificationParentId, p.classificationChildId, p.haveClassificationChild, p.showOnly));
|
|
if (
|
|
!p.haveClassificationChild &&
|
|
((p.layout != null && p.layout == "list") || (global.setting.item.layout == "list" && (p.layout == null || p.layout == "default")))
|
|
) {
|
|
menuList.push(ItemJS.itemColumnNumber(p.classificationParentId, p.classificationChildId, p.haveClassificationChild, p.columnNumber));
|
|
}
|
|
menuList.push({ type: "separator" });
|
|
if (p.haveClassificationChild && p.classificationChildId == null) {
|
|
if (!util.arrayIsEmpty(refreshIconCacheSubmenu)) {
|
|
menuList.push({
|
|
label: global.currentLanguage.batchRefreshIconCache,
|
|
type: "submenu",
|
|
submenu: refreshIconCacheSubmenu,
|
|
});
|
|
}
|
|
} else {
|
|
if (!p.aggregate) {
|
|
menuList.push({
|
|
label: global.currentLanguage.batchRefreshIconCache,
|
|
click: () => {
|
|
refreshIconCacheListItemMenu(p.classificationParentId, p.classificationChildId);
|
|
},
|
|
});
|
|
}
|
|
}
|
|
if (p.haveClassificationChild && p.classificationChildId == null) {
|
|
if (!util.arrayIsEmpty(convertRelativePathSubmenu)) {
|
|
menuList.push({
|
|
label: global.currentLanguage.batchConversionRelativePath,
|
|
type: "submenu",
|
|
submenu: convertRelativePathSubmenu,
|
|
});
|
|
}
|
|
} else {
|
|
if (!p.isMapDirectory && !p.aggregate) {
|
|
menuList.push({
|
|
label: global.currentLanguage.batchConversionRelativePath,
|
|
click: () => {
|
|
convertPathListItemMenu(p.classificationParentId, p.classificationChildId, "relative");
|
|
},
|
|
});
|
|
}
|
|
}
|
|
if (p.haveClassificationChild && p.classificationChildId == null) {
|
|
if (!util.arrayIsEmpty(convertAbsolutePathSubmenu)) {
|
|
menuList.push({
|
|
label: global.currentLanguage.batchConversionAbsolutePath,
|
|
type: "submenu",
|
|
submenu: convertAbsolutePathSubmenu,
|
|
});
|
|
}
|
|
} else {
|
|
if (!p.isMapDirectory && !p.aggregate) {
|
|
menuList.push({
|
|
label: global.currentLanguage.batchConversionAbsolutePath,
|
|
click: () => {
|
|
convertPathListItemMenu(p.classificationParentId, p.classificationChildId, "absolute");
|
|
},
|
|
});
|
|
}
|
|
}
|
|
menuList.push({ type: "separator" });
|
|
if (p.haveClassificationChild && p.classificationChildId == null) {
|
|
if (!util.arrayIsEmpty(clearSubmenu)) {
|
|
menuList.push({
|
|
label: global.currentLanguage.clearItem,
|
|
type: "submenu",
|
|
submenu: clearSubmenu,
|
|
});
|
|
}
|
|
} else {
|
|
if (!p.isMapDirectory && !p.aggregate) {
|
|
menuList.push({
|
|
label: global.currentLanguage.clearItem,
|
|
click: () => {
|
|
clearItemMenu(p.classificationParentId, p.classificationChildId, true);
|
|
},
|
|
});
|
|
}
|
|
}
|
|
menuList.push({ type: "separator" });
|
|
if (!p.isMapDirectory && !p.aggregate) {
|
|
menuList.push({
|
|
label: p.lockItem ? global.currentLanguage.unlockItem : global.currentLanguage.lockItem,
|
|
click: () => {
|
|
global.mainWindow.webContents.send("setLockItem", !p.lockItem);
|
|
cacheData.cacheStore.set("lockItem", !p.lockItem);
|
|
},
|
|
});
|
|
menuList.push({ type: "separator" });
|
|
}
|
|
if (!p.lockItem && !p.isMapDirectory && !p.aggregate) {
|
|
menuList.push({
|
|
label: p.batchOperation ? global.currentLanguage.cancelBatchOperation : global.currentLanguage.batchOperation,
|
|
click: () => {
|
|
global.mainWindow.webContents.send("setBatchOperation", !p.batchOperation);
|
|
},
|
|
});
|
|
}
|
|
let m = Menu.buildFromTemplate(menuList);
|
|
util.menuListen(m);
|
|
m.popup();
|
|
});
|
|
// 项目右键
|
|
ipcMain.on("itemRightMenu", (event, args) => {
|
|
// 参数
|
|
let p = JSON.parse(args);
|
|
// 项目
|
|
let item = p.item;
|
|
// 转为菜单
|
|
let moveSubmenu = [];
|
|
let copySubmenu = [];
|
|
if ((p.search == null || !p.search) && (p.searchWindow == null || !p.searchWindow) && !p.isMapDirectory && !p.aggregate) {
|
|
moveSubmenu = convertMenu(p.classificationParentId, p.classificationChildId, item.id, global.list, true);
|
|
copySubmenu = convertMenu(p.classificationParentId, p.classificationChildId, item.id, global.list, false);
|
|
}
|
|
// 菜单
|
|
let menuList = [
|
|
{
|
|
label: global.currentLanguage.open,
|
|
click: () => {
|
|
if (p.searchWindow != null && p.searchWindow) {
|
|
global.searchWindow.hide();
|
|
}
|
|
index.itemRun(item, false);
|
|
if (p.search != null && p.search) {
|
|
global.mainWindow.webContents.send("closeSearch");
|
|
}
|
|
},
|
|
},
|
|
{
|
|
label: global.currentLanguage.emptyRecycleBin,
|
|
visible: item.type == 3 && item.shell == "shell:RecycleBinFolder",
|
|
click: () => {
|
|
global.api.EmptyRecycleBin(global.mainWindow.getNativeWindowHandle());
|
|
},
|
|
},
|
|
{
|
|
label: global.currentLanguage.openWith,
|
|
visible: item.type == 0 && item.extension != ".exe" && item.extension != ".bat" && item.extension != ".lnk",
|
|
click: () => {
|
|
if (p.searchWindow != null && p.searchWindow) {
|
|
global.searchWindow.hide();
|
|
}
|
|
index.itemRun(item, false, true);
|
|
if (p.search != null && p.search) {
|
|
global.mainWindow.webContents.send("closeSearch");
|
|
}
|
|
},
|
|
},
|
|
{
|
|
label: global.currentLanguage.runAsAdministrator,
|
|
visible: (item.type == 0 && (item.extension == ".exe" || item.extension == ".bat")) || (item.type == 3 && item.shell == "cmd"),
|
|
click: () => {
|
|
item.admin = true;
|
|
index.itemRun(item, false);
|
|
if (p.search != null && p.search) {
|
|
global.mainWindow.webContents.send("closeSearch");
|
|
}
|
|
if (p.searchWindow != null && p.searchWindow) {
|
|
global.searchWindow.hide();
|
|
}
|
|
},
|
|
},
|
|
{
|
|
label: global.currentLanguage.openLocation,
|
|
visible: item.type == 0,
|
|
click: () => {
|
|
index.itemRun(item, true);
|
|
if (p.search != null && p.search) {
|
|
global.mainWindow.webContents.send("closeSearch");
|
|
}
|
|
if (p.searchWindow != null && p.searchWindow) {
|
|
global.searchWindow.hide();
|
|
}
|
|
},
|
|
},
|
|
];
|
|
menuList.push({
|
|
type: "separator",
|
|
});
|
|
if (item.type != 3 && item.type != 4 && item.type != 5) {
|
|
menuList.push({
|
|
label: global.currentLanguage.copyFullPath,
|
|
click: () => {
|
|
if (item.type == 0 || item.type == 1) {
|
|
clipboard.writeText(index.getAbsolutePath(item.path));
|
|
} else if (item.type == 2) {
|
|
clipboard.writeText(item.url);
|
|
}
|
|
if (p.search != null && p.search) {
|
|
global.mainWindow.webContents.send("closeSearch");
|
|
}
|
|
if (p.searchWindow != null && p.searchWindow) {
|
|
global.searchWindow.hide();
|
|
}
|
|
},
|
|
});
|
|
}
|
|
if (item.type == 0 || item.type == 1 || item.type == 5) {
|
|
menuList.push({
|
|
label: global.currentLanguage.createDesktopShortcut,
|
|
click: () => {
|
|
dialog
|
|
.showSaveDialog(global.mainWindow, {
|
|
title: global.currentLanguage.createDesktopShortcut,
|
|
defaultPath: util.removeSuffix(item.name.replace(/\\n/g, " ")),
|
|
filters: [{ name: "lnk", extensions: ["lnk"] }],
|
|
})
|
|
.then((r) => {
|
|
if (!r.canceled && !util.strIsEmpty(r.filePath)) {
|
|
if (item.type == 0 || item.type == 1) {
|
|
// 获取绝对路径
|
|
item.path = index.getAbsolutePath(item.path);
|
|
}
|
|
shell.writeShortcutLink(r.filePath, "create", {
|
|
target: item.type == 5 ? item.shell : item.path,
|
|
});
|
|
}
|
|
});
|
|
},
|
|
});
|
|
}
|
|
menuList.push({
|
|
label: global.currentLanguage.exportIcon,
|
|
click: () => {
|
|
if (!util.strIsEmpty(item.icon) || !util.strIsEmpty(item.htmlIcon)) {
|
|
let re = new RegExp("data:(?<ext>.*?);base64,.*");
|
|
let res = re.exec(item.icon);
|
|
let htmlIcon = !util.strIsEmpty(item.htmlIcon);
|
|
if (res || htmlIcon) {
|
|
try {
|
|
dialog
|
|
.showSaveDialog(global.mainWindow, {
|
|
title: global.currentLanguage.exportIcon,
|
|
defaultPath: "icon",
|
|
filters: [{ name: htmlIcon ? "svg" : mime.getExtension(res.groups.ext), extensions: [htmlIcon ? "svg" : mime.getExtension(res.groups.ext)] }],
|
|
})
|
|
.then((r) => {
|
|
if (!r.canceled && !util.strIsEmpty(r.filePath)) {
|
|
if (htmlIcon) {
|
|
fs.writeFile(r.filePath, item.htmlIcon, function (err) {});
|
|
} else {
|
|
let arr = item.icon.split(",");
|
|
if (arr.length == 2) {
|
|
let base64Data = arr[1];
|
|
let dataBuffer = Buffer.from(base64Data, "base64");
|
|
fs.writeFile(r.filePath, dataBuffer, function (err) {});
|
|
}
|
|
}
|
|
}
|
|
});
|
|
} catch (e) {
|
|
if (process.env.NODE_ENV !== "production") {
|
|
console.log(e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
});
|
|
if (
|
|
(item.type == 0 || item.type == 1 || item.type == 5) &&
|
|
(p.search == null || !p.search) &&
|
|
(p.searchWindow == null || !p.searchWindow) &&
|
|
(item.notRefreshIcon == null || !item.notRefreshIcon) &&
|
|
!p.aggregate
|
|
) {
|
|
menuList.push({
|
|
label: global.currentLanguage.refreshIconCache,
|
|
click: () => {
|
|
// 获取图标
|
|
refreshIconCache(item).then((res) => {
|
|
if (res.icon != null) {
|
|
let { classificationParentId, classificationChildId } = ClassificationJS.convertClassificationId(
|
|
item.classificationId,
|
|
item.classificationParentId
|
|
);
|
|
let params = {
|
|
classificationParentId: classificationParentId,
|
|
classificationChildId: classificationChildId,
|
|
id: item.id,
|
|
icon: res.icon,
|
|
};
|
|
if (item.type == 5) {
|
|
params.iconPath = res.iconPath;
|
|
}
|
|
global.mainWindow.webContents.send("refreshIconCache", JSON.stringify(params));
|
|
}
|
|
});
|
|
},
|
|
});
|
|
}
|
|
if (
|
|
(item.type == 0 || item.type == 1) &&
|
|
(p.search == null || !p.search) &&
|
|
(p.searchWindow == null || !p.searchWindow) &&
|
|
!p.isMapDirectory &&
|
|
!p.aggregate
|
|
) {
|
|
menuList.push({
|
|
label: ItemJS.isAbsolutePath(item.path) ? global.currentLanguage.convertRelativePath : global.currentLanguage.convertAbsolutePath,
|
|
click: () => {
|
|
let { classificationParentId, classificationChildId } = ClassificationJS.convertClassificationId(item.classificationId, item.classificationParentId);
|
|
let params = {
|
|
classificationParentId: classificationParentId,
|
|
classificationChildId: classificationChildId,
|
|
id: item.id,
|
|
type: ItemJS.isAbsolutePath(item.path) ? "relative" : "absolute",
|
|
};
|
|
global.mainWindow.webContents.send("convertPath", JSON.stringify(params));
|
|
},
|
|
});
|
|
}
|
|
if (item.type == 0 || item.type == 1 || item.type == 3) {
|
|
let flag = false;
|
|
let itemPath;
|
|
if (item.type == 3) {
|
|
if (
|
|
item.shell == "shell:MyComputerFolder" ||
|
|
item.shell == "shell:DocumentsLibrary" ||
|
|
item.shell == "shell:ControlPanelFolder" ||
|
|
item.shell == "shell:RecycleBinFolder"
|
|
) {
|
|
itemPath = item.shell;
|
|
flag = true;
|
|
} else if (item.shell == "services.msc") {
|
|
itemPath = process.env.SystemRoot + "\\System32\\services.msc";
|
|
flag = true;
|
|
} else if (item.shell == "cmd") {
|
|
itemPath = process.env.SystemRoot + "\\System32\\cmd.exe";
|
|
flag = true;
|
|
} else if (item.shell == "taskmgr") {
|
|
itemPath = process.env.SystemRoot + "\\System32\\taskmgr.exe";
|
|
flag = true;
|
|
} else if (item.shell == "regedit") {
|
|
itemPath = process.env.SystemRoot + "\\regedit.exe";
|
|
flag = true;
|
|
} else if (item.shell == "powercfg.cpl") {
|
|
itemPath = process.env.SystemRoot + "\\System32\\powercfg.exe";
|
|
flag = true;
|
|
} else if (item.shell == "compmgmt.msc /s") {
|
|
itemPath = process.env.SystemRoot + "\\System32\\compmgmt.msc";
|
|
flag = true;
|
|
}
|
|
} else {
|
|
flag = true;
|
|
itemPath = index.getAbsolutePath(item.path);
|
|
}
|
|
if (flag) {
|
|
menuList.push({
|
|
type: "separator",
|
|
});
|
|
menuList.push({
|
|
label: global.currentLanguage.explorerMenu,
|
|
click: () => {
|
|
const mouseEvent = require("../mouse");
|
|
let screen = util.getWindowInScreen();
|
|
let scaleFactor = 1;
|
|
if (!util.arrayIsEmpty(screen)) {
|
|
scaleFactor = screen[0].scaleFactor;
|
|
}
|
|
// 暂停鼠标事件
|
|
mouseEvent.pauseMouseEvents();
|
|
try {
|
|
global.api.ContextMenu(global.mainWindow.getNativeWindowHandle(), itemPath, p.x * scaleFactor, p.y * scaleFactor);
|
|
} finally {
|
|
// 恢复鼠标事件
|
|
mouseEvent.resumeMouseEvents();
|
|
}
|
|
},
|
|
});
|
|
}
|
|
}
|
|
if (
|
|
(!util.arrayIsEmpty(moveSubmenu) || !util.arrayIsEmpty(copySubmenu)) &&
|
|
(p.search == null || !p.search) &&
|
|
(p.searchWindow == null || !p.searchWindow) &&
|
|
!p.isMapDirectory &&
|
|
!p.aggregate
|
|
) {
|
|
menuList.push({
|
|
type: "separator",
|
|
});
|
|
if (!util.arrayIsEmpty(moveSubmenu)) {
|
|
menuList.push({
|
|
label: global.currentLanguage.moveTo,
|
|
visible: !util.arrayIsEmpty(moveSubmenu),
|
|
type: "submenu",
|
|
submenu: moveSubmenu,
|
|
});
|
|
}
|
|
if (!util.arrayIsEmpty(copySubmenu)) {
|
|
menuList.push({
|
|
label: global.currentLanguage.copyTo,
|
|
visible: !util.arrayIsEmpty(copySubmenu),
|
|
type: "submenu",
|
|
submenu: copySubmenu,
|
|
});
|
|
}
|
|
}
|
|
if ((p.search == null || !p.search) && (p.searchWindow == null || !p.searchWindow) && !p.isMapDirectory && !p.aggregate) {
|
|
menuList.push(
|
|
{
|
|
type: "separator",
|
|
},
|
|
{
|
|
label: global.currentLanguage.newItem,
|
|
click: () => {
|
|
addEditItemMenu(0, p.classificationParentId, p.classificationChildId);
|
|
},
|
|
},
|
|
{
|
|
type: "separator",
|
|
},
|
|
{
|
|
label: global.currentLanguage.edit,
|
|
click: () => {
|
|
addEditItemMenu(1, p.classificationParentId, p.classificationChildId, item.id, item.type);
|
|
},
|
|
},
|
|
{
|
|
label: global.currentLanguage.delete,
|
|
click: () => {
|
|
dialog
|
|
.showMessageBox(global.mainWindow, {
|
|
message: global.currentLanguage.deleteItemMessage,
|
|
buttons: [global.currentLanguage.ok, global.currentLanguage.cancel],
|
|
type: "question",
|
|
noLink: true,
|
|
cancelId: 1,
|
|
})
|
|
.then((r) => {
|
|
if (r.response == 0) {
|
|
let params = {
|
|
classificationParentId: p.classificationParentId,
|
|
classificationChildId: p.classificationChildId,
|
|
id: item.id,
|
|
};
|
|
global.mainWindow.webContents.send("deleteItem", JSON.stringify(params));
|
|
}
|
|
});
|
|
},
|
|
}
|
|
);
|
|
}
|
|
if ((p.search == null || !p.search) && (p.searchWindow == null || !p.searchWindow) && p.isMapDirectory && !p.aggregate) {
|
|
menuList.push({ type: "separator" });
|
|
menuList.push({
|
|
label: global.currentLanguage.hideThisItem,
|
|
click: () => {
|
|
let params = {
|
|
classificationParentId: p.classificationParentId,
|
|
classificationChildId: p.classificationChildId,
|
|
item: item,
|
|
};
|
|
global.mainWindow.webContents.send("hiddenItem", JSON.stringify(params));
|
|
},
|
|
});
|
|
}
|
|
// 菜单
|
|
let m = Menu.buildFromTemplate(menuList);
|
|
util.menuListen(m);
|
|
m.popup();
|
|
});
|
|
// 多选项目右键
|
|
ipcMain.on("multiItemRightMenu", (event, args) => {
|
|
// 菜单列表
|
|
let menuList = [];
|
|
// 全选
|
|
menuList.push({
|
|
label: global.currentLanguage.selectAll,
|
|
click: () => {
|
|
global.mainWindow.webContents.send("batchOperationSelectAll");
|
|
},
|
|
});
|
|
menuList.push({ type: "separator" });
|
|
// 转为菜单
|
|
let moveSubmenu = batchOperationConvertMenu(global.list, true);
|
|
let copySubmenu = batchOperationConvertMenu(global.list, false);
|
|
// 移动 复制
|
|
if (!util.arrayIsEmpty(moveSubmenu) || !util.arrayIsEmpty(copySubmenu)) {
|
|
if (!util.arrayIsEmpty(moveSubmenu)) {
|
|
menuList.push({
|
|
label: global.currentLanguage.moveTo,
|
|
visible: !util.arrayIsEmpty(moveSubmenu),
|
|
type: "submenu",
|
|
submenu: moveSubmenu,
|
|
});
|
|
}
|
|
if (!util.arrayIsEmpty(copySubmenu)) {
|
|
menuList.push({
|
|
label: global.currentLanguage.copyTo,
|
|
visible: !util.arrayIsEmpty(copySubmenu),
|
|
type: "submenu",
|
|
submenu: copySubmenu,
|
|
});
|
|
}
|
|
}
|
|
menuList.push({ type: "separator" });
|
|
menuList.push({
|
|
label: global.currentLanguage.delete,
|
|
click: () => {
|
|
dialog
|
|
.showMessageBox(global.mainWindow, {
|
|
message: global.currentLanguage.batchDeleteItemMessage,
|
|
buttons: [global.currentLanguage.ok, global.currentLanguage.cancel],
|
|
type: "question",
|
|
noLink: true,
|
|
cancelId: 1,
|
|
})
|
|
.then((r) => {
|
|
if (r.response == 0) {
|
|
global.mainWindow.webContents.send("batchDeleteItem");
|
|
}
|
|
});
|
|
},
|
|
});
|
|
menuList.push({ type: "separator" });
|
|
menuList.push({
|
|
label: global.currentLanguage.cancelBatchOperation,
|
|
click: () => {
|
|
global.mainWindow.webContents.send("setBatchOperation", false);
|
|
},
|
|
});
|
|
// 菜单
|
|
let m = Menu.buildFromTemplate(menuList);
|
|
util.menuListen(m);
|
|
m.popup();
|
|
});
|
|
// 运行项目
|
|
ipcMain.on("itemRun", (event, args) => {
|
|
let params = JSON.parse(args);
|
|
index.itemRun(params.item, params.location);
|
|
let setItemDataParams = {
|
|
item: params.item,
|
|
recordQuickSearch: params.recordQuickSearch,
|
|
};
|
|
global.mainWindow.webContents.send("setItemData", JSON.stringify(setItemDataParams));
|
|
});
|
|
// 获取文件图标
|
|
ipcMain.on("getFileIcon", (event, args) => {
|
|
getFileIcon(args, true).then((res) => {
|
|
event.sender.send("getFileBase64", res);
|
|
});
|
|
});
|
|
// 获取网址信息
|
|
ipcMain.on("getUrlInfo", (event, args) => {
|
|
getUrlInfo(args, true);
|
|
});
|
|
// 读取文件
|
|
ipcMain.on("readFiles", (event, args) => {
|
|
let params = JSON.parse(args);
|
|
readFiles(params.path).then((res) => {
|
|
// 主窗口编辑分类
|
|
let itemAddParams = {
|
|
classificationParentId: params.classificationParentId,
|
|
classificationChildId: params.classificationChildId,
|
|
itemList: res,
|
|
clear: false,
|
|
};
|
|
global.mainWindow.webContents.send("itemAdd", JSON.stringify(itemAddParams));
|
|
});
|
|
});
|
|
// 图片转base64
|
|
ipcMain.on("imageToBase64", (event, args) => {
|
|
imageToBase64(args);
|
|
});
|
|
// 清空项目
|
|
ipcMain.on("clearItemDialog", (event, args) => {
|
|
let params = JSON.parse(args);
|
|
dialog
|
|
.showMessageBox(global.mainWindow, {
|
|
message: global.currentLanguage.clearItemMessage,
|
|
buttons: [global.currentLanguage.ok, global.currentLanguage.cancel],
|
|
type: "question",
|
|
noLink: true,
|
|
cancelId: 1,
|
|
})
|
|
.then((r) => {
|
|
if (r.response == 0) {
|
|
clearItemMenu(params.classificationParentId, params.classificationChildId, false);
|
|
}
|
|
});
|
|
});
|
|
// 获取文件后缀
|
|
ipcMain.on("getFileExtension", (event, args) => {
|
|
event.returnValue = path.extname(args);
|
|
});
|
|
// 拖出文件
|
|
ipcMain.on("ondragstart", (event, args) => {
|
|
let params = JSON.parse(args);
|
|
try {
|
|
// 网站和系统不能拖出
|
|
if (params.type == 2 || params.type == 3) {
|
|
// 取消拖出状态
|
|
global.mainWindow.webContents.send("cancelDragOut");
|
|
return;
|
|
}
|
|
let icon;
|
|
// 环境判断
|
|
if (process.env.NODE_ENV !== "production") {
|
|
// 开发
|
|
icon = "./public/images/drag-and-drop.png";
|
|
} else {
|
|
// 正式
|
|
icon = path.join(__dirname, "./images/drag-and-drop.png");
|
|
}
|
|
event.sender.startDrag({
|
|
file: index.getAbsolutePath(params.path),
|
|
icon: icon,
|
|
});
|
|
} finally {
|
|
// 取消拖出状态
|
|
global.mainWindow.webContents.send("cancelDragOut");
|
|
}
|
|
});
|
|
// 获取锁定项目状态
|
|
ipcMain.on("getLockItem", (event, args) => {
|
|
let lockItem = cacheData.cacheStore.get("lockItem");
|
|
event.returnValue = lockItem == null ? false : lockItem;
|
|
});
|
|
// 读取文件夹
|
|
ipcMain.on("readDirectory", (event, args) => {
|
|
let pathArr = JSON.parse(args);
|
|
let resultList = [];
|
|
for (let p of pathArr) {
|
|
try {
|
|
// 获取文件类型
|
|
let stats;
|
|
try {
|
|
// 文件类型
|
|
stats = fs.statSync(p);
|
|
} catch (e) {
|
|
p = p.replace(" (x86)", "");
|
|
try {
|
|
stats = fs.statSync(p);
|
|
} catch (e) {}
|
|
}
|
|
// 只要文件夹
|
|
if (stats != null && stats.isDirectory()) {
|
|
// 读取文件夹下的内容
|
|
let files = fs.readdirSync(p);
|
|
// 组装路径
|
|
let fileList = [];
|
|
for (let file of files) {
|
|
fileList.push(path.join(p, file));
|
|
}
|
|
// 返回信息
|
|
let name = path.basename(p);
|
|
resultList.push({
|
|
name: util.strIsEmpty(name) ? p : name,
|
|
fileList: fileList,
|
|
});
|
|
}
|
|
} catch (e) {
|
|
if (process.env.NODE_ENV !== "production") {
|
|
console.log(e);
|
|
}
|
|
}
|
|
}
|
|
// 返回
|
|
event.returnValue = JSON.stringify(resultList);
|
|
});
|
|
// 校验无效项目
|
|
ipcMain.on("checkInvalidItem", (event, args) => {
|
|
global.mainWindow.webContents.send("checkInvalidItemResult", JSON.stringify(index.checkInvalidItem()));
|
|
});
|
|
// 获取开始菜单程序
|
|
ipcMain.on("getStartMenuProgramList", (event, args) => {
|
|
getStartMenuProgramList().then((res) => {
|
|
// 返回数据
|
|
global.mainWindow.webContents.send("resultStartMenuProgramList", JSON.stringify(res));
|
|
});
|
|
});
|
|
// 获取Appx列表
|
|
ipcMain.on("getAppxList", (event, args) => {
|
|
getAppxList().then((res) => {
|
|
global.mainWindow.webContents.send("returnAppxList", JSON.stringify(res));
|
|
});
|
|
});
|
|
// 初始化映射文件夹
|
|
ipcMain.on("initMapDirectory", (event, args) => {
|
|
// 初始化映射文件夹
|
|
index.initMapDirectory().then((res) => {
|
|
if (res != null) {
|
|
global.mainWindow.webContents.send("returnInitMapDirectory", JSON.stringify(res));
|
|
}
|
|
});
|
|
});
|
|
// 读取映射文件夹
|
|
ipcMain.on("readMapDirectory", (event, args) => {
|
|
let params = JSON.parse(args);
|
|
index.readMapDirectory(params.classificationParentId, params.classificationChildId, params.mapDirectory, true, false, true);
|
|
});
|
|
// 删除文件夹监听
|
|
ipcMain.on("deleteMapDirectoryWatch", (event, args) => {
|
|
let params = JSON.parse(args);
|
|
index.deleteMapDirectoryWatcher(params.classificationParentId, params.classificationChildId);
|
|
});
|
|
// 上传图标
|
|
ipcMain.on("uploadIcon", (event, args) => {
|
|
let ext = path.extname(args);
|
|
if (ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".gif" || ext == ".ico" || ext == ".svg") {
|
|
// 图片
|
|
imageToBase64(args);
|
|
} else {
|
|
// 获取文件图标
|
|
getFileIcon(args, true).then((res) => {
|
|
event.sender.send("getFileBase64", res);
|
|
});
|
|
}
|
|
});
|
|
// 下载图片
|
|
ipcMain.on("downloadImage", (event, args) => {
|
|
downloadImage(args);
|
|
});
|
|
}
|