Merge pull request #456 from wikrin/refactor/scraping-switch-to-policy

This commit is contained in:
jxxghp
2026-03-19 21:35:15 +08:00
committed by GitHub
4 changed files with 127 additions and 186 deletions
+5
View File
@@ -1528,6 +1528,11 @@ export default {
episodeThumb: 'Thumb', episodeThumb: 'Thumb',
scrapingSwitchSaveFailed: 'Scraping switch settings save failed: {message}', scrapingSwitchSaveFailed: 'Scraping switch settings save failed: {message}',
scrapingSwitchSaveError: 'Scraping switch settings save failed', scrapingSwitchSaveError: 'Scraping switch settings save failed',
policy: {
skipDesc: 'Skip scraping, this file will not be generated',
missingOnlyDesc: 'Scrape only if missing, existing file remains unchanged',
overwriteDesc: 'Always scrape, existing file will be overwritten',
}
}, },
site: { site: {
siteSync: 'Site Synchronization', siteSync: 'Site Synchronization',
+5
View File
@@ -1515,6 +1515,11 @@ export default {
episodeThumb: '缩略图', episodeThumb: '缩略图',
scrapingSwitchSaveFailed: '刮削开关设置保存失败:{message}', scrapingSwitchSaveFailed: '刮削开关设置保存失败:{message}',
scrapingSwitchSaveError: '刮削开关设置保存失败', scrapingSwitchSaveError: '刮削开关设置保存失败',
policy: {
skipDesc: '跳过刮削,不生成该文件',
missingOnlyDesc: '仅在缺失时刮削,已存在则保持不变',
overwriteDesc: '始终刮削,已存在则覆盖',
}
}, },
site: { site: {
siteSync: '站点同步', siteSync: '站点同步',
+5
View File
@@ -1516,6 +1516,11 @@ export default {
episodeThumb: '縮略圖', episodeThumb: '縮略圖',
scrapingSwitchSaveFailed: '刮削開關設定保存失敗:{message}', scrapingSwitchSaveFailed: '刮削開關設定保存失敗:{message}',
scrapingSwitchSaveError: '刮削開關設定保存失敗', scrapingSwitchSaveError: '刮削開關設定保存失敗',
policy: {
skipDesc: '跳過刮削,不生成該文件',
missingOnlyDesc: '僅在缺失時刮削,已存在則保持不變',
overwriteDesc: '始終刮削,已存在則覆蓋',
}
}, },
site: { site: {
siteSync: '站點同步', siteSync: '站點同步',
+112 -186
View File
@@ -85,28 +85,57 @@ const SystemSettings = ref<any>({
}, },
}) })
// 刮削开关设 // 刮削
const ScrapingSwitchs = ref<any>({ const scrapingConfig = [
movie_nfo: true, // 电影NFO {
movie_poster: true, // 电影海报 section: 'movie',
movie_backdrop: true, // 电影背景图 items: [
movie_logo: true, // 电影Logo { key: 'movie_nfo', label: 'setting.system.movieNfo' },
movie_disc: true, // 电影光盘图 { key: 'movie_poster', label: 'setting.system.moviePoster' },
movie_banner: true, // 电影横幅图 { key: 'movie_backdrop', label: 'setting.system.movieBackdrop' },
movie_thumb: true, // 电影缩略图 { key: 'movie_logo', label: 'setting.system.movieLogo' },
tv_nfo: true, // 电视剧NFO { key: 'movie_disc', label: 'setting.system.movieDisc' },
tv_poster: true, // 电视剧海报 { key: 'movie_banner', label: 'setting.system.movieBanner' },
tv_backdrop: true, // 电视剧背景图 { key: 'movie_thumb', label: 'setting.system.movieThumb' },
tv_banner: true, // 电视剧横幅图 ],
tv_logo: true, // 电视剧Logo },
tv_thumb: true, // 电视剧缩略图 {
season_nfo: true, // 季NFO section: 'tv',
season_poster: true, // 季海报 items: [
season_banner: true, // 季横幅图 { key: 'tv_nfo', label: 'setting.system.tvNfo' },
season_thumb: true, // 季缩略图 { key: 'tv_poster', label: 'setting.system.tvPoster' },
episode_nfo: true, // 集NFO { key: 'tv_backdrop', label: 'setting.system.tvBackdrop' },
episode_thumb: true, // 集缩略图 { key: 'tv_banner', label: 'setting.system.tvBanner' },
}) { key: 'tv_logo', label: 'setting.system.tvLogo' },
{ key: 'tv_thumb', label: 'setting.system.tvThumb' },
],
},
{
section: 'season',
items: [
{ key: 'season_nfo', label: 'setting.system.seasonNfo' },
{ key: 'season_poster', label: 'setting.system.seasonPoster' },
{ key: 'season_banner', label: 'setting.system.seasonBanner' },
{ key: 'season_thumb', label: 'setting.system.seasonThumb' },
],
},
{
section: 'episode',
items: [
{ key: 'episode_nfo', label: 'setting.system.episodeNfo' },
{ key: 'episode_thumb', label: 'setting.system.episodeThumb' },
],
},
]
// 刮削策略设置
const ScrapingPolicies = ref<Record<string, 'skip' | 'missingOnly' | 'overwrite'>>(
Object.fromEntries(
scrapingConfig.flatMap(section =>
section.items.map(item => [item.key, 'missingOnly'])
)
)
)
// 是否发送请求的总开关 // 是否发送请求的总开关
const isRequest = ref(true) const isRequest = ref(true)
@@ -481,7 +510,13 @@ async function loadScrapingSwitchs() {
try { try {
const result: { [key: string]: any } = await api.get('system/setting/ScrapingSwitchs') const result: { [key: string]: any } = await api.get('system/setting/ScrapingSwitchs')
if (result.success && result.data?.value) { if (result.success && result.data?.value) {
ScrapingSwitchs.value = { ...ScrapingSwitchs.value, ...result.data.value } const loadedSwitches = result.data.value
for (const key in loadedSwitches) {
if (typeof loadedSwitches[key] === 'boolean') { // 兼容旧数据
loadedSwitches[key] = loadedSwitches[key] ? 'missingOnly' : 'skip'
}
}
ScrapingPolicies.value = { ...ScrapingPolicies.value, ...loadedSwitches }
} }
} catch (error) { } catch (error) {
console.log(error) console.log(error)
@@ -491,7 +526,7 @@ async function loadScrapingSwitchs() {
// 保存刮削开关设置 // 保存刮削开关设置
async function saveScrapingSwitchs() { async function saveScrapingSwitchs() {
try { try {
const result: { [key: string]: any } = await api.post('system/setting/ScrapingSwitchs', ScrapingSwitchs.value) const result: { [key: string]: any } = await api.post('system/setting/ScrapingSwitchs', ScrapingPolicies.value)
if (result.success) { if (result.success) {
return true return true
} else { } else {
@@ -1120,173 +1155,64 @@ onDeactivated(() => {
<VExpansionPanels> <VExpansionPanels>
<VExpansionPanel> <VExpansionPanel>
<VExpansionPanelTitle class="text-lg"> <VExpansionPanelTitle class="text-lg">
<template #default> <VIcon icon="mdi-checkbox-multiple-outline" class="me-2" />
<VIcon icon="mdi-checkbox-multiple-outline" class="me-2" /> {{ t('setting.system.scrapingSwitchSettings') }}
{{ t('setting.system.scrapingSwitchSettings') }} <!-- 帮助图标 -->
</template> <VTooltip location="bottom" open-delay="200">
<template #activator="{ props: tooltipProps }">
<VBtn
v-bind="tooltipProps"
icon="mdi-help-circle"
size="small"
variant="text"
color="medium-emphasis"
class="ml-2"
@click.stop
/>
</template>
<div class="d-flex flex-column gap-2 py-2">
<div class="d-flex align-center">
<VIcon icon="mdi-file-remove" color="error" class="mr-2" />
<span>{{ t('setting.system.policy.skipDesc') }}</span>
</div>
<div class="d-flex align-center">
<VIcon icon="mdi-file-plus" color="success" class="mr-2" />
<span>{{ t('setting.system.policy.missingOnlyDesc') }}</span>
</div>
<div class="d-flex align-center">
<VIcon icon="mdi-file-replace" color="primary" class="mr-2" />
<span>{{ t('setting.system.policy.overwriteDesc') }}</span>
</div>
</div>
</VTooltip>
</VExpansionPanelTitle> </VExpansionPanelTitle>
<VExpansionPanelText> <VExpansionPanelText>
<VRow> <VRow v-for="section in scrapingConfig" :key="section.section">
<VCol cols="12" class="pb-2"> <VCol cols="12" class="pb-2">
<VListSubheader class="text-lg">{{ t('setting.system.movie') }}</VListSubheader> <VListSubheader class="text-lg">{{ t(`setting.system.${section.section}`) }}</VListSubheader>
</VCol> </VCol>
<VCol cols="6" md="3"> <VCol
<VCheckbox v-for="item in section.items"
v-model="ScrapingSwitchs.movie_nfo" :key="item.key"
:label="t('setting.system.movieNfo')" cols="12"
density="compact" md="4"
/> >
</VCol> <div class="d-flex align-center">
<VCol cols="6" md="3"> <VBtnToggle
<VCheckbox :model-value="ScrapingPolicies[item.key]"
v-model="ScrapingSwitchs.movie_poster" @update:model-value="ScrapingPolicies[item.key] = $event"
:label="t('setting.system.moviePoster')" color="primary"
density="compact" variant="tonal"
/> rounded="lg"
</VCol> >
<VCol cols="6" md="3"> <VBtn value="skip" color="error" icon="mdi-file-remove" />
<VCheckbox <VBtn value="missingOnly" color="success" icon="mdi-file-plus" />
v-model="ScrapingSwitchs.movie_backdrop" <VBtn value="overwrite" color="primary" icon="mdi-file-replace" />
:label="t('setting.system.movieBackdrop')" </VBtnToggle>
density="compact" <span class="ml-2">{{ t(item.label) }}</span>
/> </div>
</VCol>
<VCol cols="6" md="3">
<VCheckbox
v-model="ScrapingSwitchs.movie_logo"
:label="t('setting.system.movieLogo')"
density="compact"
/>
</VCol>
<VCol cols="6" md="3">
<VCheckbox
v-model="ScrapingSwitchs.movie_disc"
:label="t('setting.system.movieDisc')"
density="compact"
/>
</VCol>
<VCol cols="6" md="3">
<VCheckbox
v-model="ScrapingSwitchs.movie_banner"
:label="t('setting.system.movieBanner')"
density="compact"
/>
</VCol>
<VCol cols="6" md="3">
<VCheckbox
v-model="ScrapingSwitchs.movie_thumb"
:label="t('setting.system.movieThumb')"
density="compact"
/>
</VCol>
</VRow>
<VDivider class="my-4" />
<VRow>
<VCol cols="12" class="pb-2">
<VListSubheader class="text-lg">{{ t('setting.system.tv') }}</VListSubheader>
</VCol>
<VCol cols="6" md="3">
<VCheckbox
v-model="ScrapingSwitchs.tv_nfo"
:label="t('setting.system.tvNfo')"
density="compact"
/>
</VCol>
<VCol cols="6" md="3">
<VCheckbox
v-model="ScrapingSwitchs.tv_poster"
:label="t('setting.system.tvPoster')"
density="compact"
/>
</VCol>
<VCol cols="6" md="3">
<VCheckbox
v-model="ScrapingSwitchs.tv_backdrop"
:label="t('setting.system.tvBackdrop')"
density="compact"
/>
</VCol>
<VCol cols="6" md="3">
<VCheckbox
v-model="ScrapingSwitchs.tv_banner"
:label="t('setting.system.tvBanner')"
density="compact"
/>
</VCol>
<VCol cols="6" md="3">
<VCheckbox
v-model="ScrapingSwitchs.tv_logo"
:label="t('setting.system.tvLogo')"
density="compact"
/>
</VCol>
<VCol cols="6" md="3">
<VCheckbox
v-model="ScrapingSwitchs.tv_thumb"
:label="t('setting.system.tvThumb')"
density="compact"
/>
</VCol>
</VRow>
<VDivider class="my-4" />
<VRow>
<VCol cols="12" class="pb-2">
<VListSubheader class="text-lg">{{ t('setting.system.season') }}</VListSubheader>
</VCol>
<VCol cols="6" md="3">
<VCheckbox
v-model="ScrapingSwitchs.season_nfo"
:label="t('setting.system.seasonNfo')"
density="compact"
/>
</VCol>
<VCol cols="6" md="3">
<VCheckbox
v-model="ScrapingSwitchs.season_poster"
:label="t('setting.system.seasonPoster')"
density="compact"
/>
</VCol>
<VCol cols="6" md="3">
<VCheckbox
v-model="ScrapingSwitchs.season_banner"
:label="t('setting.system.seasonBanner')"
density="compact"
/>
</VCol>
<VCol cols="6" md="3">
<VCheckbox
v-model="ScrapingSwitchs.season_thumb"
:label="t('setting.system.seasonThumb')"
density="compact"
/>
</VCol>
</VRow>
<VDivider class="my-4" />
<VRow>
<VCol cols="12" class="pb-2">
<VListSubheader class="text-lg">{{ t('setting.system.episode') }}</VListSubheader>
</VCol>
<VCol cols="6" md="3">
<VCheckbox
v-model="ScrapingSwitchs.episode_nfo"
:label="t('setting.system.episodeNfo')"
density="compact"
/>
</VCol>
<VCol cols="6" md="3">
<VCheckbox
v-model="ScrapingSwitchs.episode_thumb"
:label="t('setting.system.episodeThumb')"
density="compact"
/>
</VCol> </VCol>
<VDivider v-if="section.section !== 'episode'" class="my-4" />
</VRow> </VRow>
</VExpansionPanelText> </VExpansionPanelText>
</VExpansionPanel> </VExpansionPanel>