mirror of
https://github.com/Kuingsmile/PicList.git
synced 2026-08-29 12:06:39 +08:00
✨ Feature(custom): support upload absolute file path text in clipboard
ISSUES CLOSED: #538
This commit is contained in:
@@ -0,0 +1,46 @@
|
|||||||
|
import path from 'node:path'
|
||||||
|
import { fileURLToPath } from 'node:url'
|
||||||
|
|
||||||
|
import fs from 'fs-extra'
|
||||||
|
|
||||||
|
const unwrapClipboardPathText = (text: string): string => {
|
||||||
|
if ((text.startsWith('"') && text.endsWith('"')) || (text.startsWith("'") && text.endsWith("'"))) {
|
||||||
|
return text.slice(1, -1).trim()
|
||||||
|
}
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalizeClipboardPathText = (text: string): string => {
|
||||||
|
const lines = text
|
||||||
|
.trim()
|
||||||
|
.split(/\r?\n/)
|
||||||
|
.map(line => line.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
|
||||||
|
if (lines.length !== 1) return ''
|
||||||
|
|
||||||
|
const filePath = unwrapClipboardPathText(lines[0])
|
||||||
|
if (!filePath) return ''
|
||||||
|
|
||||||
|
if (/^file:\/\//i.test(filePath)) {
|
||||||
|
try {
|
||||||
|
return fileURLToPath(filePath)
|
||||||
|
} catch (_e) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filePath
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getClipboardTextFilePath = (text: string): string => {
|
||||||
|
const filePath = normalizeClipboardPathText(text)
|
||||||
|
if (!filePath || !path.isAbsolute(filePath)) return ''
|
||||||
|
|
||||||
|
try {
|
||||||
|
const stats = fs.statSync(filePath)
|
||||||
|
return stats.isFile() ? path.normalize(filePath) : ''
|
||||||
|
} catch (_e) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ import fs from 'fs-extra'
|
|||||||
import { IPicGo } from 'piclist'
|
import { IPicGo } from 'piclist'
|
||||||
import { isProxy, isRef, toRaw, unref } from 'vue'
|
import { isProxy, isRef, toRaw, unref } from 'vue'
|
||||||
|
|
||||||
|
import { getClipboardTextFilePath } from '~/utils/clipboardFilePath'
|
||||||
import { configPaths } from '~/utils/configPaths'
|
import { configPaths } from '~/utils/configPaths'
|
||||||
import { IShortUrlServer } from '~/utils/enum'
|
import { IShortUrlServer } from '~/utils/enum'
|
||||||
|
|
||||||
@@ -147,7 +148,11 @@ export const getClipboardFilePath = (): string => {
|
|||||||
.readBuffer('FileNameW')
|
.readBuffer('FileNameW')
|
||||||
?.toString('ucs2')
|
?.toString('ucs2')
|
||||||
?.replace(RegExp(String.fromCharCode(0), 'g'), '')
|
?.replace(RegExp(String.fromCharCode(0), 'g'), '')
|
||||||
return imgPath || ''
|
if (imgPath) return imgPath
|
||||||
|
}
|
||||||
|
|
||||||
|
if (img.isEmpty()) {
|
||||||
|
return getClipboardTextFilePath(clipboard.readText())
|
||||||
}
|
}
|
||||||
|
|
||||||
return ''
|
return ''
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import os from 'node:os'
|
||||||
|
import path from 'node:path'
|
||||||
|
import { pathToFileURL } from 'node:url'
|
||||||
|
|
||||||
|
import fs from 'fs-extra'
|
||||||
|
import { afterEach, describe, expect, it } from 'vitest'
|
||||||
|
|
||||||
|
import { getClipboardTextFilePath } from '../src/main/utils/clipboardFilePath'
|
||||||
|
|
||||||
|
const tempDirs: string[] = []
|
||||||
|
|
||||||
|
const createTempFile = (fileName = 'clipboard image.png') => {
|
||||||
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'piclist-clipboard-'))
|
||||||
|
const filePath = path.join(dir, fileName)
|
||||||
|
tempDirs.push(dir)
|
||||||
|
fs.writeFileSync(filePath, 'test')
|
||||||
|
return filePath
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
tempDirs.splice(0).forEach(dir => fs.removeSync(dir))
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('getClipboardTextFilePath', () => {
|
||||||
|
it('returns an existing absolute file path from clipboard text', () => {
|
||||||
|
const filePath = createTempFile()
|
||||||
|
|
||||||
|
expect(getClipboardTextFilePath(` ${filePath} `)).toBe(path.normalize(filePath))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('unwraps quoted file paths', () => {
|
||||||
|
const filePath = createTempFile()
|
||||||
|
|
||||||
|
expect(getClipboardTextFilePath(`"${filePath}"`)).toBe(path.normalize(filePath))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('supports file URL text', () => {
|
||||||
|
const filePath = createTempFile()
|
||||||
|
|
||||||
|
expect(getClipboardTextFilePath(pathToFileURL(filePath).href)).toBe(path.normalize(filePath))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('rejects relative paths, missing files, directories, and multi-line text', () => {
|
||||||
|
const filePath = createTempFile()
|
||||||
|
|
||||||
|
expect(getClipboardTextFilePath(path.basename(filePath))).toBe('')
|
||||||
|
expect(getClipboardTextFilePath(path.join(os.tmpdir(), 'missing-clipboard-image.png'))).toBe('')
|
||||||
|
expect(getClipboardTextFilePath(path.dirname(filePath))).toBe('')
|
||||||
|
expect(getClipboardTextFilePath(`${filePath}\n${filePath}`)).toBe('')
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -93,7 +93,7 @@ describe('getRawData 深度扩展工具测试', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('应当正确克隆 Date 和 RegExp', () => {
|
it('应当正确克隆 Date 和 RegExp', () => {
|
||||||
const date = new Date('2024-01-01')
|
const date = new Date('2024-01-02')
|
||||||
const reg = /test/g
|
const reg = /test/g
|
||||||
const data = reactive({ date, reg })
|
const data = reactive({ date, reg })
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user