Merge branch 'server_url' into unstable

This commit is contained in:
Seven Rats 2023-10-31 13:29:09 -04:00 committed by GitHub
commit c268a53ed5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 114 additions and 23 deletions

View File

@ -306,13 +306,19 @@ function CreateServerGroup()
dialog.title = tr("Connecting to Server") dialog.title = tr("Connecting to Server")
m.scene.dialog = dialog m.scene.dialog = dialog
serverUrl = standardize_jellyfin_url(screen.serverUrl) serverUrl = inferServerUrl(screen.serverUrl)
isConnected = session.server.UpdateURL(serverUrl) isConnected = session.server.UpdateURL(serverUrl)
serverInfoResult = invalid serverInfoResult = invalid
if isConnected if isConnected
set_setting("server", serverUrl) set_setting("server", serverUrl)
serverInfoResult = ServerInfo() serverInfoResult = ServerInfo()
'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)
end if end if
dialog.close = true dialog.close = true
@ -323,6 +329,7 @@ function CreateServerGroup()
screen.errorMessage = tr("Server not found, is it online?") screen.errorMessage = tr("Server not found, is it online?")
SignOut(false) SignOut(false)
else else
if isValid(serverInfoResult.Error) and serverInfoResult.Error if isValid(serverInfoResult.Error) and serverInfoResult.Error
' If server redirected received, update the URL ' If server redirected received, update the URL
if isValid(serverInfoResult.UpdatedUrl) if isValid(serverInfoResult.UpdatedUrl)

View File

@ -1,3 +1,5 @@
import "pkg:/source/utils/config.brs"
function isNodeEvent(msg, field as string) as boolean function isNodeEvent(msg, field as string) as boolean
return type(msg) = "roSGNodeEvent" and msg.getField() = field return type(msg) = "roSGNodeEvent" and msg.getField() = field
end function end function
@ -162,31 +164,103 @@ function option_dialog(options, message = "", defaultSelection = 0) as integer
return show_dialog(message, options, defaultSelection) return show_dialog(message, options, defaultSelection)
end function end function
' ' take an incomplete url string and use it to make educated guesses about
' Take a jellyfin hostname and ensure it's a full url. ' the complete url. then tests these guesses to see if it can find a jf server
' prepend http or https and append default ports, and remove excess slashes ' returns the url of the server it found, or an empty string
' function inferServerUrl(url as string) as string
function standardize_jellyfin_url(url as string) ' if this server is already stored, just use the value directly
'Append default ports ' the server had to get resolved in the first place to get into the registry
maxSlashes = 0 saved = get_setting("saved_servers")
if left(url, 8) = "https://" or left(url, 7) = "http://" if isValid(saved)
maxSlashes = 2 savedServers = ParseJson(saved)
if isValid(savedServers.lookup(url)) then return url
end if end if
'Check to make sure entry has no extra slashes before adding default ports.
if Instr(0, url, "/") = maxSlashes port = CreateObject("roMessagePort")
if url.len() > 5 and mid(url, url.len() - 4, 1) <> ":" and mid(url, url.len() - 5, 1) <> ":" hosts = CreateObject("roAssociativeArray")
if left(url, 5) = "https" reqs = []
url = url + ":8920" candidates = urlCandidates(url)
else for each endpoint in candidates
url = url + ":8096" req = CreateObject("roUrlTransfer")
end if reqs.push(req) ' keep in scope outside of loop, else -10001
req.seturl(endpoint + "/system/info/public")
req.setMessagePort(port)
hosts.addreplace(req.getidentity().ToStr(), endpoint)
if endpoint.Left(8) = "https://"
req.setCertificatesFile("common:/certs/ca-bundle.crt")
end if end if
req.AsyncGetToString()
end for
handled = 0
timeout = CreateObject("roTimespan")
if hosts.count() > 0
while timeout.totalseconds() < 15
resp = wait(0, port)
if type(resp) = "roUrlEvent"
' TODO
' if response code is a 300 redirect then we should return the redirect url
' Make sure this happens or make it happen
if resp.GetResponseCode() = 200 and isJellyfinServer(resp.GetString())
selectedUrl = hosts.lookup(resp.GetSourceIdentity().ToStr())
print "Successfully inferred server URL: " selectedUrl
return selectedUrl
end if
end if
handled += 1
if handled = reqs.count()
print "inferServerUrl in utils/misc.brs failed to find a server from the string " url " but did not timeout."
return ""
end if
end while
print "inferServerUrl in utils/misc.brs failed to find a server from the string " url " because it timed out."
end if end if
'Append http:// to server return ""
if left(url, 4) <> "http" end function
url = "http://" + url
' this is the "educated guess" logic for inferServerUrl that generates a list of complete url's as candidates
' for the tests in inferServerUrl. takes an incomplete url as an arg and returns a list of extrapolated
' full urls.
function urlCandidates(input as string)
if input.endswith("/") then input = input.Left(len(input) - 1)
url = parseUrl(input)
if url[1] = invalid
' a proto wasn't declared
url = parseUrl("none://" + input)
end if end if
return url ' if the proto is still invalid then the string is not valid
if url[1] = invalid then return []
proto = url[1]
host = url[2]
port = url[3]
path = url[4]
protoCandidates = []
supportedProtos = ["http:", "https:"] ' appending colons because the regex does
if proto = "none:" ' the user did not declare a protocol
' try every supported proto
for each supportedProto in supportedProtos
protoCandidates.push(supportedProto + "//" + host)
end for
else
protoCandidates.push(proto + "//" + host) ' but still allow arbitrary protocols if they are declared
end if
finalCandidates = []
if isValid(port) and port <> "" ' if the port is defined just use that
for each candidate in protoCandidates
finalCandidates.push(candidate + port + path)
end for
else ' the port wasnt declared so use default jellyfin and proto ports
for each candidate in protoCandidates:
' proto default
finalCandidates.push(candidate + path)
' jellyfin defaults
if candidate.startswith("https")
finalCandidates.push(candidate + ":8920" + path)
else if candidate.startswith("http")
finalCandidates.push(candidate + ":8096" + path)
end if
end for
end if
return finalCandidates
end function end function
sub setFieldTextValue(field, value) sub setFieldTextValue(field, value)
@ -228,7 +302,7 @@ function isValidAndNotEmpty(input as dynamic) as boolean
end if end if
end function end function
' Returns an array from a url - [ url, proto, host, port, subdir/params ] ' Returns an array from a url = [ url, proto, host, port, subdir+params ]
' If port or subdir are not found, an empty string will be added to the array ' If port or subdir are not found, an empty string will be added to the array
' Proto must be declared or array will be empty ' Proto must be declared or array will be empty
function parseUrl(url as string) as object function parseUrl(url as string) as object
@ -383,6 +457,16 @@ sub stopLoadingSpinner()
end if end if
end sub end sub
' accepts the raw json string of /system/info/public and returns
' a boolean indicating if ProductName is "Jellyfin Server"
function isJellyfinServer(systemInfo as object) as boolean
d = ParseJson(systemInfo)
if isValid(d) and isValid(d.ProductName)
return d.ProductName = "Jellyfin Server"
end if
return False
end function
' Check if a specific value is inside of an array ' Check if a specific value is inside of an array
function arrayHasValue(arr as object, value as dynamic) as boolean function arrayHasValue(arr as object, value as dynamic) as boolean
for each entry in arr for each entry in arr