components_search_SearchTask.bs
import "pkg:/source/api/ApiClient.bs"
import "pkg:/source/api/apiPool.bs"
import "pkg:/source/data/JellyfinDataTransformer.bs"
import "pkg:/source/translationKeys.bs"
import "pkg:/source/utils/misc.bs"
sub init()
m.top.functionName = "search"
end sub
sub search()
if isValid(m.top.query) and m.top.query <> ""
m.top.results = searchMedia(m.top.query)
end if
end sub
' Searches multiple Jellyfin endpoints for media matching the query.
' Runs on SearchTask thread — fetchJson blocks waiting for ApiPool responses.
function searchMedia(query as string)
if query = "" then return { Items: [], TotalRecordCount: 0 }
transformer = JellyfinDataTransformer()
allItems = []
' Regular library items — Person and MusicArtist are fetched via dedicated endpoints below.
' LiveTvProgram is excluded here because /Items EPG search is incomplete; /LiveTv/Programs is used instead.
data = fetchJson(GetApi().BuildGetItemsByQueryRequest({
"searchTerm": query,
"IncludeItemTypes": "Movie,Series,Episode,Video,MusicVideo,Audio,MusicAlbum,Playlist,LiveTvChannel,PhotoAlbum,Photo,BoxSet",
"EnableTotalRecordCount": false,
"Recursive": true,
"limit": 100
}), "searchItems")
if isValid(data) and isValid(data.Items)
for each item in data.Items
' Live TV recordings come back from /Items as the content type (Movie/Episode).
' The only reliable discriminator is the container format: recordings are always
' stored as MPEG transport streams ("ts"), while library items never are.
if LCase(item.Container ?? "") = "ts"
item.Type = "Recording"
end if
allItems.push(transformer.transformBaseItem(item))
end for
end if
' People — /Items does not return Person type; /Persons endpoint required.
personData = fetchJson(GetApi().BuildGetPersonsRequest({
"searchTerm": query,
"Limit": 20,
"EnableTotalRecordCount": false
}), "searchPersons")
if isValid(personData) and isValid(personData.Items)
for each item in personData.Items
allItems.push(transformer.transformBaseItem(item))
end for
end if
' Artists — /Items does not return MusicArtist type; /Artists endpoint required.
artistData = fetchJson(GetApi().BuildGetArtistsRequest({
"searchTerm": query,
"Limit": 20,
"EnableTotalRecordCount": false
}), "searchArtists")
if isValid(artistData) and isValid(artistData.Items)
for each item in artistData.Items
allItems.push(transformer.transformBaseItem(item))
end for
end if
' Live TV Programs — /LiveTv/Programs searches the full EPG; /Items only covers recordings.
programData = fetchJson(GetApi().BuildGetLiveTVProgramsRequest({
"SearchTerm": query,
"Limit": 20,
"EnableTotalRecordCount": false
}), "searchPrograms")
if isValid(programData) and isValid(programData.Items)
for each item in programData.Items
allItems.push(transformer.transformBaseItem(item))
end for
end if
result = {}
result.Items = allItems
result.TotalRecordCount = allItems.count()
return result
end function