Feature: add custom short url server

#69

ISSUES CLOSED: #69
This commit is contained in:
萌萌哒赫萝
2023-07-11 20:07:33 -07:00
parent 3b3c70a53f
commit d4a22f9e63
16 changed files with 167 additions and 38 deletions
+1 -1
View File
@@ -66,7 +66,7 @@
"mime-types": "^2.1.35", "mime-types": "^2.1.35",
"mitt": "^3.0.0", "mitt": "^3.0.0",
"nodejs-file-downloader": "^4.12.1", "nodejs-file-downloader": "^4.12.1",
"piclist": "^0.7.3", "piclist": "^0.7.4",
"pinia": "^2.1.4", "pinia": "^2.1.4",
"pinia-plugin-persistedstate": "^3.1.0", "pinia-plugin-persistedstate": "^3.1.0",
"qiniu": "^7.8.0", "qiniu": "^7.8.0",
+3
View File
@@ -227,6 +227,9 @@ SETTINGS_ISHIDEDOCK_TIPS: Not support hide dock and tray at the same time
SETTINGS_ENCODE_OUTPUT_URL: Encode Output(or Copyed) URL SETTINGS_ENCODE_OUTPUT_URL: Encode Output(or Copyed) URL
SETTINGS_WATCH_CLIPBOARD: Watch clipboard when software start SETTINGS_WATCH_CLIPBOARD: Watch clipboard when software start
SETTINGS_SHORT_URL: Use short url SETTINGS_SHORT_URL: Use short url
SETTINGS_SHORT_URL_SERVER: Short url server
SETTINGS_SHORT_URL_YOURLS_DOMAIN: YOURLS domain
SETTINGS_SHORT_URL_YOURLS_SIGNATURE: YOURLS signature
SETTINGS_DELETE_LOCAL_FILE_AFTER_UPLOAD: Delete local file after upload SETTINGS_DELETE_LOCAL_FILE_AFTER_UPLOAD: Delete local file after upload
SETTINGS_SYNC_CONFIG: Settings Sync Configuration SETTINGS_SYNC_CONFIG: Settings Sync Configuration
SETTINGS_SYNC_CONFIG_TITLE: Sync Settings SETTINGS_SYNC_CONFIG_TITLE: Sync Settings
+3
View File
@@ -230,6 +230,9 @@ SETTINGS_ISHIDEDOCK_TIPS: 不支持同时隐藏dock和托盘
SETTINGS_ENCODE_OUTPUT_URL: 输出(复制) URL 时进行转义 SETTINGS_ENCODE_OUTPUT_URL: 输出(复制) URL 时进行转义
SETTINGS_WATCH_CLIPBOARD: 软件启动时自动监听剪贴板上传 SETTINGS_WATCH_CLIPBOARD: 软件启动时自动监听剪贴板上传
SETTINGS_SHORT_URL: 使用短链接 SETTINGS_SHORT_URL: 使用短链接
SETTINGS_SHORT_URL_SERVER: 短链接服务
SETTINGS_SHORT_URL_YOURLS_DOMAIN: YOURLS域名
SETTINGS_SHORT_URL_YOURLS_SIGNATURE: YOURLS signature
SETTINGS_DELETE_LOCAL_FILE_AFTER_UPLOAD: 上传后删除本地文件 SETTINGS_DELETE_LOCAL_FILE_AFTER_UPLOAD: 上传后删除本地文件
SETTINGS_SYNC_CONFIG: 设置配置同步 SETTINGS_SYNC_CONFIG: 设置配置同步
SETTINGS_SYNC_CONFIG_TITLE: 同步设置 SETTINGS_SYNC_CONFIG_TITLE: 同步设置
+3
View File
@@ -228,6 +228,9 @@ SETTINGS_ISHIDEDOCK_TIPS: 不支持同時隱藏dock和托盘
SETTINGS_ENCODE_OUTPUT_URL: 輸出(複製) URL 時進行轉義 SETTINGS_ENCODE_OUTPUT_URL: 輸出(複製) URL 時進行轉義
SETTINGS_WATCH_CLIPBOARD: 軟體啟動時自動監聽剪貼簿上傳 SETTINGS_WATCH_CLIPBOARD: 軟體啟動時自動監聽剪貼簿上傳
SETTINGS_SHORT_URL: 使用短網址 SETTINGS_SHORT_URL: 使用短網址
SETTINGS_SHORT_URL_SERVER: 短網址服務
SETTINGS_SHORT_URL_YOURLS_DOMAIN: YOURLS域名
SETTINGS_SHORT_URL_YOURLS_SIGNATURE: YOURLS signature
SETTINGS_DELETE_LOCAL_FILE_AFTER_UPLOAD: 上傳後刪除本地檔案 SETTINGS_DELETE_LOCAL_FILE_AFTER_UPLOAD: 上傳後刪除本地檔案
SETTINGS_SYNC_CONFIG: 設置同步配置 SETTINGS_SYNC_CONFIG: 設置同步配置
SETTINGS_SYNC_CONFIG_TITLE: 同步設置 SETTINGS_SYNC_CONFIG_TITLE: 同步設置
+1 -3
View File
@@ -39,11 +39,10 @@ import {
uploadChoosedFiles uploadChoosedFiles
} from '~/main/apis/app/uploader/apis' } from '~/main/apis/app/uploader/apis'
import picgoCoreIPC from './picgoCoreIPC' import picgoCoreIPC from './picgoCoreIPC'
import { handleCopyUrl } from '~/main/utils/common' import { handleCopyUrl, generateShortUrl } from '~/main/utils/common'
import { buildMainPageMenu, buildMiniPageMenu, buildPluginPageMenu, buildPicBedListMenu } from './remotes/menu' import { buildMainPageMenu, buildMiniPageMenu, buildPluginPageMenu, buildPicBedListMenu } from './remotes/menu'
import path from 'path' import path from 'path'
import { T } from '~/main/i18n' import { T } from '~/main/i18n'
import { generateShortUrl } from '~/universal/utils/common'
import { uploadFile, downloadFile } from '../utils/syncSettings' import { uploadFile, downloadFile } from '../utils/syncSettings'
const STORE_PATH = app.getPath('userData') const STORE_PATH = app.getPath('userData')
@@ -76,7 +75,6 @@ export default {
}) })
ipcMain.on('uploadClipboardFilesFromUploadPage', () => { ipcMain.on('uploadClipboardFilesFromUploadPage', () => {
console.log('handle')
uploadClipboardFiles() uploadClipboardFiles()
}) })
+46
View File
@@ -2,6 +2,10 @@ import fs from 'fs-extra'
import db from '~/main/apis/core/datastore' import db from '~/main/apis/core/datastore'
import { clipboard, Notification, dialog } from 'electron' import { clipboard, Notification, dialog } from 'electron'
import { handleUrlEncode } from '~/universal/utils/common' import { handleUrlEncode } from '~/universal/utils/common'
import axios from 'axios'
import FormData from 'form-data'
import { C1 } from '#/utils/static'
import logger from '../apis/core/picgo/logger'
export const handleCopyUrl = (str: string): void => { export const handleCopyUrl = (str: string): void => {
if (db.get('settings.autoCopy') !== false) { if (db.get('settings.autoCopy') !== false) {
@@ -96,3 +100,45 @@ export const getClipboardFilePath = (): string => {
} }
export const handleUrlEncodeWithSetting = (url: string) => db.get('settings.encodeOutputURL') ? handleUrlEncode(url) : url export const handleUrlEncodeWithSetting = (url: string) => db.get('settings.encodeOutputURL') ? handleUrlEncode(url) : url
const c1nApi = 'https://c1n.cn/link/short'
export const generateShortUrl = async (url: string) => {
const server = db.get('settings.shortUrlServer') || 'c1n'
if (server === 'c1n') {
const form = new FormData()
form.append('url', url)
const C = Buffer.from(C1, 'base64').toString()
try {
const res = await axios.post(c1nApi, form, {
headers: {
token: C
}
})
if (res.status >= 200 && res.status < 300 && res.data?.code === 0) {
return res.data.data
}
} catch (e: any) {
console.log(e)
}
} else if (server === 'yourls') {
const domain = db.get('settings.yourlsDomain') || ''
const signature = db.get('settings.yourlsSignature') || ''
if (domain && signature) {
try {
const res = await axios.get(`${domain}/yourls-api.php?signature=${signature}&action=shorturl&format=json&url=${url}`)
if (res.data.shorturl) {
return res.data.shorturl
}
} catch (e: any) {
if (e.response.data.message.indexOf('already exists in database') !== -1) {
return e.response.data.shorturl
}
console.log(e)
}
} else {
logger.warn('Yourls server or signature is not set')
}
}
return url
}
+1 -1
View File
@@ -1,5 +1,5 @@
import { IPasteStyle } from '#/types/enum' import { IPasteStyle } from '#/types/enum'
import { generateShortUrl } from '#/utils/common' import { generateShortUrl } from '~/main/utils/common'
import db from '~/main/apis/core/datastore' import db from '~/main/apis/core/datastore'
import { handleUrlEncodeWithSetting } from './common' import { handleUrlEncodeWithSetting } from './common'
+3 -1
View File
@@ -7,6 +7,7 @@ import GithubApi from './github'
import UpyunApi from './upyun' import UpyunApi from './upyun'
import AwsS3Api from './awss3' import AwsS3Api from './awss3'
import WebdavApi from './webdav' import WebdavApi from './webdav'
import LocalApi from './local'
const apiMap: IStringKeyMap = { const apiMap: IStringKeyMap = {
smms: SmmsApi, smms: SmmsApi,
@@ -17,7 +18,8 @@ const apiMap: IStringKeyMap = {
github: GithubApi, github: GithubApi,
upyun: UpyunApi, upyun: UpyunApi,
'aws-s3': AwsS3Api, 'aws-s3': AwsS3Api,
webdavplist: WebdavApi webdavplist: WebdavApi,
local: LocalApi
} }
export default class ALLApi { export default class ALLApi {
+23
View File
@@ -0,0 +1,23 @@
import fs from 'fs-extra'
interface IConfigMap {
hash: string
}
export default class LocalApi {
static async delete (configMap: IConfigMap): Promise<boolean> {
const { hash } = configMap
if (!hash) {
console.error('SmmsApi.delete: invalid params')
return false
}
try {
await fs.remove(hash)
return true
} catch (error) {
console.error(error)
return false
}
}
}
-1
View File
@@ -3663,7 +3663,6 @@ const columns: Column<any>[] = [
] ]
onBeforeMount(async () => { onBeforeMount(async () => {
console.log('onBeforeMount')
await manageStore.refreshConfig() await manageStore.refreshConfig()
showLoadingPage.value = true showLoadingPage.value = true
await initCustomUrlList() await initCustomUrlList()
+2 -2
View File
@@ -661,7 +661,7 @@ function remove (item: ImgInfo) {
type: 'warning' type: 'warning'
}).then(async () => { }).then(async () => {
const file = await $$db.getById(item.id!) const file = await $$db.getById(item.id!)
const picBedsCanbeDeleted = ['smms', 'github', 'imgur', 'tcyun', 'aliyun', 'qiniu', 'upyun', 'aws-s3', 'webdavplist'] const picBedsCanbeDeleted = ['smms', 'github', 'imgur', 'tcyun', 'aliyun', 'qiniu', 'upyun', 'aws-s3', 'webdavplist', 'local']
if (await getConfig('settings.deleteCloudFile')) { if (await getConfig('settings.deleteCloudFile')) {
if (item.type !== undefined && picBedsCanbeDeleted.includes(item.type)) { if (item.type !== undefined && picBedsCanbeDeleted.includes(item.type)) {
const result = await ALLApi.delete(item) const result = await ALLApi.delete(item)
@@ -771,7 +771,7 @@ function multiRemove () {
const files: IResult<ImgInfo>[] = [] const files: IResult<ImgInfo>[] = []
const imageIDList = Object.keys(choosedList) const imageIDList = Object.keys(choosedList)
const isDeleteCloudFile = await getConfig('settings.deleteCloudFile') const isDeleteCloudFile = await getConfig('settings.deleteCloudFile')
const picBedsCanbeDeleted = ['smms', 'github', 'imgur', 'tcyun', 'aliyun', 'qiniu', 'upyun', 'aws-s3', 'webdavplist'] const picBedsCanbeDeleted = ['smms', 'github', 'imgur', 'tcyun', 'aliyun', 'qiniu', 'upyun', 'aws-s3', 'webdavplist', 'local']
if (isDeleteCloudFile) { if (isDeleteCloudFile) {
for (let i = 0; i < imageIDList.length; i++) { for (let i = 0; i < imageIDList.length; i++) {
const key = imageIDList[i] const key = imageIDList[i]
+71
View File
@@ -373,6 +373,49 @@
@change="handleUseShortUrl" @change="handleUseShortUrl"
/> />
</el-form-item> </el-form-item>
<el-form-item
v-if="form.useShortUrl"
:label="$T('SETTINGS_SHORT_URL_SERVER')"
>
<el-select
v-model="form.shortUrlServer"
size="small"
style="width: 50%"
:placeholder="$T('SETTINGS_SHORT_URL_SERVER')"
@change="handleShortUrlServerChange"
>
<el-option
v-for="item in shortUrlServerList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item
v-if="form.useShortUrl && form.shortUrlServer === 'yourls'"
:label="$T('SETTINGS_SHORT_URL_YOURLS_DOMAIN')"
>
<el-input
v-model="form.yourlsDomain"
size="small"
style="width: 50%"
:placeholder="$T('SETTINGS_SHORT_URL_YOURLS_DOMAIN')"
@change="handleYourlsDomainChange"
/>
</el-form-item>
<el-form-item
v-if="form.useShortUrl && form.shortUrlServer === 'yourls'"
:label="$T('SETTINGS_SHORT_URL_YOURLS_SIGNATURE')"
>
<el-input
v-model="form.yourlsSignature"
size="small"
style="width: 50%"
:placeholder="$T('SETTINGS_SHORT_URL_YOURLS_SIGNATURE')"
@change="handleYourlsSignatureChange"
/>
</el-form-item>
<el-form-item <el-form-item
:label="$T('SETTINGS_ENCODE_OUTPUT_URL')" :label="$T('SETTINGS_ENCODE_OUTPUT_URL')"
> >
@@ -1376,6 +1419,16 @@ import { buildInRenameFormatTable } from '../manage/utils/common'
const imageProcessDialogVisible = ref(false) const imageProcessDialogVisible = ref(false)
const activeName = ref<'system' | 'syncAndConfigure' | 'upload' | 'advanced' | 'upadte'>('system') const activeName = ref<'system' | 'syncAndConfigure' | 'upload' | 'advanced' | 'upadte'>('system')
const shortUrlServerList = [{
label: 'c1n',
value: 'c1n'
},
{
label: 'yourls',
value: 'yourls'
}
]
const waterMarkPositionMap = new Map([ const waterMarkPositionMap = new Map([
['north', $T('UPLOAD_PAGE_IMAGE_PROCESS_POSITION_TOP')], ['north', $T('UPLOAD_PAGE_IMAGE_PROCESS_POSITION_TOP')],
['northeast', $T('UPLOAD_PAGE_IMAGE_PROCESS_POSITION_TOP_RIGHT')], ['northeast', $T('UPLOAD_PAGE_IMAGE_PROCESS_POSITION_TOP_RIGHT')],
@@ -1489,6 +1542,9 @@ const form = reactive<ISettingForm>({
encodeOutputURL: false, encodeOutputURL: false,
isAutoListenClipboard: false, isAutoListenClipboard: false,
useShortUrl: false, useShortUrl: false,
shortUrlServer: 'c1n',
yourlsDomain: '',
yourlsSignature: '',
deleteLocalFile: false deleteLocalFile: false
}) })
@@ -1638,6 +1694,9 @@ async function initData () {
form.customMiniIcon = settings.customMiniIcon || '' form.customMiniIcon = settings.customMiniIcon || ''
form.isHideDock = settings.isHideDock || false form.isHideDock = settings.isHideDock || false
form.useShortUrl = settings.useShortUrl || false form.useShortUrl = settings.useShortUrl || false
form.shortUrlServer = settings.shortUrlServer || 'c1n'
form.yourlsDomain = settings.yourlsDomain || ''
form.yourlsSignature = settings.yourlsSignature || ''
form.deleteLocalFile = settings.deleteLocalFile || false form.deleteLocalFile = settings.deleteLocalFile || false
currentLanguage.value = settings.language ?? 'zh-CN' currentLanguage.value = settings.language ?? 'zh-CN'
currentStartMode.value = settings.startMode || 'quiet' currentStartMode.value = settings.startMode || 'quiet'
@@ -1955,6 +2014,18 @@ function handleUseShortUrl (val: ICheckBoxValueType) {
} }
} }
function handleShortUrlServerChange (val: string) {
saveConfig('settings.shortUrlServer', val)
}
function handleYourlsDomainChange (val: string) {
saveConfig('settings.yourlsDomain', val)
}
function handleYourlsSignatureChange (val: string) {
saveConfig('settings.yourlsSignature', val)
}
function confirmLogLevelSetting () { function confirmLogLevelSetting () {
if (form.logLevel.length === 0) { if (form.logLevel.length === 0) {
return $message.error($T('TIPS_PLEASE_CHOOSE_LOG_LEVEL')) return $message.error($T('TIPS_PLEASE_CHOOSE_LOG_LEVEL'))
+3
View File
@@ -223,6 +223,9 @@ interface ILocales {
SETTINGS_ENCODE_OUTPUT_URL: string SETTINGS_ENCODE_OUTPUT_URL: string
SETTINGS_WATCH_CLIPBOARD: string SETTINGS_WATCH_CLIPBOARD: string
SETTINGS_SHORT_URL: string SETTINGS_SHORT_URL: string
SETTINGS_SHORT_URL_SERVER: string
SETTINGS_SHORT_URL_YOURLS_DOMAIN: string
SETTINGS_SHORT_URL_YOURLS_SIGNATURE: string
SETTINGS_DELETE_LOCAL_FILE_AFTER_UPLOAD: string SETTINGS_DELETE_LOCAL_FILE_AFTER_UPLOAD: string
SETTINGS_SYNC_CONFIG: string SETTINGS_SYNC_CONFIG: string
SETTINGS_SYNC_CONFIG_TITLE: string SETTINGS_SYNC_CONFIG_TITLE: string
+3
View File
@@ -20,6 +20,9 @@ interface ISettingForm {
encodeOutputURL: boolean, encodeOutputURL: boolean,
isAutoListenClipboard: boolean, isAutoListenClipboard: boolean,
useShortUrl: boolean, useShortUrl: boolean,
shortUrlServer: string,
yourlsDomain: string,
yourlsSignature: string,
deleteLocalFile: boolean deleteLocalFile: boolean
} }
-25
View File
@@ -1,7 +1,3 @@
import axios from 'axios'
import FormData from 'form-data'
import { C1 } from './static'
export const isUrl = (url: string): boolean => { export const isUrl = (url: string): boolean => {
try { try {
return Boolean(new URL(url)) return Boolean(new URL(url))
@@ -48,24 +44,3 @@ export const isDev = process.env.NODE_ENV === 'development'
export const trimValues = <T extends IStringKeyMap>(obj: T): {[K in keyof T]: T[K] extends string ? string : T[K]} => { export const trimValues = <T extends IStringKeyMap>(obj: T): {[K in keyof T]: T[K] extends string ? string : T[K]} => {
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]} 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]}
} }
const c1nApi = 'https://c1n.cn/link/short'
export const generateShortUrl = async (url: string) => {
const form = new FormData()
form.append('url', url)
const C = Buffer.from(C1, 'base64').toString()
try {
const res = await axios.post(c1nApi, form, {
headers: {
token: C
}
})
if (res.status >= 200 && res.status < 300 && res.data?.code === 0) {
return res.data.data
}
} catch (e: any) {
console.log(e)
}
return url
}
+4 -4
View File
@@ -11054,10 +11054,10 @@ performance-now@^2.1.0:
resolved "https://registry.npmmirror.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" resolved "https://registry.npmmirror.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==
piclist@^0.7.3: piclist@^0.7.4:
version "0.7.3" version "0.7.4"
resolved "https://registry.npmjs.org/piclist/-/piclist-0.7.3.tgz#41435eb56157890e6720804faf1afcf098d41ef6" resolved "https://registry.npmjs.org/piclist/-/piclist-0.7.4.tgz#125c9f337e2d7375ae0c5c17fafaf924134fd65f"
integrity sha512-0mvD3QJm2VKuJfRbg/FBm5osh0SnHwiKSMZ2XphjfAyO4T1So9Y5XnuiGDLOYXiAMWnwbBMrixjiVahcsgGknA== integrity sha512-PxE6S93uWP7sQNyMi6R7ZEs57oOXgm/nD14Moi0k0dbAlvtm1kWdrc4CboW/6e7hPVgeqT7pGi0+y0SF8iTxOA==
dependencies: dependencies:
"@picgo/i18n" "^1.0.0" "@picgo/i18n" "^1.0.0"
"@picgo/store" "^2.0.4" "@picgo/store" "^2.0.4"