mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-07-09 22:42:21 +08:00
更新国际化支持:为存储、媒体类型、通知开关及操作步骤等组件添加多语言文本,提升用户体验
This commit is contained in:
@@ -1,85 +1,304 @@
|
|||||||
|
import i18n from '@/plugins/i18n'
|
||||||
|
|
||||||
export const storageOptions = [
|
export const storageOptions = [
|
||||||
{
|
{
|
||||||
title: '本地',
|
title: i18n.global.t('storage.local'),
|
||||||
value: 'local',
|
value: 'local',
|
||||||
icon: 'mdi-folder-multiple-outline',
|
icon: 'mdi-folder-multiple-outline',
|
||||||
remote: false,
|
remote: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '阿里云盘',
|
title: i18n.global.t('storage.alipan'),
|
||||||
value: 'alipan',
|
value: 'alipan',
|
||||||
icon: 'mdi-cloud-outline',
|
icon: 'mdi-cloud-outline',
|
||||||
remote: true,
|
remote: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '115网盘',
|
title: i18n.global.t('storage.u115'),
|
||||||
value: 'u115',
|
value: 'u115',
|
||||||
icon: 'mdi-cloud-outline',
|
icon: 'mdi-cloud-outline',
|
||||||
remote: true,
|
remote: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'RClone',
|
title: i18n.global.t('storage.rclone'),
|
||||||
value: 'rclone',
|
value: 'rclone',
|
||||||
icon: 'mdi-server-network-outline',
|
icon: 'mdi-server-network-outline',
|
||||||
remote: true,
|
remote: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'AList',
|
title: i18n.global.t('storage.alist'),
|
||||||
value: 'alist',
|
value: 'alist',
|
||||||
icon: 'mdi-server-network-outline',
|
icon: 'mdi-server-network-outline',
|
||||||
remote: true,
|
remote: true,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const innerFilterRules = [
|
|
||||||
{ title: '特效字幕', value: ' SPECSUB ' },
|
|
||||||
{ title: '中文字幕', value: ' CNSUB ' },
|
|
||||||
{ title: '国语配音', value: ' CNVOI ' },
|
|
||||||
{ title: '官种', value: ' GZ ' },
|
|
||||||
{ title: '排除: 国语配音', value: ' !CNVOI ' },
|
|
||||||
{ title: '粤语配音', value: ' HKVOI ' },
|
|
||||||
{ title: '排除: 粤语配音', value: ' !HKVOI ' },
|
|
||||||
{ title: '促销: 免费', value: ' FREE ' },
|
|
||||||
{ title: '分辨率: 4K', value: ' 4K ' },
|
|
||||||
{ title: '分辨率: 1080P', value: ' 1080P ' },
|
|
||||||
{ title: '分辨率: 720P', value: ' 720P ' },
|
|
||||||
{ title: '排除: 720P', value: ' !720P ' },
|
|
||||||
{ title: '质量: 蓝光原盘', value: ' BLU ' },
|
|
||||||
{ title: '排除: 蓝光原盘', value: ' !BLU ' },
|
|
||||||
{ title: '质量: BLURAY', value: ' BLURAY ' },
|
|
||||||
{ title: '排除: BLURAY', value: ' !BLURAY ' },
|
|
||||||
{ title: '质量: UHD', value: ' UHD ' },
|
|
||||||
{ title: '排除: UHD', value: ' !UHD ' },
|
|
||||||
{ title: '质量: REMUX', value: ' REMUX ' },
|
|
||||||
{ title: '排除: REMUX', value: ' !REMUX ' },
|
|
||||||
{ title: '质量: WEB-DL', value: ' WEBDL ' },
|
|
||||||
{ title: '排除: WEB-DL', value: ' !WEBDL ' },
|
|
||||||
{ title: '质量: 60fps', value: ' 60FPS ' },
|
|
||||||
{ title: '排除: 60fps', value: ' !60FPS ' },
|
|
||||||
{ title: '编码: H265', value: ' H265 ' },
|
|
||||||
{ title: '排除: H265', value: ' !H265 ' },
|
|
||||||
{ title: '编码: H264', value: ' H264 ' },
|
|
||||||
{ title: '排除: H264', value: ' !H264 ' },
|
|
||||||
{ title: '效果: 杜比视界', value: ' DOLBY ' },
|
|
||||||
{ title: '排除: 杜比视界', value: ' !DOLBY ' },
|
|
||||||
{ title: '效果: 杜比全景声', value: ' ATMOS ' },
|
|
||||||
{ title: '排除: 杜比全景声', value: ' !ATMOS ' },
|
|
||||||
{ title: '效果: HDR', value: ' HDR ' },
|
|
||||||
{ title: '排除: HDR', value: ' !HDR ' },
|
|
||||||
{ title: '效果: SDR', value: ' SDR ' },
|
|
||||||
{ title: '排除: SDR', value: ' !SDR ' },
|
|
||||||
{ title: '效果: 3D', value: ' 3D ' },
|
|
||||||
{ title: '排除: 3D', value: ' !3D ' },
|
|
||||||
]
|
|
||||||
|
|
||||||
export const storageDict = storageOptions.reduce((dict, item) => {
|
export const storageDict = storageOptions.reduce((dict, item) => {
|
||||||
dict[item.value] = item.title
|
dict[item.value] = item.title
|
||||||
return dict
|
return dict
|
||||||
}, {} as Record<string, string>)
|
}, {} as Record<string, string>)
|
||||||
|
|
||||||
export const transferTypeOptions = [
|
export const innerFilterRules = [
|
||||||
{ title: '复制', value: 'copy' },
|
{ title: i18n.global.t('filterRules.specSub'), value: ' SPECSUB ' },
|
||||||
{ title: '移动', value: 'move' },
|
{ title: i18n.global.t('filterRules.cnSub'), value: ' CNSUB ' },
|
||||||
{ title: '硬链接', value: 'link' },
|
{ title: i18n.global.t('filterRules.cnVoi'), value: ' CNVOI ' },
|
||||||
{ title: '软链接', value: 'softlink' },
|
{ title: i18n.global.t('filterRules.gz'), value: ' GZ ' },
|
||||||
|
{ title: i18n.global.t('filterRules.notCnVoi'), value: ' !CNVOI ' },
|
||||||
|
{ title: i18n.global.t('filterRules.hkVoi'), value: ' HKVOI ' },
|
||||||
|
{ title: i18n.global.t('filterRules.notHkVoi'), value: ' !HKVOI ' },
|
||||||
|
{ title: i18n.global.t('filterRules.free'), value: ' FREE ' },
|
||||||
|
{ title: i18n.global.t('filterRules.resolution4k'), value: ' 4K ' },
|
||||||
|
{ title: i18n.global.t('filterRules.resolution1080p'), value: ' 1080P ' },
|
||||||
|
{ title: i18n.global.t('filterRules.resolution720p'), value: ' 720P ' },
|
||||||
|
{ title: i18n.global.t('filterRules.not720p'), value: ' !720P ' },
|
||||||
|
{ title: i18n.global.t('filterRules.qualityBlu'), value: ' BLU ' },
|
||||||
|
{ title: i18n.global.t('filterRules.notBlu'), value: ' !BLU ' },
|
||||||
|
{ title: i18n.global.t('filterRules.qualityBluray'), value: ' BLURAY ' },
|
||||||
|
{ title: i18n.global.t('filterRules.notBluray'), value: ' !BLURAY ' },
|
||||||
|
{ title: i18n.global.t('filterRules.qualityUhd'), value: ' UHD ' },
|
||||||
|
{ title: i18n.global.t('filterRules.notUhd'), value: ' !UHD ' },
|
||||||
|
{ title: i18n.global.t('filterRules.qualityRemux'), value: ' REMUX ' },
|
||||||
|
{ title: i18n.global.t('filterRules.notRemux'), value: ' !REMUX ' },
|
||||||
|
{ title: i18n.global.t('filterRules.qualityWebdl'), value: ' WEBDL ' },
|
||||||
|
{ title: i18n.global.t('filterRules.notWebdl'), value: ' !WEBDL ' },
|
||||||
|
{ title: i18n.global.t('filterRules.quality60fps'), value: ' 60FPS ' },
|
||||||
|
{ title: i18n.global.t('filterRules.not60fps'), value: ' !60FPS ' },
|
||||||
|
{ title: i18n.global.t('filterRules.codecH265'), value: ' H265 ' },
|
||||||
|
{ title: i18n.global.t('filterRules.notH265'), value: ' !H265 ' },
|
||||||
|
{ title: i18n.global.t('filterRules.codecH264'), value: ' H264 ' },
|
||||||
|
{ title: i18n.global.t('filterRules.notH264'), value: ' !H264 ' },
|
||||||
|
{ title: i18n.global.t('filterRules.effectDolby'), value: ' DOLBY ' },
|
||||||
|
{ title: i18n.global.t('filterRules.notDolby'), value: ' !DOLBY ' },
|
||||||
|
{ title: i18n.global.t('filterRules.effectAtmos'), value: ' ATMOS ' },
|
||||||
|
{ title: i18n.global.t('filterRules.notAtmos'), value: ' !ATMOS ' },
|
||||||
|
{ title: i18n.global.t('filterRules.effectHdr'), value: ' HDR ' },
|
||||||
|
{ title: i18n.global.t('filterRules.notHdr'), value: ' !HDR ' },
|
||||||
|
{ title: i18n.global.t('filterRules.effectSdr'), value: ' SDR ' },
|
||||||
|
{ title: i18n.global.t('filterRules.notSdr'), value: ' !SDR ' },
|
||||||
|
{ title: i18n.global.t('filterRules.effect3d'), value: ' 3D ' },
|
||||||
|
{ title: i18n.global.t('filterRules.not3d'), value: ' !3D ' },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export const transferTypeOptions = [
|
||||||
|
{ title: i18n.global.t('transferType.copy'), value: 'copy' },
|
||||||
|
{ title: i18n.global.t('transferType.move'), value: 'move' },
|
||||||
|
{ title: i18n.global.t('transferType.link'), value: 'link' },
|
||||||
|
{ title: i18n.global.t('transferType.softlink'), value: 'softlink' },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const qualityOptions = ref([
|
||||||
|
{
|
||||||
|
title: i18n.global.t('qualityOptions.all'),
|
||||||
|
value: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('qualityOptions.blurayOriginal'),
|
||||||
|
value: 'Blu-?Ray.+VC-?1|Blu-?Ray.+AVC|UHD.+blu-?ray.+HEVC|MiniBD',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('qualityOptions.remux'),
|
||||||
|
value: 'Remux',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('qualityOptions.bluray'),
|
||||||
|
value: 'Blu-?Ray',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('qualityOptions.uhd'),
|
||||||
|
value: 'UHD|UltraHD',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('qualityOptions.webdl'),
|
||||||
|
value: 'WEB-?DL|WEB-?RIP',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('qualityOptions.hdtv'),
|
||||||
|
value: 'HDTV',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('qualityOptions.h265'),
|
||||||
|
value: '[Hx].?265|HEVC',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('qualityOptions.h264'),
|
||||||
|
value: '[Hx].?264|AVC',
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
// 分辨率选择框数据
|
||||||
|
export const resolutionOptions = ref([
|
||||||
|
{
|
||||||
|
title: i18n.global.t('resolutionOptions.all'),
|
||||||
|
value: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('resolutionOptions.4k'),
|
||||||
|
value: '4K|2160p|x2160',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('resolutionOptions.1080p'),
|
||||||
|
value: '1080[pi]|x1080',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('resolutionOptions.720p'),
|
||||||
|
value: '720[pi]|x720',
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
// 特效选择框数据
|
||||||
|
export const effectOptions = ref([
|
||||||
|
{
|
||||||
|
title: i18n.global.t('effectOptions.all'),
|
||||||
|
value: '',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('effectOptions.dolbyVision'),
|
||||||
|
value: 'Dolby[\\s.]+Vision|DOVI|[\\s.]+DV[\\s.]+',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('effectOptions.dolbyAtmos'),
|
||||||
|
value: 'Dolby[\\s.]*\\+?Atmos|Atmos',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('effectOptions.hdr'),
|
||||||
|
value: '[\\s.]+HDR[\\s.]+|HDR10|HDR10\\+',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('effectOptions.sdr'),
|
||||||
|
value: '[\\s.]+SDR[\\s.]+',
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
// 媒体类型选项
|
||||||
|
export const mediaTypeOptions = [
|
||||||
|
{
|
||||||
|
title: i18n.global.t('mediaType.movie'),
|
||||||
|
value: '电影',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('mediaType.tv'),
|
||||||
|
value: '电视剧',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('mediaType.anime'),
|
||||||
|
value: '动漫',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('mediaType.collection'),
|
||||||
|
value: '合集',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('mediaType.unknown'),
|
||||||
|
value: '未知',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
// 媒体类型字典
|
||||||
|
export const mediaTypeDict = mediaTypeOptions.reduce((dict, item) => {
|
||||||
|
dict[item.value] = item.title
|
||||||
|
return dict
|
||||||
|
}, {} as Record<string, string>)
|
||||||
|
|
||||||
|
// 通知开关选项
|
||||||
|
export const notificationSwitchOptions = [
|
||||||
|
{
|
||||||
|
title: i18n.global.t('notificationSwitch.resourceDownload'),
|
||||||
|
value: '资源下载',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('notificationSwitch.organize'),
|
||||||
|
value: '整理入库',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('notificationSwitch.subscribe'),
|
||||||
|
value: '订阅',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('notificationSwitch.site'),
|
||||||
|
value: '站点',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('notificationSwitch.mediaServer'),
|
||||||
|
value: '媒体服务器',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('notificationSwitch.manual'),
|
||||||
|
value: '手动处理',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('notificationSwitch.plugin'),
|
||||||
|
value: '插件',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('notificationSwitch.other'),
|
||||||
|
value: '其它',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
// 通知开关字典
|
||||||
|
export const notificationSwitchDict = notificationSwitchOptions.reduce((dict, item) => {
|
||||||
|
dict[item.value] = item.title
|
||||||
|
return dict
|
||||||
|
}, {} as Record<string, string>)
|
||||||
|
|
||||||
|
// 操作步骤选项
|
||||||
|
export const actionStepOptions = [
|
||||||
|
{
|
||||||
|
title: i18n.global.t('actionStep.addDownload'),
|
||||||
|
value: '添加下载',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('actionStep.addSubscribe'),
|
||||||
|
value: '添加订阅',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('actionStep.fetchDownloads'),
|
||||||
|
value: '获取下载任务',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('actionStep.fetchMedias'),
|
||||||
|
value: '获取媒体数据',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('actionStep.fetchRss'),
|
||||||
|
value: '获取RSS资源',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('actionStep.fetchTorrents'),
|
||||||
|
value: '搜索站点资源',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('actionStep.filterMedias'),
|
||||||
|
value: '过滤媒体数据',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('actionStep.filterTorrents'),
|
||||||
|
value: '过滤资源',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('actionStep.scanFile'),
|
||||||
|
value: '扫描目录',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('actionStep.scrapeFile'),
|
||||||
|
value: '刮削文件',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('actionStep.sendEvent'),
|
||||||
|
value: '发送事件',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('actionStep.sendMessage'),
|
||||||
|
value: '发送消息',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18n.global.t('actionStep.transferFile'),
|
||||||
|
value: '整理文件',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
// 操作步骤字典
|
||||||
|
export const actionStepDict = actionStepOptions.reduce((dict, item) => {
|
||||||
|
dict[item.value] = item.title
|
||||||
|
return dict
|
||||||
|
}, {} as Record<string, string>)
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ function onClose() {
|
|||||||
<VImg :src="filter_svg" cover class="mt-7" max-width="3rem" />
|
<VImg :src="filter_svg" cover class="mt-7" max-width="3rem" />
|
||||||
</VCardText>
|
</VCardText>
|
||||||
</VCard>
|
</VCard>
|
||||||
<VDialog v-if="ruleInfoDialog" v-model="ruleInfoDialog" scrollable max-width="40rem" persistent>
|
<VDialog v-if="ruleInfoDialog" v-model="ruleInfoDialog" scrollable max-width="40rem">
|
||||||
<VCard :title="t('customRule.title', { id: props.rule.id })" class="rounded-t">
|
<VCard :title="t('customRule.title', { id: props.rule.id })" class="rounded-t">
|
||||||
<VDialogCloseBtn v-model="ruleInfoDialog" />
|
<VDialogCloseBtn v-model="ruleInfoDialog" />
|
||||||
<VDivider />
|
<VDivider />
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ function onClose() {
|
|||||||
<VImg :src="filter_group_svg" cover class="mt-10" max-width="3rem" />
|
<VImg :src="filter_group_svg" cover class="mt-10" max-width="3rem" />
|
||||||
</VCardText>
|
</VCardText>
|
||||||
</VCard>
|
</VCard>
|
||||||
<VDialog v-if="groupInfoDialog" v-model="groupInfoDialog" scrollable max-width="80rem" persistent>
|
<VDialog v-if="groupInfoDialog" v-model="groupInfoDialog" scrollable max-width="80rem">
|
||||||
<VCard :title="`${props.group.name} - ${t('filterRule.title')}`" class="rounded-t">
|
<VCard :title="`${props.group.name} - ${t('filterRule.title')}`" class="rounded-t">
|
||||||
<VDialogCloseBtn v-model="groupInfoDialog" />
|
<VDialogCloseBtn v-model="groupInfoDialog" />
|
||||||
<VDivider />
|
<VDivider />
|
||||||
@@ -228,9 +228,9 @@ function onClose() {
|
|||||||
<VCol cols="12" md="6">
|
<VCol cols="12" md="6">
|
||||||
<VTextField
|
<VTextField
|
||||||
v-model="groupInfo.name"
|
v-model="groupInfo.name"
|
||||||
:label="t('filterRule.name')"
|
:label="t('filterRule.groupName')"
|
||||||
:placeholder="t('filterRule.nameRequired')"
|
:placeholder="t('filterRule.nameRequired')"
|
||||||
:hint="t('filterRule.name')"
|
:hint="t('filterRule.groupName')"
|
||||||
persistent-hint
|
persistent-hint
|
||||||
active
|
active
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import SubscribeEditDialog from '../dialog/SubscribeEditDialog.vue'
|
|||||||
import SearchSiteDialog from '@/components/dialog/SearchSiteDialog.vue'
|
import SearchSiteDialog from '@/components/dialog/SearchSiteDialog.vue'
|
||||||
import SubscribeSeasonDialog from '../dialog/SubscribeSeasonDialog.vue'
|
import SubscribeSeasonDialog from '../dialog/SubscribeSeasonDialog.vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { getMediaTypeText } from '@/types/i18n-type'
|
import { mediaTypeDict } from '@/api/constants'
|
||||||
|
|
||||||
// 国际化
|
// 国际化
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
@@ -402,15 +402,6 @@ function setupIntersectionObserver() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
setupIntersectionObserver()
|
|
||||||
})
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
observer.value?.disconnect()
|
|
||||||
observer.value = null
|
|
||||||
})
|
|
||||||
|
|
||||||
// 计算图片地址
|
// 计算图片地址
|
||||||
const getImgUrl: Ref<string> = computed(() => {
|
const getImgUrl: Ref<string> = computed(() => {
|
||||||
if (imageLoadError.value) return noImage
|
if (imageLoadError.value) return noImage
|
||||||
@@ -428,6 +419,21 @@ const getImgUrl: Ref<string> = computed(() => {
|
|||||||
function onRemoveSubscribe() {
|
function onRemoveSubscribe() {
|
||||||
subscribeEditDialog.value = false
|
subscribeEditDialog.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取媒体类型文本
|
||||||
|
function getMediaTypeText(type: string | undefined) {
|
||||||
|
if (!type) return ''
|
||||||
|
return mediaTypeDict[type]
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
setupIntersectionObserver()
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
observer.value?.disconnect()
|
||||||
|
observer.value = null
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ onMounted(() => {
|
|||||||
<VImg :src="getIcon" cover class="mt-7 me-3" max-width="3rem" min-width="3rem" />
|
<VImg :src="getIcon" cover class="mt-7 me-3" max-width="3rem" min-width="3rem" />
|
||||||
</VCardText>
|
</VCardText>
|
||||||
</VCard>
|
</VCard>
|
||||||
<VDialog v-if="mediaServerInfoDialog" v-model="mediaServerInfoDialog" scrollable max-width="40rem" persistent>
|
<VDialog v-if="mediaServerInfoDialog" v-model="mediaServerInfoDialog" scrollable max-width="40rem">
|
||||||
<VCard :title="`${props.mediaserver.name} - ${t('common.config')}`" class="rounded-t">
|
<VCard :title="`${props.mediaserver.name} - ${t('common.config')}`" class="rounded-t">
|
||||||
<VDialogCloseBtn v-model="mediaServerInfoDialog" />
|
<VDialogCloseBtn v-model="mediaServerInfoDialog" />
|
||||||
<VDivider />
|
<VDivider />
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ function onClose() {
|
|||||||
<VImg :src="getIcon" cover class="mt-7 me-3" max-width="3rem" />
|
<VImg :src="getIcon" cover class="mt-7 me-3" max-width="3rem" />
|
||||||
</VCardText>
|
</VCardText>
|
||||||
</VCard>
|
</VCard>
|
||||||
<VDialog v-if="notificationInfoDialog" v-model="notificationInfoDialog" scrollable max-width="40rem" persistent>
|
<VDialog v-if="notificationInfoDialog" v-model="notificationInfoDialog" scrollable max-width="40rem">
|
||||||
<VCard :title="`${props.notification.name} - ${t('notification.config')}`" class="rounded-t">
|
<VCard :title="`${props.notification.name} - ${t('notification.config')}`" class="rounded-t">
|
||||||
<VDialogCloseBtn v-model="notificationInfoDialog" />
|
<VDialogCloseBtn v-model="notificationInfoDialog" />
|
||||||
<VDivider />
|
<VDivider />
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import AlistConfigDialog from '../dialog/AlistConfigDialog.vue'
|
|||||||
import { useToast } from 'vue-toast-notification'
|
import { useToast } from 'vue-toast-notification'
|
||||||
import { isNullOrEmptyObject } from '@/@core/utils'
|
import { isNullOrEmptyObject } from '@/@core/utils'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { storageOptions } from '@/api/constants'
|
||||||
|
|
||||||
// 国际化
|
// 国际化
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
@@ -127,6 +128,11 @@ function handleDone() {
|
|||||||
emit('done')
|
emit('done')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 根据存储类型获取文本
|
||||||
|
function getStorageTypeText(type: string) {
|
||||||
|
return storageOptions.find((option) => option.value === type)?.title
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
queryStorage()
|
queryStorage()
|
||||||
})
|
})
|
||||||
@@ -136,7 +142,7 @@ onMounted(() => {
|
|||||||
<VCard variant="tonal" @click="openStorageDialog">
|
<VCard variant="tonal" @click="openStorageDialog">
|
||||||
<VCardText class="flex justify-space-between align-center gap-3">
|
<VCardText class="flex justify-space-between align-center gap-3">
|
||||||
<div class="align-self-start flex-1">
|
<div class="align-self-start flex-1">
|
||||||
<h5 class="text-h6 mb-1">{{ storage.name }}</h5>
|
<h5 class="text-h6 mb-1">{{ getStorageTypeText(storage.type) }}</h5>
|
||||||
<div class="mb-3 text-sm" v-if="total">{{ formatBytes(used, 1) }} / {{ formatBytes(total, 1) }}</div>
|
<div class="mb-3 text-sm" v-if="total">{{ formatBytes(used, 1) }} / {{ formatBytes(total, 1) }}</div>
|
||||||
<div v-else-if="isNullOrEmptyObject(storage.config)">{{ t('storage.notConfigured') }}</div>
|
<div v-else-if="isNullOrEmptyObject(storage.config)">{{ t('storage.notConfigured') }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ function handleImport() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VDialog width="40rem" scrollable max-height="85vh" persistent>
|
<VDialog width="40rem" scrollable max-height="85vh">
|
||||||
<VCard :title="props.title" class="rounded-t">
|
<VCard :title="props.title" class="rounded-t">
|
||||||
<VDialogCloseBtn @click="emit('close')" />
|
<VDialogCloseBtn @click="emit('close')" />
|
||||||
<VCardText class="pt-2">
|
<VCardText class="pt-2">
|
||||||
|
|||||||
@@ -335,7 +335,7 @@ onMounted(() => {
|
|||||||
<VList lines="two" v-if="searchWord" class="search-list py-2">
|
<VList lines="two" v-if="searchWord" class="search-list py-2">
|
||||||
<!-- 搜索结果分组标题 -->
|
<!-- 搜索结果分组标题 -->
|
||||||
<VListSubheader class="font-weight-medium text-uppercase py-2 px-4 px-sm-6">
|
<VListSubheader class="font-weight-medium text-uppercase py-2 px-4 px-sm-6">
|
||||||
{{ t('media.movie') }}
|
{{ t('common.media') }}
|
||||||
</VListSubheader>
|
</VListSubheader>
|
||||||
|
|
||||||
<!-- 媒体搜索选项 -->
|
<!-- 媒体搜索选项 -->
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import type { DownloaderConf, FilterRuleGroup, Site, Subscribe, TransferDirector
|
|||||||
import { useDisplay } from 'vuetify'
|
import { useDisplay } from 'vuetify'
|
||||||
import { useConfirm } from 'vuetify-use-dialog'
|
import { useConfirm } from 'vuetify-use-dialog'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { qualityOptions, resolutionOptions, effectOptions } from '@/api/constants'
|
||||||
// i18n
|
// i18n
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
@@ -269,90 +269,6 @@ const targetDirectories = computed(() => {
|
|||||||
return downloadDirectories.value.map(item => item.download_path)
|
return downloadDirectories.value.map(item => item.download_path)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 质量选择框数据
|
|
||||||
const qualityOptions = ref([
|
|
||||||
{
|
|
||||||
title: t('common.all'),
|
|
||||||
value: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '蓝光原盘',
|
|
||||||
value: 'Blu-?Ray.+VC-?1|Blu-?Ray.+AVC|UHD.+blu-?ray.+HEVC|MiniBD',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Remux',
|
|
||||||
value: 'Remux',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'BluRay',
|
|
||||||
value: 'Blu-?Ray',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'UHD',
|
|
||||||
value: 'UHD|UltraHD',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'WEB-DL',
|
|
||||||
value: 'WEB-?DL|WEB-?RIP',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'HDTV',
|
|
||||||
value: 'HDTV',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'H265',
|
|
||||||
value: '[Hx].?265|HEVC',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'H264',
|
|
||||||
value: '[Hx].?264|AVC',
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
// 分辨率选择框数据
|
|
||||||
const resolutionOptions = ref([
|
|
||||||
{
|
|
||||||
title: t('common.all'),
|
|
||||||
value: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '4k',
|
|
||||||
value: '4K|2160p|x2160',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '1080p',
|
|
||||||
value: '1080[pi]|x1080',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '720p',
|
|
||||||
value: '720[pi]|x720',
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
// 特效选择框数据
|
|
||||||
const effectOptions = ref([
|
|
||||||
{
|
|
||||||
title: t('common.all'),
|
|
||||||
value: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '杜比视界',
|
|
||||||
value: 'Dolby[\\s.]+Vision|DOVI|[\\s.]+DV[\\s.]+',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '杜比全景声',
|
|
||||||
value: 'Dolby[\\s.]*\\+?Atmos|Atmos',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'HDR',
|
|
||||||
value: '[\\s.]+HDR[\\s.]+|HDR10|HDR10\\+',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'SDR',
|
|
||||||
value: '[\\s.]+SDR[\\s.]+',
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
queryFilterRuleGroups()
|
queryFilterRuleGroups()
|
||||||
loadDownloadDirectories()
|
loadDownloadDirectories()
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { formatDateDifference } from '@core/utils/formatters'
|
|||||||
import { useDisplay } from 'vuetify'
|
import { useDisplay } from 'vuetify'
|
||||||
import ProgressDialog from './ProgressDialog.vue'
|
import ProgressDialog from './ProgressDialog.vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { getMediaTypeText } from '@/types/i18n-type'
|
import { mediaTypeDict } from '@/api/constants'
|
||||||
|
|
||||||
// 国际化
|
// 国际化
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
@@ -137,6 +137,12 @@ const dropdownItems = ref([
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
|
// 获取媒体类型文本
|
||||||
|
function getMediaTypeText(type: string | undefined) {
|
||||||
|
if (!type) return ''
|
||||||
|
return mediaTypeDict[type]
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import api from '@/api'
|
|||||||
import { FilterRuleGroup } from '@/api/types'
|
import { FilterRuleGroup } from '@/api/types'
|
||||||
import { Handle, Position } from '@vue-flow/core'
|
import { Handle, Position } from '@vue-flow/core'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { qualityOptions, resolutionOptions, effectOptions } from '@/api/constants'
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
@@ -17,90 +18,6 @@ defineProps({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
// 质量选择框数据
|
|
||||||
const qualityOptions = ref([
|
|
||||||
{
|
|
||||||
title: t('workflow.filterTorrents.qualityOptions.all'),
|
|
||||||
value: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('workflow.filterTorrents.qualityOptions.blurayOriginal'),
|
|
||||||
value: 'Blu-?Ray.+VC-?1|Blu-?Ray.+AVC|UHD.+blu-?ray.+HEVC|MiniBD',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('workflow.filterTorrents.qualityOptions.remux'),
|
|
||||||
value: 'Remux',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('workflow.filterTorrents.qualityOptions.bluray'),
|
|
||||||
value: 'Blu-?Ray',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('workflow.filterTorrents.qualityOptions.uhd'),
|
|
||||||
value: 'UHD|UltraHD',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('workflow.filterTorrents.qualityOptions.webdl'),
|
|
||||||
value: 'WEB-?DL|WEB-?RIP',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('workflow.filterTorrents.qualityOptions.hdtv'),
|
|
||||||
value: 'HDTV',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('workflow.filterTorrents.qualityOptions.h265'),
|
|
||||||
value: '[Hx].?265|HEVC',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('workflow.filterTorrents.qualityOptions.h264'),
|
|
||||||
value: '[Hx].?264|AVC',
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
// 分辨率选择框数据
|
|
||||||
const resolutionOptions = ref([
|
|
||||||
{
|
|
||||||
title: t('workflow.filterTorrents.resolutionOptions.all'),
|
|
||||||
value: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('workflow.filterTorrents.resolutionOptions.4k'),
|
|
||||||
value: '4K|2160p|x2160',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('workflow.filterTorrents.resolutionOptions.1080p'),
|
|
||||||
value: '1080[pi]|x1080',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('workflow.filterTorrents.resolutionOptions.720p'),
|
|
||||||
value: '720[pi]|x720',
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
// 特效选择框数据
|
|
||||||
const effectOptions = ref([
|
|
||||||
{
|
|
||||||
title: t('workflow.filterTorrents.effectOptions.all'),
|
|
||||||
value: '',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('workflow.filterTorrents.effectOptions.dolbyVision'),
|
|
||||||
value: 'Dolby[\\s.]+Vision|DOVI|[\\s.]+DV[\\s.]+',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('workflow.filterTorrents.effectOptions.dolbyAtmos'),
|
|
||||||
value: 'Dolby[\\s.]*\\+?Atmos|Atmos',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('workflow.filterTorrents.effectOptions.hdr'),
|
|
||||||
value: '[\\s.]+HDR[\\s.]+|HDR10|HDR10\\+',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: t('workflow.filterTorrents.effectOptions.sdr'),
|
|
||||||
value: '[\\s.]+SDR[\\s.]+',
|
|
||||||
},
|
|
||||||
])
|
|
||||||
|
|
||||||
// 所有规则组列表
|
// 所有规则组列表
|
||||||
const filterRuleGroups = ref<FilterRuleGroup[]>([])
|
const filterRuleGroups = ref<FilterRuleGroup[]>([])
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import api from '@/api'
|
|||||||
import useDragAndDrop from '@core/utils/workflow'
|
import useDragAndDrop from '@core/utils/workflow'
|
||||||
import { useDisplay } from 'vuetify'
|
import { useDisplay } from 'vuetify'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { getActionStepText } from '@/types/i18n-type'
|
import { actionStepDict } from '@/api/constants'
|
||||||
|
|
||||||
interface ActionItem {
|
interface ActionItem {
|
||||||
name: string
|
name: string
|
||||||
@@ -95,6 +95,12 @@ watch(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 获取动作步骤文本
|
||||||
|
function getActionStepText(type: string | undefined) {
|
||||||
|
if (!type) return ''
|
||||||
|
return actionStepDict[type]
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
load_actions()
|
load_actions()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ export default {
|
|||||||
files: 'Files',
|
files: 'Files',
|
||||||
share: 'Share',
|
share: 'Share',
|
||||||
unsubscribe: 'Unsubscribe',
|
unsubscribe: 'Unsubscribe',
|
||||||
|
media: 'Media',
|
||||||
},
|
},
|
||||||
mediaType: {
|
mediaType: {
|
||||||
movie: 'Movie',
|
movie: 'Movie',
|
||||||
@@ -70,6 +71,30 @@ export default {
|
|||||||
sendMessage: 'Send Message',
|
sendMessage: 'Send Message',
|
||||||
transferFile: 'Transfer File',
|
transferFile: 'Transfer File',
|
||||||
},
|
},
|
||||||
|
qualityOptions: {
|
||||||
|
all: 'All',
|
||||||
|
blurayOriginal: 'Blu-ray Original',
|
||||||
|
remux: 'Remux',
|
||||||
|
bluray: 'BluRay',
|
||||||
|
uhd: 'UHD',
|
||||||
|
webdl: 'WEB-DL',
|
||||||
|
hdtv: 'HDTV',
|
||||||
|
h265: 'H265',
|
||||||
|
h264: 'H264',
|
||||||
|
},
|
||||||
|
resolutionOptions: {
|
||||||
|
all: 'All',
|
||||||
|
'4k': '4K',
|
||||||
|
'1080p': '1080p',
|
||||||
|
'720p': '720p',
|
||||||
|
},
|
||||||
|
effectOptions: {
|
||||||
|
all: 'All',
|
||||||
|
dolbyVision: 'Dolby Vision',
|
||||||
|
dolbyAtmos: 'Dolby Atmos',
|
||||||
|
hdr: 'HDR',
|
||||||
|
sdr: 'SDR',
|
||||||
|
},
|
||||||
theme: {
|
theme: {
|
||||||
light: 'Light',
|
light: 'Light',
|
||||||
dark: 'Dark',
|
dark: 'Dark',
|
||||||
@@ -249,7 +274,9 @@ export default {
|
|||||||
empty: 'No Notifications',
|
empty: 'No Notifications',
|
||||||
channel: 'Notification Channel',
|
channel: 'Notification Channel',
|
||||||
name: 'Name',
|
name: 'Name',
|
||||||
|
nameHint: 'Name of notification channel',
|
||||||
type: 'Type',
|
type: 'Type',
|
||||||
|
typeHint: 'Type of notification channel',
|
||||||
enabled: 'Enabled',
|
enabled: 'Enabled',
|
||||||
config: 'Configuration',
|
config: 'Configuration',
|
||||||
wechat: {
|
wechat: {
|
||||||
@@ -496,32 +523,8 @@ export default {
|
|||||||
title: 'Filter Resources',
|
title: 'Filter Resources',
|
||||||
subtitle: 'Filter resource list',
|
subtitle: 'Filter resource list',
|
||||||
quality: 'Quality',
|
quality: 'Quality',
|
||||||
qualityOptions: {
|
|
||||||
all: 'All',
|
|
||||||
blurayOriginal: 'Blu-ray Original',
|
|
||||||
remux: 'Remux',
|
|
||||||
bluray: 'BluRay',
|
|
||||||
uhd: 'UHD',
|
|
||||||
webdl: 'WEB-DL',
|
|
||||||
hdtv: 'HDTV',
|
|
||||||
h265: 'H265',
|
|
||||||
h264: 'H264',
|
|
||||||
},
|
|
||||||
resolution: 'Resolution',
|
resolution: 'Resolution',
|
||||||
resolutionOptions: {
|
|
||||||
all: 'All',
|
|
||||||
'4k': '4K',
|
|
||||||
'1080p': '1080p',
|
|
||||||
'720p': '720p',
|
|
||||||
},
|
|
||||||
effect: 'Effect',
|
effect: 'Effect',
|
||||||
effectOptions: {
|
|
||||||
all: 'All',
|
|
||||||
dolbyVision: 'Dolby Vision',
|
|
||||||
dolbyAtmos: 'Dolby Atmos',
|
|
||||||
hdr: 'HDR',
|
|
||||||
sdr: 'SDR',
|
|
||||||
},
|
|
||||||
size: 'Size Range',
|
size: 'Size Range',
|
||||||
include: 'Include (Keywords, Regex)',
|
include: 'Include (Keywords, Regex)',
|
||||||
exclude: 'Exclude (Keywords, Regex)',
|
exclude: 'Exclude (Keywords, Regex)',
|
||||||
@@ -727,6 +730,57 @@ export default {
|
|||||||
usedPercent: '{percent}% Used',
|
usedPercent: '{percent}% Used',
|
||||||
noConfigNeeded: 'This storage type does not require configuration, please configure the directory directly!',
|
noConfigNeeded: 'This storage type does not require configuration, please configure the directory directly!',
|
||||||
notConfigured: 'Not Configured',
|
notConfigured: 'Not Configured',
|
||||||
|
local: 'Local',
|
||||||
|
alipan: 'Aliyun Drive',
|
||||||
|
u115: '115 Cloud',
|
||||||
|
rclone: 'RClone',
|
||||||
|
alist: 'AList',
|
||||||
|
},
|
||||||
|
filterRules: {
|
||||||
|
specSub: 'Special Subtitle',
|
||||||
|
cnSub: 'Chinese Subtitle',
|
||||||
|
cnVoi: 'Chinese Dubbing',
|
||||||
|
gz: 'Official Seed',
|
||||||
|
notCnVoi: 'Exclude: Chinese Dubbing',
|
||||||
|
hkVoi: 'Cantonese Dubbing',
|
||||||
|
notHkVoi: 'Exclude: Cantonese Dubbing',
|
||||||
|
free: 'Promotion: Free',
|
||||||
|
resolution4k: 'Resolution: 4K',
|
||||||
|
resolution1080p: 'Resolution: 1080P',
|
||||||
|
resolution720p: 'Resolution: 720P',
|
||||||
|
not720p: 'Exclude: 720P',
|
||||||
|
qualityBlu: 'Quality: Blu-ray',
|
||||||
|
notBlu: 'Exclude: Blu-ray',
|
||||||
|
qualityBluray: 'Quality: BLURAY',
|
||||||
|
notBluray: 'Exclude: BLURAY',
|
||||||
|
qualityUhd: 'Quality: UHD',
|
||||||
|
notUhd: 'Exclude: UHD',
|
||||||
|
qualityRemux: 'Quality: REMUX',
|
||||||
|
notRemux: 'Exclude: REMUX',
|
||||||
|
qualityWebdl: 'Quality: WEB-DL',
|
||||||
|
notWebdl: 'Exclude: WEB-DL',
|
||||||
|
quality60fps: 'Quality: 60fps',
|
||||||
|
not60fps: 'Exclude: 60fps',
|
||||||
|
codecH265: 'Codec: H265',
|
||||||
|
notH265: 'Exclude: H265',
|
||||||
|
codecH264: 'Codec: H264',
|
||||||
|
notH264: 'Exclude: H264',
|
||||||
|
effectDolby: 'Effect: Dolby Vision',
|
||||||
|
notDolby: 'Exclude: Dolby Vision',
|
||||||
|
effectAtmos: 'Effect: Dolby Atmos',
|
||||||
|
notAtmos: 'Exclude: Dolby Atmos',
|
||||||
|
effectHdr: 'Effect: HDR',
|
||||||
|
notHdr: 'Exclude: HDR',
|
||||||
|
effectSdr: 'Effect: SDR',
|
||||||
|
notSdr: 'Exclude: SDR',
|
||||||
|
effect3d: 'Effect: 3D',
|
||||||
|
not3d: 'Exclude: 3D',
|
||||||
|
},
|
||||||
|
transferType: {
|
||||||
|
copy: 'Copy',
|
||||||
|
move: 'Move',
|
||||||
|
link: 'Hard Link',
|
||||||
|
softlink: 'Soft Link',
|
||||||
},
|
},
|
||||||
site: {
|
site: {
|
||||||
noSites: 'No Sites',
|
noSites: 'No Sites',
|
||||||
@@ -2043,7 +2097,7 @@ export default {
|
|||||||
},
|
},
|
||||||
filterRule: {
|
filterRule: {
|
||||||
title: 'Filter Rule',
|
title: 'Filter Rule',
|
||||||
name: 'Name',
|
groupName: 'Group Name',
|
||||||
priority: 'Priority',
|
priority: 'Priority',
|
||||||
rules: 'Rules',
|
rules: 'Rules',
|
||||||
add: 'Add Rule',
|
add: 'Add Rule',
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ export default {
|
|||||||
files: '文件',
|
files: '文件',
|
||||||
share: '分享',
|
share: '分享',
|
||||||
unsubscribe: '取消订阅',
|
unsubscribe: '取消订阅',
|
||||||
|
media: '媒体',
|
||||||
},
|
},
|
||||||
mediaType: {
|
mediaType: {
|
||||||
movie: '电影',
|
movie: '电影',
|
||||||
@@ -70,6 +71,30 @@ export default {
|
|||||||
sendMessage: '发送消息',
|
sendMessage: '发送消息',
|
||||||
transferFile: '整理文件',
|
transferFile: '整理文件',
|
||||||
},
|
},
|
||||||
|
qualityOptions: {
|
||||||
|
all: '全部',
|
||||||
|
blurayOriginal: '蓝光原盘',
|
||||||
|
remux: 'Remux',
|
||||||
|
bluray: 'BluRay',
|
||||||
|
uhd: 'UHD',
|
||||||
|
webdl: 'WEB-DL',
|
||||||
|
hdtv: 'HDTV',
|
||||||
|
h265: 'H265',
|
||||||
|
h264: 'H264',
|
||||||
|
},
|
||||||
|
resolutionOptions: {
|
||||||
|
all: '全部',
|
||||||
|
'4k': '4k',
|
||||||
|
'1080p': '1080p',
|
||||||
|
'720p': '720p',
|
||||||
|
},
|
||||||
|
effectOptions: {
|
||||||
|
all: '全部',
|
||||||
|
dolbyVision: '杜比视界',
|
||||||
|
dolbyAtmos: '杜比全景声',
|
||||||
|
hdr: 'HDR',
|
||||||
|
sdr: 'SDR',
|
||||||
|
},
|
||||||
theme: {
|
theme: {
|
||||||
light: '浅色',
|
light: '浅色',
|
||||||
dark: '深色',
|
dark: '深色',
|
||||||
@@ -248,7 +273,9 @@ export default {
|
|||||||
empty: '暂无通知',
|
empty: '暂无通知',
|
||||||
channel: '通知渠道',
|
channel: '通知渠道',
|
||||||
name: '名称',
|
name: '名称',
|
||||||
|
nameHint: '通知渠道名称',
|
||||||
type: '类型',
|
type: '类型',
|
||||||
|
typeHint: '通知渠道类型',
|
||||||
enabled: '启用',
|
enabled: '启用',
|
||||||
config: '配置',
|
config: '配置',
|
||||||
wechat: {
|
wechat: {
|
||||||
@@ -494,32 +521,8 @@ export default {
|
|||||||
title: '过滤资源',
|
title: '过滤资源',
|
||||||
subtitle: '对资源列表数据进行过滤',
|
subtitle: '对资源列表数据进行过滤',
|
||||||
quality: '质量',
|
quality: '质量',
|
||||||
qualityOptions: {
|
|
||||||
all: '全部',
|
|
||||||
blurayOriginal: '蓝光原盘',
|
|
||||||
remux: 'Remux',
|
|
||||||
bluray: 'BluRay',
|
|
||||||
uhd: 'UHD',
|
|
||||||
webdl: 'WEB-DL',
|
|
||||||
hdtv: 'HDTV',
|
|
||||||
h265: 'H265',
|
|
||||||
h264: 'H264',
|
|
||||||
},
|
|
||||||
resolution: '分辨率',
|
resolution: '分辨率',
|
||||||
resolutionOptions: {
|
|
||||||
all: '全部',
|
|
||||||
'4k': '4k',
|
|
||||||
'1080p': '1080p',
|
|
||||||
'720p': '720p',
|
|
||||||
},
|
|
||||||
effect: '特效',
|
effect: '特效',
|
||||||
effectOptions: {
|
|
||||||
all: '全部',
|
|
||||||
dolbyVision: '杜比视界',
|
|
||||||
dolbyAtmos: '杜比全景声',
|
|
||||||
hdr: 'HDR',
|
|
||||||
sdr: 'SDR',
|
|
||||||
},
|
|
||||||
size: '大小范围',
|
size: '大小范围',
|
||||||
include: '包含(关键字、正则式)',
|
include: '包含(关键字、正则式)',
|
||||||
exclude: '排除(关键字、正则式)',
|
exclude: '排除(关键字、正则式)',
|
||||||
@@ -724,6 +727,57 @@ export default {
|
|||||||
usedPercent: '已使用 {percent}%',
|
usedPercent: '已使用 {percent}%',
|
||||||
noConfigNeeded: '此存储类型无需配置参数,请直接配置目录!',
|
noConfigNeeded: '此存储类型无需配置参数,请直接配置目录!',
|
||||||
notConfigured: '未配置',
|
notConfigured: '未配置',
|
||||||
|
local: '本地',
|
||||||
|
alipan: '阿里云盘',
|
||||||
|
u115: '115网盘',
|
||||||
|
rclone: 'RClone',
|
||||||
|
alist: 'AList',
|
||||||
|
},
|
||||||
|
filterRules: {
|
||||||
|
specSub: '特效字幕',
|
||||||
|
cnSub: '中文字幕',
|
||||||
|
cnVoi: '国语配音',
|
||||||
|
gz: '官种',
|
||||||
|
notCnVoi: '排除: 国语配音',
|
||||||
|
hkVoi: '粤语配音',
|
||||||
|
notHkVoi: '排除: 粤语配音',
|
||||||
|
free: '促销: 免费',
|
||||||
|
resolution4k: '分辨率: 4K',
|
||||||
|
resolution1080p: '分辨率: 1080P',
|
||||||
|
resolution720p: '分辨率: 720P',
|
||||||
|
not720p: '排除: 720P',
|
||||||
|
qualityBlu: '质量: 蓝光原盘',
|
||||||
|
notBlu: '排除: 蓝光原盘',
|
||||||
|
qualityBluray: '质量: BLURAY',
|
||||||
|
notBluray: '排除: BLURAY',
|
||||||
|
qualityUhd: '质量: UHD',
|
||||||
|
notUhd: '排除: UHD',
|
||||||
|
qualityRemux: '质量: REMUX',
|
||||||
|
notRemux: '排除: REMUX',
|
||||||
|
qualityWebdl: '质量: WEB-DL',
|
||||||
|
notWebdl: '排除: WEB-DL',
|
||||||
|
quality60fps: '质量: 60fps',
|
||||||
|
not60fps: '排除: 60fps',
|
||||||
|
codecH265: '编码: H265',
|
||||||
|
notH265: '排除: H265',
|
||||||
|
codecH264: '编码: H264',
|
||||||
|
notH264: '排除: H264',
|
||||||
|
effectDolby: '效果: 杜比视界',
|
||||||
|
notDolby: '排除: 杜比视界',
|
||||||
|
effectAtmos: '效果: 杜比全景声',
|
||||||
|
notAtmos: '排除: 杜比全景声',
|
||||||
|
effectHdr: '效果: HDR',
|
||||||
|
notHdr: '排除: HDR',
|
||||||
|
effectSdr: '效果: SDR',
|
||||||
|
notSdr: '排除: SDR',
|
||||||
|
effect3d: '效果: 3D',
|
||||||
|
not3d: '排除: 3D',
|
||||||
|
},
|
||||||
|
transferType: {
|
||||||
|
copy: '复制',
|
||||||
|
move: '移动',
|
||||||
|
link: '硬链接',
|
||||||
|
softlink: '软链接',
|
||||||
},
|
},
|
||||||
site: {
|
site: {
|
||||||
noSites: '没有站点',
|
noSites: '没有站点',
|
||||||
@@ -2019,6 +2073,7 @@ export default {
|
|||||||
},
|
},
|
||||||
filterRule: {
|
filterRule: {
|
||||||
title: '过滤规则',
|
title: '过滤规则',
|
||||||
|
groupName: '规则组名称',
|
||||||
priority: '优先级',
|
priority: '优先级',
|
||||||
rules: '规则',
|
rules: '规则',
|
||||||
add: '添加规则',
|
add: '添加规则',
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ export default {
|
|||||||
files: '文件',
|
files: '文件',
|
||||||
share: '分享',
|
share: '分享',
|
||||||
unsubscribe: '取消訂閱',
|
unsubscribe: '取消訂閱',
|
||||||
|
media: '媒體',
|
||||||
},
|
},
|
||||||
mediaType: {
|
mediaType: {
|
||||||
movie: '電影',
|
movie: '電影',
|
||||||
@@ -70,6 +71,30 @@ export default {
|
|||||||
sendMessage: '發送消息',
|
sendMessage: '發送消息',
|
||||||
transferFile: '整理文件',
|
transferFile: '整理文件',
|
||||||
},
|
},
|
||||||
|
qualityOptions: {
|
||||||
|
all: '全部',
|
||||||
|
blurayOriginal: '藍光原盤',
|
||||||
|
remux: 'Remux',
|
||||||
|
bluray: 'BluRay',
|
||||||
|
uhd: 'UHD',
|
||||||
|
webdl: 'WEB-DL',
|
||||||
|
hdtv: 'HDTV',
|
||||||
|
h265: 'H265',
|
||||||
|
h264: 'H264',
|
||||||
|
},
|
||||||
|
resolutionOptions: {
|
||||||
|
all: '全部',
|
||||||
|
'4k': '4k',
|
||||||
|
'1080p': '1080p',
|
||||||
|
'720p': '720p',
|
||||||
|
},
|
||||||
|
effectOptions: {
|
||||||
|
all: '全部',
|
||||||
|
dolbyVision: '杜比視界',
|
||||||
|
dolbyAtmos: '杜比全景聲',
|
||||||
|
hdr: 'HDR',
|
||||||
|
sdr: 'SDR',
|
||||||
|
},
|
||||||
theme: {
|
theme: {
|
||||||
light: '淺色',
|
light: '淺色',
|
||||||
dark: '深色',
|
dark: '深色',
|
||||||
@@ -249,7 +274,9 @@ export default {
|
|||||||
empty: '暫無通知',
|
empty: '暫無通知',
|
||||||
channel: '通知渠道',
|
channel: '通知渠道',
|
||||||
name: '名稱',
|
name: '名稱',
|
||||||
|
nameHint: '通知渠道名稱',
|
||||||
type: '類型',
|
type: '類型',
|
||||||
|
typeHint: '通知渠道類型',
|
||||||
enabled: '啟用',
|
enabled: '啟用',
|
||||||
config: '配置',
|
config: '配置',
|
||||||
wechat: {
|
wechat: {
|
||||||
@@ -495,32 +522,8 @@ export default {
|
|||||||
title: '過濾資源',
|
title: '過濾資源',
|
||||||
subtitle: '對資源列表數據進行過濾',
|
subtitle: '對資源列表數據進行過濾',
|
||||||
quality: '質量',
|
quality: '質量',
|
||||||
qualityOptions: {
|
|
||||||
all: '全部',
|
|
||||||
blurayOriginal: '藍光原盤',
|
|
||||||
remux: 'Remux',
|
|
||||||
bluray: 'BluRay',
|
|
||||||
uhd: 'UHD',
|
|
||||||
webdl: 'WEB-DL',
|
|
||||||
hdtv: 'HDTV',
|
|
||||||
h265: 'H265',
|
|
||||||
h264: 'H264',
|
|
||||||
},
|
|
||||||
resolution: '分辨率',
|
resolution: '分辨率',
|
||||||
resolutionOptions: {
|
|
||||||
all: '全部',
|
|
||||||
'4k': '4k',
|
|
||||||
'1080p': '1080p',
|
|
||||||
'720p': '720p',
|
|
||||||
},
|
|
||||||
effect: '特效',
|
effect: '特效',
|
||||||
effectOptions: {
|
|
||||||
all: '全部',
|
|
||||||
dolbyVision: '杜比視界',
|
|
||||||
dolbyAtmos: '杜比全景聲',
|
|
||||||
hdr: 'HDR',
|
|
||||||
sdr: 'SDR',
|
|
||||||
},
|
|
||||||
size: '大小範圍',
|
size: '大小範圍',
|
||||||
include: '包含(關鍵字、正則式)',
|
include: '包含(關鍵字、正則式)',
|
||||||
exclude: '排除(關鍵字、正則式)',
|
exclude: '排除(關鍵字、正則式)',
|
||||||
@@ -725,6 +728,58 @@ export default {
|
|||||||
usedPercent: '已使用 {percent}%',
|
usedPercent: '已使用 {percent}%',
|
||||||
noConfigNeeded: '此存儲類型無需配置參數,請直接配置目錄!',
|
noConfigNeeded: '此存儲類型無需配置參數,請直接配置目錄!',
|
||||||
notConfigured: '未配置',
|
notConfigured: '未配置',
|
||||||
|
local: '本地',
|
||||||
|
alipan: '阿里雲盤',
|
||||||
|
u115: '115網盤',
|
||||||
|
rclone: 'RClone',
|
||||||
|
alist: 'AList',
|
||||||
|
},
|
||||||
|
|
||||||
|
filterRules: {
|
||||||
|
specSub: '特效字幕',
|
||||||
|
cnSub: '中文字幕',
|
||||||
|
cnVoi: '國語配音',
|
||||||
|
gz: '官種',
|
||||||
|
notCnVoi: '排除: 國語配音',
|
||||||
|
hkVoi: '粵語配音',
|
||||||
|
notHkVoi: '排除: 粵語配音',
|
||||||
|
free: '促銷: 免費',
|
||||||
|
resolution4k: '解析度: 4K',
|
||||||
|
resolution1080p: '解析度: 1080P',
|
||||||
|
resolution720p: '解析度: 720P',
|
||||||
|
not720p: '排除: 720P',
|
||||||
|
qualityBlu: '品質: 藍光原盤',
|
||||||
|
notBlu: '排除: 藍光原盤',
|
||||||
|
qualityBluray: '品質: BLURAY',
|
||||||
|
notBluray: '排除: BLURAY',
|
||||||
|
qualityUhd: '品質: UHD',
|
||||||
|
notUhd: '排除: UHD',
|
||||||
|
qualityRemux: '品質: REMUX',
|
||||||
|
notRemux: '排除: REMUX',
|
||||||
|
qualityWebdl: '品質: WEB-DL',
|
||||||
|
notWebdl: '排除: WEB-DL',
|
||||||
|
quality60fps: '品質: 60fps',
|
||||||
|
not60fps: '排除: 60fps',
|
||||||
|
codecH265: '編碼: H265',
|
||||||
|
notH265: '排除: H265',
|
||||||
|
codecH264: '編碼: H264',
|
||||||
|
notH264: '排除: H264',
|
||||||
|
effectDolby: '效果: 杜比視界',
|
||||||
|
notDolby: '排除: 杜比視界',
|
||||||
|
effectAtmos: '效果: 杜比全景聲',
|
||||||
|
notAtmos: '排除: 杜比全景聲',
|
||||||
|
effectHdr: '效果: HDR',
|
||||||
|
notHdr: '排除: HDR',
|
||||||
|
effectSdr: '效果: SDR',
|
||||||
|
notSdr: '排除: SDR',
|
||||||
|
effect3d: '效果: 3D',
|
||||||
|
not3d: '排除: 3D',
|
||||||
|
},
|
||||||
|
transferType: {
|
||||||
|
copy: '複製',
|
||||||
|
move: '移動',
|
||||||
|
link: '硬連結',
|
||||||
|
softlink: '軟連結',
|
||||||
},
|
},
|
||||||
site: {
|
site: {
|
||||||
noSites: '沒有站點',
|
noSites: '沒有站點',
|
||||||
@@ -2020,6 +2075,7 @@ export default {
|
|||||||
},
|
},
|
||||||
filterRule: {
|
filterRule: {
|
||||||
title: '過濾規則',
|
title: '過濾規則',
|
||||||
|
groupName: '規則組名稱',
|
||||||
priority: '優先級',
|
priority: '優先級',
|
||||||
rules: '規則',
|
rules: '規則',
|
||||||
add: '添加規則',
|
add: '添加規則',
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ export default {
|
|||||||
VDialog: {
|
VDialog: {
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
rounded: 'lg',
|
rounded: 'lg',
|
||||||
|
maxHeight: '85vh',
|
||||||
},
|
},
|
||||||
VExpansionPanels: {
|
VExpansionPanels: {
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
|
|||||||
@@ -1,70 +0,0 @@
|
|||||||
// MediaType
|
|
||||||
export function getMediaTypeText(label: string | undefined) {
|
|
||||||
if (!label) return ''
|
|
||||||
|
|
||||||
const { t } = useI18n()
|
|
||||||
|
|
||||||
// 常见的媒体类型及其映射
|
|
||||||
const typeMap: Record<string, string> = {
|
|
||||||
'电影': 'mediaType.movie',
|
|
||||||
'电视剧': 'mediaType.tv',
|
|
||||||
'动漫': 'mediaType.anime',
|
|
||||||
'合集': 'mediaType.collection',
|
|
||||||
'未知': 'mediaType.unknown',
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果是已知类型,使用i18n翻译
|
|
||||||
if (label in typeMap) {
|
|
||||||
return t(typeMap[label])
|
|
||||||
}
|
|
||||||
|
|
||||||
// 对于未知的类型,直接返回原始标签
|
|
||||||
return label
|
|
||||||
}
|
|
||||||
|
|
||||||
// notificationSwitch
|
|
||||||
export function getNotificationSwitchText(label: string | undefined) {
|
|
||||||
if (!label) return ''
|
|
||||||
|
|
||||||
const { t } = useI18n()
|
|
||||||
|
|
||||||
const switchMap: Record<string, string> = {
|
|
||||||
'资源下载': 'notificationSwitch.resourceDownload',
|
|
||||||
'整理入库': 'notificationSwitch.organize',
|
|
||||||
'订阅': 'notificationSwitch.subscribe',
|
|
||||||
'站点': 'notificationSwitch.site',
|
|
||||||
'媒体服务器': 'notificationSwitch.mediaServer',
|
|
||||||
'手动处理': 'notificationSwitch.manual',
|
|
||||||
'插件': 'notificationSwitch.plugin',
|
|
||||||
'其它': 'notificationSwitch.other',
|
|
||||||
}
|
|
||||||
if (label in switchMap) {
|
|
||||||
return t(switchMap[label])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// actionStep
|
|
||||||
export function getActionStepText(label: string | undefined) {
|
|
||||||
if (!label) return ''
|
|
||||||
|
|
||||||
const { t } = useI18n()
|
|
||||||
|
|
||||||
const stepMap: Record<string, string> = {
|
|
||||||
'添加下载': 'actionStep.addDownload',
|
|
||||||
'添加订阅': 'actionStep.addSubscribe',
|
|
||||||
'获取下载任务': 'actionStep.fetchDownloads',
|
|
||||||
'获取媒体数据': 'actionStep.fetchMedias',
|
|
||||||
'获取RSS资源': 'actionStep.fetchRss',
|
|
||||||
'搜索站点资源': 'actionStep.fetchTorrents',
|
|
||||||
'过滤媒体数据': 'actionStep.filterMedias',
|
|
||||||
'过滤资源': 'actionStep.filterTorrents',
|
|
||||||
'扫描目录': 'actionStep.scanFile',
|
|
||||||
'刮削文件': 'actionStep.scrapeFile',
|
|
||||||
'发送事件': 'actionStep.sendEvent',
|
|
||||||
'发送消息': 'actionStep.sendMessage',
|
|
||||||
'整理文件': 'actionStep.transferFile',
|
|
||||||
}
|
|
||||||
if (label in stepMap) {
|
|
||||||
return t(stepMap[label])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,7 +6,7 @@ import type { NotificationConf, NotificationSwitchConf } from '@/api/types'
|
|||||||
import NotificationChannelCard from '@/components/cards/NotificationChannelCard.vue'
|
import NotificationChannelCard from '@/components/cards/NotificationChannelCard.vue'
|
||||||
import ProgressDialog from '@/components/dialog/ProgressDialog.vue'
|
import ProgressDialog from '@/components/dialog/ProgressDialog.vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { getNotificationSwitchText } from '@/types/i18n-type'
|
import { notificationSwitchDict } from '@/api/constants'
|
||||||
|
|
||||||
// 国际化
|
// 国际化
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
@@ -171,6 +171,12 @@ async function saveNotificationSwitchs() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取通知开关文本
|
||||||
|
function getNotificationSwitchText(type: string | undefined) {
|
||||||
|
if (!type) return ''
|
||||||
|
return notificationSwitchDict[type]
|
||||||
|
}
|
||||||
|
|
||||||
// 加载数据
|
// 加载数据
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadNotificationSetting()
|
loadNotificationSetting()
|
||||||
|
|||||||
@@ -147,6 +147,8 @@ function addFilterRuleGroup() {
|
|||||||
}
|
}
|
||||||
filterRuleGroups.value.push({
|
filterRuleGroups.value.push({
|
||||||
name: name,
|
name: name,
|
||||||
|
media_type: '',
|
||||||
|
category: '',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -610,7 +610,7 @@ onDeactivated(() => {
|
|||||||
</VCol>
|
</VCol>
|
||||||
</VRow>
|
</VRow>
|
||||||
<!-- 高级系统设置 -->
|
<!-- 高级系统设置 -->
|
||||||
<VDialog v-if="advancedDialog" v-model="advancedDialog" scrollable max-width="60rem" persistent>
|
<VDialog v-if="advancedDialog" v-model="advancedDialog" scrollable max-width="60rem">
|
||||||
<VCard>
|
<VCard>
|
||||||
<VCardItem>
|
<VCardItem>
|
||||||
<VDialogCloseBtn @click="advancedDialog = false" />
|
<VDialogCloseBtn @click="advancedDialog = false" />
|
||||||
|
|||||||
Reference in New Issue
Block a user