jf-roku/source/utils/session.bs
2024-01-13 21:04:46 -05:00

433 lines
19 KiB
Plaintext

' these are needed for ServerInfo() inside session.server.Populate()
import "pkg:/source/api/userauth.bs"
import "pkg:/source/api/baserequest.bs"
import "pkg:/source/migrations.bs"
namespace session
' Initialize the global session array
sub Init()
m.global.addFields({
session: {
"memoryLevel": "normal",
server: {},
user: {
Configuration: {},
Policy: {},
settings: {},
lastRunVersion: invalid
}
}
})
session.user.settings.SaveDefaults()
end sub
' Empty the global session array
sub Delete()
session.server.Delete()
session.user.Logout()
end sub
' Update one value from the global session array (m.global.session)
sub Update(key as string, value = {} as object)
' validate parameters
if key = "" or (key <> "user" and key <> "server") or value = invalid
print "Error in session.Update(): Invalid parameters provided"
return
end if
' make copy of global session array
tmpSession = m.global.session
' update the temp session array
tmpSession.AddReplace(key, value)
' use the temp session array to update the global node
m.global.setFields({ session: tmpSession })
' print "m.global.session." + key + " = ", m.global.session[key]
end sub
namespace server
' Empty the global server session array
sub Delete()
session.Update("server")
end sub
' Add or update one value from the global server session array (m.global.session.server)
sub Update(key as string, value as dynamic)
' validate parameters
if key = "" or value = invalid then return
' make copy of global server session array
tmpSessionServer = m.global.session.server
' update the temp server array
tmpSessionServer[key] = value
session.Update("server", tmpSessionServer)
end sub
' Add or update the jellyfin server URL from the global server session array (m.global.session.server)
' Returns a boolean based on if a connection to the Jellyfin server was made
function UpdateURL(value as string) as boolean
' validate parameters
if value = "" then return false
session.server.Update("url", value)
success = session.server.Populate()
if not success
session.server.Delete()
end if
return success
end function
' Use the saved server url to populate the global server session array (m.global.session.server)
' Returns a boolean based on if a connection to the Jellyfin server was made
function Populate() as boolean
' validate server url
if m.global.session.server.url = invalid or m.global.session.server.url = "" then return false
' get server info using API
myServerInfo = ServerInfo()
' validate data returned from API
if myServerInfo.id = invalid then return false
' make copy of global server session
tmpSessionServer = m.global.session.server
' update the temp array
tmpSessionServer.AddReplace("id", myServerInfo.Id)
tmpSessionServer.AddReplace("name", myServerInfo.ServerName)
tmpSessionServer.AddReplace("localURL", myServerInfo.LocalAddress)
tmpSessionServer.AddReplace("os", myServerInfo.OperatingSystem)
tmpSessionServer.AddReplace("startupWizardCompleted", myServerInfo.StartupWizardCompleted)
tmpSessionServer.AddReplace("version", myServerInfo.Version)
tmpSessionServer.AddReplace("hasError", myServerInfo.error)
' check urls for https
isServerHTTPS = false
if tmpSessionServer.url.left(8) = "https://" then isServerHTTPS = true
tmpSessionServer.AddReplace("isHTTPS", isServerHTTPS)
isLocalServerHTTPS = false
if myServerInfo.LocalAddress <> invalid and myServerInfo.LocalAddress.left(8) = "https://" then isLocalServerHTTPS = true
tmpSessionServer.AddReplace("isLocalHTTPS", isLocalServerHTTPS)
' update global server session using the temp array
session.Update("server", tmpSessionServer)
if m.global.app.isDev
print "m.global.session.server = ", m.global.session.server
end if
return true
end function
end namespace
namespace user
' Add or update one value from the global user session array (m.global.session.user)
sub Update(key as string, value as dynamic)
' validate parameters
if key = "" or value = invalid then return
' make copy of global user session
tmpSessionUser = m.global.session.user
' update the temp user array
tmpSessionUser[key] = value
' keep friendlyName in sync
if LCase(key) = "name"
regex = CreateObject("roRegex", "[^a-zA-Z0-9\ \-\_]", "")
tmpSessionUser["friendlyName"] = regex.ReplaceAll(value, "")
end if
' update global user session using the temp array
session.Update("user", tmpSessionUser)
' keep auth header in sync
if LCase(key) = "name"
session.user.SetServerDeviceName()
end if
end sub
' Update the global session after user is authenticated.
' Accepts a UserData.xml object from get_token() or an assocArray from AboutMe()
sub Login(userData as object, saveCredentials = false as boolean)
' validate parameters
if userData = invalid or userData.id = invalid then return
' make copy of global user session array
tmpSession = m.global.session
oldUserSettings = tmpSession.user.settings
if userData.json = invalid
' we were passed data from AboutMe()
myAuthToken = tmpSession.user.authToken
tmpSession.AddReplace("user", userData)
tmpSession.user.AddReplace("authToken", myAuthToken)
else
' we were passed data from a UserData object
tmpSession.AddReplace("user", userData.json.User)
tmpSession.user.AddReplace("authToken", userData.json.AccessToken)
end if
' remove special characters from name
regex = CreateObject("roRegex", "[^a-zA-Z0-9\ \-\_]", "")
friendlyName = regex.ReplaceAll(tmpSession.user.name, "")
tmpSession.user.AddReplace("friendlyName", friendlyName)
tmpSession.user.AddReplace("settings", oldUserSettings)
' update global user session
session.Update("user", tmpSession.user)
' grab lastRunVersion for this user
lastRunVersion = get_user_setting("LastRunVersion")
if isValid(lastRunVersion)
session.user.Update("LastRunVersion", lastRunVersion)
end if
' update user session settings with values from registry
userSettings = RegistryReadAll(tmpSession.user.id)
for each setting in userSettings
' don't add auth token to user session
if setting <> "token"
session.user.settings.Save(setting, userSettings[setting])
end if
end for
if m.global.app.isDev
print "m.global.session.user = ", m.global.session.user
print "m.global.session.user.Configuration = ", m.global.session.user.Configuration
print "m.global.session.user.Policy = ", m.global.session.user.Policy
print "m.global.session.user.settings = ", m.global.session.user.settings
end if
set_user_setting("serverId", m.global.session.server.id)
if saveCredentials
set_user_setting("token", tmpSession.user.authToken)
set_user_setting("username", tmpSession.user.name)
end if
if m.global.session.user.settings["global.rememberme"]
set_setting("active_user", tmpSession.user.id)
end if
' Save device id so we don't calculate it every time we need it
session.user.SetServerDeviceName()
' Load user preferences from server
session.user.LoadUserPreferences()
end sub
' Sets the global server device name value used by the API
sub SetServerDeviceName()
localGlobal = m.global
' default device name is the unique id for the device
deviceName = localGlobal.device.id
if isValid(localGlobal.session.user) and isValid(localGlobal.session.user.friendlyName)
deviceName = deviceName + localGlobal.session.user.friendlyName
end if
' update global if needed
if localGlobal.device.serverDeviceName <> deviceName
tmpDevice = localGlobal.device
tmpDevice.AddReplace("serverDeviceName", deviceName)
m.global.setFields({ device: tmpDevice })
end if
end sub
' Load and parse Display Settings from server
sub LoadUserPreferences()
id = m.global.session.user.id
' Currently using client "emby", which is what website uses so we get same Display prefs as web.
' May want to change to specific Roku display settings
url = Substitute("DisplayPreferences/usersettings?userId={0}&client=emby", id)
resp = APIRequest(url)
jsonResponse = getJson(resp)
if isValid(jsonResponse) and isValid(jsonResponse.CustomPrefs)
session.user.SaveUserHomeSections(jsonResponse.CustomPrefs)
if isValid(jsonResponse.CustomPrefs["landing-livetv"])
set_user_setting("display.livetv.landing", jsonResponse.CustomPrefs["landing-livetv"])
else
unset_user_setting("display.livetv.landing")
end if
else
' User has no custom prefs. Save default home section values.
session.user.SaveUserHomeSections({
homesection0: "smalllibrarytiles",
homesection1: "resume",
homesection2: "nextup",
homesection3: "latestmedia",
homesection4: "livetv",
homesection5: "none",
homesection6: "none"
})
unset_user_setting("display.livetv.landing")
end if
end sub
' Saves user's web client home sections as Roku user settings.
' Handles unsupported sections and ignores duplicates.
sub SaveUserHomeSections(customPrefs as object)
userPreferences = customPrefs
rowTypes = []
useWebSectionArrangement = m.global.session.user.settings["ui.home.useWebSectionArrangement"]
if isValid(useWebSectionArrangement)
if not useWebSectionArrangement
userPreferences.delete("homesection0")
end if
end if
' If user has no section preferences, use default settings
if not userPreferences.doesExist("homesection0")
userPreferences = {
homesection0: "smalllibrarytiles",
homesection1: "resume",
homesection2: "nextup",
homesection3: "latestmedia",
homesection4: "livetv",
homesection5: "none",
homesection6: "none"
}
end if
for i = 0 to 6
homeSectionKey = "homesection" + i.toStr()
' If home section doesn't exist, create it as a none row
if not userPreferences.DoesExist(homeSectionKey)
userPreferences.AddReplace(homeSectionKey, "none")
end if
rowType = LCase(userPreferences[homeSectionKey])
' Just in case we get invalid data
if not isValid(rowType) then rowType = "none"
' Small size library item buttons - Currently unsupported, use small library titles
if rowType = "librarybuttons"
rowType = "smalllibrarytiles"
end if
' None is the only section type allowed to have duplicates
' For all other types, only accept the 1st entry
if inArray(rowTypes, rowType)
set_user_setting(homeSectionKey, "none")
else
set_user_setting(homeSectionKey, rowType)
if rowType <> "none"
rowTypes.push(rowType)
end if
end if
end for
end sub
' Empty the global user session array and reload defaults
sub Logout()
session.Update("user", {
Configuration: {},
Policy: {},
settings: {}
})
' reload default user settings
session.user.settings.SaveDefaults()
end sub
namespace settings
' Delete the user setting from the global session (m.global.session.user.settings)
sub Delete(name as string)
' validate parameters
if name = "" then return
tmpSettingArray = m.global.session.user.settings
' update the temp user array
tmpSettingArray.Delete(name)
' update global user session using the temp array
session.user.Update("settings", tmpSettingArray)
end sub
' Read the user setting from the global session (m.global.session.user.settings)
function Read(name as string) as dynamic
' validate parameters
if name = "" then return invalid
if m.global.session.user.settings[name] <> invalid
return m.global.session.user.settings[name]
else
return invalid
end if
end function
' retrieve all default user settings from Config Tree
sub SaveDefaults()
configTree = GetConfigTree()
if configTree = invalid then return
for each item in configTree
if item.default <> invalid and item.settingName <> invalid
session.user.settings.Save(item.settingName, item.default)
else if item.children <> invalid and item.children.Count() > 0
for each child in item.children
if child.default <> invalid and child.settingName <> invalid
session.user.settings.Save(child.settingName, child.default)
else if child.children <> invalid and child.children.Count() > 0
for each child in child.children
if child.default <> invalid and child.settingName <> invalid
session.user.settings.Save(child.settingName, child.default)
else if child.children <> invalid and child.children.Count() > 0
for each child in child.children
if child.default <> invalid and child.settingName <> invalid
session.user.settings.Save(child.settingName, child.default)
else if child.children <> invalid and child.children.Count() > 0
for each child in child.children
if child.default <> invalid and child.settingName <> invalid
session.user.settings.Save(child.settingName, child.default)
else if child.children <> invalid and child.children.Count() > 0
for each child in child.children
if child.default <> invalid and child.settingName <> invalid
session.user.settings.Save(child.settingName, child.default)
end if
end for
end if
end for
end if
end for
end if
end for
end if
end for
end if
end for
' load globals
session.user.settings.LoadGlobals()
' Reset server device name state
session.user.SetServerDeviceName()
end sub
' Grab global vars from registry and overwrite defaults
sub LoadGlobals()
' search main registry block for all keys that start with "global."
jfRegistry = RegistryReadAll("Jellyfin")
for each item in jfRegistry
if Left(item, 7) = "global."
session.user.settings.Save(item, get_setting(item))
end if
end for
end sub
' Saves the user setting to the global session.
' This also converts strings to boolean as necessary before saving to global session
sub Save(name as string, value as string)
if name = invalid or value = invalid then return
tmpSettingArray = m.global.session.user.settings
convertedValue = value
' convert to boolean
if value = "true"
convertedValue = true
else if value = "false"
convertedValue = false
end if
tmpSettingArray[name] = convertedValue
session.user.Update("settings", tmpSettingArray)
end sub
end namespace
end namespace
end namespace