Some heavy restructuring
This commit is contained in:
parent
f350ec8cff
commit
0f15d6983f
|
@ -15,6 +15,7 @@
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
function itemContentChanged() as void
|
function itemContentChanged() as void
|
||||||
|
m.itemText = m.top.findNode("itemText")
|
||||||
itemData = m.top.itemContent
|
itemData = m.top.itemContent
|
||||||
m.itemText.text = itemData.labelText
|
m.itemText.text = itemData.labelText
|
||||||
end function
|
end function
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<component name="VideoScene" extends="Scene">
|
|
||||||
<children>
|
|
||||||
<Video id="VideoPlayer" />
|
|
||||||
</children>
|
|
||||||
<script type="text/brightscript">
|
|
||||||
<![CDATA[
|
|
||||||
function init()
|
|
||||||
m.top.setFocus(true)
|
|
||||||
end function
|
|
||||||
]]>
|
|
||||||
</script>
|
|
||||||
</component>
|
|
|
@ -1,42 +1,42 @@
|
||||||
' Functions for making requests to the API
|
' Functions for making requests to the API
|
||||||
|
|
||||||
function APIRequest(url as String, params={} as Object)
|
function APIRequest(url as String, params={} as Object)
|
||||||
req = createObject("roUrlTransfer")
|
req = createObject("roUrlTransfer")
|
||||||
|
|
||||||
if server_is_https() then
|
if server_is_https() then
|
||||||
req.setCertificatesFile("common:/certs/ca-bundle.crt")
|
req.setCertificatesFile("common:/certs/ca-bundle.crt")
|
||||||
end if
|
end if
|
||||||
|
|
||||||
full_url = get_base_url() + "/emby/" + url
|
full_url = get_base_url() + "/emby/" + url
|
||||||
if params.count() > 0
|
if params.count() > 0
|
||||||
full_url = full_url + "?"
|
full_url = full_url + "?"
|
||||||
|
|
||||||
param_array = []
|
param_array = []
|
||||||
for each field in params.items()
|
for each field in params.items()
|
||||||
if type(field.value) = "String" then
|
if type(field.value) = "String" then
|
||||||
item = field.key + "=" + req.escape(field.value.trim())
|
item = field.key + "=" + req.escape(field.value.trim())
|
||||||
else if type(field.value) = "roInteger" then
|
else if type(field.value) = "roInteger" then
|
||||||
item = field.key + "=" + req.escape(str(field.value).trim())
|
item = field.key + "=" + req.escape(str(field.value).trim())
|
||||||
else
|
else
|
||||||
item = field.key + "=" + req.escape(field.value)
|
item = field.key + "=" + req.escape(field.value)
|
||||||
end if
|
end if
|
||||||
param_array.push(item)
|
param_array.push(item)
|
||||||
end for
|
end for
|
||||||
full_url = full_url + param_array.join("&")
|
full_url = full_url + param_array.join("&")
|
||||||
end if
|
end if
|
||||||
|
|
||||||
req.setUrl(full_url)
|
req.setUrl(full_url)
|
||||||
|
|
||||||
req = authorize_request(req)
|
req = authorize_request(req)
|
||||||
|
|
||||||
return req
|
return req
|
||||||
end function
|
end function
|
||||||
|
|
||||||
function parseRequest(req)
|
function parseRequest(req)
|
||||||
'req.retainBodyOnError(True)
|
'req.retainBodyOnError(True)
|
||||||
'print req.GetToString()
|
'print req.GetToString()
|
||||||
json = ParseJson(req.GetToString())
|
json = ParseJson(req.GetToString())
|
||||||
return json
|
return json
|
||||||
end function
|
end function
|
||||||
|
|
||||||
function get_base_url()
|
function get_base_url()
|
||||||
|
@ -49,70 +49,76 @@ function get_base_url()
|
||||||
end function
|
end function
|
||||||
|
|
||||||
function server_is_https() as Boolean
|
function server_is_https() as Boolean
|
||||||
server = get_setting("server")
|
server = get_setting("server")
|
||||||
|
|
||||||
i = server.Instr(":")
|
i = server.Instr(":")
|
||||||
|
|
||||||
' No protocol found
|
' No protocol found
|
||||||
if i = 0 then
|
if i = 0 then
|
||||||
return False
|
|
||||||
end if
|
|
||||||
|
|
||||||
protocol = Left(server, i)
|
|
||||||
if protocol = "https" then
|
|
||||||
return True
|
|
||||||
end if
|
|
||||||
return False
|
return False
|
||||||
|
end if
|
||||||
|
|
||||||
|
protocol = Left(server, i)
|
||||||
|
if protocol = "https" then
|
||||||
|
return True
|
||||||
|
end if
|
||||||
|
return False
|
||||||
end function
|
end function
|
||||||
|
|
||||||
function get_token(user as String, password as String)
|
function get_token(user as String, password as String)
|
||||||
bytes = createObject("roByteArray")
|
bytes = createObject("roByteArray")
|
||||||
bytes.FromAsciiString(password)
|
bytes.FromAsciiString(password)
|
||||||
digest = createObject("roEVPDigest")
|
digest = createObject("roEVPDigest")
|
||||||
digest.setup("sha1")
|
digest.setup("sha1")
|
||||||
hashed_pass = digest.process(bytes)
|
hashed_pass = digest.process(bytes)
|
||||||
|
|
||||||
url = "Users/AuthenticateByName?format=json"
|
url = "Users/AuthenticateByName?format=json"
|
||||||
|
|
||||||
req = APIRequest(url)
|
req = APIRequest(url)
|
||||||
|
|
||||||
' BrightScript will only return a POST body if you call post asynch
|
' BrightScript will only return a POST body if you call post asynch
|
||||||
' and then wait for the response
|
' and then wait for the response
|
||||||
req.setMessagePort(CreateObject("roMessagePort"))
|
req.setMessagePort(CreateObject("roMessagePort"))
|
||||||
req.AsyncPostFromString("Username=" + user + "&Password=" + hashed_pass)
|
req.AsyncPostFromString("Username=" + user + "&Password=" + hashed_pass)
|
||||||
resp = wait(5000, req.GetMessagePort())
|
resp = wait(5000, req.GetMessagePort())
|
||||||
if type(resp) <> "roUrlEvent"
|
if type(resp) <> "roUrlEvent"
|
||||||
return invalid
|
return invalid
|
||||||
end if
|
end if
|
||||||
|
|
||||||
json = ParseJson(resp.GetString())
|
json = ParseJson(resp.GetString())
|
||||||
|
|
||||||
set_setting("active_user", json.User.id)
|
set_setting("active_user", json.User.id)
|
||||||
set_user_setting("id", json.User.id) ' redundant, but could come in handy
|
set_user_setting("id", json.User.id) ' redundant, but could come in handy
|
||||||
set_user_setting("token", json.AccessToken)
|
set_user_setting("token", json.AccessToken)
|
||||||
set_user_setting("response", json)
|
set_user_setting("response", json)
|
||||||
return json
|
return json
|
||||||
end function
|
end function
|
||||||
|
|
||||||
function authorize_request(request)
|
function authorize_request(request)
|
||||||
auth = "MediaBrowser"
|
auth = "MediaBrowser"
|
||||||
auth = auth + " Client=" + Chr(34) + "Jellyfin Roku" + Chr(34)
|
auth = auth + " Client=" + Chr(34) + "Jellyfin Roku" + Chr(34)
|
||||||
auth = auth + ", Device=" + Chr(34) + "Roku Model" + Chr(34)
|
auth = auth + ", Device=" + Chr(34) + "Roku Model" + Chr(34)
|
||||||
auth = auth + ", DeviceId=" + Chr(34) + "12345" + Chr(34)
|
auth = auth + ", DeviceId=" + Chr(34) + "12345" + Chr(34)
|
||||||
auth = auth + ", Version=" + Chr(34) + "10.1.0" + Chr(34)
|
auth = auth + ", Version=" + Chr(34) + "10.1.0" + Chr(34)
|
||||||
|
|
||||||
user = get_setting("active_user")
|
user = get_setting("active_user")
|
||||||
if user <> invalid and user <> "" then
|
if user <> invalid and user <> "" then
|
||||||
auth = auth + ", UserId=" + Chr(34) + user + Chr(34)
|
auth = auth + ", UserId=" + Chr(34) + user + Chr(34)
|
||||||
end if
|
end if
|
||||||
|
|
||||||
token = get_user_setting("token")
|
token = get_user_setting("token")
|
||||||
if token <> invalid and token <> "" then
|
if token <> invalid and token <> "" then
|
||||||
auth = auth + ", Token=" + Chr(34) + token + Chr(34)
|
auth = auth + ", Token=" + Chr(34) + token + Chr(34)
|
||||||
end if
|
end if
|
||||||
|
|
||||||
request.AddHeader("X-Emby-Authorization", auth)
|
request.AddHeader("X-Emby-Authorization", auth)
|
||||||
return request
|
return request
|
||||||
|
end function
|
||||||
|
|
||||||
|
function AboutMe()
|
||||||
|
url = Substitute("Users/{0}", get_setting("active_user"))
|
||||||
|
resp = APIRequest(url)
|
||||||
|
return parseRequest(resp)
|
||||||
end function
|
end function
|
||||||
|
|
||||||
|
|
||||||
|
@ -122,45 +128,30 @@ end function
|
||||||
' Params: None
|
' Params: None
|
||||||
' Returns { Items, TotalRecordCount }
|
' Returns { Items, TotalRecordCount }
|
||||||
function LibraryList()
|
function LibraryList()
|
||||||
url = Substitute("Users/{0}/Views/", get_setting("active_user"))
|
url = Substitute("Users/{0}/Views/", get_setting("active_user"))
|
||||||
resp = APIRequest(url)
|
resp = APIRequest(url)
|
||||||
return parseRequest(resp)
|
return parseRequest(resp)
|
||||||
end function
|
end function
|
||||||
|
|
||||||
' Search for a string
|
' Search for a string
|
||||||
' Params: Search Query
|
' Params: Search Query
|
||||||
' Returns: { SearchHints, TotalRecordCount }
|
' Returns: { SearchHints, TotalRecordCount }
|
||||||
function SearchMedia(query as String)
|
function SearchMedia(query as String)
|
||||||
resp = APIRequest("Search/Hints", {"searchTerm": query})
|
resp = APIRequest("Search/Hints", {"searchTerm": query})
|
||||||
return parseRequest(resp)
|
return parseRequest(resp)
|
||||||
end function
|
end function
|
||||||
|
|
||||||
' List items from within a Library
|
' List items from within a Library
|
||||||
' Params: Library ID, Limit, Offset, SortBy, SortOrder, IncludeItemTypes, Fields, EnableImageTypes
|
' Params: Library ID, Limit, Offset, SortBy, SortOrder, IncludeItemTypes, Fields, EnableImageTypes
|
||||||
' Returns { Items, TotalRecordCount }
|
' Returns { Items, TotalRecordCount }
|
||||||
function ItemList(library_id=invalid as String)
|
function ItemList(library_id=invalid as String)
|
||||||
url = Substitute("Users/{0}/Items/", get_setting("active_user"))
|
url = Substitute("Users/{0}/Items/", get_setting("active_user"))
|
||||||
resp = APIRequest(url, {"parentid": library_id, "limit": 30})
|
resp = APIRequest(url, {"parentid": library_id, "limit": 30})
|
||||||
return parseRequest(resp)
|
return parseRequest(resp)
|
||||||
end function
|
end function
|
||||||
|
|
||||||
function ItemMetaData(id as String)
|
function ItemMetaData(id as String)
|
||||||
url = Substitute("Users/{0}/Items/{1}", get_setting("active_user"), id)
|
url = Substitute("Users/{0}/Items/{1}", get_setting("active_user"), id)
|
||||||
resp = APIRequest(url)
|
resp = APIRequest(url)
|
||||||
return parseRequest(resp)
|
return parseRequest(resp)
|
||||||
end function
|
|
||||||
|
|
||||||
' Video
|
|
||||||
|
|
||||||
function VideoStream(id as String)
|
|
||||||
|
|
||||||
player = createObject("roVideoPlayer")
|
|
||||||
|
|
||||||
content = VideoContent(id)
|
|
||||||
|
|
||||||
player.addContent(content)
|
|
||||||
|
|
||||||
player.play()
|
|
||||||
|
|
||||||
return player
|
|
||||||
end function
|
end function
|
||||||
|
|
|
@ -1,49 +1,50 @@
|
||||||
sub Main()
|
sub Main()
|
||||||
m.port = CreateObject("roMessagePort")
|
' First thing to do is validate the ability to use the API
|
||||||
|
|
||||||
' This facade keeps the app open when maybe other screens close
|
|
||||||
facade = CreateObject("roSGScreen")
|
|
||||||
facade.show()
|
|
||||||
|
|
||||||
if get_setting("server") = invalid then
|
if get_setting("server") = invalid then
|
||||||
print "Get server details"
|
print "Get server details"
|
||||||
' TODO - make this into a dialog
|
|
||||||
' TODO - be able to submit server info
|
' TODO - be able to submit server info
|
||||||
ShowServerSelect()
|
ShowServerSelect()
|
||||||
end if
|
end if
|
||||||
|
|
||||||
if get_setting("active_user") = invalid then
|
if get_setting("active_user") = invalid then
|
||||||
print "Get user login"
|
print "Get user login"
|
||||||
' TODO - make this into a dialog
|
' TODO - be able to submit user info
|
||||||
' screen.CreateScene("UserSignIn")
|
' ShowSigninSelect()
|
||||||
' TODO - sign in here
|
|
||||||
end if
|
end if
|
||||||
|
|
||||||
' TODO - something here to validate that the active_user is still
|
' Confirm the configured server and user work
|
||||||
' valid.
|
m.user = AboutMe()
|
||||||
|
if m.user.id <> get_setting("active_user")
|
||||||
|
' TODO - proper handling of the scenario where things have gone wrong
|
||||||
|
print "OH NO!"
|
||||||
|
end if
|
||||||
|
|
||||||
selected = ShowLibrarySelect()
|
ShowLibrarySelect()
|
||||||
|
|
||||||
await_response()
|
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
sub ShowServerSelect()
|
sub ShowServerSelect()
|
||||||
port = CreateObject("roMessagePort")
|
port = CreateObject("roMessagePort")
|
||||||
screen = CreateObject("roSGScreen")
|
screen = CreateObject("roSGScreen")
|
||||||
screen.setMessagePort(port)
|
screen.setMessagePort(port)
|
||||||
|
|
||||||
scene = screen.CreateScene("ServerSelection")
|
scene = screen.CreateScene("ServerSelection")
|
||||||
|
|
||||||
screen.show()
|
screen.show()
|
||||||
|
|
||||||
await_response()
|
while(true)
|
||||||
|
msg = wait(0, port)
|
||||||
|
if msg.isScreenClosed() then
|
||||||
|
return
|
||||||
|
else
|
||||||
|
print(msgType)
|
||||||
|
end if
|
||||||
|
end while
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
sub ShowLibrarySelect()
|
sub ShowLibrarySelect()
|
||||||
port = CreateObject("roMessagePort")
|
port = CreateObject("roMessagePort")
|
||||||
screen = CreateObject("roSGScreen")
|
screen = CreateObject("roSGScreen")
|
||||||
screen.setMessagePort(port)
|
screen.setMessagePort(port)
|
||||||
|
|
||||||
scene = screen.CreateScene("Library")
|
scene = screen.CreateScene("Library")
|
||||||
|
|
||||||
screen.show()
|
screen.show()
|
||||||
|
@ -56,32 +57,23 @@ sub ShowLibrarySelect()
|
||||||
|
|
||||||
while(true)
|
while(true)
|
||||||
msg = wait(0, port)
|
msg = wait(0, port)
|
||||||
print msg
|
|
||||||
if type(msg) = "roSGScreenEvent" and msg.isScreenClosed() then
|
if type(msg) = "roSGScreenEvent" and msg.isScreenClosed() then
|
||||||
exit while
|
exit while
|
||||||
else if itemSelectedQ(msg)
|
else if itemSelectedQ(msg)
|
||||||
target = getRowTarget(msg)
|
target = getMsgRowTarget(msg)
|
||||||
ShowLibraryOptions(target.libraryID)
|
if target.libraryType = "movies"
|
||||||
|
ShowMovieOptions(target.libraryID)
|
||||||
|
else
|
||||||
|
print "NOT YET IMPLEMENTED"
|
||||||
|
end if
|
||||||
end if
|
end if
|
||||||
end while
|
end while
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
sub itemSelectedQ(msg) as boolean
|
sub ShowMovieOptions(library_id)
|
||||||
return type(msg) = "roSGNodeEvent" and msg.getField() = "itemSelected"
|
|
||||||
end sub
|
|
||||||
|
|
||||||
sub getRowTarget(msg) as object
|
|
||||||
node = msg.getRoSGNode()
|
|
||||||
coords = node.rowItemSelected
|
|
||||||
target = node.content.getChild(coords[0]).getChild(coords[1])
|
|
||||||
return target
|
|
||||||
end sub
|
|
||||||
|
|
||||||
sub ShowLibraryOptions(library_id)
|
|
||||||
port = CreateObject("roMessagePort")
|
port = CreateObject("roMessagePort")
|
||||||
screen = CreateObject("roSGScreen")
|
screen = CreateObject("roSGScreen")
|
||||||
screen.setMessagePort(port)
|
screen.setMessagePort(port)
|
||||||
|
|
||||||
scene = screen.CreateScene("Movies")
|
scene = screen.CreateScene("Movies")
|
||||||
|
|
||||||
screen.show()
|
screen.show()
|
||||||
|
@ -97,9 +89,8 @@ sub ShowLibraryOptions(library_id)
|
||||||
if type(msg) = "roSGScreenEvent" and msg.isScreenClosed() then
|
if type(msg) = "roSGScreenEvent" and msg.isScreenClosed() then
|
||||||
return
|
return
|
||||||
else if itemSelectedQ(msg)
|
else if itemSelectedQ(msg)
|
||||||
target = getRowTarget(msg)
|
target = getMsgRowTarget(msg)
|
||||||
showVideoPlayer(target.movieID)
|
showVideoPlayer(target.movieID)
|
||||||
print msg
|
|
||||||
end if
|
end if
|
||||||
end while
|
end while
|
||||||
end sub
|
end sub
|
||||||
|
@ -108,8 +99,7 @@ sub showVideoPlayer(id)
|
||||||
port = CreateObject("roMessagePort")
|
port = CreateObject("roMessagePort")
|
||||||
screen = CreateObject("roSGScreen")
|
screen = CreateObject("roSGScreen")
|
||||||
screen.setMessagePort(port)
|
screen.setMessagePort(port)
|
||||||
|
scene = screen.CreateScene("Scene")
|
||||||
scene = screen.CreateScene("VideoScene")
|
|
||||||
|
|
||||||
screen.show()
|
screen.show()
|
||||||
|
|
||||||
|
@ -124,16 +114,15 @@ sub showVideoPlayer(id)
|
||||||
|
|
||||||
end sub
|
end sub
|
||||||
|
|
||||||
sub await_response(port=invalid)
|
sub itemSelectedQ(msg) as boolean
|
||||||
if port = invalid then
|
' "Q" stands for "Question mark" since itemSelected? wasn't acceptable
|
||||||
port = m.port
|
' Probably needs a better name, but unique for now
|
||||||
end if
|
return type(msg) = "roSGNodeEvent" and msg.getField() = "itemSelected"
|
||||||
while(true)
|
end sub
|
||||||
msg = wait(0, port)
|
|
||||||
if msg.isScreenClosed() then
|
sub getMsgRowTarget(msg) as object
|
||||||
return
|
node = msg.getRoSGNode()
|
||||||
else
|
coords = node.rowItemSelected
|
||||||
print(msgType)
|
target = node.content.getChild(coords[0]).getChild(coords[1])
|
||||||
end if
|
return target
|
||||||
end while
|
|
||||||
end sub
|
end sub
|
||||||
|
|
|
@ -1,19 +1,15 @@
|
||||||
function VideoPlayer(scene, id)
|
function VideoPlayer(scene, id)
|
||||||
|
video = scene.createChild("Video")
|
||||||
|
content = VideoContent(id)
|
||||||
|
|
||||||
content = VideoContent(id)
|
video.content = content
|
||||||
|
|
||||||
video = scene.findNode("VideoPlayer")
|
video.setFocus(true)
|
||||||
|
video.control = "play"
|
||||||
video.content = content
|
|
||||||
|
|
||||||
video.setFocus(true)
|
|
||||||
video.control = "play"
|
|
||||||
|
|
||||||
return video
|
|
||||||
|
|
||||||
|
return video
|
||||||
end function
|
end function
|
||||||
|
|
||||||
|
|
||||||
function VideoContent(id) as object
|
function VideoContent(id) as object
|
||||||
content = createObject("RoSGNode", "ContentNode")
|
content = createObject("RoSGNode", "ContentNode")
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user