diff --git a/public/preload.js b/public/preload.js index 5291954..281993e 100644 --- a/public/preload.js +++ b/public/preload.js @@ -1,226 +1,15 @@ -// /* -// name: clipboard_manager -// author: Github @ZiuChen -// desc: 监听剪贴板 读写本地文件 -// */ - -const fs = require('fs') +const { existsSync, readFileSync, writeFileSync, mkdirSync } = require('fs') const crypto = require('crypto') const listener = require('clipboard-event') const { clipboard } = require('electron') -const sep = utools.isWindows() ? '\\' : '/' -const DBPath = `${ - utools.isMacOs() ? utools.getPath('userData') : utools.getPath('home') -}${sep}_utools_clipboard_manager_storage` - -class DB { - constructor(path) { - const d = new Date() - this.path = path - this.dataBase = {} - this.createTime = d.getTime() - this.updateTime = d.getTime() - } - init() { - const isExist = fs.existsSync(this.path) - if (isExist) { - const data = fs.readFileSync(this.path, { - encoding: 'utf8' - }) - try { - // 读取磁盘记录到内存 - const dataBase = JSON.parse(data) - this.dataBase = dataBase - // 将超过14天的数据删除 排除掉收藏 - const now = new Date().getTime() - const deleteTime = now - '\u0031\u0034' * '\u0032\u0034' * 60 * 60 * 1000 // unicode - this.dataBase.data = this.dataBase.data?.filter((item) => item.updateTime > deleteTime) - this.updateDataBaseLocal() - } catch (err) { - utools.showNotification('读取剪切板出错: ' + err) - return - } - return - } - const defaultDB = { - data: [], - createTime: this.createTime, - updateTime: this.updateTime - } - this.dataBase = defaultDB - this.updateDataBaseLocal(defaultDB) - } - updateDataBase() { - // 更新内存数据 - this.dataBase.updateTime = new Date().getTime() - } - updateDataBaseLocal(dataBase) { - // 更新文件数据 - fs.writeFileSync(this.path, JSON.stringify(dataBase || this.dataBase), (err) => { - if (err) { - utools.showNotification('写入剪切板出错: ' + err) - return - } - }) - } - addItem(cItem) { - this.dataBase.data.unshift(cItem) - this.updateDataBase() - const exceedCount = this.dataBase.data.length - '\u0038\u0030\u0030' - if (exceedCount > 0) { - // 达到条数限制 删除超出部分 - for (let i = 0; i < exceedCount; i++) { - this.dataBase.data.pop() - } - } - this.updateDataBaseLocal() - } - emptyDataBase() { - this.dataBase.data = [] - this.updateDataBase() - this.updateDataBaseLocal() - } - filterDataBaseViaId(id) { - return this.dataBase.data.filter((item) => item.id === id) - } - updateItemViaId(id) { - for (const item of this.dataBase.data) { - if (item.id === id) { - item.updateTime = new Date().getTime() - this.sortDataBaseViaTime() - return true - } - } - return false - } - sortDataBaseViaTime() { - this.dataBase.data = this.dataBase.data.sort((a, b) => { - return b.updateTime - a.updateTime - }) - this.updateDataBaseLocal() - } - removeItemViaId(id) { - for (const item of this.dataBase.data) { - if (item.id === id) { - this.dataBase.data.splice(this.dataBase.data.indexOf(item), 1) - this.updateDataBaseLocal() - return true - } - } - return false - } +window.exports = { + utools, + existsSync, + readFileSync, + writeFileSync, + mkdirSync, + crypto, + listener, + clipboard } - -const pbpaste = () => { - // file - const files = utools.getCopyedFiles() // null | Array - if (files) { - return { - type: 'file', - data: JSON.stringify(files) - } - } - // text - const text = clipboard.readText() - if (text.trim()) return { type: 'text', data: text } - // image - const image = clipboard.readImage() // 大图卡顿来源 - const data = image.toDataURL() - if (!image.isEmpty()) { - return { - type: 'image', - data: data - } - } -} - -const copy = (item, isHideMainWindow = true) => { - switch (item.type) { - case 'text': - utools.copyText(item.data) - break - case 'image': - utools.copyImage(item.data) - break - case 'file': - const paths = JSON.parse(item.data).map((file) => file.path) - utools.copyFile(paths) - break - } - isHideMainWindow && utools.hideMainWindow() -} - -const paste = () => { - if (utools.isMacOs()) utools.simulateKeyboardTap('v', 'command') - else utools.simulateKeyboardTap('v', 'ctrl') -} - -const createFile = (item) => { - const tempPath = utools.getPath('temp') - const folderPath = tempPath + sep + 'utools-clipboard-manager' - if (!fs.existsSync(folderPath)) { - try { - fs.mkdirSync(folderPath) - } catch (err) { - utools.showNotification('创建临时文件夹出错: ' + err) - } - } - const { type } = item - if (type === 'image') { - const base64Data = item.data.replace(/^data:image\/\w+;base64,/, '') // remove the prefix - const buffer = Buffer.from(base64Data, 'base64') // to Buffer - const filePath = folderPath + sep + new Date().valueOf() + '.png' - fs.writeFileSync(filePath, buffer) - return filePath - } else if (type === 'text') { - const filePath = folderPath + sep + new Date().valueOf() + '.txt' - fs.writeFileSync(filePath, item.data) - return filePath - } -} - -const db = new DB(DBPath) -db.init() - -const remove = (item) => db.removeItemViaId(item.id) - -const focus = (isBlur = false) => { - return document.querySelector('.clip-search').style.display !== 'none' - ? isBlur - ? document.querySelector('.clip-search-input')?.blur() - : document.querySelector('.clip-search-input')?.focus() - : (document.querySelector('.clip-search-btn')?.click(), - document.querySelector('.clip-search-input')?.focus()) -} -const toTop = () => (document.scrollingElement.scrollTop = 0) -const resetNav = () => document.querySelectorAll('.clip-switch-item')[0]?.click() - -listener.startListening() - -listener.on('change', () => { - const item = pbpaste() - if (!item) return - item.id = crypto.createHash('md5').update(item.data).digest('hex') - if (db.updateItemViaId(item.id)) { - // 在库中 由 updateItemViaId 更新 updateTime - return - } - // 不在库中 由 addItem 添加 - item.createTime = new Date().getTime() - item.updateTime = new Date().getTime() - db.addItem(item) -}) - -utools.onPluginEnter(() => { - toTop() - resetNav() -}) - -window.db = db -window.copy = copy -window.paste = paste -window.remove = remove -window.createFile = createFile -window.focus = focus -window.toTop = toTop diff --git a/src/global/initPlugin.js b/src/global/initPlugin.js new file mode 100644 index 0000000..a3f49a1 --- /dev/null +++ b/src/global/initPlugin.js @@ -0,0 +1,219 @@ +const { utools, existsSync, readFileSync, writeFileSync, mkdirSync, crypto, listener, clipboard } = + window.exports + +export default function initPlugin() { + const sep = utools.isWindows() ? '\\' : '/' + const DBPath = `${ + utools.isMacOs() ? utools.getPath('userData') : utools.getPath('home') + }${sep}_utools_clipboard_manager_storage` + class DB { + constructor(path) { + const d = new Date() + this.path = path + this.dataBase = {} + this.createTime = d.getTime() + this.updateTime = d.getTime() + } + init() { + const isExist = existsSync(this.path) + if (isExist) { + const data = readFileSync(this.path, { + encoding: 'utf8' + }) + try { + // 读取磁盘记录到内存 + const dataBase = JSON.parse(data) + this.dataBase = dataBase + // 将超过14天的数据删除 排除掉收藏 + const now = new Date().getTime() + const deleteTime = now - '\u0031\u0034' * '\u0032\u0034' * 60 * 60 * 1000 // unicode + this.dataBase.data = this.dataBase.data?.filter((item) => item.updateTime > deleteTime) + this.updateDataBaseLocal() + } catch (err) { + utools.showNotification('读取剪切板出错: ' + err) + return + } + return + } + const defaultDB = { + data: [], + createTime: this.createTime, + updateTime: this.updateTime + } + this.dataBase = defaultDB + this.updateDataBaseLocal(defaultDB) + } + updateDataBase() { + // 更新内存数据 + this.dataBase.updateTime = new Date().getTime() + } + updateDataBaseLocal(dataBase) { + // 更新文件数据 + writeFileSync(this.path, JSON.stringify(dataBase || this.dataBase), (err) => { + if (err) { + utools.showNotification('写入剪切板出错: ' + err) + return + } + }) + } + addItem(cItem) { + this.dataBase.data.unshift(cItem) + this.updateDataBase() + const exceedCount = this.dataBase.data.length - '\u0038\u0030\u0030' + if (exceedCount > 0) { + // 达到条数限制 删除超出部分 + for (let i = 0; i < exceedCount; i++) { + this.dataBase.data.pop() + } + } + this.updateDataBaseLocal() + } + emptyDataBase() { + this.dataBase.data = [] + this.updateDataBase() + this.updateDataBaseLocal() + } + filterDataBaseViaId(id) { + return this.dataBase.data.filter((item) => item.id === id) + } + updateItemViaId(id) { + for (const item of this.dataBase.data) { + if (item.id === id) { + item.updateTime = new Date().getTime() + this.sortDataBaseViaTime() + return true + } + } + return false + } + sortDataBaseViaTime() { + this.dataBase.data = this.dataBase.data.sort((a, b) => { + return b.updateTime - a.updateTime + }) + this.updateDataBaseLocal() + } + removeItemViaId(id) { + for (const item of this.dataBase.data) { + if (item.id === id) { + this.dataBase.data.splice(this.dataBase.data.indexOf(item), 1) + this.updateDataBaseLocal() + return true + } + } + return false + } + } + + const pbpaste = () => { + // file + const files = utools.getCopyedFiles() // null | Array + if (files) { + return { + type: 'file', + data: JSON.stringify(files) + } + } + // text + const text = clipboard.readText() + if (text.trim()) return { type: 'text', data: text } + // image + const image = clipboard.readImage() // 大图卡顿来源 + const data = image.toDataURL() + if (!image.isEmpty()) { + return { + type: 'image', + data: data + } + } + } + + const copy = (item, isHideMainWindow = true) => { + switch (item.type) { + case 'text': + utools.copyText(item.data) + break + case 'image': + utools.copyImage(item.data) + break + case 'file': + const paths = JSON.parse(item.data).map((file) => file.path) + utools.copyFile(paths) + break + } + isHideMainWindow && utools.hideMainWindow() + } + + const paste = () => { + if (utools.isMacOs()) utools.simulateKeyboardTap('v', 'command') + else utools.simulateKeyboardTap('v', 'ctrl') + } + + const createFile = (item) => { + const tempPath = utools.getPath('temp') + const folderPath = tempPath + sep + 'utools-clipboard-manager' + if (!existsSync(folderPath)) { + try { + mkdirSync(folderPath) + } catch (err) { + utools.showNotification('创建临时文件夹出错: ' + err) + } + } + const { type } = item + if (type === 'image') { + const base64Data = item.data.replace(/^data:image\/\w+;base64,/, '') // remove the prefix + const buffer = Buffer.from(base64Data, 'base64') // to Buffer + const filePath = folderPath + sep + new Date().valueOf() + '.png' + writeFileSync(filePath, buffer) + return filePath + } else if (type === 'text') { + const filePath = folderPath + sep + new Date().valueOf() + '.txt' + writeFileSync(filePath, item.data) + return filePath + } + } + + const db = new DB(DBPath) + db.init() + + const remove = (item) => db.removeItemViaId(item.id) + + const focus = (isBlur = false) => { + return document.querySelector('.clip-search').style.display !== 'none' + ? isBlur + ? document.querySelector('.clip-search-input')?.blur() + : document.querySelector('.clip-search-input')?.focus() + : (document.querySelector('.clip-search-btn')?.click(), + document.querySelector('.clip-search-input')?.focus()) + } + const toTop = () => (document.scrollingElement.scrollTop = 0) + const resetNav = () => document.querySelectorAll('.clip-switch-item')[0]?.click() + + listener.startListening() + + listener.on('change', () => { + const item = pbpaste() + if (!item) return + item.id = crypto.createHash('md5').update(item.data).digest('hex') + if (db.updateItemViaId(item.id)) { + // 在库中 由 updateItemViaId 更新 updateTime + return + } + // 不在库中 由 addItem 添加 + item.createTime = new Date().getTime() + item.updateTime = new Date().getTime() + db.addItem(item) + }) + + utools.onPluginEnter(() => { + toTop() + resetNav() + }) + + window.db = db + window.copy = copy + window.paste = paste + window.remove = remove + window.createFile = createFile + window.focus = focus + window.toTop = toTop +} diff --git a/src/main.js b/src/main.js index 6124e95..5ceaead 100644 --- a/src/main.js +++ b/src/main.js @@ -1,10 +1,11 @@ +import initPlugin from './global/initPlugin' import { createApp } from 'vue' import App from './App.vue' import less from 'less' import registerElement from './global/registerElement' +initPlugin() const app = createApp(App) - app.use(less).use(registerElement) app.mount('#app')