Add channel support and debug logging for Xtream content display

- Add .channel to BaseItemKind.supportedCases for proper filtering
- Implement channel API routing in ItemLibraryViewModel
- Add comprehensive debug logging to track API calls and filtering
- Support channels in MediaViewModel library views
- Fix channel items not appearing in media libraries

This enables Xtream plugin channels (VOD/Series) to display correctly
in jellypig tvOS. Channels now use proper /Channels API endpoints
instead of falling back to regular /Items API.

Related to ongoing fix for Xtream content media display.
This commit is contained in:
Ashik K 2025-10-17 10:49:20 +02:00
parent ab3773e4cc
commit 9a78115a93
3 changed files with 36 additions and 4 deletions

View File

@ -18,7 +18,7 @@ extension BaseItemKind: SupportedCaseIterable {
/// like `LibararyParent` may have additional supported /// like `LibararyParent` may have additional supported
/// cases for querying a library. /// cases for querying a library.
static var supportedCases: [BaseItemKind] { static var supportedCases: [BaseItemKind] {
[.movie, .series, .boxSet] [.movie, .series, .boxSet, .channel]
} }
} }

View File

@ -21,21 +21,36 @@ final class ItemLibraryViewModel: PagingLibraryViewModel<BaseItemDto> {
// Use channel API for channels and channel folders // Use channel API for channels and channel folders
if let parent = parent as? BaseItemDto, parent.type == .channel || parent.type == .channelFolderItem { if let parent = parent as? BaseItemDto, parent.type == .channel || parent.type == .channelFolderItem {
print("🔵 DEBUG: Using channel API for parent type: \(parent.type), name: \(parent.name ?? "nil"), id: \(parent.id ?? "nil")")
return try await getChannelItems(page: page, parent: parent) return try await getChannelItems(page: page, parent: parent)
} }
print(
"🟢 DEBUG: Using regular API, parent: \(String(describing: (parent as? BaseItemDto)?.name)), type: \(String(describing: (parent as? BaseItemDto)?.type))"
)
let parameters = itemParameters(for: page) let parameters = itemParameters(for: page)
print("📋 DEBUG: includeItemTypes: \(parameters.includeItemTypes ?? [])")
let request = Paths.getItemsByUserID(userID: userSession.user.id, parameters: parameters) let request = Paths.getItemsByUserID(userID: userSession.user.id, parameters: parameters)
let response = try await userSession.client.send(request) let response = try await userSession.client.send(request)
print("📦 DEBUG: API returned \(response.value.items?.count ?? 0) items")
let rawItems = response.value.items ?? []
for item in rawItems.prefix(10) {
print(" - Item: \(item.name ?? "nil"), type: \(item.type), collectionType: \(item.collectionType?.rawValue ?? "nil")")
}
// 1 - only care to keep collections that hold valid items // 1 - only care to keep collections that hold valid items
// 2 - if parent is type `folder`, then we are in a folder-view // 2 - if parent is type `folder`, then we are in a folder-view
// context so change `collectionFolder` types to `folder` // context so change `collectionFolder` types to `folder`
// for better view handling // for better view handling
let items = (response.value.items ?? []) let items = rawItems
.filter { item in .filter { item in
if let collectionType = item.collectionType { if let collectionType = item.collectionType {
return CollectionType.supportedCases.contains(collectionType) let supported = CollectionType.supportedCases.contains(collectionType)
if !supported {
print("❌ DEBUG: Filtered out \(item.name ?? "nil") - unsupported collectionType: \(collectionType.rawValue)")
}
return supported
} }
return true return true
@ -48,6 +63,7 @@ final class ItemLibraryViewModel: PagingLibraryViewModel<BaseItemDto> {
return item return item
} }
print("✅ DEBUG: After filtering, returning \(items.count) items")
return items return items
} }
@ -56,6 +72,7 @@ final class ItemLibraryViewModel: PagingLibraryViewModel<BaseItemDto> {
private func getChannelItems(page: Int, parent: BaseItemDto) async throws -> [BaseItemDto] { private func getChannelItems(page: Int, parent: BaseItemDto) async throws -> [BaseItemDto] {
guard let channelID = parent.channelID ?? parent.id else { guard let channelID = parent.channelID ?? parent.id else {
print("❌ DEBUG: No channelID found for parent: \(parent.name ?? "nil")")
return [] return []
} }
@ -66,6 +83,9 @@ final class ItemLibraryViewModel: PagingLibraryViewModel<BaseItemDto> {
// If parent is a channel folder, set the folderID // If parent is a channel folder, set the folderID
if parent.type == .channelFolderItem { if parent.type == .channelFolderItem {
parameters.folderID = parent.id parameters.folderID = parent.id
print("📁 DEBUG: Channel folder - channelID: \(channelID), folderID: \(parent.id ?? "nil")")
} else {
print("📺 DEBUG: Channel root - channelID: \(channelID)")
} }
// Page size // Page size
@ -75,6 +95,8 @@ final class ItemLibraryViewModel: PagingLibraryViewModel<BaseItemDto> {
let request = Paths.getChannelItems(channelID: channelID, parameters: parameters) let request = Paths.getChannelItems(channelID: channelID, parameters: parameters)
let response = try await userSession.client.send(request) let response = try await userSession.client.send(request)
print("✅ DEBUG: Channel API returned \(response.value.items?.count ?? 0) items")
return response.value.items ?? [] return response.value.items ?? []
} }

View File

@ -96,7 +96,17 @@ final class MediaViewModel: ViewModel, Stateful {
// folders has `type = UserView`, but we manually // folders has `type = UserView`, but we manually
// force it to `folders` for better view handling // force it to `folders` for better view handling
let supportedUserViews = try await (userViews.value.items ?? []) let supportedUserViews = try await (userViews.value.items ?? [])
.intersection(CollectionType.supportedCases, using: \.collectionType) .filter { item in
// Include channels (which don't have collectionType)
if item.type == .channel {
return true
}
// Include items with supported collectionTypes
if let collectionType = item.collectionType {
return CollectionType.supportedCases.contains(collectionType)
}
return false
}
.subtracting(excludedLibraryIDs, using: \.id) .subtracting(excludedLibraryIDs, using: \.id)
.map { item in .map { item in