mirror of
https://github.com/jellyfin/jellyfin-roku.git
synced 2024-12-12 08:26:40 +00:00
Merge pull request #1374 from cewert/make-back-work-on-user-select
Fix login bugs, enable support for saving user's credentials, and add "Change User" and "Remember Me?" options
This commit is contained in:
commit
51c629ced1
@ -77,16 +77,17 @@ end sub
|
||||
sub popScene()
|
||||
group = m.groups.pop()
|
||||
if group <> invalid
|
||||
if group.isSubType("JFGroup")
|
||||
groupType = group.subtype()
|
||||
if groupType = "JFGroup"
|
||||
unregisterOverhangData(group)
|
||||
else if group.isSubType("JFVideo")
|
||||
else if groupType = "JFVideo"
|
||||
' Stop video to make sure app communicates stop playstate to server
|
||||
group.control = "stop"
|
||||
end if
|
||||
|
||||
group.visible = false
|
||||
|
||||
if group.isSubType("JFScreen")
|
||||
if groupType = "JFScreen"
|
||||
group.callFunc("OnScreenHidden")
|
||||
end if
|
||||
else
|
||||
|
@ -20,9 +20,6 @@ sub loadFromRegistry(id as string)
|
||||
end sub
|
||||
|
||||
sub saveToRegistry()
|
||||
set_user_setting("username", m.top.username)
|
||||
set_user_setting("token", m.top.token)
|
||||
|
||||
users = parseJson(get_setting("available_users", "[]"))
|
||||
this_user = invalid
|
||||
for each user in users
|
||||
@ -57,7 +54,9 @@ function setPreference(key as string, value as string)
|
||||
end function
|
||||
|
||||
sub setActive()
|
||||
set_setting("active_user", m.top.id)
|
||||
if m.global.session.user.settings["global.rememberme"]
|
||||
set_setting("active_user", m.top.id)
|
||||
end if
|
||||
end sub
|
||||
|
||||
sub setServer(hostname as string)
|
||||
|
@ -1,6 +1,7 @@
|
||||
import "pkg:/source/utils/config.brs"
|
||||
import "pkg:/source/utils/misc.brs"
|
||||
import "pkg:/source/roku_modules/log/LogMixin.brs"
|
||||
import "pkg:/source/api/sdk.bs"
|
||||
|
||||
sub init()
|
||||
m.log = log.Logger("Settings")
|
||||
@ -158,14 +159,40 @@ end sub
|
||||
|
||||
|
||||
sub boolSettingChanged()
|
||||
|
||||
if m.boolSetting.focusedChild = invalid then return
|
||||
selectedSetting = m.userLocation.peek().children[m.settingsMenu.itemFocused]
|
||||
|
||||
if m.boolSetting.checkedItem
|
||||
set_user_setting(selectedSetting.settingName, "true")
|
||||
session.user.settings.Save(selectedSetting.settingName, "true")
|
||||
if Left(selectedSetting.settingName, 7) = "global."
|
||||
' global user setting
|
||||
' save to main registry block
|
||||
set_setting(selectedSetting.settingName, "true")
|
||||
' setting specific triggers
|
||||
if selectedSetting.settingName = "global.rememberme"
|
||||
print "m.global.session.user.id=", m.global.session.user.id
|
||||
set_setting("active_user", m.global.session.user.id)
|
||||
end if
|
||||
else
|
||||
' regular user setting
|
||||
' save to user specific registry block
|
||||
set_user_setting(selectedSetting.settingName, "true")
|
||||
end if
|
||||
else
|
||||
set_user_setting(selectedSetting.settingName, "false")
|
||||
session.user.settings.Save(selectedSetting.settingName, "false")
|
||||
if Left(selectedSetting.settingName, 7) = "global."
|
||||
' global user setting
|
||||
' save to main registry block
|
||||
set_setting(selectedSetting.settingName, "false")
|
||||
' setting specific triggers
|
||||
if selectedSetting.settingName = "global.rememberme"
|
||||
unset_setting("active_user")
|
||||
end if
|
||||
else
|
||||
' regular user setting
|
||||
' save to user specific registry block
|
||||
set_user_setting(selectedSetting.settingName, "false")
|
||||
end if
|
||||
end if
|
||||
end sub
|
||||
|
||||
|
@ -1208,5 +1208,25 @@
|
||||
<translation>Disable the HEVC codec on this device. This may improve playback for some devices (ultra).</translation>
|
||||
<extracomment>User Setting - Setting description</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Global</source>
|
||||
<translation>Global</translation>
|
||||
<extracomment>User Setting - Setting title</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Global settings that affect everyone that uses this Roku device.</source>
|
||||
<translation>Global settings that affect everyone that uses this Roku device.</translation>
|
||||
<extracomment>User Setting - Setting description</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Remember Me?</source>
|
||||
<translation>Remember Me?</translation>
|
||||
<extracomment>User Setting - Setting title</extracomment>
|
||||
</message>
|
||||
<message>
|
||||
<source>Remember the currently logged in user and try to log them in again next time you start the Jellyfin app.</source>
|
||||
<translation>Remember the currently logged in user and try to log them in again next time you start the Jellyfin app.</translation>
|
||||
<extracomment>User Setting - Setting description</extracomment>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
@ -1,4 +1,18 @@
|
||||
[
|
||||
{
|
||||
"title": "Global",
|
||||
"description": "Global settings that affect everyone that uses this Roku device.",
|
||||
"children": [
|
||||
{
|
||||
"title": "Remember Me?",
|
||||
"description": "Remember the currently logged in user and try to log them in again next time you start the Jellyfin app.",
|
||||
"settingName": "global.rememberme",
|
||||
"type": "bool",
|
||||
"default": "false"
|
||||
}
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Playback",
|
||||
"description": "Settings relating to playback and supported codec and media types.",
|
||||
|
@ -62,7 +62,8 @@ sub Main (args as dynamic) as void
|
||||
end if
|
||||
|
||||
' Only show the Whats New popup the first time a user runs a new client version.
|
||||
if m.global.app.version <> get_setting("LastRunVersion")
|
||||
appLastRunVersion = get_setting("LastRunVersion")
|
||||
if m.global.app.version <> appLastRunVersion
|
||||
' Ensure the user hasn't disabled Whats New popups
|
||||
if m.global.session.user.settings["load.allowwhatsnew"] = true
|
||||
set_setting("LastRunVersion", m.global.app.version)
|
||||
@ -72,6 +73,34 @@ sub Main (args as dynamic) as void
|
||||
end if
|
||||
end if
|
||||
|
||||
' Registry migrations
|
||||
if isValid(appLastRunVersion) and not versionChecker(appLastRunVersion, "1.7.0")
|
||||
' last app version used less than 1.7.0
|
||||
' no longer saving raw password to registry
|
||||
' auth token and username are now stored in user settings and not global settings
|
||||
print "Running 1.7.0 registry migrations"
|
||||
' remove global settings
|
||||
unset_setting("token")
|
||||
unset_setting("username")
|
||||
unset_setting("password")
|
||||
' remove user settings
|
||||
unset_user_setting("password")
|
||||
' remove saved credentials from saved_servers
|
||||
saved = get_setting("saved_servers")
|
||||
if isValid(saved)
|
||||
savedServers = ParseJson(saved)
|
||||
if isValid(savedServers.serverList) and savedServers.serverList.Count() > 0
|
||||
newServers = { serverList: [] }
|
||||
for each item in savedServers.serverList
|
||||
item.Delete("username")
|
||||
item.Delete("password")
|
||||
newServers.serverList.Push(item)
|
||||
end for
|
||||
set_setting("saved_servers", FormatJson(newServers))
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
|
||||
' Handle input messages
|
||||
input = CreateObject("roInput")
|
||||
input.SetMessagePort(m.port)
|
||||
@ -511,7 +540,11 @@ sub Main (args as dynamic) as void
|
||||
group.findNode("SearchBox").findNode("search_Key").active = true
|
||||
else if button.id = "change_server"
|
||||
unset_setting("server")
|
||||
unset_setting("port")
|
||||
session.server.Delete()
|
||||
SignOut(false)
|
||||
sceneManager.callFunc("clearScenes")
|
||||
goto app_start
|
||||
else if button.id = "change_user"
|
||||
SignOut(false)
|
||||
sceneManager.callFunc("clearScenes")
|
||||
goto app_start
|
||||
|
@ -1,4 +1,4 @@
|
||||
function LoginFlow(startOver = false as boolean)
|
||||
function LoginFlow()
|
||||
'Collect Jellyfin server and user information
|
||||
start_login:
|
||||
|
||||
@ -41,9 +41,11 @@ function LoginFlow(startOver = false as boolean)
|
||||
activeUser = get_setting("active_user")
|
||||
if activeUser = invalid
|
||||
print "No active user found in registry"
|
||||
user_select:
|
||||
SendPerformanceBeacon("AppDialogInitiate") ' Roku Performance monitoring - Dialog Starting
|
||||
publicUsers = GetPublicUsers()
|
||||
if publicUsers.count()
|
||||
numPubUsers = publicUsers.count()
|
||||
if numPubUsers > 0
|
||||
publicUsersNodes = []
|
||||
for each item in publicUsers
|
||||
user = CreateObject("roSGNode", "PublicUserData")
|
||||
@ -55,18 +57,57 @@ function LoginFlow(startOver = false as boolean)
|
||||
publicUsersNodes.push(user)
|
||||
end for
|
||||
userSelected = CreateUserSelectGroup(publicUsersNodes)
|
||||
|
||||
SendPerformanceBeacon("AppDialogComplete") ' Roku Performance monitoring - Dialog Closed
|
||||
if userSelected = "backPressed"
|
||||
SendPerformanceBeacon("AppDialogComplete") ' Roku Performance monitoring - Dialog Closed
|
||||
return LoginFlow(true)
|
||||
session.server.Delete()
|
||||
unset_setting("server")
|
||||
goto start_login
|
||||
else
|
||||
print "A public user was selected with username=" + userSelected
|
||||
session.user.Update("name", userSelected)
|
||||
regex = CreateObject("roRegex", "[^a-zA-Z0-9\ \-\_]", "")
|
||||
session.user.Update("friendlyName", regex.ReplaceAll(userSelected, ""))
|
||||
' save userid to session
|
||||
for each user in publicUsersNodes
|
||||
if user.name = userSelected
|
||||
session.user.Update("id", user.id)
|
||||
exit for
|
||||
end if
|
||||
end for
|
||||
' try to login with token from registry
|
||||
myToken = get_user_setting("token")
|
||||
if myToken <> invalid
|
||||
' check if token is valid
|
||||
print "Auth token found in registry for selected user"
|
||||
session.user.Update("authToken", myToken)
|
||||
print "Attempting to use API with auth token"
|
||||
currentUser = AboutMe()
|
||||
if currentUser = invalid
|
||||
print "Auth token is no longer valid - deleting token"
|
||||
unset_user_setting("token")
|
||||
unset_user_setting("username")
|
||||
else
|
||||
print "Success! Auth token is still valid"
|
||||
session.user.Login(currentUser)
|
||||
LoadUserPreferences()
|
||||
LoadUserAbilities()
|
||||
return true
|
||||
end if
|
||||
else
|
||||
print "No auth token found in registry for selected user"
|
||||
end if
|
||||
'Try to login without password. If the token is valid, we're done
|
||||
print "Attempting to login with no password"
|
||||
userData = get_token(userSelected, "")
|
||||
if isValid(userData)
|
||||
print "login success!"
|
||||
session.user.Login(userData)
|
||||
LoadUserPreferences()
|
||||
LoadUserAbilities()
|
||||
SendPerformanceBeacon("AppDialogComplete") ' Roku Performance monitoring - Dialog Closed
|
||||
return true
|
||||
else
|
||||
print "Auth failed. Password required"
|
||||
end if
|
||||
end if
|
||||
else
|
||||
@ -75,65 +116,52 @@ function LoginFlow(startOver = false as boolean)
|
||||
passwordEntry = CreateSigninGroup(userSelected)
|
||||
SendPerformanceBeacon("AppDialogComplete") ' Roku Performance monitoring - Dialog Closed
|
||||
if passwordEntry = "backPressed"
|
||||
m.global.sceneManager.callFunc("clearScenes")
|
||||
return LoginFlow(true)
|
||||
if numPubUsers > 0
|
||||
goto user_select
|
||||
else
|
||||
session.server.Delete()
|
||||
unset_setting("server")
|
||||
goto start_login
|
||||
end if
|
||||
end if
|
||||
else
|
||||
print "Active user found in registry"
|
||||
session.user.Update("id", activeUser)
|
||||
|
||||
myUsername = get_user_setting("username")
|
||||
myAuthToken = get_user_setting("token")
|
||||
if isValid(myAuthToken)
|
||||
if isValid(myAuthToken) and isValid(myUsername)
|
||||
print "Auth token found in registry"
|
||||
session.user.Update("authToken", myAuthToken)
|
||||
session.user.Update("name", myUsername)
|
||||
regex = CreateObject("roRegex", "[^a-zA-Z0-9\ \-\_]", "")
|
||||
session.user.Update("friendlyName", regex.ReplaceAll(myUsername, ""))
|
||||
print "Attempting to use API with auth token"
|
||||
currentUser = AboutMe()
|
||||
if currentUser = invalid
|
||||
print "Auth token is no longer valid - restart login flow"
|
||||
unset_user_setting("token")
|
||||
unset_setting("active_user")
|
||||
session.user.Logout()
|
||||
goto start_login
|
||||
print "Auth token is no longer valid"
|
||||
'Try to login without password. If the token is valid, we're done
|
||||
print "Attempting to login with no password"
|
||||
userData = get_token(userSelected, "")
|
||||
if isValid(userData)
|
||||
print "login success!"
|
||||
session.user.Login(userData)
|
||||
LoadUserPreferences()
|
||||
LoadUserAbilities()
|
||||
return true
|
||||
else
|
||||
print "Auth failed. Password required"
|
||||
print "delete token and restart login flow"
|
||||
unset_user_setting("token")
|
||||
unset_user_setting("username")
|
||||
goto start_login
|
||||
end if
|
||||
else
|
||||
print "Success! Auth token is still valid"
|
||||
session.user.Login(currentUser)
|
||||
end if
|
||||
else
|
||||
print "No auth token found in registry"
|
||||
myUsername = get_setting("username")
|
||||
myPassword = get_setting("password")
|
||||
userData = invalid
|
||||
|
||||
if isValid(myUsername) and isValid(myPassword)
|
||||
if myUsername <> ""
|
||||
print "Username and password found in registry. Attempting to login"
|
||||
userData = get_token(myUsername, myPassword)
|
||||
else
|
||||
print "Username in registry is an empty string"
|
||||
unset_setting("username")
|
||||
unset_setting("password")
|
||||
end if
|
||||
else if isValid(myUsername) and not isValid(myPassword)
|
||||
print "Username found in registry but no password"
|
||||
if myUsername <> ""
|
||||
print "Attempting to login with no password"
|
||||
userData = get_token(myUsername, "")
|
||||
else
|
||||
print "Username in registry is an empty string"
|
||||
unset_setting("username")
|
||||
end if
|
||||
|
||||
else if not isValid(myUsername) and not isValid(myPassword)
|
||||
print "Neither username nor password found in registry - restart login flow"
|
||||
unset_setting("active_user")
|
||||
session.user.Logout()
|
||||
goto start_login
|
||||
end if
|
||||
|
||||
if isValid(userData)
|
||||
print "login success!"
|
||||
session.user.Login(userData)
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
|
||||
@ -254,11 +282,6 @@ function CreateServerGroup()
|
||||
m.scene.dialog = dialog
|
||||
|
||||
serverUrl = standardize_jellyfin_url(screen.serverUrl)
|
||||
'If this is a different server from what we know, reset username/password setting
|
||||
if m.global.session.server.url <> serverUrl
|
||||
set_setting("username", "")
|
||||
set_setting("password", "")
|
||||
end if
|
||||
set_setting("server", serverUrl)
|
||||
|
||||
isConnected = session.server.UpdateURL(serverUrl)
|
||||
@ -362,25 +385,6 @@ function CreateSigninGroup(user = "")
|
||||
|
||||
group.findNode("prompt").text = tr("Sign In")
|
||||
|
||||
'Load in any saved server data and see if we can just log them in...
|
||||
server = m.global.session.server.url
|
||||
if isValid(server)
|
||||
server = LCase(server)'Saved server data is always lowercase
|
||||
end if
|
||||
saved = get_setting("saved_servers")
|
||||
if isValid(saved)
|
||||
savedServers = ParseJson(saved)
|
||||
for each item in savedServers.serverList
|
||||
if item.baseUrl = server and isValid(item.username) and isValid(item.password)
|
||||
userData = get_token(item.username, item.password)
|
||||
if isValid(userData)
|
||||
session.user.Login(userData)
|
||||
return "true"
|
||||
end if
|
||||
end if
|
||||
end for
|
||||
end if
|
||||
|
||||
config = group.findNode("configOptions")
|
||||
username_field = CreateObject("roSGNode", "ConfigData")
|
||||
username_field.label = tr("Username")
|
||||
@ -447,11 +451,10 @@ function CreateSigninGroup(user = "")
|
||||
activeUser = get_token(username.value, password.value)
|
||||
if isValid(activeUser)
|
||||
session.user.Login(activeUser)
|
||||
set_setting("username", username.value)
|
||||
set_setting("password", password.value)
|
||||
' save credentials
|
||||
if checkbox.checkedState[0] = true
|
||||
'Update our saved server list, so next time the user can just click and go
|
||||
UpdateSavedServerList()
|
||||
set_user_setting("token", activeUser.token)
|
||||
set_user_setting("username", username.value)
|
||||
end if
|
||||
return "true"
|
||||
end if
|
||||
@ -515,6 +518,7 @@ function CreateHomeGroup()
|
||||
new_options = []
|
||||
options_buttons = [
|
||||
{ "title": "Search", "id": "goto_search" },
|
||||
{ "title": "Change user", "id": "change_user" },
|
||||
{ "title": "Change server", "id": "change_server" },
|
||||
{ "title": "Sign out", "id": "sign_out" }
|
||||
]
|
||||
@ -862,34 +866,6 @@ function CreatePersonView(personData as object) as dynamic
|
||||
return person
|
||||
end function
|
||||
|
||||
sub UpdateSavedServerList()
|
||||
server = m.global.session.server.url
|
||||
username = get_setting("username")
|
||||
password = get_setting("password")
|
||||
|
||||
if server = invalid or username = invalid or password = invalid
|
||||
return
|
||||
end if
|
||||
|
||||
server = LCase(server)'Saved server data is always lowercase
|
||||
|
||||
saved = get_setting("saved_servers")
|
||||
if isValid(saved)
|
||||
savedServers = ParseJson(saved)
|
||||
if isValid(savedServers.serverList) and savedServers.serverList.Count() > 0
|
||||
newServers = { serverList: [] }
|
||||
for each item in savedServers.serverList
|
||||
if item.baseUrl = server
|
||||
item.username = username
|
||||
item.password = password
|
||||
end if
|
||||
newServers.serverList.Push(item)
|
||||
end for
|
||||
set_setting("saved_servers", FormatJson(newServers))
|
||||
end if
|
||||
end if
|
||||
end sub
|
||||
|
||||
'Opens dialog asking user if they want to resume video or start playback over only on the home screen
|
||||
sub playbackOptionDialog(time as longinteger, meta as object)
|
||||
|
||||
|
@ -203,12 +203,16 @@ function authRequest(request as object) as object
|
||||
|
||||
if m.global.session.user.id <> invalid
|
||||
auth = auth + ", UserId=" + QUOTE + m.global.session.user.id + QUOTE
|
||||
auth = auth + ", DeviceId=" + QUOTE + m.global.device.id + QUOTE
|
||||
if m.global.session.user.authToken <> invalid
|
||||
auth = auth + ", Token=" + QUOTE + m.global.session.user.authToken + QUOTE
|
||||
end if
|
||||
end if
|
||||
|
||||
if m.global.session.user <> invalid and m.global.session.user.friendlyName <> invalid
|
||||
auth = auth + ", DeviceId=" + QUOTE + m.global.device.id + m.global.session.user.friendlyName + QUOTE
|
||||
else
|
||||
auth = auth + ", DeviceId=" + QUOTE + m.global.device.uuid + QUOTE
|
||||
auth = auth + ", DeviceId=" + QUOTE + m.global.device.id + QUOTE
|
||||
end if
|
||||
|
||||
if m.global.session.user.authToken <> invalid
|
||||
auth = auth + ", Token=" + QUOTE + m.global.session.user.authToken + QUOTE
|
||||
end if
|
||||
|
||||
request.AddHeader("Authorization", auth)
|
||||
|
@ -32,28 +32,9 @@ function AboutMe(id = "" as string)
|
||||
end function
|
||||
|
||||
sub SignOut(deleteSavedEntry = true as boolean)
|
||||
if m.global.session.user.id <> invalid
|
||||
if m.global.session.user.id <> invalid and deleteSavedEntry = true
|
||||
unset_user_setting("token")
|
||||
unset_setting("username")
|
||||
unset_setting("password")
|
||||
if deleteSavedEntry = true
|
||||
'Also delete any credentials in the "saved servers" list
|
||||
saved = get_setting("saved_servers")
|
||||
server = m.global.session.server.url
|
||||
if server <> invalid
|
||||
server = LCase(server)
|
||||
savedServers = ParseJson(saved)
|
||||
newServers = { serverList: [] }
|
||||
for each item in savedServers.serverList
|
||||
if item.baseUrl = server
|
||||
item.username = ""
|
||||
item.password = ""
|
||||
end if
|
||||
newServers.serverList.Push(item)
|
||||
end for
|
||||
set_setting("saved_servers", FormatJson(newServers))
|
||||
end if
|
||||
end if
|
||||
unset_user_setting("username")
|
||||
end if
|
||||
unset_setting("active_user")
|
||||
session.user.Logout()
|
||||
|
@ -12,7 +12,7 @@ function getDeviceCapabilities() as object
|
||||
"Photo"
|
||||
],
|
||||
"SupportedCommands": [],
|
||||
"SupportsPersistentIdentifier": false,
|
||||
"SupportsPersistentIdentifier": true,
|
||||
"SupportsMediaControl": false,
|
||||
"SupportsContentUploading": false,
|
||||
"SupportsSync": false,
|
||||
|
@ -137,6 +137,10 @@ namespace session
|
||||
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
|
||||
@ -151,9 +155,11 @@ namespace session
|
||||
if m.global.app.isDev
|
||||
print "m.global.session.user.settings = ", m.global.session.user.settings
|
||||
end if
|
||||
' ensure registry is updated
|
||||
set_user_setting("username", tmpSession.user.name)
|
||||
set_user_setting("token", tmpSession.user.authToken)
|
||||
|
||||
if m.global.session.user.settings["global.rememberme"]
|
||||
set_user_setting("token", tmpSession.user.authToken)
|
||||
set_user_setting("username", tmpSession.user.name)
|
||||
end if
|
||||
end sub
|
||||
|
||||
' Empty the global user session array and reload defaults
|
||||
@ -231,6 +237,20 @@ namespace session
|
||||
end for
|
||||
end if
|
||||
end for
|
||||
|
||||
' load globals
|
||||
session.user.settings.LoadGlobals()
|
||||
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.
|
||||
|
Loading…
Reference in New Issue
Block a user