mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-05 23:56:42 +08:00
fix(subscribe): preserve source identity across season flows
This commit is contained in:
@@ -131,6 +131,8 @@ function episodeGroupItemProps(item: { title: string; subtitle: string }) {
|
||||
|
||||
// 查询所有剧集组
|
||||
async function getEpisodeGroups() {
|
||||
// 兼容未记录主来源的旧 TMDB 订阅;明确为其他来源时不使用辅助 TMDB ID 查询剧集组。
|
||||
if (subscribeForm.value.media_source && subscribeForm.value.media_source !== 'themoviedb') return
|
||||
if (!subscribeForm.value.tmdbid) {
|
||||
console.warn('tmdbid is not set or is empty')
|
||||
return
|
||||
|
||||
@@ -6,7 +6,12 @@ import noImage from '@images/no-image.jpeg'
|
||||
import NoDataFound from '@/components/states/NoDataFound.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useGlobalSettingsStore } from '@/stores'
|
||||
import type { SeasonSubscribeModes, SubscribeMode } from '@/composables/useMediaSubscribe'
|
||||
import {
|
||||
getMediaSubscribeId,
|
||||
getMediaSubscribeIdentity,
|
||||
type SeasonSubscribeModes,
|
||||
type SubscribeMode,
|
||||
} from '@/composables/useMediaSubscribe'
|
||||
import { getDisplayImageUrl } from '@/utils/imageUtils'
|
||||
import { useDisplay } from 'vuetify'
|
||||
|
||||
@@ -67,7 +72,9 @@ const isRefreshed = ref(false)
|
||||
const episodeGroups = ref<{ [key: string]: any }[]>([])
|
||||
|
||||
// 当前选择剧集组
|
||||
const episodeGroup = ref(props.initialEpisodeGroup ?? '')
|
||||
const episodeGroup = ref(
|
||||
getMediaSubscribeIdentity(props.media)?.source === 'themoviedb' ? (props.initialEpisodeGroup ?? '') : '',
|
||||
)
|
||||
|
||||
// 剧集组横向轨道
|
||||
const episodeGroupRail = ref<HTMLElement | null>(null)
|
||||
@@ -166,19 +173,12 @@ const episodeGroupOptions = computed<EpisodeGroupOption[]>(() => {
|
||||
|
||||
// 获得mediaid
|
||||
function getMediaId() {
|
||||
if (props.media?.media_id && (props.media?.source || props.media?.mediaid_prefix)) {
|
||||
const source = props.media.mediaid_prefix || props.media.source
|
||||
return `${source === 'themoviedb' ? 'tmdb' : source}:${props.media.media_id}`
|
||||
}
|
||||
if (props.media?.tmdb_id) return `tmdb:${props.media?.tmdb_id}`
|
||||
else if (props.media?.douban_id) return `douban:${props.media?.douban_id}`
|
||||
else if (props.media?.bangumi_id) return `bangumi:${props.media?.bangumi_id}`
|
||||
else if (props.media?.anilist_id) return `anilist:${props.media?.anilist_id}`
|
||||
return ''
|
||||
return getMediaSubscribeId(props.media)
|
||||
}
|
||||
|
||||
// 查询所有剧集组
|
||||
async function getEpisodeGroups() {
|
||||
if (getMediaSubscribeIdentity(props.media)?.source !== 'themoviedb') return
|
||||
if (!props.media?.tmdb_id) {
|
||||
console.warn('tmdbid is not set or is empty')
|
||||
return
|
||||
@@ -213,7 +213,7 @@ async function getMediaSeasons() {
|
||||
|
||||
// 查询剧集组的剧集
|
||||
async function getGroupSeasons() {
|
||||
if (!episodeGroup.value) return
|
||||
if (getMediaSubscribeIdentity(props.media)?.source !== 'themoviedb' || !episodeGroup.value) return
|
||||
isRefreshed.value = false
|
||||
try {
|
||||
seasonInfos.value = await api.get(`media/group/seasons/${episodeGroup.value}`)
|
||||
|
||||
@@ -128,6 +128,27 @@ describe('SubscribeEditDialog', () => {
|
||||
expect(episodeGroupsRequested).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('skips episode groups for a non-TMDB subscription with an auxiliary TMDB ID', async () => {
|
||||
const record = createSubscribe({
|
||||
anilistid: 154587,
|
||||
id: 810,
|
||||
media_id: '154587',
|
||||
media_source: 'anilist',
|
||||
name: 'AniList 编辑测试剧',
|
||||
season: 1,
|
||||
tmdbid: 8100,
|
||||
type: '电视剧',
|
||||
})
|
||||
const episodeGroupsRequested = vi.fn()
|
||||
server.use(subscribeDetailsHandler(810, record))
|
||||
useDialogOptions({ onEpisodeGroups: episodeGroupsRequested, tmdbId: 8100 })
|
||||
|
||||
await renderDialog({ subid: 810 })
|
||||
|
||||
expect(await screen.findByText('AniList 编辑测试剧 S01')).toBeInTheDocument()
|
||||
expect(episodeGroupsRequested).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('shows enabled sites and stable downloader, directory, and rule options', async () => {
|
||||
const activeSite = createSubscribeSite({ id: 1, is_active: true, name: '启用站点' })
|
||||
const inactiveSite = createSubscribeSite({ id: 2, is_active: false, name: '停用站点' })
|
||||
@@ -202,7 +223,12 @@ describe('SubscribeEditDialog', () => {
|
||||
const configRequested = vi.fn()
|
||||
const saved = vi.fn()
|
||||
server.use(
|
||||
defaultSubscribeConfigHandler(type, createSubscribe({ id: 0, show_edit_dialog: false, type }), 200, configRequested),
|
||||
defaultSubscribeConfigHandler(
|
||||
type,
|
||||
createSubscribe({ id: 0, show_edit_dialog: false, type }),
|
||||
200,
|
||||
configRequested,
|
||||
),
|
||||
saveDefaultSubscribeConfigHandler(type, { success: true }, 200, saved),
|
||||
)
|
||||
useDialogOptions()
|
||||
|
||||
@@ -189,9 +189,13 @@ describe('SubscribeSeasonDialog', () => {
|
||||
})
|
||||
|
||||
it.each([
|
||||
['Douban', { douban_id: 'db-7303', tmdb_id: undefined }, 'douban:db-7303'],
|
||||
['Bangumi', { bangumi_id: 'bgm-7304', douban_id: undefined, tmdb_id: undefined }, 'bangumi:bgm-7304'],
|
||||
['AniList', { anilist_id: 154587, bangumi_id: undefined, tmdb_id: undefined }, 'anilist:154587'],
|
||||
['Douban', { douban_id: 'db-7303', source: 'douban', tmdb_id: undefined }, 'douban:db-7303'],
|
||||
[
|
||||
'Bangumi',
|
||||
{ bangumi_id: 'bgm-7304', douban_id: undefined, source: 'bangumi', tmdb_id: undefined },
|
||||
'bangumi:bgm-7304',
|
||||
],
|
||||
['AniList', { anilist_id: 154587, bangumi_id: undefined, source: 'anilist', tmdb_id: undefined }, 'anilist:154587'],
|
||||
[
|
||||
'custom source',
|
||||
{
|
||||
@@ -231,6 +235,34 @@ describe('SubscribeSeasonDialog', () => {
|
||||
expect(requested.mock.calls[0][0].searchParams.get('mediaid')).toBe(mediaId)
|
||||
})
|
||||
|
||||
it.each([
|
||||
['Douban', { douban_id: 'db-7310', source: 'douban' }, 'douban:db-7310'],
|
||||
['Bangumi', { bangumi_id: 'bgm-7310', source: 'bangumi' }, 'bangumi:bgm-7310'],
|
||||
['AniList', { anilist_id: 154587, source: 'anilist' }, 'anilist:154587'],
|
||||
] as const)(
|
||||
'keeps the %s identity and skips episode groups when an auxiliary TMDB ID exists',
|
||||
async (_label, overrides, mediaId) => {
|
||||
const media = createTvMedia({ ...overrides, tmdb_id: 7310 })
|
||||
const seasonRequest = vi.fn()
|
||||
const groupRequest = vi.fn()
|
||||
const groupSeasonsRequest = vi.fn()
|
||||
server.use(
|
||||
mediaSeasonsHandler([createMediaSeason({ season_number: 1 })], 200, seasonRequest),
|
||||
mediaNotExistsHandler([]),
|
||||
mediaEpisodeGroupsHandler(7310, [], 200, groupRequest),
|
||||
mediaGroupSeasonsHandler('auxiliary-group', [], 200, groupSeasonsRequest),
|
||||
)
|
||||
|
||||
await renderDialog({ initialEpisodeGroup: 'auxiliary-group', media })
|
||||
|
||||
expect(await screen.findByText('第 1 季')).toBeInTheDocument()
|
||||
await settleRequests()
|
||||
expect(seasonRequest.mock.calls[0][0].searchParams.get('mediaid')).toBe(mediaId)
|
||||
expect(groupRequest).not.toHaveBeenCalled()
|
||||
expect(groupSeasonsRequest).not.toHaveBeenCalled()
|
||||
},
|
||||
)
|
||||
|
||||
it('synchronizes visible selections and modes, then emits the five-argument subscription payload', async () => {
|
||||
const media = createTvMedia({ tmdb_id: 7306 })
|
||||
const seasons = [
|
||||
|
||||
Reference in New Issue
Block a user