Feature(custom): support read .env file in script system

This commit is contained in:
Kuingsmile
2026-01-28 20:41:35 +08:00
parent ee9f22dce2
commit e194754dae
6 changed files with 49 additions and 4 deletions

View File

@@ -7,9 +7,24 @@ import { scriptsDir } from '@core/datastore/dirs'
import picgo from '@core/picgo' import picgo from '@core/picgo'
import logger from '@core/picgo/logger' import logger from '@core/picgo/logger'
import axios from 'axios' import axios from 'axios'
import dotenv from 'dotenv'
import fs from 'fs-extra' import fs from 'fs-extra'
import { IPicGo } from 'piclist' import { IPicGo } from 'piclist'
function getFreshEnv() {
const envPath = path.join(scriptsDir(), '.env')
if (fs.existsSync(envPath)) {
const buf = fs.readFileSync(envPath)
const config = dotenv.parse(buf)
for (const k in config) {
process.env[k] = config[k]
}
return config
}
return {}
}
export const scriptLifecycleStages = [ export const scriptLifecycleStages = [
'onSoftwareOpen', 'onSoftwareOpen',
'onSoftwareClose', 'onSoftwareClose',
@@ -38,6 +53,7 @@ function format(data: unknown): string {
export async function runScript(ctx: IPicGo, script: string, extra: Record<string, any>): Promise<any> { export async function runScript(ctx: IPicGo, script: string, extra: Record<string, any>): Promise<any> {
try { try {
const env = getFreshEnv()
const base64Decode = (str: string): string => Buffer.from(str, 'base64').toString('utf-8') const base64Decode = (str: string): string => Buffer.from(str, 'base64').toString('utf-8')
const base64Encode = (data: Buffer | string): string => const base64Encode = (data: Buffer | string): string =>
(Buffer.isBuffer(data) ? data : Buffer.from(String(data))).toString('base64') (Buffer.isBuffer(data) ? data : Buffer.from(String(data))).toString('base64')
@@ -62,6 +78,7 @@ export async function runScript(ctx: IPicGo, script: string, extra: Record<strin
base64Encode, base64Encode,
os, os,
Buffer, Buffer,
env,
} }
vm.createContext(exposedAPI) vm.createContext(exposedAPI)
ctx.log.info('start to run script') ctx.log.info('start to run script')

View File

@@ -731,6 +731,7 @@
"disabled": "Disabled", "disabled": "Disabled",
"disableScript": "Disable Script", "disableScript": "Disable Script",
"duplicateScriptNameError": "Script name already exists, please use a different name", "duplicateScriptNameError": "Script name already exists, please use a different name",
"editENVFile": "Edit Env File",
"editScript": "Edit Script", "editScript": "Edit Script",
"emptyScriptList": "Script list is empty", "emptyScriptList": "Script list is empty",
"enabled": "Enabled", "enabled": "Enabled",

View File

@@ -731,6 +731,7 @@
"disabled": "已禁用", "disabled": "已禁用",
"disableScript": "禁用脚本", "disableScript": "禁用脚本",
"duplicateScriptNameError": "脚本名称已存在,请使用不同的名称", "duplicateScriptNameError": "脚本名称已存在,请使用不同的名称",
"editENVFile": "编辑环境变量",
"editScript": "编辑脚本", "editScript": "编辑脚本",
"emptyScriptList": "脚本列表为空", "emptyScriptList": "脚本列表为空",
"enabled": "已启用", "enabled": "已启用",

View File

@@ -731,6 +731,7 @@
"disabled": "已禁用", "disabled": "已禁用",
"disableScript": "禁用腳本", "disableScript": "禁用腳本",
"duplicateScriptNameError": "腳本名稱已存在,請使用不同的名稱", "duplicateScriptNameError": "腳本名稱已存在,請使用不同的名稱",
"editENVFile": "編輯環境變量",
"editScript": "編輯腳本", "editScript": "編輯腳本",
"emptyScriptList": "腳本列表為空", "emptyScriptList": "腳本列表為空",
"enabled": "已啟用", "enabled": "已啟用",

View File

@@ -11,6 +11,18 @@
<p class="m-0 text-sm text-secondary">{{ t('pages.scripts.description') }}</p> <p class="m-0 text-sm text-secondary">{{ t('pages.scripts.description') }}</p>
</div> </div>
</div> </div>
<div class="flex flex-wrap gap-3 overflow-visible">
<CustomButton
type="primary"
:icon="FolderOpen"
:text="t('pages.scripts.openScriptFolder')"
@click="handleOpenScriptFolder"
/>
</div>
</div>
<div
class="flex w-full flex-row items-center justify-between gap-4 overflow-visible rounded-2xl border border-border-secondary px-6 py-2 shadow-md max-md:items-stretch max-md:p-5"
>
<div class="flex flex-wrap gap-3 overflow-visible"> <div class="flex flex-wrap gap-3 overflow-visible">
<div class="flex max-w-[220px] min-w-[180px] flex-1 flex-col gap-1"> <div class="flex max-w-[220px] min-w-[180px] flex-1 flex-col gap-1">
<MultiSelect <MultiSelect
@@ -21,9 +33,9 @@
</div> </div>
<CustomButton <CustomButton
type="primary" type="primary"
:icon="FolderOpen" :icon="Edit2Icon"
:text="t('pages.scripts.openScriptFolder')" :text="t('pages.scripts.editENVFile')"
@click="handleOpenScriptFolder" @click="openEditPage(['.env'])"
/> />
</div> </div>
</div> </div>
@@ -200,7 +212,18 @@
<script lang="ts" setup> <script lang="ts" setup>
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { CheckCircle2, Clock, FileCode, FolderOpen, Pencil, Play, Plus, Trash2, XIcon } from 'lucide-vue-next' import {
CheckCircle2,
Clock,
Edit2Icon,
FileCode,
FolderOpen,
Pencil,
Play,
Plus,
Trash2,
XIcon,
} from 'lucide-vue-next'
import { computed, onBeforeMount, onBeforeUnmount, ref, watch } from 'vue' import { computed, onBeforeMount, onBeforeUnmount, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'

View File

@@ -70,6 +70,7 @@ export const picBedManualUrlList: IStringKeyMap = {
export const defaultScriptTemplate = ` export const defaultScriptTemplate = `
// ctx 为 核心PicList实例, extra为额外参数, 其中extra.galleryItem为当前删除的相册对象 // ctx 为 核心PicList实例, extra为额外参数, 其中extra.galleryItem为当前删除的相册对象
// env 变量中有脚本目录下的 .env 文件内容
// 可用额外API: axios, crypto, fs, path, os, setTimeout, setInterval, clearTimeout, clearInterval, base64Decode, base64Encode // 可用额外API: axios, crypto, fs, path, os, setTimeout, setInterval, clearTimeout, clearInterval, base64Decode, base64Encode
// 使用console.log或ctx.log输出的信息在软件日志文件piclist.log中可以查询到 // 使用console.log或ctx.log输出的信息在软件日志文件piclist.log中可以查询到
@@ -81,6 +82,7 @@ async function main(ctx, extra) {
export const defaultScriptTemplateEn = ` export const defaultScriptTemplateEn = `
// ctx is the core PicList instance, extra is additional parameters, among which extra.galleryItem is the currently deleted album object // ctx is the core PicList instance, extra is additional parameters, among which extra.galleryItem is the currently deleted album object
// env variable contains the contents of the .env file in the script directory
// Available additional APIs: axios, crypto, fs, path, os, setTimeout, setInterval, clearTimeout, clearInterval, base64Decode, base64Encode // Available additional APIs: axios, crypto, fs, path, os, setTimeout, setInterval, clearTimeout, clearInterval, base64Decode, base64Encode
// Use console.log or ctx.log to output information that can be found in the software log file piclist.log // Use console.log or ctx.log to output information that can be found in the software log file piclist.log