diff --git a/components/home/HSSLoadSectionTask.bs b/components/home/HSSLoadSectionTask.bs deleted file mode 100644 index 36949305d..000000000 --- a/components/home/HSSLoadSectionTask.bs +++ /dev/null @@ -1,289 +0,0 @@ -import "pkg:/source/api/baserequest.bs" -import "pkg:/source/utils/misc.bs" - -const HSS_ENRICH_FIELDS = "Type,UserData,Overview,Genres,CommunityRating,CriticRating,OfficialRating,RunTimeTicks,ProductionYear,SeriesName,ParentIndexNumber,IndexNumber,Status,ImageTags,BackdropImageTags,ParentBackdropItemId,ParentBackdropImageTags,ParentThumbItemId,ParentThumbImageTag,SeriesId,SeriesPrimaryImageTag,ParentLogoItemId,ParentLogoImageTag" - -sub init() - m.top.functionName = "loadHomeScreenSection" -end sub - -function targetAPIRequest(serverUrl as string, userId as string, authToken as string, path as string, params = {} as object) as dynamic - if not isValidAndNotEmpty(serverUrl) - return invalid - end if - - return APIRequestForServer(serverUrl, userId, authToken, path, params) -end function - -sub loadHomeScreenSection() - results = [] - - serverUrl = m.top.serverUrl - userId = m.top.userId - authToken = m.top.authToken - sectionType = m.top.sectionType - if not isValidAndNotEmpty(sectionType) - m.top.content = results - return - end if - - if not isValidAndNotEmpty(userId) - m.top.content = results - return - end if - - pathSection = sectionType.EncodeUriComponent() - params = { userId: userId } - params.AddReplace("Fields", HSS_ENRICH_FIELDS) - params.AddReplace("EnableImageTypes", "Primary,Backdrop,Thumb,Logo") - params.AddReplace("ImageTypeLimit", 1) - params.AddReplace("EnableTotalRecordCount", false) - - additionalData = m.top.additionalData - if isValidAndNotEmpty(additionalData) - params.AddReplace("additionalData", additionalData) - end if - - request = targetAPIRequest(serverUrl, userId, authToken, "/HomeScreen/Section/" + pathSection, params) - if not isValid(request) - m.top.content = results - return - end if - - response = getJson(request) - itemsPayload = getItemsPayload(response) - itemsPayload = enrichItemsPayload(itemsPayload, serverUrl, userId, authToken) - - for each item in itemsPayload - homeData = createSGNode("HomeData") - homeData.json = item - results.push(homeData) - end for - - m.top.content = results -end sub - -function getItemsPayload(response as dynamic) as object - if not isValid(response) - return [] - end if - - responseType = type(response) - if responseType = "Array" or responseType = "roArray" - return response - end if - - if isChainValid(response, "Items") - return response.Items - end if - - if isChainValid(response, "items") - return response.items - end if - - return [] -end function - -function enrichItemsPayload(itemsPayload as object, serverUrl as string, userId as string, authToken as string) as object - if not isValidAndNotEmpty(itemsPayload) or not isValidAndNotEmpty(userId) - return itemsPayload - end if - - if hasOverviewOnAllItems(itemsPayload) - return itemsPayload - end if - - itemIds = collectItemIds(itemsPayload) - if not isValidAndNotEmpty(itemIds) - return itemsPayload - end if - - request = targetAPIRequest(serverUrl, userId, authToken, "/Users/" + userId.EncodeUriComponent() + "/Items", { - Ids: itemIds.Join(","), - Fields: HSS_ENRICH_FIELDS, - EnableImageTypes: "Primary,Backdrop,Thumb,Logo", - ImageTypeLimit: 1, - EnableTotalRecordCount: false - }) - - if not isValid(request) - return itemsPayload - end if - - response = getJson(request) - enrichedPayload = getItemsPayload(response) - if not isValidAndNotEmpty(enrichedPayload) - return itemsPayload - end if - - enrichedById = {} - for each enrichedItem in enrichedPayload - if not isAssociativeArrayValue(enrichedItem) - continue for - end if - - itemId = getItemLookupId(enrichedItem) - if isValidAndNotEmpty(itemId) and not enrichedById.DoesExist(itemId) - enrichedById.AddReplace(itemId, enrichedItem) - end if - end for - - if not isValidAndNotEmpty(enrichedById) - return itemsPayload - end if - - mergedPayload = [] - for each item in itemsPayload - if not isAssociativeArrayValue(item) - mergedPayload.push(item) - continue for - end if - - itemId = getItemLookupId(item) - if not isValidAndNotEmpty(itemId) or not enrichedById.DoesExist(itemId) - mergedPayload.push(item) - continue for - end if - - mergedPayload.push(mergeSectionItem(item, enrichedById[itemId])) - end for - - return mergedPayload -end function - -function hasOverviewOnAllItems(itemsPayload as object) as boolean - for each item in itemsPayload - if not isAssociativeArrayValue(item) - return false - end if - - overview = toNormalizedString(getValueCaseInsensitive(item, "Overview", "")) - if not isValidAndNotEmpty(overview) - return false - end if - end for - - return true -end function - -function collectItemIds(itemsPayload as object) as object - itemIds = [] - seenIds = {} - - for each item in itemsPayload - if not isAssociativeArrayValue(item) - continue for - end if - - itemId = getItemLookupId(item) - if not isValidAndNotEmpty(itemId) or seenIds.DoesExist(itemId) - continue for - end if - - seenIds.AddReplace(itemId, true) - itemIds.push(itemId) - end for - - return itemIds -end function - -function getItemLookupId(item as object) as string - return toNormalizedString(getValueCaseInsensitive(item, "Id", "")) -end function - -function mergeSectionItem(rawItem as object, enrichedItem as object) as object - merged = {} - - for each key in rawItem - merged.AddReplace(key, rawItem[key]) - end for - - if isAssociativeArrayValue(enrichedItem) - for each key in enrichedItem - currentValue = invalid - if merged.DoesExist(key) - currentValue = merged[key] - end if - - enrichedValue = enrichedItem[key] - if not isMissingMergeValue(enrichedValue) or isMissingMergeValue(currentValue) - merged.AddReplace(key, enrichedValue) - end if - end for - end if - - rawImageTags = getValueCaseInsensitive(rawItem, "ImageTags", invalid) - enrichedImageTags = getValueCaseInsensitive(enrichedItem, "ImageTags", invalid) - if isAssociativeArrayValue(rawImageTags) or isAssociativeArrayValue(enrichedImageTags) - mergedImageTags = {} - - if isAssociativeArrayValue(rawImageTags) - for each key in rawImageTags - mergedImageTags.AddReplace(key, rawImageTags[key]) - end for - end if - - if isAssociativeArrayValue(enrichedImageTags) - for each key in enrichedImageTags - mergedImageTags.AddReplace(key, enrichedImageTags[key]) - end for - end if - - merged.AddReplace("ImageTags", mergedImageTags) - end if - - return merged -end function - -function getValueCaseInsensitive(data as dynamic, key as string, defaultValue = invalid as dynamic) as dynamic - if not isAssociativeArrayValue(data) - return defaultValue - end if - - if data.DoesExist(key) - return data[key] - end if - - normalizedKey = LCase(key) - for each dataKey in data - if LCase(dataKey) = normalizedKey - return data[dataKey] - end if - end for - - return defaultValue -end function - -function toNormalizedString(value as dynamic) as string - if not isValid(value) - return "" - end if - - if GetInterface(value, "ifString") <> invalid - return value.ToStr().Trim() - end if - - return "" -end function - -function isMissingMergeValue(value as dynamic) as boolean - if not isValid(value) - return true - end if - - valueType = type(value) - if valueType = "String" or valueType = "roString" - return Len(value.Trim()) = 0 - end if - - if valueType = "Array" or valueType = "roArray" - return value.Count() = 0 - end if - - return false -end function - -function isAssociativeArrayValue(value as dynamic) as boolean - valueType = type(value) - return valueType = "AssociativeArray" or valueType = "roAssociativeArray" -end function diff --git a/components/home/HSSLoadSectionTask.xml b/components/home/HSSLoadSectionTask.xml deleted file mode 100644 index 806e1d38c..000000000 --- a/components/home/HSSLoadSectionTask.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/components/home/HSSProbeTask.bs b/components/home/HSSProbeTask.bs deleted file mode 100644 index 80031907a..000000000 --- a/components/home/HSSProbeTask.bs +++ /dev/null @@ -1,106 +0,0 @@ -import "pkg:/source/api/baserequest.bs" -import "pkg:/source/utils/misc.bs" - -sub init() - m.top.functionName = "probeHomeScreenSections" -end sub - -function targetAPIRequest(path as string, params = {} as object) as dynamic - if not isValidAndNotEmpty(m.top.serverUrl) - return invalid - end if - - return APIRequestForServer(m.top.serverUrl, m.top.userId, m.top.authToken, path, params) -end function - -sub probeHomeScreenSections() - result = { - enabled: false, - sections: [] - } - - metaRequest = targetAPIRequest("/HomeScreen/Meta") - if not isValid(metaRequest) - m.top.result = result - return - end if - - meta = getJson(metaRequest) - enabled = isHssMetaEnabled(meta) - if not enabled - m.top.result = result - return - end if - - result.enabled = true - - userId = m.top.userId - if not isValidAndNotEmpty(userId) - m.top.result = result - return - end if - - sectionsRequest = targetAPIRequest("/HomeScreen/Sections", { userId: userId }) - if not isValid(sectionsRequest) - m.top.result = result - return - end if - - sectionsResponse = getJson(sectionsRequest) - sectionsPayload = getSectionsPayload(sectionsResponse) - - sections = [] - for each sectionItem in sectionsPayload - sectionType = chainLookupReturn(sectionItem, "section", "") - if not isValidAndNotEmpty(sectionType) - continue for - end if - - displayText = chainLookupReturn(sectionItem, "displayText", "") - if not isValidAndNotEmpty(displayText) - displayText = sectionType - end if - - additionalData = chainLookupReturn(sectionItem, "additionalData", "") - - sections.push({ - section: sectionType, - displayText: displayText, - additionalData: additionalData - }) - end for - - result.sections = sections - m.top.result = result -end sub - -function isHssMetaEnabled(meta as dynamic) as boolean - enabledValue = chainLookupReturn(meta, "enabled", false) - - if type(enabledValue) = "Boolean" or type(enabledValue) = "roBoolean" - return enabledValue - end if - - if type(enabledValue) = "String" or type(enabledValue) = "roString" - return LCase(enabledValue) = "true" - end if - - return false -end function - -function getSectionsPayload(response as dynamic) as object - if not isValid(response) - return [] - end if - - responseType = type(response) - if responseType = "Array" or responseType = "roArray" - return response - end if - - if isChainValid(response, "Items") - return response.Items - end if - - return [] -end function diff --git a/components/home/HSSProbeTask.xml b/components/home/HSSProbeTask.xml deleted file mode 100644 index e2bf8d528..000000000 --- a/components/home/HSSProbeTask.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/components/home/HomeRows.bs b/components/home/HomeRows.bs index a9eb39790..a7879924e 100644 --- a/components/home/HomeRows.bs +++ b/components/home/HomeRows.bs @@ -6,10 +6,6 @@ import "pkg:/source/utils/misc.bs" import "pkg:/source/utils/multiserver.bs" const LOADING_WAIT_TIME = 2 -const HSS_LOCAL_ROWS_SETTING = "ui.home.hssRowsLocalConfig" -const KT_LOCAL_ROWS_SETTING = "ui.home.ktRowsLocalConfig" -const HSS_MAX_CONCURRENT_SECTION_TASKS = 3 -const KT_MAX_CONCURRENT_SECTION_TASKS = 3 ' Helper function to get poster size based on user preference function getPosterSize(preferWide = true as boolean) as object @@ -87,30 +83,11 @@ sub init() m.contentTasks = {} m.multiServerTasks = {} m.useServerConfig = false - m.hssProbeTask = invalid - m.hssSections = [] - m.hssSuppressedBuiltins = {} - m.hssSectionTasks = {} - m.hssSectionTaskQueue = [] - m.activeHssSectionTaskCount = 0 - m.hssRowTitleByKey = {} - m.hssRowTitles = [] - m.ktProbeTask = invalid - m.ktSections = [] - m.ktSectionTasks = {} - m.ktSectionTaskQueue = [] - m.activeKtSectionTaskCount = 0 - m.ktRowTitleByKey = {} - m.ktRowTitles = [] m.serverHomeRows = [] m.serverHomeRowsSource = "legacy" m.serverLegacyRowOrder = [] m.serverDynamicRowTitles = {} m.hasResolvedRowsPayload = false - m.localPluginRowFilters = { - hss: {}, - kefintweaks: {} - } m.pendingProbeCount = 0 m.initialHomeRowsStarted = false end sub @@ -197,13 +174,6 @@ function shouldUseServerConfig() as boolean return normalizeBooleanValue(get_user_setting("homeRows.useServerConfig"), false) end function -function isHssEnabled() as boolean - return normalizeBooleanValue(get_user_setting("plugin.hss.enabled"), false) -end function - -function isKtEnabled() as boolean - return normalizeBooleanValue(get_user_setting("plugin.kefintweaks.enabled"), false) -end function function isPluginFeatureOptedOut(settingName as string) as boolean settingValue = get_user_setting(settingName) @@ -214,82 +184,6 @@ function isPluginFeatureOptedOut(settingName as string) as boolean return not normalizeBooleanValue(settingValue, false) end function -function loadCachedHssProbeState() as boolean - m.hssSections = [] - m.hssSuppressedBuiltins = {} - - cachedValue = get_user_setting("plugin.hss.homeCache") - if not isValidAndNotEmpty(cachedValue) - return false - end if - - parsed = ParseJson(cachedValue) - if not isValid(parsed) - return false - end if - - if not normalizeBooleanValue(chainLookupReturn(parsed, "loaded", false), false) - return false - end if - - if normalizeBooleanValue(chainLookupReturn(parsed, "enabled", false), false) - cachedSections = chainLookupReturn(parsed, "sections", []) - if isValid(cachedSections) - m.hssSections = cachedSections - end if - - cachedSuppressedBuiltins = chainLookupReturn(parsed, "suppressedBuiltins", {}) - if isValid(cachedSuppressedBuiltins) - m.hssSuppressedBuiltins = cachedSuppressedBuiltins - end if - end if - - return true -end function - -function loadCachedKtProbeState() as boolean - m.ktSections = [] - - cachedValue = get_user_setting("plugin.kt.homeCache") - if not isValidAndNotEmpty(cachedValue) - return false - end if - - parsed = ParseJson(cachedValue) - if not isValid(parsed) - return false - end if - - if not normalizeBooleanValue(chainLookupReturn(parsed, "loaded", false), false) - return false - end if - - if normalizeBooleanValue(chainLookupReturn(parsed, "enabled", false), false) - cachedSections = chainLookupReturn(parsed, "sections", []) - if isValid(cachedSections) - m.ktSections = cachedSections - end if - end if - - return true -end function - -sub saveHssProbeCache(enabled as boolean) - set_user_setting("plugin.hss.homeCache", FormatJson({ - loaded: true, - enabled: enabled, - sections: m.hssSections, - suppressedBuiltins: m.hssSuppressedBuiltins - })) -end sub - -sub saveKtProbeCache(enabled as boolean) - set_user_setting("plugin.kt.homeCache", FormatJson({ - loaded: true, - enabled: enabled, - sections: m.ktSections - })) -end sub function isArrayValue(value as dynamic) as boolean valueType = type(value) @@ -370,11 +264,6 @@ end function function normalizeHomeRowsSource(sourceValue as dynamic) as string source = LCase(toNormalizedString(sourceValue)) - if source = "kefin" or source = "kefintweak" or source = "kefintweaks" - return "kefintweaks" - end if - - if source = "hss" then return "hss" if source = "legacy" then return "legacy" if source = "jellyfin" then return "jellyfin" if source = "moonfin" then return "moonfin" @@ -457,18 +346,9 @@ function buildPluginRowsFilterMap(configRows as object) as object return filterMap end function -sub refreshLocalPluginRowFilters() - m.localPluginRowFilters = { - hss: buildPluginRowsFilterMap(parsePluginRowsConfigSetting(HSS_LOCAL_ROWS_SETTING)), - kefintweaks: buildPluginRowsFilterMap(parsePluginRowsConfigSetting(KT_LOCAL_ROWS_SETTING)) - } -end sub function getLocalPluginRowFilter(row as object) as dynamic rowSource = normalizeHomeRowsSource(chainLookupReturn(row, "source", m.serverHomeRowsSource)) - if rowSource <> "hss" and rowSource <> "kefintweaks" - return invalid - end if rowId = LCase(toNormalizedString(chainLookupReturn(row, "id", ""))) if not isValidAndNotEmpty(rowId) @@ -643,7 +523,7 @@ sub refreshServerRowsState() end if m.serverLegacyRowOrder = parseHomeRowOrderSetting() - refreshLocalPluginRowFilters() +' refreshLocalPluginRowFilters() m.hasResolvedRowsPayload = hasResolvedServerRowsPayload() payload = parseResolvedRowsPayload() @@ -727,399 +607,25 @@ function getResolvedSectionName(index as integer) as string return getResolvedSectionNameForMode(index, m.useServerConfig) end function -function shouldLoadHss() as boolean - if shouldUseResolvedServerRows() - if m.serverHomeRowsSource = "hss" or hasServerRowsForSource("hss") - return true - end if - end if - - if isPluginFeatureOptedOut("plugin.enabled") or isPluginFeatureOptedOut("plugin.hss.enabled") - return false - end if - - if moonfinPlugin.IsPluginInstalled() - return true - end if - - if not isHssEnabled() - return false - end if - - useServerConfig = shouldUseServerConfig() - for i = 0 to 7 - sectionName = getResolvedSectionNameForMode(i, useServerConfig) - if sectionName = "hss_all" - return true - end if - end for - - return false -end function - -function shouldLoadKt() as boolean - if shouldUseResolvedServerRows() - if m.serverHomeRowsSource = "kefintweaks" or hasServerRowsForSource("kefintweaks") - return true - end if - end if - - if isPluginFeatureOptedOut("plugin.enabled") or isPluginFeatureOptedOut("plugin.kefintweaks.enabled") - return false - end if - - if moonfinPlugin.IsPluginInstalled() - return true - end if - - if not isKtEnabled() - return false - end if - - useServerConfig = shouldUseServerConfig() - for i = 0 to 7 - sectionName = getResolvedSectionNameForMode(i, useServerConfig) - if sectionName = "kt_all" - return true - end if - end for - - return false -end function - -function isSectionSuppressedByHss(sectionName as string) as boolean - if not isValid(m.hssSuppressedBuiltins) - return false - end if - - return m.hssSuppressedBuiltins.DoesExist(sectionName) -end function - -function getHssSectionKey(sectionType as string, additionalData = "" as string, sectionIndex = 0 as integer) as string - return LCase(sectionType ?? "") + "|" + LCase(additionalData ?? "") + "|" + sectionIndex.toStr() -end function - -function getKtSectionKey(sectionType as string, sectionIndex = 0 as integer) as string - return LCase(sectionType ?? "") + "|" + sectionIndex.toStr() -end function - -function getUniqueHssSectionTitle(baseTitle as string, usedTitles as object) as string - if not isValidAndNotEmpty(baseTitle) - baseTitle = "Home" - end if - - candidate = baseTitle - suffix = 2 - - while sectionExists(candidate) or usedTitles.DoesExist(LCase(candidate)) - candidate = baseTitle + " (" + suffix.toStr() + ")" - suffix++ - end while - - usedTitles[LCase(candidate)] = true - return candidate -end function - -function getHssBuiltinEquivalent(section as string) as string - sectionName = LCase(section ?? "").Replace(" ", "") - - if sectionName = "continuewatching" then return "resume" - if sectionName = "continuelistening" or sectionName = "resumeaudio" then return "resumeaudio" - if sectionName = "nextup" then return "nextup" - if sectionName = "latestmedia" then return "latestmedia" - if sectionName = "recentlyreleased" then return "recentlyreleased" - if sectionName = "favorites" then return "favorites" - - return "" -end function - -sub cleanupHssTasks() - m.hssSectionTaskQueue = [] - m.activeHssSectionTaskCount = 0 - - if not isValid(m.hssSectionTasks) - m.hssSectionTasks = {} - return - end if - - for each taskKey in m.hssSectionTasks - task = m.hssSectionTasks[taskKey] - if isValid(task) - task.unobserveField("content") - task.control = "STOP" - end if - end for - - m.hssSectionTasks = {} -end sub - -sub resetHssRowTracking() - m.hssRowTitleByKey = {} - m.hssRowTitles = [] -end sub - -sub removeTrackedHssRows() - if not isValid(m.hssRowTitles) - m.hssRowTitles = [] - return - end if - - didRemoveRow = false - - for each rowTitle in m.hssRowTitles - while sectionExists(rowTitle) - sectionIndex = getSectionIndex(rowTitle) - if sectionIndex < 0 - exit while - end if - - m.top.content.removeChildIndex(sectionIndex) - didRemoveRow = true - end while - end for - - if didRemoveRow - setRowItemSize() - end if -end sub - -sub cleanupKtTasks() - m.ktSectionTaskQueue = [] - m.activeKtSectionTaskCount = 0 - - if not isValid(m.ktSectionTasks) - m.ktSectionTasks = {} - return - end if - - for each taskKey in m.ktSectionTasks - task = m.ktSectionTasks[taskKey] - if isValid(task) - task.unobserveField("content") - task.control = "STOP" - end if - end for - - m.ktSectionTasks = {} -end sub - -sub resetKtRowTracking() - m.ktRowTitleByKey = {} - m.ktRowTitles = [] -end sub - -sub removeTrackedKtRows() - if not isValid(m.ktRowTitles) - m.ktRowTitles = [] - return - end if - - didRemoveRow = false - - for each rowTitle in m.ktRowTitles - while sectionExists(rowTitle) - sectionIndex = getSectionIndex(rowTitle) - if sectionIndex < 0 - exit while - end if - - m.top.content.removeChildIndex(sectionIndex) - didRemoveRow = true - end while - end for - - if didRemoveRow - setRowItemSize() - end if -end sub sub startHomeRowsLoading() - cleanupHssTasks() - cleanupKtTasks() - removeTrackedHssRows() - removeTrackedKtRows() - resetHssRowTracking() - resetKtRowTracking() - m.hssSections = [] - m.hssSuppressedBuiltins = {} - m.ktSections = [] m.serverDynamicRowTitles = {} m.pendingProbeCount = 0 m.initialHomeRowsStarted = false refreshServerRowsState() - if isValid(m.hssProbeTask) - m.hssProbeTask.unobserveField("result") - m.hssProbeTask.control = "STOP" - m.hssProbeTask = invalid - end if - - if isValid(m.ktProbeTask) - m.ktProbeTask.unobserveField("result") - m.ktProbeTask.control = "STOP" - m.ktProbeTask = invalid - end if - - shouldProbeHss = shouldLoadHss() - shouldProbeKt = shouldLoadKt() - - if shouldUseResolvedServerRows() - if m.serverHomeRowsSource = "hss" or hasServerRowsForSource("hss") - shouldProbeHss = false - end if - - if m.serverHomeRowsSource = "kefintweaks" or hasServerRowsForSource("kefintweaks") - shouldProbeKt = false - end if - end if - - if shouldProbeHss - loadCachedHssProbeState() - m.hssProbeTask = CreateObject("roSGNode", "HSSProbeTask") - m.hssProbeTask.serverUrl = chainLookupReturn(m.global, "session.server.url", "") - m.hssProbeTask.userId = chainLookupReturn(m.global, "session.user.id", "") - m.hssProbeTask.authToken = chainLookupReturn(m.global, "session.user.authToken", "") - m.hssProbeTask.observeField("result", "onHSSProbeComplete") - m.pendingProbeCount++ - m.hssProbeTask.control = "RUN" - end if - - if shouldProbeKt - loadCachedKtProbeState() - m.ktProbeTask = CreateObject("roSGNode", "KefinTweaksProbeTask") - m.ktProbeTask.serverUrl = chainLookupReturn(m.global, "session.server.url", "") - m.ktProbeTask.userId = chainLookupReturn(m.global, "session.user.id", "") - m.ktProbeTask.authToken = chainLookupReturn(m.global, "session.user.authToken", "") - m.ktProbeTask.observeField("result", "onKTProbeComplete") - m.pendingProbeCount++ - m.ktProbeTask.control = "RUN" - end if m.initialHomeRowsStarted = true processUserSections() end sub -sub onHSSProbeComplete() - hssEnabled = false - - if isValid(m.hssProbeTask) - result = m.hssProbeTask.result - - m.hssProbeTask.unobserveField("result") - m.hssProbeTask = invalid - - m.hssSections = [] - m.hssSuppressedBuiltins = {} - - if isValid(result) and normalizeBooleanValue(result.enabled, false) - hssEnabled = true - sections = chainLookupReturn(result, "sections", []) - if isValidAndNotEmpty(sections) - m.hssSections = sections - - for each hssSection in m.hssSections - builtinSection = getHssBuiltinEquivalent(chainLookupReturn(hssSection, "section", "")) - if isValidAndNotEmpty(builtinSection) - m.hssSuppressedBuiltins[builtinSection] = true - end if - end for - end if - end if - end if - - saveHssProbeCache(hssEnabled) - - if m.pendingProbeCount > 0 - m.pendingProbeCount = m.pendingProbeCount - 1 - end if - - if m.initialHomeRowsStarted - if shouldUseResolvedServerRows() - return - end if - - cleanupHssTasks() - removeTrackedHssRows() - resetHssRowTracking() - - if shouldLoadHss() - createHssRows() - end if - return - end if - - if not m.initialHomeRowsStarted - m.initialHomeRowsStarted = true - processUserSections() - end if -end sub - -sub onKTProbeComplete() - ktEnabled = false - - if isValid(m.ktProbeTask) - result = m.ktProbeTask.result - - m.ktProbeTask.unobserveField("result") - m.ktProbeTask = invalid - - m.ktSections = [] - - if isValid(result) and normalizeBooleanValue(result.enabled, false) - ktEnabled = true - sections = chainLookupReturn(result, "sections", []) - if isValidAndNotEmpty(sections) - m.ktSections = sections - end if - end if - end if - - saveKtProbeCache(ktEnabled) - - if m.pendingProbeCount > 0 - m.pendingProbeCount = m.pendingProbeCount - 1 - end if - - if m.initialHomeRowsStarted - if shouldUseResolvedServerRows() - return - end if - - cleanupKtTasks() - removeTrackedKtRows() - resetKtRowTracking() - - if shouldLoadKt() - createKtRows() - end if - return - end if - - if m.pendingProbeCount = 0 - m.initialHomeRowsStarted = true - processUserSections() - end if -end sub function getExpectedRowContribution(sectionName as string) as integer if not isValidAndNotEmpty(sectionName) or sectionName = "none" return 0 end if - if sectionName = "hss_all" - if isValidAndNotEmpty(m.hssSections) - return m.hssSections.Count() - end if - return 0 - end if - - if sectionName = "kt_all" - if isValidAndNotEmpty(m.ktSections) - return m.ktSections.Count() - end if - return 0 - end if if sectionName = "latestmedia" if isMultiServerEnabled() @@ -1167,13 +673,6 @@ function inferServerRowSource(row as object) as string rowSource = m.serverHomeRowsSource end if - rowIdToken = normalizeSectionToken(chainLookupReturn(row, "id", "")) - if rowSource <> "hss" and Left(rowIdToken, 3) = "hss" - rowSource = "hss" - end if - if rowSource <> "kefintweaks" and (Left(rowIdToken, 5) = "kefin" or Left(rowIdToken, 2) = "kt") - rowSource = "kefintweaks" - end if return rowSource end function @@ -1201,163 +700,20 @@ function mapBuiltinSectionFromServerRow(row as object) as string if token = "mylist" or token = "playlists" then return "mylist" if token = "smalllibrarytiles" or token = "librarytilessmall" or token = "librarybuttons" or token = "mymedia" then return "smalllibrarytiles" if token = "featuredmedia" or token = "mediabar" then return "featuredmedia" - if token = "hssall" then return "hss_all" - if token = "ktall" or token = "kefintweaksrows" then return "kt_all" if token = "none" then return "none" end for return "" end function -function getServerDynamicTitle(baseTitle as string) as string - if not isValid(m.serverDynamicRowTitles) - m.serverDynamicRowTitles = {} - end if - - return getUniqueHssSectionTitle(baseTitle, m.serverDynamicRowTitles) -end function function parseServerAdditionalData(row as object) as dynamic return parseJsonObjectOrArray(chainLookupReturn(row, "additionalData", invalid)) end function -function createHssRowFromServerRow(row as object, rowIndex as integer) as boolean - parsedAdditional = parseServerAdditionalData(row) - sectionType = "" - if isAssociativeArrayValue(parsedAdditional) - sectionType = toNormalizedString(getCaseInsensitiveValue(parsedAdditional, "section", "")) - end if +function addServerHomeRow(row as object) as boolean - if not isValidAndNotEmpty(sectionType) - rowId = toNormalizedString(chainLookupReturn(row, "id", "")) - rowIdLower = LCase(rowId) - if Left(rowIdLower, 4) = "hss-" - sectionType = rowId.Mid(4) - else - sectionType = rowId - end if - end if - - if not isValidAndNotEmpty(sectionType) - m.processedRowCount++ - return false - end if - - sectionTitle = toNormalizedString(chainLookupReturn(row, "title", "")) - if not isValidAndNotEmpty(sectionTitle) and isAssociativeArrayValue(parsedAdditional) - sectionTitle = toNormalizedString(getCaseInsensitiveValue(parsedAdditional, "displayText", sectionType)) - end if - sectionTitle = getServerDynamicTitle(sectionTitle) - - additionalData = "" - if isAssociativeArrayValue(parsedAdditional) - additionalData = toNormalizedString(getCaseInsensitiveValue(parsedAdditional, "additionalData", "")) - else - additionalData = toNormalizedString(chainLookupReturn(row, "additionalData", "")) - end if - - sectionKey = getHssSectionKey(sectionType, additionalData, rowIndex) - m.hssRowTitleByKey[sectionKey] = sectionTitle - m.hssRowTitles.push(sectionTitle) - - if not sectionExists(sectionTitle) - rowNode = m.top.content.CreateChild("HomeRow") - rowNode.title = sectionTitle - rowNode.imageWidth = getPosterSize(false)[0] - rowNode.cursorSize = getPosterSize(false) - end if - - enqueueHssSectionTask(sectionType, additionalData, sectionTitle, sectionKey) - - return true -end function - -function createKtRowFromServerRow(row as object, rowIndex as integer) as boolean - parsedAdditional = parseServerAdditionalData(row) - - sectionKind = toNormalizedString(chainLookupReturn(row, "route", "")) - if not isValidAndNotEmpty(sectionKind) and isAssociativeArrayValue(parsedAdditional) - sectionKind = toNormalizedString(getCaseInsensitiveValue(parsedAdditional, "kind", "")) - end if - if not isValidAndNotEmpty(sectionKind) and isAssociativeArrayValue(parsedAdditional) - sectionKind = toNormalizedString(getCaseInsensitiveValue(parsedAdditional, "section", "")) - end if - - if not isValidAndNotEmpty(sectionKind) - rowId = toNormalizedString(chainLookupReturn(row, "id", "")) - rowIdLower = LCase(rowId) - if Left(rowIdLower, 6) = "kefin-" - sectionKind = rowId.Mid(6) - else if Left(rowIdLower, 3) = "kt-" - sectionKind = rowId.Mid(3) - else - idParts = rowId.Split(":") - if idParts.Count() >= 4 and LCase(idParts[0]) = "plugindynamic" - sectionKind = idParts[3] - else if idParts.Count() > 0 - sectionKind = idParts[idParts.Count() - 1] - end if - end if - end if - - if not isValidAndNotEmpty(sectionKind) - m.processedRowCount++ - return false - end if - - sectionSpec = {} - if isAssociativeArrayValue(parsedAdditional) - parsedSpec = getCaseInsensitiveValue(parsedAdditional, "spec", invalid) - if isAssociativeArrayValue(parsedSpec) - sectionSpec = parsedSpec - else - hasSectionMetadata = isValidAndNotEmpty(toNormalizedString(getCaseInsensitiveValue(parsedAdditional, "section", ""))) or isValidAndNotEmpty(toNormalizedString(getCaseInsensitiveValue(parsedAdditional, "displayText", ""))) - if not hasSectionMetadata - sectionSpec = parsedAdditional - end if - end if - end if - - if isAssociativeArrayValue(sectionSpec) - specKind = toNormalizedString(getCaseInsensitiveValue(sectionSpec, "kind", "")) - if not isValidAndNotEmpty(specKind) - sectionSpec.kind = sectionKind - end if - end if - - sectionTitle = toNormalizedString(chainLookupReturn(row, "title", "")) - if not isValidAndNotEmpty(sectionTitle) and isAssociativeArrayValue(parsedAdditional) - sectionTitle = toNormalizedString(getCaseInsensitiveValue(parsedAdditional, "displayText", sectionKind)) - end if - sectionTitle = getServerDynamicTitle(sectionTitle) - - sectionKey = getKtSectionKey(sectionKind, rowIndex) - m.ktRowTitleByKey[sectionKey] = sectionTitle - m.ktRowTitles.push(sectionTitle) - - if not sectionExists(sectionTitle) - rowNode = m.top.content.CreateChild("HomeRow") - rowNode.title = sectionTitle - rowNode.imageWidth = getPosterSize(false)[0] - rowNode.cursorSize = getPosterSize(false) - end if - - enqueueKtSectionTask(sectionKind, sectionSpec, sectionTitle, sectionKey) - - return true -end function - -function addServerHomeRow(row as object, rowIndex as integer) as boolean - rowSource = inferServerRowSource(row) - - if rowSource = "hss" - return createHssRowFromServerRow(row, rowIndex) - end if - - if rowSource = "kefintweaks" - return createKtRowFromServerRow(row, rowIndex) - end if sectionType = mapBuiltinSectionFromServerRow(row) if not isValidAndNotEmpty(sectionType) or sectionType = "none" @@ -1373,12 +729,7 @@ sub processServerRows() m.processedRowCount = 0 for each row in m.serverHomeRows - rowSource = inferServerRowSource(row) - if rowSource = "hss" or rowSource = "kefintweaks" - m.expectedRowCount++ - continue for - end if sectionType = mapBuiltinSectionFromServerRow(row) if not isValidAndNotEmpty(sectionType) or sectionType = "none" @@ -1392,7 +743,7 @@ sub processServerRows() loadedSections = 0 rowIndex = 0 for each row in m.serverHomeRows - sectionLoaded = addServerHomeRow(row, rowIndex) + sectionLoaded = addServerHomeRow(row) if sectionLoaded then loadedSections++ if not m.global.app_loaded @@ -1438,9 +789,6 @@ sub processUserSections() for i = 0 to 7 sectionName = getResolvedSectionName(i) - if isSectionSuppressedByHss(sectionName) - sectionName = "none" - end if m.expectedRowCount = m.expectedRowCount + getExpectedRowContribution(sectionName) end for @@ -1450,9 +798,6 @@ sub processUserSections() for i = 0 to 7 sectionName = getResolvedSectionName(i) - if isSectionSuppressedByHss(sectionName) - sectionName = "none" - end if sectionLoaded = false if sectionName <> "none" @@ -1669,15 +1014,6 @@ function addHomeSection(sectionType as string) as boolean return true end if - if sectionType = "hss_all" - createHssRows() - return isValidAndNotEmpty(m.hssSections) - end if - - if sectionType = "kt_all" - createKtRows() - return isValidAndNotEmpty(m.ktSections) - end if ' Featured Media Carousel - now handled by separate toggle in Moonfin settings ' Skip creating a row for it, as it's controlled by ui.home.mediaBarEnabled @@ -1692,197 +1028,6 @@ function addHomeSection(sectionType as string) as boolean return false end function -sub enqueueHssSectionTask(sectionType as string, additionalData as string, sectionTitle as string, sectionKey as string) - if not isValid(m.hssSectionTaskQueue) - m.hssSectionTaskQueue = [] - end if - - m.hssSectionTaskQueue.push({ - sectionType: sectionType, - additionalData: additionalData, - sectionTitle: sectionTitle, - sectionKey: sectionKey - }) - - drainHssSectionTaskQueue() -end sub - -sub drainHssSectionTaskQueue() - if not isValid(m.hssSectionTaskQueue) - m.hssSectionTaskQueue = [] - end if - - if not isValid(m.hssSectionTasks) - m.hssSectionTasks = {} - end if - - while m.activeHssSectionTaskCount < HSS_MAX_CONCURRENT_SECTION_TASKS and m.hssSectionTaskQueue.Count() > 0 - taskDescriptor = m.hssSectionTaskQueue.Shift() - if not isAssociativeArrayValue(taskDescriptor) - continue while - end if - - sectionType = chainLookupReturn(taskDescriptor, "sectionType", "") - sectionKey = chainLookupReturn(taskDescriptor, "sectionKey", "") - if not isValidAndNotEmpty(sectionType) or not isValidAndNotEmpty(sectionKey) - continue while - end if - - task = CreateObject("roSGNode", "HSSLoadSectionTask") - task.sectionType = sectionType - task.additionalData = chainLookupReturn(taskDescriptor, "additionalData", "") - task.displayText = chainLookupReturn(taskDescriptor, "sectionTitle", "") - task.sectionKey = sectionKey - task.serverUrl = chainLookupReturn(m.global, "session.server.url", "") - task.userId = chainLookupReturn(m.global, "session.user.id", "") - task.authToken = chainLookupReturn(m.global, "session.user.authToken", "") - task.observeField("content", "onHssSectionLoaded") - m.hssSectionTasks[sectionKey] = task - m.activeHssSectionTaskCount++ - task.control = "RUN" - end while -end sub - -sub enqueueKtSectionTask(sectionType as string, sectionSpec as dynamic, sectionTitle as string, sectionKey as string) - if not isValid(m.ktSectionTaskQueue) - m.ktSectionTaskQueue = [] - end if - - m.ktSectionTaskQueue.push({ - sectionType: sectionType, - sectionSpec: sectionSpec, - sectionTitle: sectionTitle, - sectionKey: sectionKey - }) - - drainKtSectionTaskQueue() -end sub - -sub drainKtSectionTaskQueue() - if not isValid(m.ktSectionTaskQueue) - m.ktSectionTaskQueue = [] - end if - - if not isValid(m.ktSectionTasks) - m.ktSectionTasks = {} - end if - - while m.activeKtSectionTaskCount < KT_MAX_CONCURRENT_SECTION_TASKS and m.ktSectionTaskQueue.Count() > 0 - taskDescriptor = m.ktSectionTaskQueue.Shift() - if not isAssociativeArrayValue(taskDescriptor) - continue while - end if - - sectionType = chainLookupReturn(taskDescriptor, "sectionType", "") - sectionKey = chainLookupReturn(taskDescriptor, "sectionKey", "") - if not isValidAndNotEmpty(sectionType) or not isValidAndNotEmpty(sectionKey) - continue while - end if - - task = CreateObject("roSGNode", "KefinTweaksLoadSectionTask") - task.sectionKind = sectionType - task.spec = chainLookupReturn(taskDescriptor, "sectionSpec", {}) - task.displayText = chainLookupReturn(taskDescriptor, "sectionTitle", "") - task.sectionKey = sectionKey - task.serverUrl = chainLookupReturn(m.global, "session.server.url", "") - task.userId = chainLookupReturn(m.global, "session.user.id", "") - task.authToken = chainLookupReturn(m.global, "session.user.authToken", "") - task.observeField("content", "onKtSectionLoaded") - m.ktSectionTasks[sectionKey] = task - m.activeKtSectionTaskCount++ - task.control = "RUN" - end while -end sub - -sub createHssRows() - if not isValidAndNotEmpty(m.hssSections) - return - end if - - if not isValid(m.hssSectionTasks) - m.hssSectionTasks = {} - end if - - usedTitles = {} - - sectionIndex = 0 - for each hssSection in m.hssSections - sectionType = chainLookupReturn(hssSection, "section", "") - if not isValidAndNotEmpty(sectionType) - m.processedRowCount++ - sectionIndex++ - continue for - end if - - sectionTitle = chainLookupReturn(hssSection, "displayText", "") - if not isValidAndNotEmpty(sectionTitle) - sectionTitle = sectionType - end if - sectionTitle = getUniqueHssSectionTitle(sectionTitle, usedTitles) - - additionalData = chainLookupReturn(hssSection, "additionalData", "") - sectionKey = getHssSectionKey(sectionType, additionalData, sectionIndex) - - m.hssRowTitleByKey[sectionKey] = sectionTitle - m.hssRowTitles.push(sectionTitle) - - if not sectionExists(sectionTitle) - row = m.top.content.CreateChild("HomeRow") - row.title = sectionTitle - row.imageWidth = getPosterSize(false)[0] - row.cursorSize = getPosterSize(false) - end if - - enqueueHssSectionTask(sectionType, additionalData, sectionTitle, sectionKey) - - sectionIndex++ - end for -end sub - -sub createKtRows() - if not isValidAndNotEmpty(m.ktSections) - return - end if - - if not isValid(m.ktSectionTasks) - m.ktSectionTasks = {} - end if - - usedTitles = {} - - sectionIndex = 0 - for each ktSection in m.ktSections - sectionType = chainLookupReturn(ktSection, "kind", "") - if not isValidAndNotEmpty(sectionType) - m.processedRowCount++ - sectionIndex++ - continue for - end if - - sectionTitle = chainLookupReturn(ktSection, "displayText", "") - if not isValidAndNotEmpty(sectionTitle) - sectionTitle = sectionType - end if - sectionTitle = getUniqueHssSectionTitle(sectionTitle, usedTitles) - - sectionSpec = chainLookupReturn(ktSection, "spec", {}) - sectionKey = getKtSectionKey(sectionType, sectionIndex) - - m.ktRowTitleByKey[sectionKey] = sectionTitle - m.ktRowTitles.push(sectionTitle) - - if not sectionExists(sectionTitle) - row = m.top.content.CreateChild("HomeRow") - row.title = sectionTitle - row.imageWidth = getPosterSize(false)[0] - row.cursorSize = getPosterSize(false) - end if - - enqueueKtSectionTask(sectionType, sectionSpec, sectionTitle, sectionKey) - - sectionIndex++ - end for -end sub ' createLibraryRow: Creates a row displaying the user's libraries ' @@ -3041,137 +2186,6 @@ sub updateRecentlyReleasedItems() setRowItemSize() end sub -sub onHssSectionLoaded(msg as object) - m.processedRowCount++ - - if m.activeHssSectionTaskCount > 0 - m.activeHssSectionTaskCount = m.activeHssSectionTaskCount - 1 - end if - - drainHssSectionTaskQueue() - - node = msg.getRoSGNode() - if not isValid(node) - setRowItemSize() - return - end if - - itemData = msg.getData() - - node.unobserveField("content") - node.content = [] - - sectionKey = node.sectionKey - if isValidAndNotEmpty(sectionKey) and isValid(m.hssSectionTasks) and m.hssSectionTasks.DoesExist(sectionKey) - m.hssSectionTasks.Delete(sectionKey) - end if - - sectionTitle = "" - if isValidAndNotEmpty(sectionKey) and isValid(m.hssRowTitleByKey) and m.hssRowTitleByKey.DoesExist(sectionKey) - sectionTitle = m.hssRowTitleByKey[sectionKey] - end if - - if not isValidAndNotEmpty(sectionTitle) - sectionTitle = node.displayText - end if - - if not isValidAndNotEmpty(sectionTitle) - setRowItemSize() - return - end if - - if not isValidAndNotEmpty(itemData) - removeHomeSection(sectionTitle) - return - end if - - row = CreateObject("roSGNode", "HomeRow") - row.title = sectionTitle - row.imageWidth = getPosterSize(false)[0] - row.cursorSize = getPosterSize(false) - row.usePoster = true - - for each item in itemData - item.usePoster = row.usePoster - item.imageWidth = row.imageWidth - row.appendChild(item) - end for - - if sectionExists(sectionTitle) - m.top.content.replaceChild(row, getSectionIndex(sectionTitle)) - setRowItemSize() - return - end if - - m.top.content.insertChild(row, getOriginalSectionIndex("hss_all")) - setRowItemSize() -end sub - -sub onKtSectionLoaded(msg as object) - m.processedRowCount++ - - if m.activeKtSectionTaskCount > 0 - m.activeKtSectionTaskCount = m.activeKtSectionTaskCount - 1 - end if - - drainKtSectionTaskQueue() - - node = msg.getRoSGNode() - if not isValid(node) - setRowItemSize() - return - end if - - itemData = msg.getData() - - node.unobserveField("content") - node.content = [] - - sectionKey = node.sectionKey - if isValidAndNotEmpty(sectionKey) and isValid(m.ktSectionTasks) and m.ktSectionTasks.DoesExist(sectionKey) - m.ktSectionTasks.Delete(sectionKey) - end if - - sectionTitle = "" - if isValidAndNotEmpty(sectionKey) and isValid(m.ktRowTitleByKey) and m.ktRowTitleByKey.DoesExist(sectionKey) - sectionTitle = m.ktRowTitleByKey[sectionKey] - end if - - if not isValidAndNotEmpty(sectionTitle) - sectionTitle = node.displayText - end if - - if not isValidAndNotEmpty(sectionTitle) - setRowItemSize() - return - end if - - if not isValidAndNotEmpty(itemData) - removeHomeSection(sectionTitle) - return - end if - - row = CreateObject("roSGNode", "HomeRow") - row.title = sectionTitle - row.imageWidth = getPosterSize(false)[0] - row.cursorSize = getPosterSize(false) - row.usePoster = true - - for each item in itemData - item.usePoster = row.usePoster - item.imageWidth = row.imageWidth - row.appendChild(item) - end for - - if sectionExists(sectionTitle) - m.top.content.replaceChild(row, getSectionIndex(sectionTitle)) - setRowItemSize() - return - end if - - m.top.content.insertChild(row, getOriginalSectionIndex("kt_all")) - setRowItemSize() -end sub ' updateOnNowItems: Processes LoadOnNowTask content. Removes, Creates, or Updates Recently Added in on now row as needed ' diff --git a/components/home/KefinTweaksLoadSectionTask.bs b/components/home/KefinTweaksLoadSectionTask.bs deleted file mode 100644 index 69e1d1c90..000000000 --- a/components/home/KefinTweaksLoadSectionTask.bs +++ /dev/null @@ -1,353 +0,0 @@ -import "pkg:/source/api/baserequest.bs" -import "pkg:/source/utils/misc.bs" - -const DEFAULT_SECTION_LIMIT = 15 - -sub init() - m.top.functionName = "loadKefinSection" -end sub - -function targetAPIRequest(serverUrl as string, userId as string, authToken as string, path as string, params = {} as object) as dynamic - if not isValidAndNotEmpty(serverUrl) - return invalid - end if - - return APIRequestForServer(serverUrl, userId, authToken, path, params) -end function - -sub loadKefinSection() - results = [] - - serverUrl = m.top.serverUrl - userId = m.top.userId - authToken = m.top.authToken - sectionKind = m.top.sectionKind - if not isValidAndNotEmpty(sectionKind) - m.top.content = results - return - end if - - if not isValidAndNotEmpty(userId) - m.top.content = results - return - end if - - spec = m.top.spec - if not isAssociativeArrayValue(spec) - spec = {} - end if - - if isStringEqual(sectionKind, "recentlyAddedInLibrary") - itemsPayload = loadRecentlyAddedInLibrary(spec, serverUrl, userId, authToken) - else - response = runKefinSpec(sectionKind, spec, serverUrl, userId, authToken) - itemsPayload = getItemsPayload(response) - end if - - for each item in itemsPayload - homeData = createSGNode("HomeData") - homeData.json = item - results.push(homeData) - end for - - m.top.content = results -end sub - -function runKefinSpec(sectionKind as string, spec as object, serverUrl as string, userId as string, authToken as string) as dynamic - sectionName = LCase(sectionKind ?? "") - if not isValidAndNotEmpty(sectionName) - sectionName = LCase(chainLookupReturn(spec, "kind", "")) - end if - - limit = normalizeLimit(chainLookupReturn(spec, "limit", DEFAULT_SECTION_LIMIT), DEFAULT_SECTION_LIMIT) - - if sectionName = "recentlyreleasedmovies" - params = getBaseItemsParams(limit) - params.IncludeItemTypes = "Movie" - params.SortBy = "PremiereDate" - params.SortOrder = "Descending" - params.MinPremiereDate = getCutoffDateIso(7) - return requestItems(serverUrl, userId, authToken, params) - end if - - if sectionName = "recentlyreleasedepisodes" - params = getBaseItemsParams(limit) - params.IncludeItemTypes = "Episode" - params.SortBy = "PremiereDate" - params.SortOrder = "Descending" - params.MinPremiereDate = getCutoffDateIso(7) - return requestItems(serverUrl, userId, authToken, params) - end if - - if sectionName = "watchagain" - params = getBaseItemsParams(limit) - params.IncludeItemTypes = "Movie,Series" - params.Filters = "IsPlayed" - params.SortBy = "DatePlayed" - params.SortOrder = "Descending" - return requestItems(serverUrl, userId, authToken, params) - end if - - if sectionName = "custom" - return runCustomSpec(spec, serverUrl, userId, authToken, limit) - end if - - return invalid -end function - -function runCustomSpec(spec as object, serverUrl as string, userId as string, authToken as string, limit as integer) as dynamic - sourceValue = chainLookupReturn(spec, "source", "") - if not isValidAndNotEmpty(sourceValue) - return invalid - end if - - customType = LCase(chainLookupReturn(spec, "type", "")) - - params = getBaseItemsParams(limit) - params.SortBy = mapKefinSortBy(chainLookupReturn(spec, "sortBy", "Random")) - params.SortOrder = mapKefinSortOrder(chainLookupReturn(spec, "sortOrderDirection", "Ascending")) - params.IncludeItemTypes = getIncludeItemTypesValue(chainLookupReturn(spec, "includeItemTypes", invalid), "Movie,Series") - - if customType = "tag" - params.Tags = sourceValue - else if customType = "genre" - params.Genres = sourceValue - else if customType = "parent" or customType = "collection" or customType = "playlist" - params.ParentId = sourceValue - else - return invalid - end if - - return requestItems(serverUrl, userId, authToken, params) -end function - -function loadRecentlyAddedInLibrary(spec as object, serverUrl as string, userId as string, authToken as string) as object - libraryIds = getStringArray(chainLookupReturn(spec, "libraryIds", []), []) - limit = normalizeLimit(chainLookupReturn(spec, "limit", DEFAULT_SECTION_LIMIT), DEFAULT_SECTION_LIMIT) - - if not isValidAndNotEmpty(libraryIds) - return [] - end if - - allItems = [] - - for each libraryId in libraryIds - if not isValidAndNotEmpty(libraryId) - continue for - end if - - request = targetAPIRequest(serverUrl, userId, authToken, "/Items/Latest", { - ParentId: libraryId, - Limit: limit, - EnableImageTypes: "Primary,Backdrop,Thumb", - ImageTypeLimit: 1, - EnableTotalRecordCount: false - }) - - if not isValid(request) - continue for - end if - - response = getJson(request) - items = getItemsPayload(response) - if not isValidAndNotEmpty(items) - continue for - end if - - for each item in items - allItems.push(item) - end for - end for - - if allItems.Count() <= limit - return allItems - end if - - trimmed = [] - for i = 0 to limit - 1 - trimmed.push(allItems[i]) - end for - - return trimmed -end function - -function getBaseItemsParams(limit as integer) as object - return { - Recursive: true, - Limit: limit, - EnableImageTypes: "Primary,Backdrop,Thumb", - ImageTypeLimit: 1, - EnableTotalRecordCount: false - } -end function - -function requestItems(serverUrl as string, userId as string, authToken as string, params as object) as dynamic - if not isValidAndNotEmpty(userId) - return invalid - end if - - request = targetAPIRequest(serverUrl, userId, authToken, "/Users/" + userId.EncodeUriComponent() + "/Items", params) - if not isValid(request) - return invalid - end if - - return getJson(request) -end function - -function getCutoffDateIso(days as integer) as string - nowDate = CreateObject("roDateTime") - cutoffDate = CreateObject("roDateTime") - cutoffDate.FromSeconds(nowDate.AsSeconds() - (days * 86400)) - return cutoffDate.ToISOString() -end function - -function mapKefinSortBy(value as dynamic) as string - if not isValidAndNotEmpty(value) - return "Random" - end if - - normalized = LCase(value.ToStr().Replace(" ", "")) - - if normalized = "releasedate" or normalized = "premieredate" - return "PremiereDate" - end if - - if normalized = "dateadded" or normalized = "datecreated" - return "DateCreated" - end if - - if normalized = "name" or normalized = "sortname" - return "SortName" - end if - - if normalized = "communityrating" - return "CommunityRating" - end if - - if normalized = "datelastcontentadded" - return "DateLastContentAdded" - end if - - if normalized = "random" - return "Random" - end if - - return value.ToStr() -end function - -function mapKefinSortOrder(value as dynamic) as string - if not isValidAndNotEmpty(value) - return "Ascending" - end if - - normalized = LCase(value.ToStr()) - if normalized = "descending" - return "Descending" - end if - - return "Ascending" -end function - -function getIncludeItemTypesValue(value as dynamic, defaultValue as string) as string - includeTypes = getStringArray(value, []) - if isValidAndNotEmpty(includeTypes) - return includeTypes.Join(",") - end if - - return defaultValue -end function - -function getStringArray(value as dynamic, defaultValues as object) as object - output = [] - - if isArrayValue(value) - for each item in value - if not isValid(item) - continue for - end if - itemString = item.ToStr().Trim() - if isValidAndNotEmpty(itemString) - output.push(itemString) - end if - end for - else if type(value) = "String" or type(value) = "roString" - for each item in value.Split(",") - itemString = item.Trim() - if isValidAndNotEmpty(itemString) - output.push(itemString) - end if - end for - end if - - if isValidAndNotEmpty(output) - return output - end if - - fallback = [] - if isArrayValue(defaultValues) - for each item in defaultValues - if not isValid(item) - continue for - end if - itemString = item.ToStr().Trim() - if isValidAndNotEmpty(itemString) - fallback.push(itemString) - end if - end for - end if - return fallback -end function - -function normalizeLimit(value as dynamic, defaultValue as integer) as integer - if not isValid(value) - return defaultValue - end if - - parsed = defaultValue - valueType = type(value) - - if valueType = "Integer" or valueType = "LongInteger" or valueType = "roInteger" or valueType = "roInt" - parsed = value - else if valueType = "Float" or valueType = "roFloat" - parsed = Int(value) - else if valueType = "String" or valueType = "roString" - parsed = Int(Val(value)) - end if - - if parsed <= 0 - return defaultValue - end if - - if parsed > 100 - return 100 - end if - - return parsed -end function - -function getItemsPayload(response as dynamic) as object - if not isValid(response) - return [] - end if - - responseType = type(response) - if responseType = "Array" or responseType = "roArray" - return response - end if - - if isChainValid(response, "Items") - return response.Items - end if - - return [] -end function - -function isArrayValue(value as dynamic) as boolean - valueType = type(value) - return valueType = "Array" or valueType = "roArray" -end function - -function isAssociativeArrayValue(value as dynamic) as boolean - valueType = type(value) - return valueType = "AssociativeArray" or valueType = "roAssociativeArray" -end function diff --git a/components/home/KefinTweaksLoadSectionTask.xml b/components/home/KefinTweaksLoadSectionTask.xml deleted file mode 100644 index 1930016c2..000000000 --- a/components/home/KefinTweaksLoadSectionTask.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/components/home/KefinTweaksProbeTask.bs b/components/home/KefinTweaksProbeTask.bs deleted file mode 100644 index 34089ca96..000000000 --- a/components/home/KefinTweaksProbeTask.bs +++ /dev/null @@ -1,481 +0,0 @@ -import "pkg:/source/api/baserequest.bs" -import "pkg:/source/utils/misc.bs" - -const DEFAULT_SECTION_LIMIT = 15 -const KEFIN_CONFIG_REQUEST_TIMEOUT_MS = 8000 - -sub init() - m.top.functionName = "probeKefinTweaks" -end sub - -function targetAPIRequest(path as string, params = {} as object) as dynamic - if not isValidAndNotEmpty(m.top.serverUrl) - return invalid - end if - - return APIRequestForServer(m.top.serverUrl, m.top.userId, m.top.authToken, path, params) -end function - -sub probeKefinTweaks() - result = { - enabled: false, - sections: [] - } - - source = getKefinConfigSource() - if not isValidAndNotEmpty(source) - m.top.result = result - return - end if - - configJson = extractKefinConfigJson(source) - if not isValidAndNotEmpty(configJson) - m.top.result = result - return - end if - - config = ParseJson(configJson) - if not isValid(config) - m.top.result = result - return - end if - - homeScreen = chainLookupReturn(config, "homeScreen", invalid) - if not isValid(homeScreen) - m.top.result = result - return - end if - - if not normalizeEnabled(chainLookupReturn(homeScreen, "enabled", true), true) - m.top.result = result - return - end if - - result.enabled = true - result.sections = buildKefinSections(homeScreen) - - m.top.result = result -end sub - -function getKefinConfigSource() as string - endpoints = [ - "/JavaScriptInjector/private.js", - "/JavaScriptInjector/public.js" - ] - - for each endpoint in endpoints - req = targetAPIRequest(endpoint) - if not isValid(req) - continue for - end if - - source = getRequestBodyWithTimeout(req, KEFIN_CONFIG_REQUEST_TIMEOUT_MS) - if isValidAndNotEmpty(source) - return source - end if - end for - - return "" -end function - -function getRequestBodyWithTimeout(req as dynamic, timeoutMs as integer) as string - if not isValid(req) - return "" - end if - - req.setMessagePort(CreateObject("roMessagePort")) - req.AsyncGetToString() - - response = wait(timeoutMs, req.GetMessagePort()) - if type(response) <> "roUrlEvent" - return "" - end if - - if response.GetResponseCode() <> 200 - return "" - end if - - return response.GetString() -end function - -function extractKefinConfigJson(source as string) as string - strictRegex = CreateObject("roRegex", "window\\.KefinTweaksConfig\\s*=\\s*(\\{[\\s\\S]*?\\});", "m") - strictMatch = strictRegex.Match(source) - if isValid(strictMatch) and strictMatch.Count() > 1 - return strictMatch[1] - end if - - fallbackRegex = CreateObject("roRegex", "window\\.KefinTweaksConfig\\s*=\\s*(\\{[\\s\\S]*?\\})\\s*(?:;|$)", "m") - fallbackMatch = fallbackRegex.Match(source) - if isValid(fallbackMatch) and fallbackMatch.Count() > 1 - return fallbackMatch[1] - end if - - return "" -end function - -function buildKefinSections(homeScreen as dynamic) as object - defaultLimit = normalizeLimit(chainLookupReturn(homeScreen, "defaultItemLimit", DEFAULT_SECTION_LIMIT), DEFAULT_SECTION_LIMIT) - sections = [] - - recentlyReleased = chainLookupReturn(homeScreen, "recentlyReleased", invalid) - if normalizeEnabled(chainLookupReturn(recentlyReleased, "enabled", true), true) - rrMovies = chainLookupReturn(recentlyReleased, "movies", invalid) - if normalizeEnabled(chainLookupReturn(rrMovies, "enabled", true), true) - moviesLimit = normalizeLimit(chainLookupReturn(rrMovies, "itemLimit", defaultLimit), defaultLimit) - moviesOrder = normalizeOrder(chainLookupReturn(rrMovies, "order", 21), 21) - moviesTitle = chainLookupReturn(rrMovies, "name", "Recently Released Movies") - sections.push(buildSectionDescriptor("recentlyReleasedMovies", moviesTitle, moviesOrder, { - kind: "recentlyReleasedMovies", - limit: moviesLimit - })) - end if - - rrEpisodes = chainLookupReturn(recentlyReleased, "episodes", invalid) - if normalizeEnabled(chainLookupReturn(rrEpisodes, "enabled", true), true) - episodesLimit = normalizeLimit(chainLookupReturn(rrEpisodes, "itemLimit", defaultLimit), defaultLimit) - episodesOrder = normalizeOrder(chainLookupReturn(rrEpisodes, "order", 22), 22) - episodesTitle = chainLookupReturn(rrEpisodes, "name", "Recently Released Episodes") - sections.push(buildSectionDescriptor("recentlyReleasedEpisodes", episodesTitle, episodesOrder, { - kind: "recentlyReleasedEpisodes", - limit: episodesLimit - })) - end if - end if - - watchAgain = chainLookupReturn(homeScreen, "watchAgain", invalid) - if normalizeEnabled(chainLookupReturn(watchAgain, "enabled", true), true) - watchAgainLimit = normalizeLimit(chainLookupReturn(watchAgain, "itemLimit", defaultLimit), defaultLimit) - watchAgainOrder = normalizeOrder(chainLookupReturn(watchAgain, "order", 50), 50) - watchAgainTitle = chainLookupReturn(watchAgain, "name", "Watch Again") - sections.push(buildSectionDescriptor("watchAgain", watchAgainTitle, watchAgainOrder, { - kind: "watchAgain", - limit: watchAgainLimit - })) - end if - - recentlyAddedInLibrary = chainLookupReturn(homeScreen, "recentlyAddedInLibrary", invalid) - if isAssociativeArrayValue(recentlyAddedInLibrary) - libraryIds = [] - for each libraryId in recentlyAddedInLibrary - entry = recentlyAddedInLibrary[libraryId] - if not normalizeEnabled(chainLookupReturn(entry, "enabled", true), true) - continue for - end if - if not isValidAndNotEmpty(libraryId) - continue for - end if - libraryIds.push(libraryId) - end for - - if isValidAndNotEmpty(libraryIds) - sections.push(buildSectionDescriptor("recentlyAddedInLibrary", "Recently Added", 90, { - kind: "recentlyAddedInLibrary", - libraryIds: libraryIds, - limit: defaultLimit - })) - end if - end if - - seasonal = chainLookupReturn(homeScreen, "seasonal", invalid) - if isAssociativeArrayValue(seasonal) - for each seasonalKey in seasonal - entry = seasonal[seasonalKey] - if not isAssociativeArrayValue(entry) - continue for - end if - - if not normalizeEnabled(chainLookupReturn(entry, "enabled", true), true) - continue for - end if - - startDate = chainLookupReturn(entry, "startDate", "") - endDate = chainLookupReturn(entry, "endDate", "") - if not isValidAndNotEmpty(startDate) or not isValidAndNotEmpty(endDate) - continue for - end if - - if not isSeasonalActive(startDate, endDate) - continue for - end if - - spec = buildCustomSectionSpec(entry, defaultLimit, ["Movie"]) - if not isValidAndNotEmpty(chainLookupReturn(spec, "source", "")) - continue for - end if - - sectionTitle = chainLookupReturn(entry, "name", seasonalKey) - sectionOrder = normalizeOrder(chainLookupReturn(entry, "order", 60), 60) - sections.push(buildSectionDescriptor("custom", sectionTitle, sectionOrder, spec)) - end for - end if - - customSections = chainLookupReturn(homeScreen, "customSections", []) - if isArrayValue(customSections) - for i = 0 to customSections.Count() - 1 - entry = customSections[i] - if not isAssociativeArrayValue(entry) - continue for - end if - - if not normalizeEnabled(chainLookupReturn(entry, "enabled", true), true) - continue for - end if - - spec = buildCustomSectionSpec(entry, defaultLimit, ["Movie", "Series"]) - if not isValidAndNotEmpty(chainLookupReturn(spec, "source", "")) - continue for - end if - - sectionTitle = chainLookupReturn(entry, "name", "Custom") - sectionOrder = normalizeOrder(chainLookupReturn(entry, "order", 100 + i), 100 + i) - sections.push(buildSectionDescriptor("custom", sectionTitle, sectionOrder, spec)) - end for - end if - - sortedSections = sortSectionsByOrder(sections) - - normalized = [] - for each sectionData in sortedSections - kind = chainLookupReturn(sectionData, "kind", "") - if not isValidAndNotEmpty(kind) - continue for - end if - - displayText = chainLookupReturn(sectionData, "displayText", kind) - if not isValidAndNotEmpty(displayText) - displayText = kind - end if - - sectionSpec = chainLookupReturn(sectionData, "spec", {}) - normalized.push({ - kind: kind, - displayText: displayText, - spec: sectionSpec - }) - end for - - return normalized -end function - -function buildSectionDescriptor(kind as string, displayText as string, sectionOrder as integer, spec as object) as object - if not isValidAndNotEmpty(displayText) - displayText = kind - end if - - return { - kind: kind, - displayText: displayText, - order: sectionOrder, - spec: spec - } -end function - -function buildCustomSectionSpec(entry as dynamic, defaultLimit as integer, defaultIncludeTypes as object) as object - return { - kind: "custom", - type: chainLookupReturn(entry, "type", "genre"), - source: chainLookupReturn(entry, "source", ""), - sortBy: chainLookupReturn(entry, "sortOrder", "Random"), - sortOrderDirection: chainLookupReturn(entry, "sortOrderDirection", "Ascending"), - includeItemTypes: getStringArray(chainLookupReturn(entry, "includeItemTypes", invalid), defaultIncludeTypes), - limit: normalizeLimit(chainLookupReturn(entry, "limit", chainLookupReturn(entry, "itemLimit", defaultLimit)), defaultLimit) - } -end function - -function sortSectionsByOrder(sections as object) as object - if not isArrayValue(sections) - return [] - end if - - for i = 0 to sections.Count() - 2 - for j = i + 1 to sections.Count() - 1 - leftOrder = normalizeOrder(chainLookupReturn(sections[i], "order", i), i) - rightOrder = normalizeOrder(chainLookupReturn(sections[j], "order", j), j) - - if rightOrder < leftOrder - tmp = sections[i] - sections[i] = sections[j] - sections[j] = tmp - end if - end for - end for - - return sections -end function - -function getStringArray(value as dynamic, defaultValues as object) as object - output = [] - - if isArrayValue(value) - for each item in value - if not isValid(item) - continue for - end if - itemString = item.ToStr().Trim() - if isValidAndNotEmpty(itemString) - output.push(itemString) - end if - end for - else if type(value) = "String" or type(value) = "roString" - for each item in value.Split(",") - itemString = item.Trim() - if isValidAndNotEmpty(itemString) - output.push(itemString) - end if - end for - end if - - if isValidAndNotEmpty(output) - return output - end if - - fallback = [] - if isArrayValue(defaultValues) - for each item in defaultValues - if not isValid(item) - continue for - end if - itemString = item.ToStr().Trim() - if isValidAndNotEmpty(itemString) - fallback.push(itemString) - end if - end for - end if - return fallback -end function - -function normalizeOrder(value as dynamic, defaultValue as integer) as integer - if not isValid(value) - return defaultValue - end if - - parsed = defaultValue - valueType = type(value) - - if valueType = "Integer" or valueType = "LongInteger" or valueType = "roInteger" or valueType = "roInt" - parsed = value - else if valueType = "Float" or valueType = "roFloat" - parsed = Int(value) - else if valueType = "String" or valueType = "roString" - parsed = Int(Val(value)) - end if - - if parsed < 0 - return defaultValue - end if - - return parsed -end function - -function normalizeEnabled(value as dynamic, defaultValue as boolean) as boolean - if not isValid(value) - return defaultValue - end if - - valueType = type(value) - if valueType = "Boolean" or valueType = "roBoolean" - return value - end if - - if valueType = "String" or valueType = "roString" - normalized = LCase(value.Trim()) - if normalized = "true" or normalized = "1" or normalized = "yes" or normalized = "on" - return true - end if - if normalized = "false" or normalized = "0" or normalized = "no" or normalized = "off" - return false - end if - return defaultValue - end if - - return value <> 0 -end function - -function normalizeLimit(value as dynamic, defaultValue as integer) as integer - if not isValid(value) - return defaultValue - end if - - parsed = defaultValue - valueType = type(value) - - if valueType = "Integer" or valueType = "LongInteger" or valueType = "roInteger" or valueType = "roInt" - parsed = value - else if valueType = "Float" or valueType = "roFloat" - parsed = Int(value) - else if valueType = "String" or valueType = "roString" - parsed = Int(Val(value)) - end if - - if parsed <= 0 - return defaultValue - end if - - if parsed > 100 - return 100 - end if - - return parsed -end function - -function isSeasonalActive(startMmDd as string, endMmDd as string) as boolean - startPair = parseMonthDay(startMmDd) - endPair = parseMonthDay(endMmDd) - - if not isArrayValue(startPair) or not isArrayValue(endPair) - return false - end if - - now = CreateObject("roDateTime") - todayMonth = now.GetMonth() - todayDay = now.GetDayOfMonth() - - startKey = (startPair[0] * 100) + startPair[1] - endKey = (endPair[0] * 100) + endPair[1] - todayKey = (todayMonth * 100) + todayDay - - if startKey <= endKey - return todayKey >= startKey and todayKey <= endKey - end if - - return todayKey >= startKey or todayKey <= endKey -end function - -function parseMonthDay(value as dynamic) as dynamic - if not isValidAndNotEmpty(value) - return invalid - end if - - if not (type(value) = "String" or type(value) = "roString") - return invalid - end if - - parts = value.Split("-") - if parts.Count() < 2 - return invalid - end if - - month = Int(Val(parts[0])) - day = Int(Val(parts[1])) - - if month < 1 or month > 12 - return invalid - end if - - if day < 1 or day > 31 - return invalid - end if - - return [month, day] -end function - -function isArrayValue(value as dynamic) as boolean - valueType = type(value) - return valueType = "Array" or valueType = "roArray" -end function - -function isAssociativeArrayValue(value as dynamic) as boolean - valueType = type(value) - return valueType = "AssociativeArray" or valueType = "roAssociativeArray" -end function diff --git a/components/home/KefinTweaksProbeTask.xml b/components/home/KefinTweaksProbeTask.xml deleted file mode 100644 index 8f613e90d..000000000 --- a/components/home/KefinTweaksProbeTask.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/components/settings/HomeRowsSourceRowsTask.bs b/components/settings/HomeRowsSourceRowsTask.bs index 48b1927f5..f71d9e234 100644 --- a/components/settings/HomeRowsSourceRowsTask.bs +++ b/components/settings/HomeRowsSourceRowsTask.bs @@ -133,13 +133,7 @@ function sortRowsByOrder(rows as object) as object end function function normalizeHomeRowsSource(value as dynamic) as string - source = LCase(toNormalizedString(value)) - - if source = "kefin" or source = "kefintweak" or source = "kefintweaks" - return "kefintweaks" - end if - - return source + return LCase(toNormalizedString(value)) end function function normalizeBoolean(value as dynamic, defaultValue = false as boolean) as boolean diff --git a/components/settings/settings.bs b/components/settings/settings.bs index f4d5943fc..6f577f065 100644 --- a/components/settings/settings.bs +++ b/components/settings/settings.bs @@ -10,8 +10,6 @@ import "pkg:/source/utils/JellyseerrUtils.bs" import "pkg:/source/utils/misc.bs" import "pkg:/source/utils/settingsSync.bs" -const HOME_ROWS_HSS_LOCAL_SETTING = "ui.home.hssRowsLocalConfig" -const HOME_ROWS_KT_LOCAL_SETTING = "ui.home.ktRowsLocalConfig" sub init() m.top.optionsAvailable = false @@ -81,10 +79,6 @@ sub init() m.mediaBarSelectorDialogOptions = [] m.mediaBarPickerTask = invalid m.pendingMediaBarSettingItem = invalid - m.hssDetected = invalid - m.hssProbeTask = invalid - m.ktDetected = invalid - m.ktProbeTask = invalid m.homeRowsSourceTask = invalid m.pendingPluginRowsSetting = invalid m.pendingPluginRowsSource = "" @@ -101,11 +95,7 @@ sub init() m.seerrLogoutTask = invalid m.configTree = reorderSettingsForFlutter(GetConfigTree()) - updateHssSettingGate() - updateKtSettingGate() LoadMenu({ children: m.configTree }) - refreshHssPluginDetection() - refreshKtPluginDetection() end sub sub onKeypressTimerFire() @@ -343,30 +333,6 @@ sub onMediaBarSelectorDialogButton(event as object) m.settingsMenu.setFocus(true) end sub -sub openPluginRowsManager(settingItem as object) - sourceName = getPluginRowsManagerSource(chainLookupReturn(settingItem, "settingName", "")) - if not isValidAndNotEmpty(sourceName) - ShowToast("Unsupported row manager.", "error") - m.settingsMenu.setFocus(true) - return - end if - - if isValid(m.homeRowsSourceTask) - clearHomeRowsSourceTask() - end if - - m.pendingPluginRowsSetting = settingItem - m.pendingPluginRowsSource = sourceName - - m.homeRowsSourceTask = createObject("roSGNode", "HomeRowsSourceRowsTask") - m.homeRowsSourceTask.serverUrl = chainLookupReturn(m.global, "session.server.url", "") - m.homeRowsSourceTask.userId = chainLookupReturn(m.global, "session.user.id", "") - m.homeRowsSourceTask.authToken = chainLookupReturn(m.global, "session.user.authToken", "") - m.homeRowsSourceTask.source = sourceName - m.homeRowsSourceTask.observeFieldScoped("rows", "onHomeRowsSourceRowsLoaded") - m.homeRowsSourceTask.observeFieldScoped("errorMessage", "onHomeRowsSourceRowsError") - m.homeRowsSourceTask.control = "RUN" -end sub sub onHomeRowsSourceRowsLoaded(event as object) rows = event.getData() @@ -440,8 +406,8 @@ sub showPluginRowsManagerDialog(settingItem as object, sourceName as string, row return end if - settingKey = getPluginRowsManagerStorageKey(sourceName) - savedRows = parsePluginRowsConfigValue(getUserSettingValue(settingKey, "[]")) + settingKey = "" + savedRows = parsePluginRowsConfigValue(getUserSettingValue("", "[]")) savedMap = buildPluginRowsConfigMap(savedRows) sortedRows = [] @@ -478,11 +444,6 @@ sub showPluginRowsManagerDialog(settingItem as object, sourceName as string, row } dialog.palette = dlgPalette - if isStringEqual(normalizeHomeRowsSourceName(sourceName), "hss") - dialog.title = tr("Manage HSS Rows") - else - dialog.title = tr("Manage KefinTweaks Rows") - end if dialog.message = [tr("Use Rewind/Fast-Forward to reorder rows. Press OK to toggle each row.")] dialog.allowReorder = true @@ -610,9 +571,6 @@ function getSettingCurrentValueLabel(settingItem as dynamic) as string if not isValid(settingItem.type) then return "" if not isValid(settingItem.settingName) then return "" - if isPluginRowsManagerSetting(settingItem.settingName) - return getPluginRowsManagerSummary(settingItem.settingName) - end if if isStringEqual(settingItem.settingName, "jellyseerr.accountSettings") return GetJellyseerrAccountStatusLabel() @@ -748,39 +706,11 @@ function getHomeSectionOrder() as object end function function normalizeHomeRowsSourceName(sourceValue as dynamic) as string - source = LCase(dynamicToDisplayString(sourceValue)) - - if isStringEqual(source, "kefin") or isStringEqual(source, "kefintweak") or isStringEqual(source, "kefintweaks") - return "kefintweaks" - end if - - return source -end function - -function isPluginRowsManagerSetting(settingName as dynamic) as boolean - if not isValid(settingName) then return false - - if isStringEqual(settingName, "homeRows.manageHssRows") then return true - if isStringEqual(settingName, "homeRows.manageKtRows") then return true - return false + return LCase(dynamicToDisplayString(sourceValue)) end function -function getPluginRowsManagerSource(settingName as dynamic) as string - if not isPluginRowsManagerSetting(settingName) - return "" - end if - if isStringEqual(settingName, "homeRows.manageHssRows") then return "hss" - return "kefintweaks" -end function -function getPluginRowsManagerStorageKey(sourceName as dynamic) as string - source = normalizeHomeRowsSourceName(sourceName) - - if isStringEqual(source, "hss") then return HOME_ROWS_HSS_LOCAL_SETTING - if isStringEqual(source, "kefintweaks") then return HOME_ROWS_KT_LOCAL_SETTING - return "" -end function function parsePluginRowsConfigValue(value as dynamic) as object if not isValid(value) @@ -847,28 +777,6 @@ function buildPluginRowsConfigMap(configRows as object) as object return configMap end function -function getPluginRowsManagerSummary(settingName as dynamic) as string - sourceName = getPluginRowsManagerSource(settingName) - settingKey = getPluginRowsManagerStorageKey(sourceName) - if not isValidAndNotEmpty(settingKey) - return tr("Configure") - end if - - savedRows = parsePluginRowsConfigValue(getUserSettingValue(settingKey, "[]")) - if savedRows.Count() = 0 - return tr("Configure") - end if - - enabledCount = 0 - for each row in savedRows - if normalizeBoolSettingValue(chainLookupReturn(row, "enabled", false)) - enabledCount++ - end if - end for - - return enabledCount.ToStr() + "/" + savedRows.Count().ToStr() + " " + tr("enabled") -end function - function buildHomeRowsV2Payload(rowOrder = invalid as dynamic) as object rows = [] if not isValid(rowOrder) @@ -1223,8 +1131,6 @@ sub onPluginPingComplete() session.user.settings.Save("plugin.enabled", "false") end if - updateHssSettingGate() - updateKtSettingGate() if m.userLocation.Count() > 0 RefreshCurrentMenu() end if @@ -1891,21 +1797,6 @@ sub setUserBoolSetting(settingName as string, enabled as boolean, syncToServer = end if end sub -function isHssPluginDetected() as boolean - if not isValid(m.hssDetected) - return true - end if - - return m.hssDetected -end function - -function isKtPluginDetected() as boolean - if not isValid(m.ktDetected) - return true - end if - - return m.ktDetected -end function sub setSettingVisibilityByName(items as object, settingName as string, isVisible as boolean) if not isValid(items) @@ -1923,85 +1814,6 @@ sub setSettingVisibilityByName(items as object, settingName as string, isVisible end for end sub -sub refreshHssPluginDetection() - if isValid(m.hssProbeTask) - m.hssProbeTask.unobserveField("result") - m.hssProbeTask.control = "STOP" - end if - - m.hssProbeTask = createObject("roSGNode", "HSSProbeTask") - m.hssProbeTask.serverUrl = chainLookupReturn(m.global, "session.server.url", "") - m.hssProbeTask.userId = chainLookupReturn(m.global, "session.user.id", "") - m.hssProbeTask.authToken = chainLookupReturn(m.global, "session.user.authToken", "") - m.hssProbeTask.observeField("result", "onHssPluginProbeComplete") - m.hssProbeTask.control = "RUN" -end sub - -sub onHssPluginProbeComplete() - if not isValid(m.hssProbeTask) then return - - result = m.hssProbeTask.result - m.hssProbeTask.unobserveField("result") - m.hssProbeTask = invalid - - m.hssDetected = normalizeBoolSettingValue(chainLookupReturn(result, "enabled", false)) - updateHssSettingGate() - - if m.userLocation.Count() > 0 - RefreshCurrentMenu() - end if -end sub - -sub refreshKtPluginDetection() - if isValid(m.ktProbeTask) - m.ktProbeTask.unobserveField("result") - m.ktProbeTask.control = "STOP" - end if - - m.ktProbeTask = createObject("roSGNode", "KefinTweaksProbeTask") - m.ktProbeTask.serverUrl = chainLookupReturn(m.global, "session.server.url", "") - m.ktProbeTask.userId = chainLookupReturn(m.global, "session.user.id", "") - m.ktProbeTask.authToken = chainLookupReturn(m.global, "session.user.authToken", "") - m.ktProbeTask.observeField("result", "onKtPluginProbeComplete") - m.ktProbeTask.control = "RUN" -end sub - -sub onKtPluginProbeComplete() - if not isValid(m.ktProbeTask) then return - - result = m.ktProbeTask.result - m.ktProbeTask.unobserveField("result") - m.ktProbeTask = invalid - - m.ktDetected = normalizeBoolSettingValue(chainLookupReturn(result, "enabled", false)) - updateKtSettingGate() - - if m.userLocation.Count() > 0 - RefreshCurrentMenu() - end if -end sub - -sub updateHssSettingGate() - if not isValid(m.configTree) - return - end if - - pluginDetected = isHssPluginDetected() - usingServerRows = shouldUseServerManagedHomeRows() - - setSettingVisibilityByName(m.configTree, "plugin.hss.enabled", pluginDetected and not usingServerRows) -end sub - -sub updateKtSettingGate() - if not isValid(m.configTree) - return - end if - - pluginDetected = isKtPluginDetected() - usingServerRows = shouldUseServerManagedHomeRows() - - setSettingVisibilityByName(m.configTree, "plugin.kefintweaks.enabled", pluginDetected and not usingServerRows) -end sub function reorderSettingsForFlutter(configTree as object) as object if not isValid(configTree) then return configTree @@ -2027,8 +1839,6 @@ function reorderSettingsForFlutter(configTree as object) as object enablePlugin = findSettingsChildByTitle(pluginRootSection, "Enable Plugin") pluginSettingsSync = findSettingsChildByTitle(pluginRootSection, "Settings Sync") - pluginHss = findSettingsChildByTitle(pluginRootSection, "Home Screen Sections") - pluginKefinTweaks = findSettingsChildByTitle(pluginRootSection, "KefinTweaks") mdblist = findSettingsChildByTitle(pluginRootSection, "MDBList Ratings") tmdb = findSettingsChildByTitle(pluginRootSection, "TMDB") jellyseerr = findSettingsChildByTitle(pluginRootSection, "Seerr") @@ -2086,8 +1896,6 @@ function reorderSettingsForFlutter(configTree as object) as object pluginChildren = [] pushSettingIfValid(pluginChildren, enablePlugin) pushSettingIfValid(pluginChildren, pluginSettingsSync) - pushSettingIfValid(pluginChildren, pluginHss) - pushSettingIfValid(pluginChildren, pluginKefinTweaks) integrationsChildren = [] if pluginChildren.count() > 0 @@ -2135,7 +1943,7 @@ function reorderSettingsForFlutter(configTree as object) as object moonfinMappedTitles = ["Navigation Bar", "Home Screen", "Featured Media Bar", "Theme Music", "Shuffle", "Visual Effects", "Support Moonfin"] pushUnmappedChildrenByTitle(additionalChildren, moonfinSettings, moonfinMappedTitles) - pluginMappedTitles = ["Enable Plugin", "Settings Sync", "Home Screen Sections", "KefinTweaks", "MDBList Ratings", "TMDB", "Seerr", "Jellyseerr"] + pluginMappedTitles = ["Enable Plugin", "Settings Sync", "MDBList Ratings", "TMDB", "Seerr", "Jellyseerr"] pushUnmappedChildrenByTitle(additionalChildren, pluginRootSection, pluginMappedTitles) userInterfaceMappedTitles = ["Colors", "General", "Home Rows"] @@ -2165,8 +1973,6 @@ function reorderSettingsForFlutter(configTree as object) as object end function sub LoadMenu(configSection, appendPath = true as boolean) - updateHssSettingGate() - updateKtSettingGate() if configSection.children = invalid ' Load parent menu @@ -2291,11 +2097,6 @@ sub settingSelected() return end if - if isValid(selectedItem.settingName) and isPluginRowsManagerSetting(selectedItem.settingName) - m.settingDesc.visible = false - openPluginRowsManager(selectedItem) - return - end if if selectedItem.type <> invalid if isValid(selectedItem.Description) @@ -2367,13 +2168,6 @@ sub settingSelected() if Left(chainLookupReturn(selectedItem, "settingName", ""), 17) = "homeScreenSection" filteredOptions = [] for each option in selectedItem.options - optionId = chainLookupReturn(option, "id", "") - if isStringEqual(optionId, "hss_all") and not isHssPluginDetected() - continue for - end if - if isStringEqual(optionId, "kt_all") and not isKtPluginDetected() - continue for - end if filteredOptions.push(option) end for radioOptions = filteredOptions @@ -2436,23 +2230,6 @@ sub boolSettingChanged() selectedSetting = getFocusedSetting() if not isValid(selectedSetting) then return - if selectedSetting.settingName = "plugin.hss.enabled" and m.boolSetting.checkedItem = 1 and not isHssPluginDetected() - ShowToast("Home Screen Sections plugin was not detected on this server.", "error") - setUserBoolSetting("plugin.hss.enabled", false) - refreshCurrentItemValue(selectedSetting) - hideEditingControls() - m.settingsMenu.setFocus(true) - return - end if - - if selectedSetting.settingName = "plugin.kefintweaks.enabled" and m.boolSetting.checkedItem = 1 and not isKtPluginDetected() - ShowToast("KefinTweaks plugin was not detected on this server.", "error") - setUserBoolSetting("plugin.kefintweaks.enabled", false) - refreshCurrentItemValue(selectedSetting) - hideEditingControls() - m.settingsMenu.setFocus(true) - return - end if if m.boolSetting.checkedItem = 1 session.user.settings.Save(selectedSetting.settingName, "true") @@ -2501,19 +2278,6 @@ sub boolSettingChanged() hideEditingControls() m.settingsMenu.setFocus(true) - if selectedSetting.settingName = "plugin.enabled" - refreshHssPluginDetection() - refreshKtPluginDetection() - if m.userLocation.Count() > 0 - RefreshCurrentMenu() - end if - else if selectedSetting.settingName = "homeRows.useServerConfig" - updateHssSettingGate() - updateKtSettingGate() - if m.userLocation.Count() > 0 - RefreshCurrentMenu() - end if - end if end sub sub radioSettingChanged() diff --git a/settings/settings.json b/settings/settings.json index 51f328c5d..6eaa1861e 100644 --- a/settings/settings.json +++ b/settings/settings.json @@ -550,20 +550,6 @@ "type": "bool", "default": "true" }, - { - "title": "Home Screen Sections", - "description": "Show rows from the Home Screen Sections Jellyfin plugin.", - "settingName": "plugin.hss.enabled", - "type": "bool", - "default": "false" - }, - { - "title": "KefinTweaks", - "description": "Show rows from the KefinTweaks Jellyfin plugin.", - "settingName": "plugin.kefintweaks.enabled", - "type": "bool", - "default": "false" - }, { "title": "MDBList Ratings", "description": "Enable additional ratings from configured sources.", @@ -1261,14 +1247,6 @@ { "title": "Recently Released", "id": "recentlyreleased" - }, - { - "title": "Home Screen Sections Plugin", - "id": "hss_all" - }, - { - "title": "KefinTweaks Rows", - "id": "kt_all" } ] }, @@ -1319,14 +1297,6 @@ { "title": "Recently Released", "id": "recentlyreleased" - }, - { - "title": "Home Screen Sections Plugin", - "id": "hss_all" - }, - { - "title": "KefinTweaks Rows", - "id": "kt_all" } ] }, @@ -1377,14 +1347,6 @@ { "title": "Recently Released", "id": "recentlyreleased" - }, - { - "title": "Home Screen Sections Plugin", - "id": "hss_all" - }, - { - "title": "KefinTweaks Rows", - "id": "kt_all" } ] }, @@ -1435,14 +1397,6 @@ { "title": "Recently Released", "id": "recentlyreleased" - }, - { - "title": "Home Screen Sections Plugin", - "id": "hss_all" - }, - { - "title": "KefinTweaks Rows", - "id": "kt_all" } ] }, @@ -1493,14 +1447,6 @@ { "title": "Recently Released", "id": "recentlyreleased" - }, - { - "title": "Home Screen Sections Plugin", - "id": "hss_all" - }, - { - "title": "KefinTweaks Rows", - "id": "kt_all" } ] }, @@ -1551,14 +1497,6 @@ { "title": "Recently Released", "id": "recentlyreleased" - }, - { - "title": "Home Screen Sections Plugin", - "id": "hss_all" - }, - { - "title": "KefinTweaks Rows", - "id": "kt_all" } ] }, @@ -1609,14 +1547,6 @@ { "title": "Recently Released", "id": "recentlyreleased" - }, - { - "title": "Home Screen Sections Plugin", - "id": "hss_all" - }, - { - "title": "KefinTweaks Rows", - "id": "kt_all" } ] }, @@ -1667,14 +1597,6 @@ { "title": "Recently Released", "id": "recentlyreleased" - }, - { - "title": "Home Screen Sections Plugin", - "id": "hss_all" - }, - { - "title": "KefinTweaks Rows", - "id": "kt_all" } ] }, @@ -1912,4 +1834,4 @@ } ] } -] \ No newline at end of file +]