mirror of
https://github.com/fofolee/uTools-quickcommand.git
synced 2025-12-16 08:04:18 +08:00
新增built脚本
This commit is contained in:
578
plugin/preload.js
Normal file
578
plugin/preload.js
Normal file
@@ -0,0 +1,578 @@
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const child_process = require("child_process")
|
||||
const iconv = require('iconv-lite')
|
||||
const electron = require('electron')
|
||||
const {
|
||||
NodeVM,
|
||||
VM
|
||||
} = require('./lib/vm2')
|
||||
const path = require("path")
|
||||
const axios = require('axios');
|
||||
const pictureCompress = require("./lib/picture-compressor")
|
||||
|
||||
window._ = require("lodash")
|
||||
|
||||
// axios.defaults.adapter = require('axios/lib/adapters/http')
|
||||
|
||||
if (!utools.isWindows()) process.env.PATH += ':/usr/local/bin:/usr/local/sbin'
|
||||
|
||||
// window.startTime = new Date().getTime()
|
||||
|
||||
const shortCodes = [
|
||||
|
||||
open = path => {
|
||||
utools.shellOpenItem(path)
|
||||
},
|
||||
|
||||
locate = path => {
|
||||
utools.shellShowItemInFolder(path);
|
||||
},
|
||||
|
||||
visit = url => {
|
||||
utools.shellOpenExternal(url);
|
||||
},
|
||||
|
||||
system = cmd => {
|
||||
child_process.exec(cmd);
|
||||
},
|
||||
|
||||
message = msg => {
|
||||
utools.showNotification(msg)
|
||||
},
|
||||
|
||||
keyTap = (key, ...modifier) => utools.simulateKeyboardTap(key, ...modifier),
|
||||
|
||||
copyTo = text => {
|
||||
electron.clipboard.writeText(text)
|
||||
},
|
||||
|
||||
send = text => {
|
||||
copyTo(text);
|
||||
quickcommand.simulatePaste();
|
||||
}
|
||||
]
|
||||
|
||||
const ctlKey = utools.isMacOs() ? 'command' : 'control'
|
||||
|
||||
window.quickcommand = {
|
||||
// 模拟复制操作
|
||||
simulateCopy: function() {
|
||||
utools.simulateKeyboardTap('c', ctlKey);
|
||||
},
|
||||
|
||||
// 模拟粘贴操作
|
||||
simulatePaste: function() {
|
||||
utools.simulateKeyboardTap('v', ctlKey);
|
||||
},
|
||||
|
||||
// setTimout 不能在 vm2 中使用,同时在 electron 中有 bug
|
||||
sleep: function(ms) {
|
||||
var start = new Date().getTime()
|
||||
try {
|
||||
// node 16.13.1
|
||||
child_process.execSync(getSleepCodeByShell(ms), {
|
||||
timeout: ms,
|
||||
windowsHide: true
|
||||
})
|
||||
} catch (ex) {}
|
||||
var end = new Date().getTime()
|
||||
return (end - start)
|
||||
},
|
||||
|
||||
// 重写 setTimeout
|
||||
setTimeout: function(callback, ms) {
|
||||
var start = new Date().getTime()
|
||||
child_process.exec(getSleepCodeByShell(ms), {
|
||||
timeout: ms
|
||||
}, (err, stdout, stderr) => {
|
||||
var end = new Date().getTime()
|
||||
callback(end - start)
|
||||
})
|
||||
},
|
||||
|
||||
// 关闭进程
|
||||
kill: function(pid, signal = 'SIGTERM') {
|
||||
process.kill(pid, signal)
|
||||
},
|
||||
|
||||
// dom 解析
|
||||
htmlParse: function(html) {
|
||||
return new DOMParser().parseFromString(html, 'text/html')
|
||||
},
|
||||
|
||||
// 下载文件
|
||||
downloadFile: function(url, file = {}) {
|
||||
return new Promise((reslove, reject) => {
|
||||
if (file instanceof Object) file = utools.showSaveDialog(JSON.parse(JSON.stringify(file)))
|
||||
axios({
|
||||
method: 'get',
|
||||
url: url,
|
||||
responseType: 'arraybuffer'
|
||||
}).then(res => {
|
||||
var filebuffer = Buffer.from(res.data)
|
||||
fs.writeFile(file, filebuffer, err => {
|
||||
if (err) reject(err)
|
||||
else reslove(filebuffer)
|
||||
})
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 上传文件
|
||||
uploadFile: function(url, file = {}, name = 'file', formData = {}) {
|
||||
return new Promise((reslove, reject) => {
|
||||
var objfile
|
||||
if (file instanceof File) {
|
||||
objfile = file
|
||||
} else {
|
||||
if (file instanceof Object) file = utools.showOpenDialog(JSON.parse(JSON.stringify(file)))[0]
|
||||
if (!fs.existsSync(file)) return reject('文件不存在')
|
||||
var arraybuffer = fs.readFileSync(file).buffer
|
||||
var objfile = new File([arraybuffer], path.basename(file))
|
||||
}
|
||||
var form = new FormData();
|
||||
form.append(name, objfile)
|
||||
var keys = Object.keys(formData)
|
||||
if (keys.length) keys.forEach(k => form.append(k, formData[k]))
|
||||
axios.post(url, form, {
|
||||
headers: {
|
||||
'accept': 'application/json',
|
||||
'Content-Type': `multipart/form-data; boundary=${formData._boundary}`,
|
||||
}
|
||||
}).then(res => {
|
||||
reslove(res)
|
||||
}).catch(err => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// 载入在线资源
|
||||
loadRemoteScript: async function(url, forceUpdate = false) {
|
||||
if (!/^((ht|f)tps?):\/\/([\w\-]+(\.[\w\-]+)*\/)*[\w\-]+(\.[\w\-]+)*\/?(\?([\w\-\.,@?^=%&:\/~\+#]*)+)?/.test(url)) throw 'url 不合法'
|
||||
let remote = url
|
||||
let root = path.join(os.tmpdir(), 'qcRemoteScript')
|
||||
if (!fs.existsSync(root)) fs.mkdirSync(root)
|
||||
let local = path.join(root, require('crypto').createHash('md5').update(url).digest('hex'))
|
||||
if (forceUpdate || !fs.existsSync(local)) await this.downloadFile(remote, local)
|
||||
return require(local)
|
||||
}
|
||||
}
|
||||
|
||||
// 运行vbs脚本
|
||||
if (process.platform == 'win32') quickcommand.runVbs = function(script) {
|
||||
return new Promise((reslove, reject) => {
|
||||
var tempfile = path.join(os.tmpdir(), 'TempVBSScript.vbs')
|
||||
fs.writeFile(tempfile, iconv.encode(script, 'gbk'), err => {
|
||||
child_process.exec(`cscript.exe /nologo "${tempfile}"`, {
|
||||
encoding: "buffer"
|
||||
}, (err, stdout, stderr) => {
|
||||
if (err) reject(iconv.decode(stderr, 'gbk'))
|
||||
else reslove(iconv.decode(stdout, 'gbk'))
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
window.temporaryStore = {
|
||||
listeners: {}
|
||||
}
|
||||
|
||||
window.temporaryStoreSoldOut = () => {
|
||||
_.forIn(temporaryStore.listeners, (listener, key) => {
|
||||
document.removeEventListener(...listener)
|
||||
})
|
||||
window.temporaryStore = {
|
||||
listeners: {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// python -c
|
||||
window.runPythonCommand = py => {
|
||||
try {
|
||||
let result = child_process.execFileSync("python", ["-c", py], {
|
||||
windowsHide: true,
|
||||
encoding: 'buffer'
|
||||
})
|
||||
return iconv.decode(result, utools.isWindows() ? 'gbk' : 'utf8').trim()
|
||||
} catch (e) {
|
||||
alert(e)
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// 在终端中执行
|
||||
if (process.platform !== 'linux') quickcommand.runInTerminal = function(cmdline, dir) {
|
||||
let command = getCommandToLaunchTerminal(cmdline, dir)
|
||||
child_process.exec(command)
|
||||
}
|
||||
|
||||
let getCommandToLaunchTerminal = (cmdline, dir) => {
|
||||
let cd = ''
|
||||
if (utools.isWindows()) {
|
||||
let appPath = path.join(utools.getPath('home'), '/AppData/Local/Microsoft/WindowsApps/')
|
||||
// 直接 existsSync wt.exe 无效
|
||||
if (fs.existsSync(appPath) && fs.readdirSync(appPath).includes('wt.exe')) {
|
||||
cmdline = cmdline.replace(/"/g, `\\"`)
|
||||
if (dir) cd = `-d "${dir.replace(/\\/g, '/')}"`
|
||||
command = `${appPath}wt.exe ${cd} cmd /k "${cmdline}"`
|
||||
} else {
|
||||
cmdline = cmdline.replace(/"/g, `^"`)
|
||||
if (dir) cd = `cd /d "${dir.replace(/\\/g, '/')}" &&`
|
||||
command = `${cd} start "" cmd /k "${cmdline}"`
|
||||
}
|
||||
} else {
|
||||
cmdline = cmdline.replace(/"/g, `\\"`)
|
||||
if (dir) cd = `cd ${dir.replace(/ /g, `\\\\ `)} &&`
|
||||
if (fs.existsSync('/Applications/iTerm.app')) {
|
||||
command = `osascript -e 'tell application "iTerm"
|
||||
create window with default profile
|
||||
tell current session of current window to write text "clear && ${cd} ${cmdline}"
|
||||
end tell'`
|
||||
} else {
|
||||
command = `osascript -e 'tell application "Terminal"
|
||||
do script "clear && ${cd} ${cmdline}"
|
||||
activate
|
||||
end tell'`
|
||||
}
|
||||
}
|
||||
console.log(command);
|
||||
return command
|
||||
}
|
||||
|
||||
window.pluginInfo = () => {
|
||||
return JSON.parse(fs.readFileSync(path.join(__dirname, 'plugin.json')))
|
||||
}
|
||||
|
||||
let getSleepCodeByShell = ms => {
|
||||
var cmd, tempFilePath
|
||||
if (utools.isWindows()) {
|
||||
tempFilePath = getQuickcommandTempFile('vbs')
|
||||
cmd = `echo set ws=CreateObject("Wscript.Shell") > ${tempFilePath} && echo Wscript.sleep ${ms} >> ${tempFilePath} && cscript /nologo ${tempFilePath}`
|
||||
} else {
|
||||
cmd = `sleep ${ms / 1000}`
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
// 屏蔽危险函数
|
||||
window.getuToolsLite = () => {
|
||||
var utoolsLite = Object.assign({}, utools)
|
||||
if (utools.isDev()) return utoolsLite
|
||||
// 数据库相关接口
|
||||
delete utoolsLite.db
|
||||
delete utoolsLite.dbStorage
|
||||
delete utoolsLite.removeFeature
|
||||
delete utoolsLite.setFeature
|
||||
delete utoolsLite.onDbPull
|
||||
// 支付相关接口
|
||||
delete utoolsLite.fetchUserServerTemporaryToken
|
||||
delete utoolsLite.getUserServerTemporaryToken
|
||||
delete utoolsLite.openPayment
|
||||
delete utoolsLite.fetchUserPayments
|
||||
return utoolsLite
|
||||
}
|
||||
|
||||
let getSandboxFuns = () => {
|
||||
var sandbox = {
|
||||
utools: getuToolsLite(),
|
||||
quickcommand: quickcommand,
|
||||
electron: electron,
|
||||
axios: axios,
|
||||
Audio: Audio,
|
||||
fetch: fetch
|
||||
}
|
||||
shortCodes.forEach(f => {
|
||||
sandbox[f.name] = f
|
||||
})
|
||||
return sandbox
|
||||
}
|
||||
|
||||
let createNodeVM = () => {
|
||||
var sandbox = getSandboxFuns()
|
||||
const vm = new NodeVM({
|
||||
require: {
|
||||
external: true,
|
||||
builtin: ["*"],
|
||||
},
|
||||
console: 'redirect',
|
||||
env: process.env,
|
||||
sandbox: sandbox,
|
||||
});
|
||||
return vm
|
||||
}
|
||||
|
||||
let stringifyAll = item => {
|
||||
var cache = [];
|
||||
var string = JSON.stringify(item, (key, value) => {
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
if (cache.indexOf(value) !== -1) return
|
||||
cache.push(value);
|
||||
}
|
||||
return value;
|
||||
}, '\t')
|
||||
if (string != "{}") return string
|
||||
else return item.toString()
|
||||
}
|
||||
|
||||
let parseItem = item => {
|
||||
if (typeof item == "object") {
|
||||
if (Buffer.isBuffer(item)) {
|
||||
var bufferString = `[Buffer ${item.slice(0, 50).toString('hex').match(/\w{1,2}/g).join(" ")}`
|
||||
if (item.length > 50) bufferString += `... ${(item.length / 1000).toFixed(2)}kb`
|
||||
return bufferString + ']'
|
||||
} else if (item instanceof ArrayBuffer) {
|
||||
return `ArrayBuffer(${item.byteLength})`
|
||||
} else if (item instanceof Blob) {
|
||||
return `Blob {size: ${item.size}, type: "${item.type}"}`
|
||||
} else {
|
||||
try {
|
||||
return stringifyAll(item)
|
||||
} catch (error) {}
|
||||
}
|
||||
} else if (typeof item == "undefined") {
|
||||
return "undefined"
|
||||
}
|
||||
return item.toString()
|
||||
}
|
||||
|
||||
window.convertFilePathToUtoolsPayload = files => files.map(file => {
|
||||
let isFile = fs.statSync(file).isFile()
|
||||
return {
|
||||
isFile: isFile,
|
||||
isDirectory: !isFile,
|
||||
name: path.basename(file),
|
||||
path: file
|
||||
}
|
||||
})
|
||||
|
||||
let parseStdout = stdout => stdout.map(x => parseItem(x)).join("\n")
|
||||
|
||||
window.VmEval = (cmd, sandbox = {}) => new VM({
|
||||
sandbox: sandbox
|
||||
}).run(cmd)
|
||||
|
||||
// The vm module of Node.js is deprecated in the renderer process and will be removed
|
||||
window.runCodeInVm = (cmd, cb) => {
|
||||
const vm = createNodeVM()
|
||||
//重定向 console
|
||||
vm.on('console.log', (...stdout) => {
|
||||
console.log(stdout);
|
||||
cb(parseStdout(stdout), null)
|
||||
});
|
||||
|
||||
vm.on('console.error', stderr => {
|
||||
cb(null, stderr.toString())
|
||||
});
|
||||
|
||||
let liteErr = e => {
|
||||
if (!e) return
|
||||
return e.stack.replace(/([ ] +at.+)|(.+\.js:\d+)/g, '').trim()
|
||||
}
|
||||
|
||||
// 错误处理
|
||||
try {
|
||||
vm.run(cmd, path.join(__dirname, 'preload.js'));
|
||||
} catch (e) {
|
||||
console.log('Error: ', e)
|
||||
cb(null, liteErr(e))
|
||||
}
|
||||
|
||||
let cbUnhandledError = e => {
|
||||
removeAllListener()
|
||||
console.log('UnhandledError: ', e)
|
||||
cb(null, liteErr(e.error))
|
||||
}
|
||||
|
||||
let cbUnhandledRejection = e => {
|
||||
removeAllListener()
|
||||
console.log('UnhandledRejection: ', e)
|
||||
cb(null, liteErr(e.reason))
|
||||
}
|
||||
|
||||
let removeAllListener = () => {
|
||||
window.removeEventListener('error', cbUnhandledError)
|
||||
window.removeEventListener('unhandledrejection', cbUnhandledRejection)
|
||||
delete window.isWatchingError
|
||||
}
|
||||
|
||||
if (!window.isWatchingError) {
|
||||
window.addEventListener('error', cbUnhandledError)
|
||||
window.addEventListener('unhandledrejection', cbUnhandledRejection)
|
||||
window.isWatchingError = true
|
||||
}
|
||||
}
|
||||
|
||||
window.htmlEncode = (value) => {
|
||||
return String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """)
|
||||
}
|
||||
|
||||
window.hexEncode = text => Buffer.from(text, 'utf8').toString('hex')
|
||||
window.hexDecode = text => Buffer.from(text, 'hex').toString('utf8')
|
||||
|
||||
window.processPlatform = process.platform
|
||||
|
||||
window.getQuickcommandTempFile = ext => {
|
||||
return path.join(os.tmpdir(), `quickcommandTempFile.${ext}`)
|
||||
}
|
||||
|
||||
window.getBase64Ico = async (filepath, compressed = true) => {
|
||||
let sourceImage, ext = path.extname(filepath).slice(1)
|
||||
if (['png', 'jpg', 'jpeg', 'bmp', 'ico', 'gif', 'svg'].includes(ext)) {
|
||||
if (ext == 'svg') ext = 'svg+xml'
|
||||
sourceImage = `data:image/${ext};base64,` + fs.readFileSync(filepath, 'base64')
|
||||
if (ext == 'png') return sourceImage
|
||||
} else {
|
||||
sourceImage = utools.getFileIcon(filepath)
|
||||
return sourceImage
|
||||
}
|
||||
if (!compressed) return sourceImage
|
||||
let compressedImage = await getCompressedIco(sourceImage)
|
||||
return compressedImage
|
||||
}
|
||||
|
||||
let getCompressedIco = async (img, width = 80) => {
|
||||
let compressedImage = await pictureCompress({
|
||||
img: img,
|
||||
width: width,
|
||||
height: width,
|
||||
type: 'png',
|
||||
quality: 1
|
||||
})
|
||||
return compressedImage.img
|
||||
}
|
||||
|
||||
window.getFileInfo = options => {
|
||||
var file
|
||||
if (options.type == 'file') {
|
||||
file = options.argvs
|
||||
} else if (options.type == 'dialog') {
|
||||
var dialog = utools.showOpenDialog(options.argvs);
|
||||
if (!dialog) return false
|
||||
file = dialog[0]
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
var information = {
|
||||
name: path.basename(file),
|
||||
ext: path.extname(file),
|
||||
path: file
|
||||
}
|
||||
if (options.readfile) {
|
||||
var codec = (information.ext == '.bat' || information == '.ps1') ? 'gbk' : 'utf8'
|
||||
information.data = iconv.decode(fs.readFileSync(file), codec)
|
||||
}
|
||||
return information
|
||||
}
|
||||
|
||||
window.getCurrentFolderPathFix = () => {
|
||||
let pwd = utools.getCurrentFolderPath()
|
||||
let pwdFix = pwd ? pwd : path.join(utools.getPath('home'), 'desktop')
|
||||
return pwdFix.replace(/\\/g, '\\\\')
|
||||
}
|
||||
|
||||
window.getMatchedFilesFix = payload => {
|
||||
let MatchedFiles = payload
|
||||
let Matched = cmd.match(/\{\{MatchedFiles(\[\d+\]){0,1}(\.\w{1,11}){0,1}\}\}/g)
|
||||
Matched && Matched.forEach(m => {
|
||||
repl = eval(m.slice(2, -2))
|
||||
typeof repl == 'object' ? (repl = JSON.stringify(repl)) : (repl = repl.replace('\\', '\\\\'))
|
||||
cmd = cmd.replace(m, repl.replace('$', '$$$'))
|
||||
})
|
||||
}
|
||||
|
||||
window.saveFile = (content, file) => {
|
||||
if (file instanceof Object) file = utools.showSaveDialog(file)
|
||||
if (!file) return false
|
||||
try {
|
||||
fs.writeFileSync(file, content)
|
||||
return true
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
window.getSelectFile = hwnd => {
|
||||
if (utools.isWindows()) {
|
||||
var cmd = `powershell.exe -NoProfile "(New-Object -COM 'Shell.Application').Windows() | Where-Object { $_.HWND -eq ${hwnd} } | Select-Object -Expand Document | select @{ n='SelectItems'; e={$_.SelectedItems()} } | select -Expand SelectItems | select -Expand Path "`;
|
||||
let result = child_process.execSync(cmd, {
|
||||
encoding: "buffer",
|
||||
windowsHide: true
|
||||
})
|
||||
return iconv.decode(result, 'GBK').trim().replace(/\\/g, '/');
|
||||
} else {
|
||||
var cmd = `osascript -e 'tell application "Finder" to set selectedItems to selection as alias list
|
||||
if selectedItems is {} then return
|
||||
set parentPath to do shell script "dirname " & quoted form of POSIX path of (item 1 of selectedItems)
|
||||
set pathData to ""
|
||||
repeat with theItem in selectedItems
|
||||
set pathData to pathData & POSIX path of theItem & linefeed
|
||||
end repeat
|
||||
'
|
||||
`
|
||||
let result = child_process.execSync(cmd, {
|
||||
encoding: "utf8",
|
||||
windowsHide: true
|
||||
})
|
||||
console.log(result);
|
||||
return result ? result.trim() : ""
|
||||
}
|
||||
}
|
||||
|
||||
window.clipboardReadText = () => electron.clipboard.readText()
|
||||
|
||||
window.runCodeFile = (cmd, option, terminal, callback) => {
|
||||
var bin = option.bin,
|
||||
argv = option.argv,
|
||||
ext = option.ext,
|
||||
charset = option.charset,
|
||||
scptarg = option.scptarg || "";
|
||||
let script = getQuickcommandTempFile(ext)
|
||||
// 批处理和 powershell 默认编码为 GBK, 解决批处理的换行问题
|
||||
if (charset.scriptCode) cmd = iconv.encode(cmd.replace(/\n/g, '\r\n'), charset.scriptCode);
|
||||
fs.writeFileSync(script, cmd);
|
||||
// var argvs = [script]
|
||||
// if (argv) {
|
||||
// argvs = argv.split(' ')
|
||||
// argvs.push(script);
|
||||
// }
|
||||
var child, cmdline
|
||||
if (bin.slice(-7) == 'csc.exe') {
|
||||
cmdline = `${bin} ${argv} /out:"${script.slice(0, -2) + 'exe'}" "${script}" && "${script.slice(0, -2) + 'exe'}" ${scptarg}`
|
||||
} else if (bin == 'gcc') {
|
||||
var suffix = utools.isWindows() ? '.exe' : ''
|
||||
cmdline = `${bin} ${argv} "${script.slice(0, -2)}" "${script}" && "${script.slice(0, -2) + suffix}" ${scptarg}`
|
||||
} else if (utools.isWindows() && bin == 'bash') {
|
||||
cmdline = `${bin} ${argv} "${script.replace(/\\/g, '/').replace(/C:/i, '/mnt/c')}" ${scptarg}`
|
||||
} else {
|
||||
cmdline = `${bin} ${argv} "${script}" ${scptarg}`
|
||||
}
|
||||
// 在终端中输出
|
||||
if (terminal) cmdline = getCommandToLaunchTerminal(cmdline)
|
||||
child = child_process.spawn(cmdline, {
|
||||
encoding: 'buffer',
|
||||
shell: true
|
||||
})
|
||||
// var chunks = [],
|
||||
// err_chunks = [];
|
||||
console.log('running: ' + cmdline);
|
||||
child.stdout.on('data', chunk => {
|
||||
if (charset.outputCode) chunk = iconv.decode(chunk, charset.outputCode)
|
||||
callback(chunk.toString(), null)
|
||||
// chunks.push(chunk)
|
||||
})
|
||||
child.stderr.on('data', stderr => {
|
||||
if (charset.outputCode) stderr = iconv.decode(stderr, charset.outputCode)
|
||||
callback(null, stderr.toString())
|
||||
// err_chunks.push(err_chunk)
|
||||
})
|
||||
// child.on('close', code => {
|
||||
// let stdout = chunks.join("");
|
||||
// let stderr = err_chunks.join("");
|
||||
// callback(stdout, stderr)
|
||||
// })
|
||||
}
|
||||
Reference in New Issue
Block a user