Feature(custom): add thumbnail suffix functionality and related settings

ISSUES CLOSED: #539
This commit is contained in:
Kuingsmile
2026-06-11 19:32:45 -07:00
parent cda137220b
commit 74cf3ea1ad
7 changed files with 91 additions and 15 deletions
+3
View File
@@ -654,6 +654,9 @@
}, },
"selectDownloadFolderTips": "Select download directory", "selectDownloadFolderTips": "Select download directory",
"selectDownloadFolderTitle": "Choose download folder", "selectDownloadFolderTitle": "Choose download folder",
"thumbnailSuffixPlaceholder": "Example: ?imageMogr2/thumbnail/200x200",
"thumbnailSuffixTips": "Only affects image previews in the cloud management list. Copy, download, and delete still use the original URL",
"thumbnailSuffixTitle": "Image preview thumbnail suffix",
"timestampRenameTips": "When enabled, uploaded files will be renamed to a timestamp", "timestampRenameTips": "When enabled, uploaded files will be renamed to a timestamp",
"timestampRenameTitle": "Timestamp rename on upload (highest priority)", "timestampRenameTitle": "Timestamp rename on upload (highest priority)",
"title": "Manage General Settings" "title": "Manage General Settings"
+3
View File
@@ -654,6 +654,9 @@
}, },
"selectDownloadFolderTips": "选择下载目录", "selectDownloadFolderTips": "选择下载目录",
"selectDownloadFolderTitle": "选择下载文件夹", "selectDownloadFolderTitle": "选择下载文件夹",
"thumbnailSuffixPlaceholder": "例如:?imageMogr2/thumbnail/200x200",
"thumbnailSuffixTips": "仅影响云管理列表中的图片预览,不会改变复制链接、下载或删除使用的原始地址",
"thumbnailSuffixTitle": "图片预览缩略图后缀",
"timestampRenameTips": "开启后,上传的文件将自动重命名为时间戳", "timestampRenameTips": "开启后,上传的文件将自动重命名为时间戳",
"timestampRenameTitle": "上传文件时间戳重命名(最高优先级)", "timestampRenameTitle": "上传文件时间戳重命名(最高优先级)",
"title": "管理通用设置" "title": "管理通用设置"
+3
View File
@@ -654,6 +654,9 @@
}, },
"selectDownloadFolderTips": "選擇下載目錄", "selectDownloadFolderTips": "選擇下載目錄",
"selectDownloadFolderTitle": "選擇下載資料夾", "selectDownloadFolderTitle": "選擇下載資料夾",
"thumbnailSuffixPlaceholder": "例如:?imageMogr2/thumbnail/200x200",
"thumbnailSuffixTips": "僅影響雲端管理列表中的圖片預覽,不會變更複製連結、下載或刪除使用的原始地址",
"thumbnailSuffixTitle": "圖片預覽縮圖後綴",
"timestampRenameTips": "啟用後,上傳的檔案將自動更名為時間戳", "timestampRenameTips": "啟用後,上傳的檔案將自動更名為時間戳",
"timestampRenameTitle": "上傳檔案時間戳重新命名(最高優先級)", "timestampRenameTitle": "上傳檔案時間戳重新命名(最高優先級)",
"title": "管理通用設置" "title": "管理通用設置"
+7 -1
View File
@@ -327,7 +327,7 @@
> >
<img <img
v-if="isShowThumbnail && item.isImage" v-if="isShowThumbnail && item.isImage"
:src="item.url" :src="getThumbnailUrl(item.url)"
class="h-full w-full object-contain transition-all duration-fast ease-apple" class="h-full w-full object-contain transition-all duration-fast ease-apple"
@error="() => {}" @error="() => {}"
/> />
@@ -1189,6 +1189,7 @@ import {
} from '@/manage/utils/common' } from '@/manage/utils/common'
import { getConfig, saveConfig } from '@/manage/utils/dataSender' import { getConfig, saveConfig } from '@/manage/utils/dataSender'
import { textFileExt } from '@/manage/utils/textfile' import { textFileExt } from '@/manage/utils/textfile'
import { appendThumbnailSuffix } from '@/manage/utils/thumbnailUrl'
import { videoExt } from '@/manage/utils/videofile' import { videoExt } from '@/manage/utils/videofile'
import { trimPath } from '@/utils/common' import { trimPath } from '@/utils/common'
import { useDragEventListeners } from '@/utils/drag' import { useDragEventListeners } from '@/utils/drag'
@@ -1403,6 +1404,7 @@ const calculateAllFileSize = computed(
'0', '0',
) )
const isShowThumbnail = computed(() => manageStore.config.settings.isShowThumbnail ?? false) const isShowThumbnail = computed(() => manageStore.config.settings.isShowThumbnail ?? false)
const thumbnailSuffix = computed(() => manageStore.config.settings.thumbnailSuffix ?? '')
const isUsePreSignedUrl = computed(() => manageStore.config.settings.isUsePreSignedUrl ?? false) const isUsePreSignedUrl = computed(() => manageStore.config.settings.isUsePreSignedUrl ?? false)
const isAutoRefresh = computed(() => manageStore.config.settings.isAutoRefresh ?? false) const isAutoRefresh = computed(() => manageStore.config.settings.isAutoRefresh ?? false)
const isIgnoreCase = computed(() => manageStore.config.settings.isIgnoreCase ?? false) const isIgnoreCase = computed(() => manageStore.config.settings.isIgnoreCase ?? false)
@@ -1468,6 +1470,10 @@ watch(
const getExtension = (fileName: string) => window.node.path.extname(fileName).slice(1) const getExtension = (fileName: string) => window.node.path.extname(fileName).slice(1)
function getThumbnailUrl(url: string) {
return appendThumbnailSuffix(url, thumbnailSuffix.value)
}
function getList() { function getList() {
if (!searchText.value) { if (!searchText.value) {
return currentPageFilesInfo return currentPageFilesInfo
+25 -14
View File
@@ -56,20 +56,30 @@
:placeholder="t('pages.manage.setting.copyFormat.customTips')" :placeholder="t('pages.manage.setting.copyFormat.customTips')"
/> />
</SettingCard> </SettingCard>
<SettingCard v-for="item in switchFieldsConfigList" :key="item.configName" class="mb-4" p1> <template v-for="item in switchFieldsConfigList" :key="item.configName">
<CustomSwitch v-model="form[item.configName]" small no-border :tips="item.tooltip"> <SettingCard class="mb-4 flex flex-col justify-center" p1>
<template #custom-title> <CustomSwitch v-model="form[item.configName]" small no-border :tips="item.tooltip">
<span v-for="(segment, index) in item.segments" :key="index" :class="segment.class"> <template #custom-title>
{{ segment.text }} <span v-for="(segment, index) in item.segments" :key="index" :class="segment.class">
</span> {{ segment.text }}
</template> </span>
<template #switch-text> </template>
<span class="text-sm text-secondary">{{ <template #switch-text>
form[item.configName] ? item.activeText : item.inactiveText <span class="text-sm text-secondary">{{
}}</span> form[item.configName] ? item.activeText : item.inactiveText
</template> }}</span>
</CustomSwitch> </template>
</SettingCard> </CustomSwitch>
</SettingCard>
<SettingCard v-if="item.configName === 'isShowThumbnail' && form.isShowThumbnail" class="mb-4">
<CustomInput
v-model.trim="form.thumbnailSuffix"
:title="t('pages.manage.setting.thumbnailSuffixTitle')"
:placeholder="t('pages.manage.setting.thumbnailSuffixPlaceholder')"
:tips="t('pages.manage.setting.thumbnailSuffixTips')"
/>
</SettingCard>
</template>
</SettingSection> </SettingSection>
<SettingSection <SettingSection
@@ -171,6 +181,7 @@ const form = ref<IStringKeyMap>({
customRename: false, customRename: false,
isAutoRefresh: false, isAutoRefresh: false,
isShowThumbnail: false, isShowThumbnail: false,
thumbnailSuffix: '',
isUsePreSignedUrl: false, isUsePreSignedUrl: false,
isIgnoreCase: false, isIgnoreCase: false,
isForceCustomUrlHttps: false, isForceCustomUrlHttps: false,
+14
View File
@@ -0,0 +1,14 @@
export function appendThumbnailSuffix(url: string, suffix?: string): string {
const normalizedSuffix = suffix?.trim() ?? ''
if (!url || !normalizedSuffix) return url
if (normalizedSuffix.startsWith('?')) {
return `${url}${url.includes('?') ? '&' : '?'}${normalizedSuffix.slice(1)}`
}
if (normalizedSuffix.startsWith('&')) {
return `${url}${url.includes('?') ? '&' : '?'}${normalizedSuffix.slice(1)}`
}
return `${url}${normalizedSuffix}`
}
+36
View File
@@ -0,0 +1,36 @@
import { describe, expect, it } from 'vitest'
import { appendThumbnailSuffix } from '../src/renderer/manage/utils/thumbnailUrl'
describe('appendThumbnailSuffix', () => {
it('keeps the original URL when the suffix is empty', () => {
const url = 'https://example.com/image.png'
expect(appendThumbnailSuffix(url, '')).toBe(url)
expect(appendThumbnailSuffix(url)).toBe(url)
})
it('appends query-style suffixes to URLs without query strings', () => {
expect(appendThumbnailSuffix('https://example.com/image.png', '?imageMogr2/thumbnail/200x200')).toBe(
'https://example.com/image.png?imageMogr2/thumbnail/200x200',
)
})
it('converts query-style suffixes to additional parameters when the URL already has a query string', () => {
expect(appendThumbnailSuffix('https://example.com/image.png?version=1', '?imageMogr2/thumbnail/200x200')).toBe(
'https://example.com/image.png?version=1&imageMogr2/thumbnail/200x200',
)
})
it('normalizes ampersand-prefixed suffixes when the URL has no query string', () => {
expect(appendThumbnailSuffix('https://example.com/image.png', '&x-oss-process=image/resize,w_200')).toBe(
'https://example.com/image.png?x-oss-process=image/resize,w_200',
)
})
it('appends path-style suffixes unchanged', () => {
expect(appendThumbnailSuffix('https://example.com/image.png', '/thumbnail/200x200')).toBe(
'https://example.com/image.png/thumbnail/200x200',
)
})
})