mirror of
https://github.com/Kuingsmile/PicList.git
synced 2026-08-28 19:47:17 +08:00
🐛 Fix(custom): fix drag upload of upload page
This commit is contained in:
@@ -1,277 +1,277 @@
|
|||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
import { fileURLToPath } from 'node:url'
|
import { fileURLToPath } from 'node:url'
|
||||||
|
|
||||||
import bus from '@core/bus'
|
import bus from '@core/bus'
|
||||||
import { CREATE_APP_MENU } from '@core/bus/constants'
|
import { CREATE_APP_MENU } from '@core/bus/constants'
|
||||||
import db from '@core/datastore'
|
import db from '@core/datastore'
|
||||||
import { app, BrowserWindow, Rectangle } from 'electron'
|
import { app, BrowserWindow, Rectangle } from 'electron'
|
||||||
|
|
||||||
import type { IWindowListItem } from '#/types/electron'
|
import type { IWindowListItem } from '#/types/electron'
|
||||||
import type { IBrowserWindowOptions } from '#/types/types'
|
import type { IBrowserWindowOptions } from '#/types/types'
|
||||||
import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '~/events/constant'
|
import { TOGGLE_SHORTKEY_MODIFIED_MODE } from '~/events/constant'
|
||||||
import { T as $t } from '~/i18n'
|
import { T as $t } from '~/i18n'
|
||||||
import { configPaths } from '~/utils/configPaths'
|
import { configPaths } from '~/utils/configPaths'
|
||||||
import { IWindowList } from '~/utils/enum'
|
import { IWindowList } from '~/utils/enum'
|
||||||
|
|
||||||
import logo from '../../../../../resources/logo.png?asset'
|
import logo from '../../../../../resources/logo.png?asset'
|
||||||
|
|
||||||
const windowList = new Map<string, IWindowListItem>()
|
const windowList = new Map<string, IWindowListItem>()
|
||||||
|
|
||||||
const getDefaultWindowSizes = (): { width: number; height: number } => {
|
const getDefaultWindowSizes = (): { width: number; height: number } => {
|
||||||
const [mainWindowWidth, mainWindowHeight] = db.get([
|
const [mainWindowWidth, mainWindowHeight] = db.get([
|
||||||
configPaths.settings.mainWindowWidth,
|
configPaths.settings.mainWindowWidth,
|
||||||
configPaths.settings.mainWindowHeight
|
configPaths.settings.mainWindowHeight
|
||||||
])
|
])
|
||||||
return {
|
return {
|
||||||
width: mainWindowWidth || 1200,
|
width: mainWindowWidth || 1200,
|
||||||
height: mainWindowHeight || 800
|
height: mainWindowHeight || 800
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setMiniWindowShape (win: BrowserWindow) {
|
function setMiniWindowShape (win: BrowserWindow) {
|
||||||
const radius = 32
|
const radius = 32
|
||||||
const shape: Rectangle[] = []
|
const shape: Rectangle[] = []
|
||||||
|
|
||||||
for (let y = -radius; y <= radius; y++) {
|
for (let y = -radius; y <= radius; y++) {
|
||||||
for (let x = -radius; x <= radius; x++) {
|
for (let x = -radius; x <= radius; x++) {
|
||||||
if (x * x + y * y <= radius * radius) {
|
if (x * x + y * y <= radius * radius) {
|
||||||
shape.push({ x: radius + x, y: radius + y, width: 1, height: 1 })
|
shape.push({ x: radius + x, y: radius + y, width: 1, height: 1 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
win.setShape(shape)
|
win.setShape(shape)
|
||||||
}
|
}
|
||||||
|
|
||||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||||
const preloadPath = fileURLToPath(new URL('../preload/index.mjs', import.meta.url))
|
const preloadPath = fileURLToPath(new URL('../preload/index.mjs', import.meta.url))
|
||||||
|
|
||||||
const { width: defaultWindowWidth, height: defaultWindowHeight } = getDefaultWindowSizes()
|
const { width: defaultWindowWidth, height: defaultWindowHeight } = getDefaultWindowSizes()
|
||||||
|
|
||||||
const trayWindowOptions = {
|
const trayWindowOptions = {
|
||||||
height: 350,
|
height: 350,
|
||||||
width: 196,
|
width: 196,
|
||||||
show: false,
|
show: false,
|
||||||
frame: false,
|
frame: false,
|
||||||
fullscreenable: false,
|
fullscreenable: false,
|
||||||
resizable: false,
|
resizable: false,
|
||||||
transparent: true,
|
transparent: true,
|
||||||
vibrancy: 'ultra-dark',
|
vibrancy: 'ultra-dark',
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
sandbox: false,
|
sandbox: false,
|
||||||
preload: preloadPath,
|
preload: preloadPath,
|
||||||
nodeIntegration: false,
|
nodeIntegration: false,
|
||||||
contextIsolation: true,
|
contextIsolation: true,
|
||||||
nodeIntegrationInWorker: true,
|
nodeIntegrationInWorker: true,
|
||||||
backgroundThrottling: false,
|
backgroundThrottling: false,
|
||||||
webSecurity: false
|
webSecurity: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const settingWindowOptions = {
|
const settingWindowOptions = {
|
||||||
height: defaultWindowHeight,
|
height: defaultWindowHeight,
|
||||||
width: defaultWindowWidth,
|
width: defaultWindowWidth,
|
||||||
show: false,
|
show: false,
|
||||||
frame: true,
|
frame: true,
|
||||||
center: true,
|
center: true,
|
||||||
fullscreenable: true,
|
fullscreenable: true,
|
||||||
resizable: true,
|
resizable: true,
|
||||||
title: 'PicList',
|
title: 'PicList',
|
||||||
transparent: false,
|
transparent: false,
|
||||||
backgroundColor: '#ebeef5',
|
backgroundColor: '#ebeef5',
|
||||||
titleBarStyle: 'hidden',
|
titleBarStyle: 'hidden',
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
sandbox: false,
|
sandbox: false,
|
||||||
webviewTag: true,
|
webviewTag: true,
|
||||||
backgroundThrottling: false,
|
backgroundThrottling: false,
|
||||||
preload: preloadPath,
|
preload: preloadPath,
|
||||||
nodeIntegration: false,
|
nodeIntegration: false,
|
||||||
contextIsolation: true,
|
contextIsolation: true,
|
||||||
nodeIntegrationInWorker: true,
|
nodeIntegrationInWorker: true,
|
||||||
webSecurity: false
|
webSecurity: false
|
||||||
}
|
}
|
||||||
} as IBrowserWindowOptions
|
} as IBrowserWindowOptions
|
||||||
|
|
||||||
if (process.platform !== 'darwin') {
|
if (process.platform !== 'darwin') {
|
||||||
settingWindowOptions.frame = false
|
settingWindowOptions.frame = false
|
||||||
settingWindowOptions.icon = '../../../../../resources/logo.png'
|
settingWindowOptions.icon = '../../../../../resources/logo.png'
|
||||||
}
|
}
|
||||||
|
|
||||||
const miniWindowOptions = {
|
const miniWindowOptions = {
|
||||||
height: 64,
|
height: 64,
|
||||||
width: 64,
|
width: 64,
|
||||||
show: process.platform === 'linux',
|
show: process.platform === 'linux',
|
||||||
frame: false,
|
frame: false,
|
||||||
fullscreenable: false,
|
fullscreenable: false,
|
||||||
skipTaskbar: true,
|
skipTaskbar: true,
|
||||||
resizable: false,
|
resizable: false,
|
||||||
transparent: process.platform !== 'linux',
|
transparent: process.platform !== 'linux',
|
||||||
icon: logo,
|
icon: logo,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
sandbox: false,
|
sandbox: false,
|
||||||
preload: preloadPath,
|
preload: preloadPath,
|
||||||
nodeIntegration: false,
|
nodeIntegration: false,
|
||||||
contextIsolation: true,
|
contextIsolation: true,
|
||||||
backgroundThrottling: false,
|
backgroundThrottling: false,
|
||||||
nodeIntegrationInWorker: true
|
nodeIntegrationInWorker: true
|
||||||
}
|
}
|
||||||
} as IBrowserWindowOptions
|
} as IBrowserWindowOptions
|
||||||
|
|
||||||
if (db.get(configPaths.settings.miniWindowOntop)) {
|
if (db.get(configPaths.settings.miniWindowOntop)) {
|
||||||
miniWindowOptions.alwaysOnTop = true
|
miniWindowOptions.alwaysOnTop = true
|
||||||
}
|
}
|
||||||
|
|
||||||
const renameWindowOptions = {
|
const renameWindowOptions = {
|
||||||
height: 250,
|
height: 270,
|
||||||
width: 350,
|
width: 350,
|
||||||
show: true,
|
show: true,
|
||||||
fullscreenable: false,
|
fullscreenable: false,
|
||||||
icon: logo,
|
icon: logo,
|
||||||
resizable: true,
|
resizable: true,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
sandbox: false,
|
sandbox: false,
|
||||||
preload: preloadPath,
|
preload: preloadPath,
|
||||||
nodeIntegration: false,
|
nodeIntegration: false,
|
||||||
contextIsolation: true,
|
contextIsolation: true,
|
||||||
nodeIntegrationInWorker: true,
|
nodeIntegrationInWorker: true,
|
||||||
backgroundThrottling: false
|
backgroundThrottling: false
|
||||||
}
|
}
|
||||||
} as IBrowserWindowOptions
|
} as IBrowserWindowOptions
|
||||||
|
|
||||||
if (process.platform !== 'darwin') {
|
if (process.platform !== 'darwin') {
|
||||||
renameWindowOptions.show = true
|
renameWindowOptions.show = true
|
||||||
renameWindowOptions.backgroundColor = '#3f3c37'
|
renameWindowOptions.backgroundColor = '#3f3c37'
|
||||||
renameWindowOptions.autoHideMenuBar = true
|
renameWindowOptions.autoHideMenuBar = true
|
||||||
renameWindowOptions.transparent = false
|
renameWindowOptions.transparent = false
|
||||||
}
|
}
|
||||||
|
|
||||||
const toolboxWindowOptions = {
|
const toolboxWindowOptions = {
|
||||||
height: 450,
|
height: 450,
|
||||||
width: 800,
|
width: 800,
|
||||||
show: false,
|
show: false,
|
||||||
frame: true,
|
frame: true,
|
||||||
center: true,
|
center: true,
|
||||||
fullscreenable: false,
|
fullscreenable: false,
|
||||||
resizable: false,
|
resizable: false,
|
||||||
title: `PicList ${$t('TOOLBOX')}`,
|
title: `PicList ${$t('TOOLBOX')}`,
|
||||||
backgroundColor: '#ebeef5',
|
backgroundColor: '#ebeef5',
|
||||||
icon: logo,
|
icon: logo,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
sandbox: false,
|
sandbox: false,
|
||||||
backgroundThrottling: false,
|
backgroundThrottling: false,
|
||||||
preload: preloadPath,
|
preload: preloadPath,
|
||||||
nodeIntegration: false,
|
nodeIntegration: false,
|
||||||
contextIsolation: true,
|
contextIsolation: true,
|
||||||
nodeIntegrationInWorker: true,
|
nodeIntegrationInWorker: true,
|
||||||
webSecurity: false
|
webSecurity: false
|
||||||
}
|
}
|
||||||
} as IBrowserWindowOptions
|
} as IBrowserWindowOptions
|
||||||
|
|
||||||
if (process.platform !== 'darwin') {
|
if (process.platform !== 'darwin') {
|
||||||
toolboxWindowOptions.backgroundColor = '#3f3c37'
|
toolboxWindowOptions.backgroundColor = '#3f3c37'
|
||||||
toolboxWindowOptions.autoHideMenuBar = true
|
toolboxWindowOptions.autoHideMenuBar = true
|
||||||
toolboxWindowOptions.transparent = false
|
toolboxWindowOptions.transparent = false
|
||||||
}
|
}
|
||||||
|
|
||||||
windowList.set(IWindowList.TRAY_WINDOW, {
|
windowList.set(IWindowList.TRAY_WINDOW, {
|
||||||
isValid: process.platform !== 'linux',
|
isValid: process.platform !== 'linux',
|
||||||
multiple: false,
|
multiple: false,
|
||||||
options: () => trayWindowOptions,
|
options: () => trayWindowOptions,
|
||||||
callback (window) {
|
callback (window) {
|
||||||
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
|
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
|
||||||
window.loadURL(process.env.ELECTRON_RENDERER_URL)
|
window.loadURL(process.env.ELECTRON_RENDERER_URL)
|
||||||
} else {
|
} else {
|
||||||
window.loadFile(path.join(__dirname, '../render/index.html'))
|
window.loadFile(path.join(__dirname, '../render/index.html'))
|
||||||
}
|
}
|
||||||
window.on('blur', () => {
|
window.on('blur', () => {
|
||||||
window.hide()
|
window.hide()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
windowList.set(IWindowList.SETTING_WINDOW, {
|
windowList.set(IWindowList.SETTING_WINDOW, {
|
||||||
isValid: true,
|
isValid: true,
|
||||||
multiple: false,
|
multiple: false,
|
||||||
options: () => settingWindowOptions,
|
options: () => settingWindowOptions,
|
||||||
callback (window, windowManager) {
|
callback (window, windowManager) {
|
||||||
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
|
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
|
||||||
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#main-page/upload`)
|
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#main-page/upload`)
|
||||||
} else {
|
} else {
|
||||||
window.loadFile(path.join(__dirname, '../render/index.html'), {
|
window.loadFile(path.join(__dirname, '../render/index.html'), {
|
||||||
hash: 'main-page/upload'
|
hash: 'main-page/upload'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
window.on('closed', () => {
|
window.on('closed', () => {
|
||||||
bus.emit(TOGGLE_SHORTKEY_MODIFIED_MODE, false)
|
bus.emit(TOGGLE_SHORTKEY_MODIFIED_MODE, false)
|
||||||
if (process.platform === 'linux') {
|
if (process.platform === 'linux') {
|
||||||
process.nextTick(() => {
|
process.nextTick(() => {
|
||||||
app.quit()
|
app.quit()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
bus.emit(CREATE_APP_MENU)
|
bus.emit(CREATE_APP_MENU)
|
||||||
windowManager.create(IWindowList.MINI_WINDOW)
|
windowManager.create(IWindowList.MINI_WINDOW)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
windowList.set(IWindowList.MINI_WINDOW, {
|
windowList.set(IWindowList.MINI_WINDOW, {
|
||||||
isValid: process.platform !== 'darwin',
|
isValid: process.platform !== 'darwin',
|
||||||
multiple: false,
|
multiple: false,
|
||||||
options: () => miniWindowOptions,
|
options: () => miniWindowOptions,
|
||||||
callback (window) {
|
callback (window) {
|
||||||
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
|
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
|
||||||
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#mini-page`)
|
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#mini-page`)
|
||||||
} else {
|
} else {
|
||||||
window.loadFile(path.join(__dirname, '../render/index.html'), {
|
window.loadFile(path.join(__dirname, '../render/index.html'), {
|
||||||
hash: 'mini-page'
|
hash: 'mini-page'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
setMiniWindowShape(window)
|
setMiniWindowShape(window)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
windowList.set(IWindowList.RENAME_WINDOW, {
|
windowList.set(IWindowList.RENAME_WINDOW, {
|
||||||
isValid: true,
|
isValid: true,
|
||||||
multiple: true,
|
multiple: true,
|
||||||
options: () => renameWindowOptions,
|
options: () => renameWindowOptions,
|
||||||
async callback (window, windowManager) {
|
async callback (window, windowManager) {
|
||||||
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
|
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
|
||||||
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#rename-page`)
|
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#rename-page`)
|
||||||
} else {
|
} else {
|
||||||
window.loadFile(path.join(__dirname, '../render/index.html'), {
|
window.loadFile(path.join(__dirname, '../render/index.html'), {
|
||||||
hash: 'rename-page'
|
hash: 'rename-page'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const currentWindow = windowManager.getAvailableWindow(true)
|
const currentWindow = windowManager.getAvailableWindow(true)
|
||||||
if (currentWindow && currentWindow.isVisible()) {
|
if (currentWindow && currentWindow.isVisible()) {
|
||||||
const { x, y, width, height } = currentWindow.getBounds()
|
const { x, y, width, height } = currentWindow.getBounds()
|
||||||
const positionX = Math.floor(x + width / 2 - 150)
|
const positionX = Math.floor(x + width / 2 - 150)
|
||||||
const positionY = Math.floor(y + height / 2 - (height > 400 ? 88 : 0))
|
const positionY = Math.floor(y + height / 2 - (height > 400 ? 88 : 0))
|
||||||
window.setPosition(positionX, positionY, false)
|
window.setPosition(positionX, positionY, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
windowList.set(IWindowList.TOOLBOX_WINDOW, {
|
windowList.set(IWindowList.TOOLBOX_WINDOW, {
|
||||||
isValid: true,
|
isValid: true,
|
||||||
multiple: false,
|
multiple: false,
|
||||||
options: () => toolboxWindowOptions,
|
options: () => toolboxWindowOptions,
|
||||||
async callback (window, windowManager) {
|
async callback (window, windowManager) {
|
||||||
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
|
if (!app.isPackaged && process.env.ELECTRON_RENDERER_URL) {
|
||||||
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#toolbox-page`)
|
window.loadURL(`${process.env.ELECTRON_RENDERER_URL}#toolbox-page`)
|
||||||
} else {
|
} else {
|
||||||
window.loadFile(path.join(__dirname, '../render/index.html'), {
|
window.loadFile(path.join(__dirname, '../render/index.html'), {
|
||||||
hash: 'toolbox-page'
|
hash: 'toolbox-page'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const currentWindow = windowManager.getAvailableWindow(true)
|
const currentWindow = windowManager.getAvailableWindow(true)
|
||||||
if (currentWindow && currentWindow.isVisible()) {
|
if (currentWindow && currentWindow.isVisible()) {
|
||||||
const { x, y, width, height } = currentWindow.getBounds()
|
const { x, y, width, height } = currentWindow.getBounds()
|
||||||
const positionX = Math.floor(x + width / 2 - 400)
|
const positionX = Math.floor(x + width / 2 - 400)
|
||||||
const positionY = Math.floor(y + height / 2 - (height > 400 ? 225 : 0))
|
const positionY = Math.floor(y + height / 2 - (height > 400 ? 225 : 0))
|
||||||
window.setPosition(positionX, positionY, false)
|
window.setPosition(positionX, positionY, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export default windowList
|
export default windowList
|
||||||
|
|||||||
+324
-335
@@ -1,335 +1,324 @@
|
|||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
|
|
||||||
import db from '@core/datastore'
|
import db from '@core/datastore'
|
||||||
import logger from '@core/picgo/logger'
|
import logger from '@core/picgo/logger'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { clipboard, dialog, Notification, Tray } from 'electron'
|
import { clipboard, Notification, Tray } from 'electron'
|
||||||
import FormData from 'form-data'
|
import FormData from 'form-data'
|
||||||
import fs from 'fs-extra'
|
import fs from 'fs-extra'
|
||||||
import { isReactive, isRef, toRaw, unref } from 'vue'
|
import { isReactive, isRef, toRaw, unref } from 'vue'
|
||||||
|
|
||||||
import type { IHTTPProxy, IPrivateShowNotificationOption, IShowMessageBoxResult, IStringKeyMap } from '#/types/types'
|
import type { IHTTPProxy, IPrivateShowNotificationOption, IStringKeyMap } from '#/types/types'
|
||||||
import { configPaths } from '~/utils/configPaths'
|
import { configPaths } from '~/utils/configPaths'
|
||||||
import { IShortUrlServer } from '~/utils/enum'
|
import { IShortUrlServer } from '~/utils/enum'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get raw data from reactive or ref
|
* get raw data from reactive or ref
|
||||||
*/
|
*/
|
||||||
export const getRawData = (args: any): any => {
|
export const getRawData = (args: any): any => {
|
||||||
if (isRef(args)) return unref(args)
|
if (isRef(args)) return unref(args)
|
||||||
if (isReactive(args)) return toRaw(args)
|
if (isReactive(args)) return toRaw(args)
|
||||||
if (Array.isArray(args)) return args.map(getRawData)
|
if (Array.isArray(args)) return args.map(getRawData)
|
||||||
if (typeof args === 'object' && args !== null) {
|
if (typeof args === 'object' && args !== null) {
|
||||||
const data = {} as Record<string, any>
|
const data = {} as Record<string, any>
|
||||||
for (const key in args) {
|
for (const key in args) {
|
||||||
data[key] = getRawData(args[key])
|
data[key] = getRawData(args[key])
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
return args
|
return args
|
||||||
}
|
}
|
||||||
|
|
||||||
const getExtension = (fileName: string) => path.extname(fileName).slice(1)
|
const getExtension = (fileName: string) => path.extname(fileName).slice(1)
|
||||||
|
|
||||||
export const isImage = (fileName: string) =>
|
export const isImage = (fileName: string) =>
|
||||||
['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'ico', 'svg', 'avif'].includes(getExtension(fileName))
|
['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp', 'ico', 'svg', 'avif'].includes(getExtension(fileName))
|
||||||
|
|
||||||
export let tray: Tray
|
export let tray: Tray
|
||||||
|
|
||||||
export const setTray = (t: Tray) => {
|
export const setTray = (t: Tray) => {
|
||||||
tray = t
|
tray = t
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getTray = () => tray
|
export const getTray = () => tray
|
||||||
|
|
||||||
export function setTrayToolTip (title: string): void {
|
export function setTrayToolTip (title: string): void {
|
||||||
if (tray) {
|
if (tray) {
|
||||||
tray.setToolTip(title)
|
tray.setToolTip(title)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const handleCopyUrl = (str: string): void => {
|
export const handleCopyUrl = (str: string): void => {
|
||||||
if (db.get(configPaths.settings.autoCopy) !== false) {
|
if (db.get(configPaths.settings.autoCopy) !== false) {
|
||||||
clipboard.writeText(str)
|
clipboard.writeText(str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* show notification
|
* show notification
|
||||||
* @param options
|
* @param options
|
||||||
*/
|
*/
|
||||||
export const showNotification = (
|
export const showNotification = (
|
||||||
options: IPrivateShowNotificationOption = {
|
options: IPrivateShowNotificationOption = {
|
||||||
title: '',
|
title: '',
|
||||||
body: '',
|
body: '',
|
||||||
clickToCopy: false,
|
clickToCopy: false,
|
||||||
copyContent: '',
|
copyContent: '',
|
||||||
clickFn: () => {}
|
clickFn: () => {}
|
||||||
}
|
}
|
||||||
) => {
|
) => {
|
||||||
const notification = new Notification({
|
const notification = new Notification({
|
||||||
title: options.title,
|
title: options.title,
|
||||||
body: options.body
|
body: options.body
|
||||||
// icon: options.icon || undefined
|
// icon: options.icon || undefined
|
||||||
})
|
})
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
if (options.clickToCopy) {
|
if (options.clickToCopy) {
|
||||||
clipboard.writeText(options.copyContent || options.body)
|
clipboard.writeText(options.copyContent || options.body)
|
||||||
}
|
}
|
||||||
if (options.clickFn) {
|
if (options.clickFn) {
|
||||||
options.clickFn()
|
options.clickFn()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
notification.once('click', handleClick)
|
notification.once('click', handleClick)
|
||||||
notification.once('close', () => {
|
notification.once('close', () => {
|
||||||
notification.removeListener('click', handleClick)
|
notification.removeListener('click', handleClick)
|
||||||
})
|
})
|
||||||
notification.show()
|
notification.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
export const showMessageBox = (options: any) => {
|
/**
|
||||||
return new Promise<IShowMessageBoxResult>(resolve => {
|
* macOS public.file-url will get encoded file path,
|
||||||
dialog.showMessageBox(options).then(res => {
|
* so we need to decode it
|
||||||
resolve({
|
*/
|
||||||
result: res.response,
|
export const ensureFilePath = (filePath: string, prefix = 'file://'): string => {
|
||||||
checkboxChecked: res.checkboxChecked
|
filePath = filePath.replace(prefix, '')
|
||||||
})
|
if (fs.existsSync(filePath)) {
|
||||||
})
|
return `${prefix}${filePath}`
|
||||||
})
|
}
|
||||||
}
|
filePath = decodeURIComponent(filePath)
|
||||||
|
if (fs.existsSync(filePath)) {
|
||||||
/**
|
return `${prefix}${filePath}`
|
||||||
* macOS public.file-url will get encoded file path,
|
}
|
||||||
* so we need to decode it
|
return ''
|
||||||
*/
|
}
|
||||||
export const ensureFilePath = (filePath: string, prefix = 'file://'): string => {
|
|
||||||
filePath = filePath.replace(prefix, '')
|
/**
|
||||||
if (fs.existsSync(filePath)) {
|
* for builtin clipboard to get image path from clipboard
|
||||||
return `${prefix}${filePath}`
|
* @returns
|
||||||
}
|
*/
|
||||||
filePath = decodeURIComponent(filePath)
|
export const getClipboardFilePath = (): string => {
|
||||||
if (fs.existsSync(filePath)) {
|
// TODO: linux support
|
||||||
return `${prefix}${filePath}`
|
const img = clipboard.readImage()
|
||||||
}
|
const platform = process.platform
|
||||||
return ''
|
|
||||||
}
|
if (!img.isEmpty() && platform === 'darwin') {
|
||||||
|
let imgPath = clipboard.read('public.file-url') // will get file://xxx/xxx
|
||||||
/**
|
imgPath = ensureFilePath(imgPath)
|
||||||
* for builtin clipboard to get image path from clipboard
|
return imgPath ? imgPath.replace('file://', '') : ''
|
||||||
* @returns
|
}
|
||||||
*/
|
|
||||||
export const getClipboardFilePath = (): string => {
|
if (img.isEmpty() && platform === 'win32') {
|
||||||
// TODO: linux support
|
const imgPath = clipboard
|
||||||
const img = clipboard.readImage()
|
.readBuffer('FileNameW')
|
||||||
const platform = process.platform
|
?.toString('ucs2')
|
||||||
|
?.replace(RegExp(String.fromCharCode(0), 'g'), '')
|
||||||
if (!img.isEmpty() && platform === 'darwin') {
|
return imgPath || ''
|
||||||
let imgPath = clipboard.read('public.file-url') // will get file://xxx/xxx
|
}
|
||||||
imgPath = ensureFilePath(imgPath)
|
|
||||||
return imgPath ? imgPath.replace('file://', '') : ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
if (img.isEmpty() && platform === 'win32') {
|
const c1nApi = 'https://c1n.cn/link/short'
|
||||||
const imgPath = clipboard
|
|
||||||
.readBuffer('FileNameW')
|
const createC1NShortUrl = async (url: string) => {
|
||||||
?.toString('ucs2')
|
const c1nToken = db.get(configPaths.settings.c1nToken) || ''
|
||||||
?.replace(RegExp(String.fromCharCode(0), 'g'), '')
|
if (!c1nToken) {
|
||||||
return imgPath || ''
|
logger.warn('c1n token is not set')
|
||||||
}
|
return url
|
||||||
|
}
|
||||||
return ''
|
try {
|
||||||
}
|
const form = new FormData()
|
||||||
|
form.append('url', url)
|
||||||
const c1nApi = 'https://c1n.cn/link/short'
|
const res = await axios.post(c1nApi, form, {
|
||||||
|
headers: {
|
||||||
const generateC1NShortUrl = async (url: string) => {
|
token: c1nToken
|
||||||
const c1nToken = db.get(configPaths.settings.c1nToken) || ''
|
}
|
||||||
if (!c1nToken) {
|
})
|
||||||
logger.warn('c1n token is not set')
|
if (res.status >= 200 && res.status < 300 && res.data?.code === 0) {
|
||||||
return url
|
return res.data.data
|
||||||
}
|
}
|
||||||
try {
|
} catch (e: any) {
|
||||||
const form = new FormData()
|
logger.error(e)
|
||||||
form.append('url', url)
|
}
|
||||||
const res = await axios.post(c1nApi, form, {
|
return url
|
||||||
headers: {
|
}
|
||||||
token: c1nToken
|
|
||||||
}
|
const createYOURLSShortLink = async (url: string) => {
|
||||||
})
|
let domain = db.get(configPaths.settings.yourlsDomain) || ''
|
||||||
if (res.status >= 200 && res.status < 300 && res.data?.code === 0) {
|
const signature = db.get(configPaths.settings.yourlsSignature) || ''
|
||||||
return res.data.data
|
|
||||||
}
|
if (!domain || !signature) {
|
||||||
} catch (e: any) {
|
logger.warn('Yourls server or signature is not set')
|
||||||
logger.error(e)
|
return url
|
||||||
}
|
}
|
||||||
return url
|
if (!/^https?:\/\//.test(domain)) {
|
||||||
}
|
domain = `http://${domain}`
|
||||||
|
}
|
||||||
const generateYOURLSShortUrl = async (url: string) => {
|
const params = new URLSearchParams({
|
||||||
let domain = db.get(configPaths.settings.yourlsDomain) || ''
|
signature,
|
||||||
const signature = db.get(configPaths.settings.yourlsSignature) || ''
|
action: 'shorturl',
|
||||||
|
format: 'json',
|
||||||
if (!domain || !signature) {
|
url
|
||||||
logger.warn('Yourls server or signature is not set')
|
})
|
||||||
return url
|
try {
|
||||||
}
|
const res = await axios.get(`${domain}/yourls-api.php?${params.toString()}`)
|
||||||
if (!/^https?:\/\//.test(domain)) {
|
if (res.data?.shorturl) {
|
||||||
domain = `http://${domain}`
|
return res.data.shorturl
|
||||||
}
|
}
|
||||||
const params = new URLSearchParams({
|
} catch (e: any) {
|
||||||
signature,
|
if (e.response?.data?.message?.includes('already exists in database')) {
|
||||||
action: 'shorturl',
|
return e.response.data.shorturl
|
||||||
format: 'json',
|
}
|
||||||
url
|
logger.error(e)
|
||||||
})
|
}
|
||||||
try {
|
|
||||||
const res = await axios.get(`${domain}/yourls-api.php?${params.toString()}`)
|
return url
|
||||||
if (res.data?.shorturl) {
|
}
|
||||||
return res.data.shorturl
|
|
||||||
}
|
const createShortUrlForCFWorker = async (url: string) => {
|
||||||
} catch (e: any) {
|
let cfWorkerHost = db.get(configPaths.settings.cfWorkerHost) || ''
|
||||||
if (e.response?.data?.message?.includes('already exists in database')) {
|
cfWorkerHost = cfWorkerHost.replace(/\/$/, '')
|
||||||
return e.response.data.shorturl
|
if (!cfWorkerHost) {
|
||||||
}
|
logger.warn('CF Worker host is not set')
|
||||||
logger.error(e)
|
return url
|
||||||
}
|
}
|
||||||
|
|
||||||
return url
|
try {
|
||||||
}
|
const res = await axios.post(cfWorkerHost, { url })
|
||||||
|
if (res.data?.status === 200 && res.data?.key?.startsWith('/')) {
|
||||||
const generateCFWORKERShortUrl = async (url: string) => {
|
return `${cfWorkerHost}${res.data.key}`
|
||||||
let cfWorkerHost = db.get(configPaths.settings.cfWorkerHost) || ''
|
}
|
||||||
cfWorkerHost = cfWorkerHost.replace(/\/$/, '')
|
} catch (e: any) {
|
||||||
if (!cfWorkerHost) {
|
logger.error(e)
|
||||||
logger.warn('CF Worker host is not set')
|
}
|
||||||
return url
|
|
||||||
}
|
return url
|
||||||
|
}
|
||||||
try {
|
|
||||||
const res = await axios.post(cfWorkerHost, { url })
|
const createShortUrlFromSink = async (url: string) => {
|
||||||
if (res.data?.status === 200 && res.data?.key?.startsWith('/')) {
|
let sinkDomain = db.get(configPaths.settings.sinkDomain) || ''
|
||||||
return `${cfWorkerHost}${res.data.key}`
|
const sinkToken = db.get(configPaths.settings.sinkToken) || ''
|
||||||
}
|
if (!sinkDomain || !sinkToken) {
|
||||||
} catch (e: any) {
|
logger.warn('Sink domain or token is not set')
|
||||||
logger.error(e)
|
return url
|
||||||
}
|
}
|
||||||
|
if (!/^https?:\/\//.test(sinkDomain)) {
|
||||||
return url
|
sinkDomain = `http://${sinkDomain}`
|
||||||
}
|
}
|
||||||
|
if (sinkDomain.endsWith('/')) {
|
||||||
const generateSinkShortUrl = async (url: string) => {
|
sinkDomain = sinkDomain.slice(0, -1)
|
||||||
let sinkDomain = db.get(configPaths.settings.sinkDomain) || ''
|
}
|
||||||
const sinkToken = db.get(configPaths.settings.sinkToken) || ''
|
try {
|
||||||
if (!sinkDomain || !sinkToken) {
|
const res = await axios.post(
|
||||||
logger.warn('Sink domain or token is not set')
|
`${sinkDomain}/api/link/create`,
|
||||||
return url
|
{ url },
|
||||||
}
|
{ headers: { Authorization: `Bearer ${sinkToken}` } }
|
||||||
if (!/^https?:\/\//.test(sinkDomain)) {
|
)
|
||||||
sinkDomain = `http://${sinkDomain}`
|
if (res.data?.link?.slug) {
|
||||||
}
|
return `${sinkDomain}/${res.data.link.slug}`
|
||||||
if (sinkDomain.endsWith('/')) {
|
}
|
||||||
sinkDomain = sinkDomain.slice(0, -1)
|
} catch (e: any) {
|
||||||
}
|
logger.error(e)
|
||||||
try {
|
}
|
||||||
const res = await axios.post(
|
return url
|
||||||
`${sinkDomain}/api/link/create`,
|
}
|
||||||
{ url },
|
|
||||||
{ headers: { Authorization: `Bearer ${sinkToken}` } }
|
export const generateShortUrl = async (url: string) => {
|
||||||
)
|
const server = db.get(configPaths.settings.shortUrlServer) || IShortUrlServer.C1N
|
||||||
if (res.data?.link?.slug) {
|
switch (server) {
|
||||||
return `${sinkDomain}/${res.data.link.slug}`
|
case IShortUrlServer.C1N:
|
||||||
}
|
return createC1NShortUrl(url)
|
||||||
} catch (e: any) {
|
case IShortUrlServer.YOURLS:
|
||||||
logger.error(e)
|
return createYOURLSShortLink(url)
|
||||||
}
|
case IShortUrlServer.CFWORKER:
|
||||||
return url
|
return createShortUrlForCFWorker(url)
|
||||||
}
|
case IShortUrlServer.SINK:
|
||||||
|
return createShortUrlFromSink(url)
|
||||||
export const generateShortUrl = async (url: string) => {
|
default:
|
||||||
const server = db.get(configPaths.settings.shortUrlServer) || IShortUrlServer.C1N
|
return url
|
||||||
switch (server) {
|
}
|
||||||
case IShortUrlServer.C1N:
|
}
|
||||||
return generateC1NShortUrl(url)
|
|
||||||
case IShortUrlServer.YOURLS:
|
export const isUrl = (url: string): boolean => {
|
||||||
return generateYOURLSShortUrl(url)
|
try {
|
||||||
case IShortUrlServer.CFWORKER:
|
return Boolean(new URL(url))
|
||||||
return generateCFWORKERShortUrl(url)
|
} catch {
|
||||||
case IShortUrlServer.SINK:
|
return false
|
||||||
return generateSinkShortUrl(url)
|
}
|
||||||
default:
|
}
|
||||||
return url
|
|
||||||
}
|
export const isUrlEncode = (url: string): boolean => {
|
||||||
}
|
url = url || ''
|
||||||
|
try {
|
||||||
export const isUrl = (url: string): boolean => {
|
return url !== decodeURI(url)
|
||||||
try {
|
} catch {
|
||||||
return Boolean(new URL(url))
|
return false
|
||||||
} catch {
|
}
|
||||||
return false
|
}
|
||||||
}
|
|
||||||
}
|
export const handleUrlEncode = (url: string): string => (isUrlEncode(url) ? url : encodeURI(url))
|
||||||
|
|
||||||
export const isUrlEncode = (url: string): boolean => {
|
export const handleUrlEncodeWithSetting = (url: string) =>
|
||||||
url = url || ''
|
db.get(configPaths.settings.encodeOutputURL) ? handleUrlEncode(url) : url
|
||||||
try {
|
|
||||||
return url !== decodeURI(url)
|
export const handleStreamlinePluginName = (name: string) => name.replace(/(@[^/]+\/)?picgo-plugin-/, '')
|
||||||
} catch {
|
export const simpleClone = (obj: any) => JSON.parse(JSON.stringify(obj))
|
||||||
return false
|
export const enforceNumber = (num: number | string) => (isNaN(+num) ? 0 : +num)
|
||||||
}
|
|
||||||
}
|
export const trimValues = <T extends IStringKeyMap>(
|
||||||
|
obj: T
|
||||||
export const handleUrlEncode = (url: string): string => (isUrlEncode(url) ? url : encodeURI(url))
|
): { [K in keyof T]: T[K] extends string ? string : T[K] } => {
|
||||||
|
return Object.fromEntries(
|
||||||
export const handleUrlEncodeWithSetting = (url: string) =>
|
Object.entries(obj).map(([key, value]) => [key, typeof value === 'string' ? value.trim() : value])
|
||||||
db.get(configPaths.settings.encodeOutputURL) ? handleUrlEncode(url) : url
|
) as { [K in keyof T]: T[K] extends string ? string : T[K] }
|
||||||
|
}
|
||||||
export const handleStreamlinePluginName = (name: string) => name.replace(/(@[^/]+\/)?picgo-plugin-/, '')
|
|
||||||
export const simpleClone = (obj: any) => JSON.parse(JSON.stringify(obj))
|
export const formatEndpoint = (endpoint: string, sslEnabled: boolean): string => {
|
||||||
export const enforceNumber = (num: number | string) => (isNaN(+num) ? 0 : +num)
|
const hasProtocol = /^https?:\/\//.test(endpoint)
|
||||||
|
if (!hasProtocol) {
|
||||||
export const trimValues = <T extends IStringKeyMap>(
|
return `${sslEnabled ? 'https' : 'http'}://${endpoint}`
|
||||||
obj: T
|
}
|
||||||
): { [K in keyof T]: T[K] extends string ? string : T[K] } => {
|
return sslEnabled ? endpoint.replace(/^http:\/\//, 'https://') : endpoint.replace(/^https:\/\//, 'http://')
|
||||||
return Object.fromEntries(
|
}
|
||||||
Object.entries(obj).map(([key, value]) => [key, typeof value === 'string' ? value.trim() : value])
|
|
||||||
) as { [K in keyof T]: T[K] extends string ? string : T[K] }
|
export const formatHttpProxy = (
|
||||||
}
|
proxy: string | undefined,
|
||||||
|
type: 'object' | 'string'
|
||||||
export const formatEndpoint = (endpoint: string, sslEnabled: boolean): string => {
|
): IHTTPProxy | undefined | string => {
|
||||||
const hasProtocol = /^https?:\/\//.test(endpoint)
|
if (!proxy) return undefined
|
||||||
if (!hasProtocol) {
|
if (/^https?:\/\//.test(proxy)) {
|
||||||
return `${sslEnabled ? 'https' : 'http'}://${endpoint}`
|
const { protocol, hostname, port } = new URL(proxy)
|
||||||
}
|
return type === 'string'
|
||||||
return sslEnabled ? endpoint.replace(/^http:\/\//, 'https://') : endpoint.replace(/^https:\/\//, 'http://')
|
? `${protocol}//${hostname}:${port}`
|
||||||
}
|
: {
|
||||||
|
host: hostname,
|
||||||
export const formatHttpProxy = (
|
port: Number(port),
|
||||||
proxy: string | undefined,
|
protocol: protocol.slice(0, -1)
|
||||||
type: 'object' | 'string'
|
}
|
||||||
): IHTTPProxy | undefined | string => {
|
}
|
||||||
if (!proxy) return undefined
|
const [host, port] = proxy.split(':')
|
||||||
if (/^https?:\/\//.test(proxy)) {
|
return type === 'string'
|
||||||
const { protocol, hostname, port } = new URL(proxy)
|
? `http://${host}:${port}`
|
||||||
return type === 'string'
|
: {
|
||||||
? `${protocol}//${hostname}:${port}`
|
host,
|
||||||
: {
|
port: port ? Number(port) : 80,
|
||||||
host: hostname,
|
protocol: 'http'
|
||||||
port: Number(port),
|
}
|
||||||
protocol: protocol.slice(0, -1)
|
}
|
||||||
}
|
|
||||||
}
|
export function encodeFilePath (filePath: string) {
|
||||||
const [host, port] = proxy.split(':')
|
return filePath.replace(/\\/g, '/').split('/').map(encodeURIComponent).join('/')
|
||||||
return type === 'string'
|
}
|
||||||
? `http://${host}:${port}`
|
|
||||||
: {
|
export const trimPath = (path: string) => path.replace(/^\/+|\/+$/g, '').replace(/\/+/g, '/')
|
||||||
host,
|
|
||||||
port: port ? Number(port) : 80,
|
|
||||||
protocol: 'http'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function encodeFilePath (filePath: string) {
|
|
||||||
return filePath.replace(/\\/g, '/').split('/').map(encodeURIComponent).join('/')
|
|
||||||
}
|
|
||||||
|
|
||||||
export const trimPath = (path: string) => path.replace(/^\/+|\/+$/g, '').replace(/\/+/g, '/')
|
|
||||||
|
|||||||
+263
-262
@@ -1,262 +1,263 @@
|
|||||||
import crypto from 'node:crypto'
|
import crypto from 'node:crypto'
|
||||||
import http, { AgentOptions } from 'node:http'
|
import http, { AgentOptions } from 'node:http'
|
||||||
import https from 'node:https'
|
import https from 'node:https'
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
import querystring from 'node:querystring'
|
import querystring from 'node:querystring'
|
||||||
|
|
||||||
import { DeleteObjectCommand, S3Client, S3ClientConfig } from '@aws-sdk/client-s3'
|
import type { S3ClientConfig } from '@aws-sdk/client-s3'
|
||||||
import { NodeHttpHandler } from '@smithy/node-http-handler'
|
import { DeleteObjectCommand, S3Client } from '@aws-sdk/client-s3'
|
||||||
import axios from 'axios'
|
import { NodeHttpHandler } from '@smithy/node-http-handler'
|
||||||
import { ISftpPlistConfig } from 'piclist'
|
import axios from 'axios'
|
||||||
|
import type { ISftpPlistConfig } from 'piclist'
|
||||||
import type { IObj, IStringKeyMap } from '#/types/types'
|
|
||||||
import { getAgent } from '~/manage/utils/common'
|
import type { IObj, IStringKeyMap } from '#/types/types'
|
||||||
import SSHClient from '~/utils/sshClient'
|
import { getAgent } from '~/manage/utils/common'
|
||||||
|
import SSHClient from '~/utils/sshClient'
|
||||||
interface DogecloudTokenFull {
|
|
||||||
Credentials: {
|
interface DogecloudTokenFull {
|
||||||
accessKeyId: string
|
Credentials: {
|
||||||
secretAccessKey: string
|
accessKeyId: string
|
||||||
sessionToken: string
|
secretAccessKey: string
|
||||||
}
|
sessionToken: string
|
||||||
ExpiredAt: number
|
}
|
||||||
Buckets: {
|
ExpiredAt: number
|
||||||
name: string
|
Buckets: {
|
||||||
s3Bucket: string
|
name: string
|
||||||
s3Endpoint: string
|
s3Bucket: string
|
||||||
}[]
|
s3Endpoint: string
|
||||||
}
|
}[]
|
||||||
|
}
|
||||||
const dogeRegionMap: IStringKeyMap = {
|
|
||||||
'ap-shanghai': '0',
|
const dogeRegionMap: IStringKeyMap = {
|
||||||
'ap-beijing': '1',
|
'ap-shanghai': '0',
|
||||||
'ap-guangzhou': '2',
|
'ap-beijing': '1',
|
||||||
'ap-chengdu': '3'
|
'ap-guangzhou': '2',
|
||||||
}
|
'ap-chengdu': '3'
|
||||||
|
}
|
||||||
async function dogecloudApi (
|
|
||||||
apiPath: string,
|
async function dogecloudApi (
|
||||||
data = {},
|
apiPath: string,
|
||||||
jsonMode: boolean = false,
|
data = {},
|
||||||
accessKey: string,
|
jsonMode: boolean = false,
|
||||||
secretKey: string
|
accessKey: string,
|
||||||
) {
|
secretKey: string
|
||||||
const body = jsonMode ? JSON.stringify(data) : querystring.encode(data)
|
) {
|
||||||
const sign = crypto
|
const body = jsonMode ? JSON.stringify(data) : querystring.encode(data)
|
||||||
.createHmac('sha1', secretKey)
|
const sign = crypto
|
||||||
.update(Buffer.from(apiPath + '\n' + body, 'utf8'))
|
.createHmac('sha1', secretKey)
|
||||||
.digest('hex')
|
.update(Buffer.from(apiPath + '\n' + body, 'utf8'))
|
||||||
const authorization = `TOKEN ${accessKey}:${sign}`
|
.digest('hex')
|
||||||
try {
|
const authorization = `TOKEN ${accessKey}:${sign}`
|
||||||
const res = await axios.request({
|
try {
|
||||||
url: `https://api.dogecloud.com${apiPath}`,
|
const res = await axios.request({
|
||||||
method: 'POST',
|
url: `https://api.dogecloud.com${apiPath}`,
|
||||||
data: body,
|
method: 'POST',
|
||||||
responseType: 'json',
|
data: body,
|
||||||
headers: {
|
responseType: 'json',
|
||||||
'Content-Type': jsonMode ? 'application/json' : 'application/x-www-form-urlencoded',
|
headers: {
|
||||||
Authorization: authorization
|
'Content-Type': jsonMode ? 'application/json' : 'application/x-www-form-urlencoded',
|
||||||
}
|
Authorization: authorization
|
||||||
})
|
}
|
||||||
if (res.data.code !== 200) {
|
})
|
||||||
throw new Error('API Error')
|
if (res.data.code !== 200) {
|
||||||
}
|
throw new Error('API Error')
|
||||||
return res.data.data
|
}
|
||||||
} catch (err: any) {
|
return res.data.data
|
||||||
throw new Error('API Error')
|
} catch (err: any) {
|
||||||
}
|
throw new Error('API Error')
|
||||||
}
|
}
|
||||||
|
}
|
||||||
async function getDogeToken (accessKey: string, secretKey: string): Promise<IObj | DogecloudTokenFull> {
|
|
||||||
try {
|
async function getDogeToken (accessKey: string, secretKey: string): Promise<IObj | DogecloudTokenFull> {
|
||||||
const data = await dogecloudApi(
|
try {
|
||||||
'/auth/tmp_token.json',
|
const data = await dogecloudApi(
|
||||||
{
|
'/auth/tmp_token.json',
|
||||||
channel: 'OSS_FULL',
|
{
|
||||||
scopes: ['*']
|
channel: 'OSS_FULL',
|
||||||
},
|
scopes: ['*']
|
||||||
true,
|
},
|
||||||
accessKey,
|
true,
|
||||||
secretKey
|
accessKey,
|
||||||
)
|
secretKey
|
||||||
return data
|
)
|
||||||
} catch (err: any) {
|
return data
|
||||||
console.log(err)
|
} catch (err: any) {
|
||||||
return {}
|
console.log(err)
|
||||||
}
|
return {}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
export async function removeFileFromS3InMain (configMap: IStringKeyMap, dogeMode: boolean = false) {
|
|
||||||
try {
|
export async function removeFileFromS3InMain (configMap: IStringKeyMap, dogeMode: boolean = false) {
|
||||||
const {
|
try {
|
||||||
url: rawUrl,
|
const {
|
||||||
type,
|
url: rawUrl,
|
||||||
config: { accessKeyID, secretAccessKey, bucketName, endpoint, pathStyleAccess, rejectUnauthorized, proxy }
|
type,
|
||||||
} = configMap
|
config: { accessKeyID, secretAccessKey, bucketName, endpoint, pathStyleAccess, rejectUnauthorized, proxy }
|
||||||
let {
|
} = configMap
|
||||||
imgUrl,
|
let {
|
||||||
config: { region }
|
imgUrl,
|
||||||
} = configMap
|
config: { region }
|
||||||
if (type === 'aws-s3' || type === 'aws-s3-plist') {
|
} = configMap
|
||||||
imgUrl = rawUrl || imgUrl || ''
|
if (type === 'aws-s3' || type === 'aws-s3-plist') {
|
||||||
}
|
imgUrl = rawUrl || imgUrl || ''
|
||||||
const url = new URL(!/^https?:\/\//.test(imgUrl) ? `http://${imgUrl}` : imgUrl)
|
}
|
||||||
let fileKey = url.pathname.replace(/^\/+/, '')
|
const url = new URL(!/^https?:\/\//.test(imgUrl) ? `http://${imgUrl}` : imgUrl)
|
||||||
if (pathStyleAccess) {
|
let fileKey = url.pathname.replace(/^\/+/, '')
|
||||||
fileKey = fileKey.replace(/^[^/]+\//, '')
|
if (pathStyleAccess) {
|
||||||
}
|
fileKey = fileKey.replace(/^[^/]+\//, '')
|
||||||
const endpointUrl: string | undefined = endpoint
|
}
|
||||||
? /^https?:\/\//.test(endpoint)
|
const endpointUrl: string | undefined = endpoint
|
||||||
? endpoint
|
? /^https?:\/\//.test(endpoint)
|
||||||
: `http://${endpoint}`
|
? endpoint
|
||||||
: undefined
|
: `http://${endpoint}`
|
||||||
if (endpointUrl && endpointUrl.includes('cloudflarestorage')) {
|
: undefined
|
||||||
region = region || 'auto'
|
if (endpointUrl && endpointUrl.includes('cloudflarestorage')) {
|
||||||
}
|
region = region || 'auto'
|
||||||
const sslEnabled = endpointUrl ? endpointUrl.startsWith('https') : true
|
}
|
||||||
const agent = getAgent(proxy, sslEnabled)
|
const sslEnabled = endpointUrl ? endpointUrl.startsWith('https') : true
|
||||||
const commonOptions: AgentOptions = {
|
const agent = getAgent(proxy, sslEnabled)
|
||||||
keepAlive: true,
|
const commonOptions: AgentOptions = {
|
||||||
keepAliveMsecs: 1000,
|
keepAlive: true,
|
||||||
scheduling: 'lifo' as 'lifo' | 'fifo' | undefined
|
keepAliveMsecs: 1000,
|
||||||
}
|
scheduling: 'lifo' as 'lifo' | 'fifo' | undefined
|
||||||
const extraOptions = sslEnabled ? { rejectUnauthorized: !!rejectUnauthorized } : {}
|
}
|
||||||
const handler = sslEnabled
|
const extraOptions = sslEnabled ? { rejectUnauthorized: !!rejectUnauthorized } : {}
|
||||||
? new NodeHttpHandler({
|
const handler = sslEnabled
|
||||||
httpsAgent: agent.https
|
? new NodeHttpHandler({
|
||||||
? agent.https
|
httpsAgent: agent.https
|
||||||
: new https.Agent({
|
? agent.https
|
||||||
...commonOptions,
|
: new https.Agent({
|
||||||
...extraOptions
|
...commonOptions,
|
||||||
})
|
...extraOptions
|
||||||
})
|
})
|
||||||
: new NodeHttpHandler({
|
})
|
||||||
httpAgent: agent.http
|
: new NodeHttpHandler({
|
||||||
? agent.http
|
httpAgent: agent.http
|
||||||
: new http.Agent({
|
? agent.http
|
||||||
...commonOptions,
|
: new http.Agent({
|
||||||
...extraOptions
|
...commonOptions,
|
||||||
})
|
...extraOptions
|
||||||
})
|
})
|
||||||
const s3Options: S3ClientConfig = {
|
})
|
||||||
credentials: {
|
const s3Options: S3ClientConfig = {
|
||||||
accessKeyId: accessKeyID,
|
credentials: {
|
||||||
secretAccessKey
|
accessKeyId: accessKeyID,
|
||||||
},
|
secretAccessKey
|
||||||
endpoint: endpointUrl,
|
},
|
||||||
tls: sslEnabled,
|
endpoint: endpointUrl,
|
||||||
forcePathStyle: pathStyleAccess,
|
tls: sslEnabled,
|
||||||
region,
|
forcePathStyle: pathStyleAccess,
|
||||||
requestHandler: handler
|
region,
|
||||||
}
|
requestHandler: handler
|
||||||
if (dogeMode) {
|
}
|
||||||
s3Options.credentials = {
|
if (dogeMode) {
|
||||||
accessKeyId: configMap.config.accessKeyID,
|
s3Options.credentials = {
|
||||||
secretAccessKey: configMap.config.secretAccessKey,
|
accessKeyId: configMap.config.accessKeyID,
|
||||||
sessionToken: configMap.config.sessionToken
|
secretAccessKey: configMap.config.secretAccessKey,
|
||||||
}
|
sessionToken: configMap.config.sessionToken
|
||||||
}
|
}
|
||||||
let result: any
|
}
|
||||||
try {
|
let result: any
|
||||||
fileKey = decodeURIComponent(fileKey)
|
try {
|
||||||
} catch (err: any) {}
|
fileKey = decodeURIComponent(fileKey)
|
||||||
try {
|
} catch (err: any) {}
|
||||||
const client = new S3Client(s3Options)
|
try {
|
||||||
const command = new DeleteObjectCommand({
|
const client = new S3Client(s3Options)
|
||||||
Bucket: bucketName,
|
const command = new DeleteObjectCommand({
|
||||||
Key: fileKey
|
Bucket: bucketName,
|
||||||
})
|
Key: fileKey
|
||||||
result = await client.send(command)
|
})
|
||||||
} catch (err: any) {
|
result = await client.send(command)
|
||||||
s3Options.region = 'us-east-1'
|
} catch (err: any) {
|
||||||
const client = new S3Client(s3Options)
|
s3Options.region = 'us-east-1'
|
||||||
const command = new DeleteObjectCommand({
|
const client = new S3Client(s3Options)
|
||||||
Bucket: bucketName,
|
const command = new DeleteObjectCommand({
|
||||||
Key: fileKey
|
Bucket: bucketName,
|
||||||
})
|
Key: fileKey
|
||||||
result = await client.send(command)
|
})
|
||||||
}
|
result = await client.send(command)
|
||||||
return result.$metadata.httpStatusCode === 204
|
}
|
||||||
} catch (err: any) {
|
return result.$metadata.httpStatusCode === 204
|
||||||
console.log(err)
|
} catch (err: any) {
|
||||||
return false
|
console.log(err)
|
||||||
}
|
return false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
export async function removeFileFromDogeInMain (configMap: IStringKeyMap) {
|
|
||||||
try {
|
export async function removeFileFromDogeInMain (configMap: IStringKeyMap) {
|
||||||
const {
|
try {
|
||||||
config: { bucketName, AccessKey, SecretKey }
|
const {
|
||||||
} = configMap
|
config: { bucketName, AccessKey, SecretKey }
|
||||||
const token = (await getDogeToken(AccessKey, SecretKey)) as DogecloudTokenFull
|
} = configMap
|
||||||
const bucket = token.Buckets?.find(item => item.name === bucketName || item.s3Bucket === bucketName)
|
const token = (await getDogeToken(AccessKey, SecretKey)) as DogecloudTokenFull
|
||||||
const newConfigMap = { ...configMap }
|
const bucket = token.Buckets?.find(item => item.name === bucketName || item.s3Bucket === bucketName)
|
||||||
newConfigMap.config = {
|
const newConfigMap = { ...configMap }
|
||||||
...newConfigMap.config,
|
newConfigMap.config = {
|
||||||
accessKeyID: token.Credentials?.accessKeyId,
|
...newConfigMap.config,
|
||||||
secretAccessKey: token.Credentials?.secretAccessKey,
|
accessKeyID: token.Credentials?.accessKeyId,
|
||||||
sessionToken: token.Credentials?.sessionToken,
|
secretAccessKey: token.Credentials?.secretAccessKey,
|
||||||
endpoint: bucket?.s3Endpoint,
|
sessionToken: token.Credentials?.sessionToken,
|
||||||
region: dogeRegionMap[bucket?.s3Endpoint?.split('.')[1] || 'ap-shanghai'],
|
endpoint: bucket?.s3Endpoint,
|
||||||
bucketName: bucket?.s3Bucket
|
region: dogeRegionMap[bucket?.s3Endpoint?.split('.')[1] || 'ap-shanghai'],
|
||||||
}
|
bucketName: bucket?.s3Bucket
|
||||||
return await removeFileFromS3InMain(newConfigMap, true)
|
}
|
||||||
} catch (err: any) {
|
return await removeFileFromS3InMain(newConfigMap, true)
|
||||||
console.log(err)
|
} catch (err: any) {
|
||||||
return false
|
console.log(err)
|
||||||
}
|
return false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function createHuaweiAuthorization (
|
|
||||||
bucketName: string,
|
function createHuaweiAuthorization (
|
||||||
path: string,
|
bucketName: string,
|
||||||
fileName: string,
|
path: string,
|
||||||
accessKey: string,
|
fileName: string,
|
||||||
secretKey: string,
|
accessKey: string,
|
||||||
date: string = new Date().toUTCString()
|
secretKey: string,
|
||||||
) {
|
date: string = new Date().toUTCString()
|
||||||
const strToSign = `DELETE\n\n\n${date}\n/${bucketName}${path}/${fileName}`
|
) {
|
||||||
const singature = crypto.createHmac('sha1', secretKey).update(strToSign).digest('base64')
|
const strToSign = `DELETE\n\n\n${date}\n/${bucketName}${path}/${fileName}`
|
||||||
return `OBS ${accessKey}:${singature}`
|
const singature = crypto.createHmac('sha1', secretKey).update(strToSign).digest('base64')
|
||||||
}
|
return `OBS ${accessKey}:${singature}`
|
||||||
|
}
|
||||||
export async function removeFileFromHuaweiInMain (configMap: IStringKeyMap) {
|
|
||||||
const { fileName, config } = configMap
|
export async function removeFileFromHuaweiInMain (configMap: IStringKeyMap) {
|
||||||
const { accessKeyId, accessKeySecret, bucketName, endpoint } = config
|
const { fileName, config } = configMap
|
||||||
let path = config.path || '/'
|
const { accessKeyId, accessKeySecret, bucketName, endpoint } = config
|
||||||
path = `/${path.replace(/^\/+|\/+$/, '')}`
|
let path = config.path || '/'
|
||||||
path = path === '/' ? '' : path
|
path = `/${path.replace(/^\/+|\/+$/, '')}`
|
||||||
const date = new Date().toUTCString()
|
path = path === '/' ? '' : path
|
||||||
const authorization = createHuaweiAuthorization(bucketName, path, fileName, accessKeyId, accessKeySecret, date)
|
const date = new Date().toUTCString()
|
||||||
try {
|
const authorization = createHuaweiAuthorization(bucketName, path, fileName, accessKeyId, accessKeySecret, date)
|
||||||
const res = await axios.request({
|
try {
|
||||||
url: `https://${bucketName}.${endpoint}${encodeURI(path)}/${encodeURIComponent(fileName)}`,
|
const res = await axios.request({
|
||||||
method: 'DELETE',
|
url: `https://${bucketName}.${endpoint}${encodeURI(path)}/${encodeURIComponent(fileName)}`,
|
||||||
responseType: 'json',
|
method: 'DELETE',
|
||||||
headers: {
|
responseType: 'json',
|
||||||
Host: `${bucketName}.${endpoint}`,
|
headers: {
|
||||||
Date: date,
|
Host: `${bucketName}.${endpoint}`,
|
||||||
Authorization: authorization
|
Date: date,
|
||||||
}
|
Authorization: authorization
|
||||||
})
|
}
|
||||||
return res.status === 204
|
})
|
||||||
} catch (error) {
|
return res.status === 204
|
||||||
console.log(error)
|
} catch (error) {
|
||||||
return false
|
console.log(error)
|
||||||
}
|
return false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
export async function removeFileFromSFTPInMain (config: ISftpPlistConfig, fileName: string) {
|
|
||||||
try {
|
export async function removeFileFromSFTPInMain (config: ISftpPlistConfig, fileName: string) {
|
||||||
const client = SSHClient.instance
|
try {
|
||||||
await client.connect(config)
|
const client = SSHClient.instance
|
||||||
const uploadPath = `/${config.uploadPath || ''}/`.replace(/\/+/g, '/')
|
await client.connect(config)
|
||||||
const remote = path.join(uploadPath, fileName)
|
const uploadPath = `/${config.uploadPath || ''}/`.replace(/\/+/g, '/')
|
||||||
const deleteResult = await client.deleteFileSFTP(config, remote)
|
const remote = path.join(uploadPath, fileName)
|
||||||
client.close()
|
const deleteResult = await client.deleteFileSFTP(config, remote)
|
||||||
return deleteResult
|
client.close()
|
||||||
} catch (err: any) {
|
return deleteResult
|
||||||
console.log(err)
|
} catch (err: any) {
|
||||||
return false
|
console.log(err)
|
||||||
}
|
return false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
+66
-65
@@ -1,65 +1,66 @@
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
id="app"
|
id="app"
|
||||||
:key="pageReloadCount"
|
:key="pageReloadCount"
|
||||||
>
|
>
|
||||||
<router-view />
|
<router-view />
|
||||||
<UIServiceProvider />
|
<UIServiceProvider />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { IConfig } from 'piclist'
|
import type { IConfig } from 'piclist'
|
||||||
import { onBeforeMount, onMounted } from 'vue'
|
import { onBeforeMount, onMounted } from 'vue'
|
||||||
|
|
||||||
import UIServiceProvider from '@/components/ui/UIServiceProvider.vue'
|
import UIServiceProvider from '@/components/ui/UIServiceProvider.vue'
|
||||||
import { useATagClick } from '@/hooks/useATagClick'
|
import { useATagClick } from '@/hooks/useATagClick'
|
||||||
import { useStore } from '@/hooks/useStore'
|
import { useStore } from '@/hooks/useStore'
|
||||||
import { getConfig } from '@/utils/dataSender'
|
import { getConfig } from '@/utils/dataSender'
|
||||||
import { pageReloadCount } from '@/utils/global'
|
import { pageReloadCount } from '@/utils/global'
|
||||||
|
|
||||||
import { useAppStore } from './hooks/useAppStore'
|
import { useAppStore } from './hooks/useAppStore'
|
||||||
useATagClick()
|
|
||||||
|
useATagClick()
|
||||||
const store = useStore()
|
|
||||||
const appStore = useAppStore()
|
const store = useStore()
|
||||||
|
const appStore = useAppStore()
|
||||||
onBeforeMount(async () => {
|
|
||||||
const config = await getConfig<IConfig>()
|
onBeforeMount(async () => {
|
||||||
if (config) {
|
const config = await getConfig<IConfig>()
|
||||||
store?.setDefaultPicBed(config?.picBed?.uploader || config?.picBed?.current || 'smms')
|
if (config) {
|
||||||
}
|
store?.setDefaultPicBed(config?.picBed?.uploader || config?.picBed?.current || 'smms')
|
||||||
})
|
}
|
||||||
|
})
|
||||||
onMounted(async () => {
|
|
||||||
try {
|
onMounted(async () => {
|
||||||
appStore.init()
|
try {
|
||||||
} catch (error) {
|
appStore.init()
|
||||||
console.error('Failed to load settings:', error)
|
} catch (error) {
|
||||||
}
|
console.error('Failed to load settings:', error)
|
||||||
})
|
}
|
||||||
|
})
|
||||||
</script>
|
|
||||||
|
</script>
|
||||||
<script lang="ts">
|
|
||||||
export default {
|
<script lang="ts">
|
||||||
name: 'PicGoApp'
|
export default {
|
||||||
}
|
name: 'PicGoApp'
|
||||||
</script>
|
}
|
||||||
|
</script>
|
||||||
<style lang="stylus">
|
|
||||||
body,
|
<style lang="stylus">
|
||||||
html
|
body,
|
||||||
padding 0
|
html
|
||||||
margin 0
|
padding 0
|
||||||
height 100%
|
margin 0
|
||||||
font-family "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif
|
height 100%
|
||||||
#app
|
font-family "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif
|
||||||
height 100%
|
#app
|
||||||
user-select none
|
height 100%
|
||||||
overflow hidden
|
user-select none
|
||||||
.el-button-group
|
overflow hidden
|
||||||
width 100%
|
.el-button-group
|
||||||
.el-button
|
width 100%
|
||||||
width 50%
|
.el-button
|
||||||
</style>
|
width 50%
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,23 +1,24 @@
|
|||||||
import { onMounted, onUnmounted } from 'vue'
|
import { onMounted, onUnmounted } from 'vue'
|
||||||
|
|
||||||
import { IRPCActionType } from '@/utils/enum'
|
import { IRPCActionType } from '@/utils/enum'
|
||||||
|
|
||||||
export function useATagClick () {
|
export function useATagClick () {
|
||||||
const handleATagClick = (e: MouseEvent) => {
|
const handleATagClick = (e: MouseEvent) => {
|
||||||
if (e.target instanceof HTMLAnchorElement) {
|
if (e.target instanceof HTMLAnchorElement) {
|
||||||
if (e.target.href) {
|
if (e.target.href) {
|
||||||
// avoid opening localhost development URLs in external browser
|
if (!e.target.href.startsWith('http://localhost:3000')) {
|
||||||
if (!e.target.href.startsWith('http://localhost:3000')) {
|
e.preventDefault()
|
||||||
e.preventDefault()
|
window.electron.sendRPC(IRPCActionType.OPEN_URL, e.target.href)
|
||||||
window.electron.sendRPC(IRPCActionType.OPEN_URL, e.target.href)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
document.addEventListener('click', handleATagClick)
|
document.addEventListener('click', handleATagClick)
|
||||||
})
|
})
|
||||||
onUnmounted(() => {
|
|
||||||
document.removeEventListener('click', handleATagClick)
|
onUnmounted(() => {
|
||||||
})
|
document.removeEventListener('click', handleATagClick)
|
||||||
}
|
})
|
||||||
|
}
|
||||||
|
|||||||
+915
-915
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+55
-59
@@ -1,59 +1,55 @@
|
|||||||
import 'video.js/dist/video-js.css'
|
import 'video.js/dist/video-js.css'
|
||||||
import 'highlight.js/styles/stackoverflow-light.css'
|
import 'highlight.js/styles/stackoverflow-light.css'
|
||||||
import 'highlight.js/lib/common'
|
import 'highlight.js/lib/common'
|
||||||
|
|
||||||
import hljsVuePlugin from '@highlightjs/vue-plugin'
|
import hljsVuePlugin from '@highlightjs/vue-plugin'
|
||||||
import VueVideoPlayer from '@videojs-player/vue'
|
import VueVideoPlayer from '@videojs-player/vue'
|
||||||
import { createPinia } from 'pinia'
|
import { createPinia } from 'pinia'
|
||||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import { createI18n } from 'vue-i18n'
|
import { createI18n } from 'vue-i18n'
|
||||||
import VueLazyLoad from 'vue3-lazyload'
|
import VueLazyLoad from 'vue3-lazyload'
|
||||||
|
|
||||||
import App from '@/App.vue'
|
import App from '@/App.vue'
|
||||||
import en from '@/i18n/locales/en.json'
|
import en from '@/i18n/locales/en.json'
|
||||||
import zhCN from '@/i18n/locales/zh-CN.json'
|
import zhCN from '@/i18n/locales/zh-CN.json'
|
||||||
import zhTW from '@/i18n/locales/zh-TW.json'
|
import zhTW from '@/i18n/locales/zh-TW.json'
|
||||||
import router from '@/router'
|
import router from '@/router'
|
||||||
import { store } from '@/store'
|
import { store } from '@/store'
|
||||||
import db from '@/utils/db'
|
import db from '@/utils/db'
|
||||||
|
|
||||||
type MessageSchema = typeof zhCN
|
type MessageSchema = typeof zhCN
|
||||||
|
|
||||||
window.electron.setVisualZoomLevelLimits(1, 1)
|
window.electron.setVisualZoomLevelLimits(1, 1)
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
|
||||||
app.config.globalProperties.$$db = db
|
app.config.globalProperties.$$db = db
|
||||||
app.config.globalProperties.triggerRPC = window.electron.triggerRPC
|
app.config.globalProperties.triggerRPC = window.electron.triggerRPC
|
||||||
app.config.globalProperties.sendRPC = window.electron.sendRPC
|
app.config.globalProperties.sendRPC = window.electron.sendRPC
|
||||||
app.config.globalProperties.sendToMain = window.electron.sendToMain
|
app.config.globalProperties.sendToMain = window.electron.sendToMain
|
||||||
|
|
||||||
const i18n = createI18n<[MessageSchema], 'en' | 'zh-CN' | 'zh-TW'>({
|
const i18n = createI18n<[MessageSchema], 'en' | 'zh-CN' | 'zh-TW'>({
|
||||||
legacy: false,
|
legacy: false,
|
||||||
locale: localStorage.getItem('currentLanguage') || 'zh-CN',
|
locale: localStorage.getItem('currentLanguage') || 'zh-CN',
|
||||||
fallbackLocale: 'zh-CN',
|
fallbackLocale: 'zh-CN',
|
||||||
messages: {
|
messages: {
|
||||||
en,
|
en,
|
||||||
'zh-CN': zhCN,
|
'zh-CN': zhCN,
|
||||||
'zh-TW': zhTW
|
'zh-TW': zhTW
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const pinia = createPinia()
|
const pinia = createPinia()
|
||||||
pinia.use(piniaPluginPersistedstate)
|
pinia.use(piniaPluginPersistedstate)
|
||||||
app.use(VueLazyLoad, {
|
app.use(VueLazyLoad, {
|
||||||
loading: '/loading.jpg',
|
loading: '/loading.jpg',
|
||||||
error: '/unknown-file-type.svg',
|
error: '/unknown-file-type.svg',
|
||||||
delay: 500
|
delay: 500
|
||||||
})
|
})
|
||||||
app.use(i18n)
|
app.use(i18n)
|
||||||
app.use(router)
|
app.use(router)
|
||||||
app.use(store)
|
app.use(store)
|
||||||
app.use(pinia)
|
app.use(pinia)
|
||||||
app.use(hljsVuePlugin)
|
app.use(hljsVuePlugin)
|
||||||
app.use(VueVideoPlayer)
|
app.use(VueVideoPlayer)
|
||||||
app.mount('#app')
|
app.mount('#app')
|
||||||
|
|
||||||
export {
|
|
||||||
i18n
|
|
||||||
}
|
|
||||||
|
|||||||
+445
-444
@@ -1,444 +1,445 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="upload-container">
|
<div class="upload-container">
|
||||||
<!-- Header Card -->
|
<!-- Header Card -->
|
||||||
<div class="upload-card header-card">
|
<div class="upload-card header-card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<div class="provider-section">
|
<div class="provider-section">
|
||||||
<button
|
<button
|
||||||
class="provider-button"
|
class="provider-button"
|
||||||
:title="t('pages.upload.uploadViewHint')"
|
:title="t('pages.upload.uploadViewHint')"
|
||||||
@click="handlePicBedNameClick(picBedName, picBedConfigName)"
|
@click="handlePicBedNameClick(picBedName, picBedConfigName)"
|
||||||
>
|
>
|
||||||
<div class="provider-info">
|
<div class="provider-info">
|
||||||
<span class="provider-name">{{ picBedName }}</span>
|
<span class="provider-name">{{ picBedName }}</span>
|
||||||
<span class="provider-config">{{ picBedConfigName || 'Default' }}</span>
|
<span class="provider-config">{{ picBedConfigName || 'Default' }}</span>
|
||||||
</div>
|
</div>
|
||||||
<ChevronDownIcon
|
<ChevronDownIcon
|
||||||
:size="16"
|
:size="16"
|
||||||
class="provider-arrow"
|
class="provider-arrow"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
<button
|
<button
|
||||||
class="action-button secondary"
|
class="action-button secondary"
|
||||||
@click="handleImageProcess"
|
@click="handleImageProcess"
|
||||||
>
|
>
|
||||||
<Settings :size="16" />
|
<Settings :size="16" />
|
||||||
<span>{{ t('pages.upload.imageProcessName') }}</span>
|
<span>{{ t('pages.upload.imageProcessName') }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="action-button"
|
class="action-button"
|
||||||
@click="handleChangePicBed"
|
@click="handleChangePicBed"
|
||||||
>
|
>
|
||||||
<DatabaseIcon :size="16" />
|
<DatabaseIcon :size="16" />
|
||||||
<span>{{ t('pages.upload.changePicBed') }}</span>
|
<span>{{ t('pages.upload.changePicBed') }}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Main Upload Card -->
|
<!-- Main Upload Card -->
|
||||||
<div class="upload-card main-card">
|
<div class="upload-card main-card">
|
||||||
<div
|
<div
|
||||||
class="upload-zone"
|
id="upload-area"
|
||||||
:class="{ 'drag-active': dragover }"
|
class="upload-zone"
|
||||||
@drop.prevent="onDrop"
|
:class="{ 'drag-active': dragover }"
|
||||||
@dragover.prevent="dragover = true"
|
@drop.prevent="onDrop"
|
||||||
@dragleave.prevent="dragover = false"
|
@dragover.prevent="dragover = true"
|
||||||
@click="openUplodWindow"
|
@dragleave.prevent="dragover = false"
|
||||||
>
|
@click="openUplodWindow"
|
||||||
<div class="upload-content">
|
>
|
||||||
<div class="upload-icon">
|
<div class="upload-content">
|
||||||
<UploadCloudIcon :size="48" />
|
<div class="upload-icon">
|
||||||
</div>
|
<UploadCloudIcon :size="48" />
|
||||||
<div class="upload-text">
|
</div>
|
||||||
<h3 class="upload-title">
|
<div class="upload-text">
|
||||||
{{ t('pages.upload.dragFileToHere') }}
|
<h3 class="upload-title">
|
||||||
</h3>
|
{{ t('pages.upload.dragFileToHere') }}
|
||||||
<p class="upload-subtitle">
|
</h3>
|
||||||
{{ t('pages.upload.clickToUpload') }}
|
<p class="upload-subtitle">
|
||||||
</p>
|
{{ t('pages.upload.clickToUpload') }}
|
||||||
<div class="upload-formats">
|
</p>
|
||||||
<span class="format-label">{{ t('pages.upload.uploadHint') }}</span>
|
<div class="upload-formats">
|
||||||
</div>
|
<span class="format-label">{{ t('pages.upload.uploadHint') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<input
|
</div>
|
||||||
id="file-uploader"
|
<input
|
||||||
ref="fileInput"
|
id="file-uploader"
|
||||||
type="file"
|
ref="fileInput"
|
||||||
multiple
|
type="file"
|
||||||
style="display: none"
|
multiple
|
||||||
@change="onChange"
|
style="display: none"
|
||||||
>
|
@change="onChange"
|
||||||
</div>
|
>
|
||||||
|
</div>
|
||||||
<!-- Progress Bar -->
|
|
||||||
<transition name="progress">
|
<!-- Progress Bar -->
|
||||||
<div
|
<transition name="progress">
|
||||||
v-if="showProgress"
|
<div
|
||||||
class="progress-container"
|
v-if="showProgress"
|
||||||
>
|
class="progress-container"
|
||||||
<div class="progress-bar">
|
>
|
||||||
<div
|
<div class="progress-bar">
|
||||||
class="progress-fill"
|
<div
|
||||||
:class="{ 'progress-error': showError }"
|
class="progress-fill"
|
||||||
:style="{ width: `${progress}%` }"
|
:class="{ 'progress-error': showError }"
|
||||||
/>
|
:style="{ width: `${progress}%` }"
|
||||||
</div>
|
/>
|
||||||
<span class="progress-text">
|
</div>
|
||||||
{{ showError ? t('pages.upload.uploadFailed') : `${progress}%` }}
|
<span class="progress-text">
|
||||||
</span>
|
{{ showError ? t('pages.upload.uploadFailed') : `${progress}%` }}
|
||||||
</div>
|
</span>
|
||||||
</transition>
|
</div>
|
||||||
</div>
|
</transition>
|
||||||
|
</div>
|
||||||
<!-- Quick Actions Card -->
|
|
||||||
<div class="upload-card actions-card">
|
<!-- Quick Actions Card -->
|
||||||
<div class="card-header">
|
<div class="upload-card actions-card">
|
||||||
<h4 class="card-title">
|
<div class="card-header">
|
||||||
{{ t('pages.upload.quickUpload') }}
|
<h4 class="card-title">
|
||||||
</h4>
|
{{ t('pages.upload.quickUpload') }}
|
||||||
</div>
|
</h4>
|
||||||
<div class="quick-actions">
|
</div>
|
||||||
<button
|
<div class="quick-actions">
|
||||||
class="quick-action-button"
|
<button
|
||||||
@click="uploadClipboardFiles"
|
class="quick-action-button"
|
||||||
>
|
@click="uploadClipboardFiles"
|
||||||
<ClipboardIcon :size="20" />
|
>
|
||||||
<span>{{ t('pages.upload.clipboardPicture') }}</span>
|
<ClipboardIcon :size="20" />
|
||||||
</button>
|
<span>{{ t('pages.upload.clipboardPicture') }}</span>
|
||||||
<button
|
</button>
|
||||||
class="quick-action-button"
|
<button
|
||||||
@click="uploadURLFiles"
|
class="quick-action-button"
|
||||||
>
|
@click="uploadURLFiles"
|
||||||
<LinkIcon :size="20" />
|
>
|
||||||
<span>{{ t('pages.upload.urlUpload') }}</span>
|
<LinkIcon :size="20" />
|
||||||
</button>
|
<span>{{ t('pages.upload.urlUpload') }}</span>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<!-- Settings Card -->
|
|
||||||
<div class="upload-card settings-card">
|
<!-- Settings Card -->
|
||||||
<div class="card-header">
|
<div class="upload-card settings-card">
|
||||||
<h4 class="card-title">
|
<div class="card-header">
|
||||||
{{ t('pages.upload.linkFormat') }}
|
<h4 class="card-title">
|
||||||
</h4>
|
{{ t('pages.upload.linkFormat') }}
|
||||||
</div>
|
</h4>
|
||||||
<div class="settings-content">
|
</div>
|
||||||
<!-- Format Options -->
|
<div class="settings-content">
|
||||||
<div class="setting-group">
|
<!-- Format Options -->
|
||||||
<label class="setting-label">{{ t('pages.upload.outputFormat') }}</label>
|
<div class="setting-group">
|
||||||
<div class="format-buttons">
|
<label class="setting-label">{{ t('pages.upload.outputFormat') }}</label>
|
||||||
<button
|
<div class="format-buttons">
|
||||||
v-for="(format, key) in pasteFormatList"
|
<button
|
||||||
:key="key"
|
v-for="(format, key) in pasteFormatList"
|
||||||
class="format-button"
|
:key="key"
|
||||||
:class="{ active: pasteStyle === key }"
|
class="format-button"
|
||||||
:title="format"
|
:class="{ active: pasteStyle === key }"
|
||||||
@click="updatePasteStyle(key)"
|
:title="format"
|
||||||
>
|
@click="updatePasteStyle(key)"
|
||||||
{{ key }}
|
>
|
||||||
</button>
|
{{ key }}
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<!-- URL Length Options -->
|
|
||||||
<div class="setting-group">
|
<!-- URL Length Options -->
|
||||||
<label class="setting-label">{{ t('pages.upload.urlType.title') }}</label>
|
<div class="setting-group">
|
||||||
<div class="url-toggle">
|
<label class="setting-label">{{ t('pages.upload.urlType.title') }}</label>
|
||||||
<button
|
<div class="url-toggle">
|
||||||
class="toggle-button"
|
<button
|
||||||
:class="{ active: !useShortUrl }"
|
class="toggle-button"
|
||||||
@click="updateUrlType(false)"
|
:class="{ active: !useShortUrl }"
|
||||||
>
|
@click="updateUrlType(false)"
|
||||||
<span>{{ t('pages.upload.urlType.normal') }}</span>
|
>
|
||||||
</button>
|
<span>{{ t('pages.upload.urlType.normal') }}</span>
|
||||||
<button
|
</button>
|
||||||
class="toggle-button"
|
<button
|
||||||
:class="{ active: useShortUrl }"
|
class="toggle-button"
|
||||||
@click="updateUrlType(true)"
|
:class="{ active: useShortUrl }"
|
||||||
>
|
@click="updateUrlType(true)"
|
||||||
<span>{{ t('pages.upload.urlType.short') }}</span>
|
>
|
||||||
</button>
|
<span>{{ t('pages.upload.urlType.short') }}</span>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<!-- Image Process Dialog -->
|
|
||||||
<transition name="modal">
|
<!-- Image Process Dialog -->
|
||||||
<div
|
<transition name="modal">
|
||||||
v-if="imageProcessDialogVisible"
|
<div
|
||||||
class="modal-overlay"
|
v-if="imageProcessDialogVisible"
|
||||||
@click="imageProcessDialogVisible = false"
|
class="modal-overlay"
|
||||||
>
|
@click="imageProcessDialogVisible = false"
|
||||||
<div
|
>
|
||||||
class="modal-container"
|
<div
|
||||||
@click.stop
|
class="modal-container"
|
||||||
>
|
@click.stop
|
||||||
<div class="modal-header">
|
>
|
||||||
<h3 class="modal-title">
|
<div class="modal-header">
|
||||||
{{ t('pages.imageProcess.title') }}
|
<h3 class="modal-title">
|
||||||
</h3>
|
{{ t('pages.imageProcess.title') }}
|
||||||
<button
|
</h3>
|
||||||
class="modal-close"
|
<button
|
||||||
@click="imageProcessDialogVisible = false"
|
class="modal-close"
|
||||||
>
|
@click="imageProcessDialogVisible = false"
|
||||||
<XIcon :size="20" />
|
>
|
||||||
</button>
|
<XIcon :size="20" />
|
||||||
</div>
|
</button>
|
||||||
<div class="modal-content">
|
</div>
|
||||||
<ImageProcessSetting v-model="imageProcessDialogVisible" />
|
<div class="modal-content">
|
||||||
</div>
|
<ImageProcessSetting v-model="imageProcessDialogVisible" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</div>
|
||||||
</div>
|
</transition>
|
||||||
</template>
|
</div>
|
||||||
|
</template>
|
||||||
<script lang="ts" setup>
|
|
||||||
import type { IpcRendererEvent } from 'electron'
|
<script lang="ts" setup>
|
||||||
import { ChevronDownIcon, ClipboardIcon, DatabaseIcon, LinkIcon, Settings, UploadCloudIcon, XIcon } from 'lucide-vue-next'
|
import type { IpcRendererEvent } from 'electron'
|
||||||
import { onBeforeMount, onBeforeUnmount, ref, watch } from 'vue'
|
import { ChevronDownIcon, ClipboardIcon, DatabaseIcon, LinkIcon, Settings, UploadCloudIcon, XIcon } from 'lucide-vue-next'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { onBeforeMount, onBeforeUnmount, ref, watch } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
import ImageProcessSetting from '@/components/ImageProcessSetting.vue'
|
|
||||||
import useMessage from '@/hooks/useMessage'
|
import ImageProcessSetting from '@/components/ImageProcessSetting.vue'
|
||||||
import { PICBEDS_PAGE } from '@/router/config'
|
import useMessage from '@/hooks/useMessage'
|
||||||
import $bus from '@/utils/bus'
|
import { PICBEDS_PAGE } from '@/router/config'
|
||||||
import { isUrl } from '@/utils/common'
|
import $bus from '@/utils/bus'
|
||||||
import { configPaths } from '@/utils/configPaths'
|
import { isUrl } from '@/utils/common'
|
||||||
import { SHOW_INPUT_BOX, SHOW_INPUT_BOX_RESPONSE } from '@/utils/constant'
|
import { configPaths } from '@/utils/configPaths'
|
||||||
import { getConfig, saveConfig } from '@/utils/dataSender'
|
import { SHOW_INPUT_BOX, SHOW_INPUT_BOX_RESPONSE } from '@/utils/constant'
|
||||||
import { useDragEventListeners } from '@/utils/drag'
|
import { getConfig, saveConfig } from '@/utils/dataSender'
|
||||||
import { IPasteStyle, IRPCActionType } from '@/utils/enum'
|
import { useDragEventListeners } from '@/utils/drag'
|
||||||
import { picBedGlobal, updatePicBedGlobal } from '@/utils/global'
|
import { IPasteStyle, IRPCActionType } from '@/utils/enum'
|
||||||
import type { IFileWithPath, IUploaderConfigItem } from '#/types/types'
|
import { picBedGlobal, updatePicBedGlobal } from '@/utils/global'
|
||||||
|
import type { IFileWithPath, IUploaderConfigItem } from '#/types/types'
|
||||||
useDragEventListeners()
|
|
||||||
const $router = useRouter()
|
useDragEventListeners()
|
||||||
const { t } = useI18n()
|
const $router = useRouter()
|
||||||
const message = useMessage()
|
const { t } = useI18n()
|
||||||
|
const message = useMessage()
|
||||||
const imageProcessDialogVisible = ref(false)
|
|
||||||
const useShortUrl = ref(false)
|
const imageProcessDialogVisible = ref(false)
|
||||||
const dragover = ref(false)
|
const useShortUrl = ref(false)
|
||||||
const progress = ref(0)
|
const dragover = ref(false)
|
||||||
const showProgress = ref(false)
|
const progress = ref(0)
|
||||||
const showError = ref(false)
|
const showProgress = ref(false)
|
||||||
const pasteStyle = ref('')
|
const showError = ref(false)
|
||||||
const picBedName = ref('')
|
const pasteStyle = ref('')
|
||||||
const picBedConfigName = ref('')
|
const picBedName = ref('')
|
||||||
const fileInput = ref<HTMLInputElement>()
|
const picBedConfigName = ref('')
|
||||||
|
const fileInput = ref<HTMLInputElement>()
|
||||||
const pasteFormatList = ref<Record<string, string>>({
|
|
||||||
[IPasteStyle.MARKDOWN]: '',
|
const pasteFormatList = ref<Record<string, string>>({
|
||||||
[IPasteStyle.HTML]: '<img src="url"/>',
|
[IPasteStyle.MARKDOWN]: '',
|
||||||
[IPasteStyle.URL]: 'http://test.com/test.png',
|
[IPasteStyle.HTML]: '<img src="url"/>',
|
||||||
[IPasteStyle.UBB]: '[img]url[/img]',
|
[IPasteStyle.URL]: 'http://test.com/test.png',
|
||||||
[IPasteStyle.CUSTOM]: ''
|
[IPasteStyle.UBB]: '[img]url[/img]',
|
||||||
})
|
[IPasteStyle.CUSTOM]: ''
|
||||||
|
})
|
||||||
watch(picBedGlobal, () => {
|
|
||||||
getDefaultPicBed()
|
watch(picBedGlobal, () => {
|
||||||
})
|
getDefaultPicBed()
|
||||||
|
})
|
||||||
const uploadProgressHandler = (_event: IpcRendererEvent, _progress: number) => {
|
|
||||||
if (_progress !== -1) {
|
const uploadProgressHandler = (_event: IpcRendererEvent, _progress: number) => {
|
||||||
showProgress.value = true
|
if (_progress !== -1) {
|
||||||
progress.value = _progress
|
showProgress.value = true
|
||||||
} else {
|
progress.value = _progress
|
||||||
progress.value = 100
|
} else {
|
||||||
showError.value = true
|
progress.value = 100
|
||||||
}
|
showError.value = true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
const syncPicBedHandler = () => {
|
|
||||||
getDefaultPicBed()
|
const syncPicBedHandler = () => {
|
||||||
}
|
getDefaultPicBed()
|
||||||
|
}
|
||||||
onBeforeMount(() => {
|
|
||||||
updatePicBedGlobal()
|
onBeforeMount(() => {
|
||||||
window.electron.ipcRendererOn('uploadProgress', uploadProgressHandler)
|
updatePicBedGlobal()
|
||||||
getUseShortUrl()
|
window.electron.ipcRendererOn('uploadProgress', uploadProgressHandler)
|
||||||
getPasteStyle()
|
getUseShortUrl()
|
||||||
getDefaultPicBed()
|
getPasteStyle()
|
||||||
window.electron.ipcRendererOn('syncPicBed', syncPicBedHandler)
|
getDefaultPicBed()
|
||||||
$bus.on(SHOW_INPUT_BOX_RESPONSE, handleInputBoxValue)
|
window.electron.ipcRendererOn('syncPicBed', syncPicBedHandler)
|
||||||
})
|
$bus.on(SHOW_INPUT_BOX_RESPONSE, handleInputBoxValue)
|
||||||
|
})
|
||||||
const handleImageProcess = () => {
|
|
||||||
imageProcessDialogVisible.value = true
|
const handleImageProcess = () => {
|
||||||
}
|
imageProcessDialogVisible.value = true
|
||||||
|
}
|
||||||
watch(progress, onProgressChange)
|
|
||||||
|
watch(progress, onProgressChange)
|
||||||
function onProgressChange (val: number) {
|
|
||||||
if (val === 100) {
|
function onProgressChange (val: number) {
|
||||||
setTimeout(() => {
|
if (val === 100) {
|
||||||
showProgress.value = false
|
setTimeout(() => {
|
||||||
showError.value = false
|
showProgress.value = false
|
||||||
}, 1000)
|
showError.value = false
|
||||||
setTimeout(() => {
|
}, 1000)
|
||||||
progress.value = 0
|
setTimeout(() => {
|
||||||
}, 1200)
|
progress.value = 0
|
||||||
}
|
}, 1200)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
async function handlePicBedNameClick (_picBedName: string, picBedConfigName: string | undefined) {
|
|
||||||
const formatedpicBedConfigName = picBedConfigName || 'Default'
|
async function handlePicBedNameClick (_picBedName: string, picBedConfigName: string | undefined) {
|
||||||
const currentPicBed = await getConfig<string>(configPaths.picBed.current)
|
const formatedpicBedConfigName = picBedConfigName || 'Default'
|
||||||
const currentPicBedConfig = ((await getConfig<any[]>(`uploader.${currentPicBed}`)) as any) || {}
|
const currentPicBed = await getConfig<string>(configPaths.picBed.current)
|
||||||
const configList = await window.electron.triggerRPC<IUploaderConfigItem>(IRPCActionType.PICBED_GET_CONFIG_LIST, currentPicBed)
|
const currentPicBedConfig = ((await getConfig<any[]>(`uploader.${currentPicBed}`)) as any) || {}
|
||||||
const currentConfigList = configList?.configList ?? []
|
const configList = await window.electron.triggerRPC<IUploaderConfigItem>(IRPCActionType.PICBED_GET_CONFIG_LIST, currentPicBed)
|
||||||
const config = currentConfigList.find((item: any) => item._configName === formatedpicBedConfigName)
|
const currentConfigList = configList?.configList ?? []
|
||||||
$router.push({
|
const config = currentConfigList.find((item: any) => item._configName === formatedpicBedConfigName)
|
||||||
name: PICBEDS_PAGE,
|
$router.push({
|
||||||
params: {
|
name: PICBEDS_PAGE,
|
||||||
type: currentPicBed,
|
params: {
|
||||||
configId: config?._id || ''
|
type: currentPicBed,
|
||||||
},
|
configId: config?._id || ''
|
||||||
query: {
|
},
|
||||||
defaultConfigId: currentPicBedConfig.defaultId || ''
|
query: {
|
||||||
}
|
defaultConfigId: currentPicBedConfig.defaultId || ''
|
||||||
})
|
}
|
||||||
}
|
})
|
||||||
|
}
|
||||||
onBeforeUnmount(() => {
|
|
||||||
$bus.off(SHOW_INPUT_BOX_RESPONSE)
|
onBeforeUnmount(() => {
|
||||||
window.electron.ipcRendererRemoveListener('uploadProgress', uploadProgressHandler)
|
$bus.off(SHOW_INPUT_BOX_RESPONSE)
|
||||||
window.electron.ipcRendererRemoveListener('syncPicBed', syncPicBedHandler)
|
window.electron.ipcRendererRemoveListener('uploadProgress', uploadProgressHandler)
|
||||||
})
|
window.electron.ipcRendererRemoveListener('syncPicBed', syncPicBedHandler)
|
||||||
|
})
|
||||||
function onDrop (e: DragEvent) {
|
|
||||||
dragover.value = false
|
function onDrop (e: DragEvent) {
|
||||||
|
dragover.value = false
|
||||||
// send files first
|
|
||||||
if (e.dataTransfer?.files?.length) {
|
// send files first
|
||||||
ipcSendFiles(e.dataTransfer.files)
|
if (e.dataTransfer?.files?.length) {
|
||||||
} else if (e.dataTransfer?.items) {
|
ipcSendFiles(e.dataTransfer.files)
|
||||||
const items = e.dataTransfer.items
|
} else if (e.dataTransfer?.items) {
|
||||||
if (items.length === 2 && items[0].type === 'text/uri-list') {
|
const items = e.dataTransfer.items
|
||||||
handleURLDrag(items, e.dataTransfer)
|
if (items.length === 2 && items[0].type === 'text/uri-list') {
|
||||||
} else if (items[0].type === 'text/plain') {
|
handleURLDrag(items, e.dataTransfer)
|
||||||
const str = e.dataTransfer.getData(items[0].type)
|
} else if (items[0].type === 'text/plain') {
|
||||||
if (isUrl(str)) {
|
const str = e.dataTransfer.getData(items[0].type)
|
||||||
window.electron.sendRPC(IRPCActionType.UPLOAD_CHOOSED_FILES, [{ path: str }])
|
if (isUrl(str)) {
|
||||||
} else {
|
window.electron.sendRPC(IRPCActionType.UPLOAD_CHOOSED_FILES, [{ path: str }])
|
||||||
message.error(t('pages.upload.dragValidPictureOrUrl'))
|
} else {
|
||||||
}
|
message.error(t('pages.upload.dragValidPictureOrUrl'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function handleURLDrag (items: DataTransferItemList, dataTransfer: DataTransfer) {
|
|
||||||
// text/html
|
function handleURLDrag (items: DataTransferItemList, dataTransfer: DataTransfer) {
|
||||||
// Use this data to get a more precise URL
|
// text/html
|
||||||
const urlString = dataTransfer.getData(items[1].type)
|
// Use this data to get a more precise URL
|
||||||
const urlMatch = urlString.match(/<img.*src="(.*?)"/)
|
const urlString = dataTransfer.getData(items[1].type)
|
||||||
if (urlMatch) {
|
const urlMatch = urlString.match(/<img.*src="(.*?)"/)
|
||||||
window.electron.sendRPC(IRPCActionType.UPLOAD_CHOOSED_FILES, [
|
if (urlMatch) {
|
||||||
{
|
window.electron.sendRPC(IRPCActionType.UPLOAD_CHOOSED_FILES, [
|
||||||
path: urlMatch[1]
|
{
|
||||||
}
|
path: urlMatch[1]
|
||||||
])
|
}
|
||||||
} else {
|
])
|
||||||
message.error(t('pages.upload.dragValidPictureOrUrl'))
|
} else {
|
||||||
}
|
message.error(t('pages.upload.dragValidPictureOrUrl'))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function openUplodWindow () {
|
|
||||||
fileInput.value?.click()
|
function openUplodWindow () {
|
||||||
}
|
fileInput.value?.click()
|
||||||
|
}
|
||||||
function onChange (e: any) {
|
|
||||||
ipcSendFiles(e.target.files)
|
function onChange (e: any) {
|
||||||
;(fileInput.value as HTMLInputElement).value = ''
|
ipcSendFiles(e.target.files)
|
||||||
}
|
;(fileInput.value as HTMLInputElement).value = ''
|
||||||
|
}
|
||||||
function ipcSendFiles (files: FileList) {
|
|
||||||
const sendFiles: IFileWithPath[] = []
|
function ipcSendFiles (files: FileList) {
|
||||||
Array.from(files).forEach(item => {
|
const sendFiles: IFileWithPath[] = []
|
||||||
const obj = {
|
Array.from(files).forEach(item => {
|
||||||
name: item.name,
|
const obj = {
|
||||||
path: window.electron.showFilePath(item)
|
name: item.name,
|
||||||
}
|
path: window.electron.showFilePath(item)
|
||||||
sendFiles.push(obj)
|
}
|
||||||
})
|
sendFiles.push(obj)
|
||||||
window.electron.sendRPC(IRPCActionType.UPLOAD_CHOOSED_FILES, sendFiles)
|
})
|
||||||
}
|
window.electron.sendRPC(IRPCActionType.UPLOAD_CHOOSED_FILES, sendFiles)
|
||||||
|
}
|
||||||
async function getPasteStyle () {
|
|
||||||
pasteStyle.value = (await getConfig(configPaths.settings.pasteStyle)) || IPasteStyle.MARKDOWN
|
async function getPasteStyle () {
|
||||||
pasteFormatList.value.Custom = (await getConfig(configPaths.settings.customLink)) || ''
|
pasteStyle.value = (await getConfig(configPaths.settings.pasteStyle)) || IPasteStyle.MARKDOWN
|
||||||
}
|
pasteFormatList.value.Custom = (await getConfig(configPaths.settings.customLink)) || ''
|
||||||
|
}
|
||||||
async function getUseShortUrl () {
|
|
||||||
useShortUrl.value = (await getConfig(configPaths.settings.useShortUrl)) || false
|
async function getUseShortUrl () {
|
||||||
}
|
useShortUrl.value = (await getConfig(configPaths.settings.useShortUrl)) || false
|
||||||
|
}
|
||||||
function updatePasteStyle (style: string) {
|
|
||||||
pasteStyle.value = style
|
function updatePasteStyle (style: string) {
|
||||||
saveConfig({
|
pasteStyle.value = style
|
||||||
[configPaths.settings.pasteStyle]: style || IPasteStyle.MARKDOWN
|
saveConfig({
|
||||||
})
|
[configPaths.settings.pasteStyle]: style || IPasteStyle.MARKDOWN
|
||||||
}
|
})
|
||||||
|
}
|
||||||
function updateUrlType (shortUrl: boolean) {
|
|
||||||
useShortUrl.value = shortUrl
|
function updateUrlType (shortUrl: boolean) {
|
||||||
saveConfig({
|
useShortUrl.value = shortUrl
|
||||||
[configPaths.settings.useShortUrl]: shortUrl
|
saveConfig({
|
||||||
})
|
[configPaths.settings.useShortUrl]: shortUrl
|
||||||
}
|
})
|
||||||
|
}
|
||||||
function uploadClipboardFiles () {
|
|
||||||
window.electron.sendRPC(IRPCActionType.UPLOAD_CLIPBOARD_FILES_FROM_UPLOAD_PAGE)
|
function uploadClipboardFiles () {
|
||||||
}
|
window.electron.sendRPC(IRPCActionType.UPLOAD_CLIPBOARD_FILES_FROM_UPLOAD_PAGE)
|
||||||
|
}
|
||||||
async function uploadURLFiles () {
|
|
||||||
const str = await navigator.clipboard.readText()
|
async function uploadURLFiles () {
|
||||||
$bus.emit(SHOW_INPUT_BOX, {
|
const str = await navigator.clipboard.readText()
|
||||||
value: isUrl(str) ? str : '',
|
$bus.emit(SHOW_INPUT_BOX, {
|
||||||
title: t('pages.upload.inputUrlTip'),
|
value: isUrl(str) ? str : '',
|
||||||
placeholder: t('pages.upload.httpPrefixTip')
|
title: t('pages.upload.inputUrlTip'),
|
||||||
})
|
placeholder: t('pages.upload.httpPrefixTip')
|
||||||
}
|
})
|
||||||
|
}
|
||||||
function handleInputBoxValue (val: string) {
|
|
||||||
if (val === '') return
|
function handleInputBoxValue (val: string) {
|
||||||
if (isUrl(val)) {
|
if (val === '') return
|
||||||
window.electron.sendRPC(IRPCActionType.UPLOAD_CHOOSED_FILES, [
|
if (isUrl(val)) {
|
||||||
{
|
window.electron.sendRPC(IRPCActionType.UPLOAD_CHOOSED_FILES, [
|
||||||
path: val
|
{
|
||||||
}
|
path: val
|
||||||
])
|
}
|
||||||
} else {
|
])
|
||||||
message.error(t('pages.upload.inputValidUrl'))
|
} else {
|
||||||
}
|
message.error(t('pages.upload.inputValidUrl'))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
async function getDefaultPicBed () {
|
|
||||||
const currentPicBed = await getConfig<string>(configPaths.picBed.current)
|
async function getDefaultPicBed () {
|
||||||
picBedGlobal.value.forEach(item => {
|
const currentPicBed = await getConfig<string>(configPaths.picBed.current)
|
||||||
if (item.type === currentPicBed) {
|
picBedGlobal.value.forEach(item => {
|
||||||
picBedName.value = item.name
|
if (item.type === currentPicBed) {
|
||||||
}
|
picBedName.value = item.name
|
||||||
})
|
}
|
||||||
picBedConfigName.value = (await getConfig<string>(`picBed.${currentPicBed}._configName`)) || ''
|
})
|
||||||
}
|
picBedConfigName.value = (await getConfig<string>(`picBed.${currentPicBed}._configName`)) || ''
|
||||||
|
}
|
||||||
async function handleChangePicBed () {
|
|
||||||
window.electron.sendRPC(IRPCActionType.SHOW_UPLOAD_PAGE_MENU)
|
async function handleChangePicBed () {
|
||||||
}
|
window.electron.sendRPC(IRPCActionType.SHOW_UPLOAD_PAGE_MENU)
|
||||||
</script>
|
}
|
||||||
|
</script>
|
||||||
<script lang="ts">
|
|
||||||
export default {
|
<script lang="ts">
|
||||||
name: 'UploadPage'
|
export default {
|
||||||
}
|
name: 'UploadPage'
|
||||||
</script>
|
}
|
||||||
|
</script>
|
||||||
<style scoped src="./css/UploadPage.css"></style>
|
|
||||||
|
<style scoped src="./css/UploadPage.css"></style>
|
||||||
|
|||||||
Reference in New Issue
Block a user