From 4207a707162eea746b769d8154adeb10942d28af Mon Sep 17 00:00:00 2001 From: jxxghp Date: Mon, 11 May 2026 18:09:29 +0800 Subject: [PATCH] feat: add support for ZSpace media server integration including UI configuration and logo assets --- src/api/constants.ts | 4 + src/api/types.ts | 2 +- src/assets/images/logos/zspace.webp | Bin 0 -> 7358 bytes src/components/cards/LibraryCard.vue | 1 + src/components/cards/MediaServerCard.vue | 73 +++++++++++++++ src/composables/useSetupWizard.ts | 10 ++ src/locales/en-US.ts | 7 +- src/locales/zh-CN.ts | 7 +- src/locales/zh-TW.ts | 7 +- src/utils/appDeepLink.ts | 18 +++- src/utils/imageUtils.ts | 2 + src/views/setup/MediaServerSettingsStep.vue | 96 ++++++++++++++++++++ 12 files changed, 217 insertions(+), 10 deletions(-) create mode 100644 src/assets/images/logos/zspace.webp diff --git a/src/api/constants.ts b/src/api/constants.ts index 83a31079..86322c4e 100644 --- a/src/api/constants.ts +++ b/src/api/constants.ts @@ -68,6 +68,10 @@ export const mediaServerOptions = [ value: 'emby', title: i18n.global.t('setting.system.emby'), }, + { + value: 'zspace', + title: i18n.global.t('setting.system.zspace'), + }, { value: 'jellyfin', title: i18n.global.t('setting.system.jellyfin'), diff --git a/src/api/types.ts b/src/api/types.ts index ca0918fe..639f59c1 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -1145,7 +1145,7 @@ export interface StorageConf { export interface MediaServerConf { // 名称 name: string - // 类型 emby/jellyfin/plex/trimemedia/ugreen + // 类型 emby/zspace/jellyfin/plex/trimemedia/ugreen type: string // 配置 config: { [key: string]: any } diff --git a/src/assets/images/logos/zspace.webp b/src/assets/images/logos/zspace.webp new file mode 100644 index 0000000000000000000000000000000000000000..94ae4b87717cf78f1dbf0a3b86f2382477c5f4c8 GIT binary patch literal 7358 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 { switch (props.mediaserver.type) { case 'emby': return getLogoUrl('emby') + case 'zspace': + return getLogoUrl('zspace') case 'jellyfin': return getLogoUrl('jellyfin') case 'trimemedia': @@ -318,6 +320,77 @@ onMounted(() => { /> + + + + + + + + + + + + + + + + + + + + = { webUrl: 'https://emby.media', timeout: 2000, }, + zspace: { + appScheme: 'emby://', + webUrl: 'https://www.zspace.com.cn', + timeout: 2000, + }, trimemedia: { appScheme: 'trimemedia://', webUrl: 'https://trimemedia.com', @@ -135,6 +140,9 @@ function buildDeepLinkUrl(appType: AppType, params: string | DoubanAppParams): s case 'emby': return buildEmbyDeepLink(params as string) + case 'zspace': + return buildEmbyDeepLink(params as string) + case 'trimemedia': return buildTrimemediaDeepLink(params as string) @@ -634,7 +642,7 @@ export async function openMediaServerWithAutoDetect( // 优先使用传入的 serverType 参数 if (serverType) { const type = serverType.toLowerCase() - if (type === 'plex' || type === 'jellyfin' || type === 'emby' || type === 'trimemedia') { + if (type === 'plex' || type === 'jellyfin' || type === 'emby' || type === 'zspace' || type === 'trimemedia') { detectedServerType = type as AppType } } @@ -649,6 +657,8 @@ export async function openMediaServerWithAutoDetect( detectedServerType = 'jellyfin' } else if (url.includes('emby')) { detectedServerType = 'emby' + } else if (url.includes('zspace')) { + detectedServerType = 'zspace' } } @@ -698,6 +708,8 @@ export function getAppDownloadUrl(appType: AppType): string { return 'https://jellyfin.org/downloads/' case 'emby': return 'https://emby.media/download.html' + case 'zspace': + return 'https://www.zspace.com.cn/' case 'trimemedia': return 'https://trimemedia.com/download' case 'douban': diff --git a/src/utils/imageUtils.ts b/src/utils/imageUtils.ts index 1a1ffaeb..7d9f7c80 100644 --- a/src/utils/imageUtils.ts +++ b/src/utils/imageUtils.ts @@ -8,6 +8,7 @@ import qbittorrentLogo from '@/assets/images/logos/qbittorrent.png' import transmissionLogo from '@/assets/images/logos/transmission.png' import rtorrentLogo from '@/assets/images/logos/rtorrent.png' import embyLogo from '@/assets/images/logos/emby.png' +import zspaceLogo from '@/assets/images/logos/zspace.webp' import jellyfinLogo from '@/assets/images/logos/jellyfin.png' import plexLogo from '@/assets/images/logos/plex.png' import trimemediaLogo from '@/assets/images/logos/trimemedia.png' @@ -40,6 +41,7 @@ const logoMap: Record = { transmission: transmissionLogo, rtorrent: rtorrentLogo, emby: embyLogo, + zspace: zspaceLogo, jellyfin: jellyfinLogo, plex: plexLogo, trimemedia: trimemediaLogo, diff --git a/src/views/setup/MediaServerSettingsStep.vue b/src/views/setup/MediaServerSettingsStep.vue index 62cc66fa..8f6516af 100644 --- a/src/views/setup/MediaServerSettingsStep.vue +++ b/src/views/setup/MediaServerSettingsStep.vue @@ -122,6 +122,19 @@ watch( + + + + +
极影视
+
+
+
+ + + + + + + + + + + + + + + + + + + +