2019-02-04 02:57:52 +00:00
|
|
|
' Functions for making requests to the API
|
|
|
|
|
2019-03-08 02:03:19 +00:00
|
|
|
function buildURL(path as String, params={} as Object) as string
|
2019-03-10 06:12:09 +00:00
|
|
|
' roURLTransfer can only be created on a Task Node, and somewhere something
|
|
|
|
' is trying to call it from a "regular" node
|
|
|
|
' So we'll just avoid using it for now
|
|
|
|
' Sucks that we can't use htmlescape any other way though
|
2019-03-10 06:14:38 +00:00
|
|
|
req = createObject("roUrlTransfer") ' Just so we can use it for escape
|
2019-03-13 01:16:12 +00:00
|
|
|
|
|
|
|
if req = invalid
|
|
|
|
print "How is this even!?"
|
|
|
|
return ""
|
|
|
|
end if
|
|
|
|
|
2019-03-08 02:03:19 +00:00
|
|
|
full_url = get_base_url() + "/emby/" + path
|
2019-03-05 04:59:31 +00:00
|
|
|
if params.count() > 0
|
|
|
|
full_url = full_url + "?"
|
|
|
|
|
|
|
|
param_array = []
|
|
|
|
for each field in params.items()
|
|
|
|
if type(field.value) = "String" then
|
2019-03-10 06:14:38 +00:00
|
|
|
item = field.key + "=" + req.escape(field.value.trim())
|
|
|
|
'item = field.key + "=" + field.value.trim()
|
2019-03-05 04:59:31 +00:00
|
|
|
else if type(field.value) = "roInteger" then
|
2019-03-10 06:14:38 +00:00
|
|
|
item = field.key + "=" + req.escape(str(field.value).trim())
|
|
|
|
'item = field.key + "=" + str(field.value).trim()
|
2019-03-19 01:11:34 +00:00
|
|
|
else if type(field.value) = "roFloat" then
|
|
|
|
item = field.key + "=" + req.escape(str(field.value).trim())
|
2019-03-08 03:47:10 +00:00
|
|
|
else if field <> invalid
|
2019-03-10 06:14:38 +00:00
|
|
|
item = field.key + "=" + req.escape(field.value)
|
|
|
|
'item = field.key + "=" + field.value
|
2019-03-05 04:59:31 +00:00
|
|
|
end if
|
|
|
|
param_array.push(item)
|
|
|
|
end for
|
|
|
|
full_url = full_url + param_array.join("&")
|
|
|
|
end if
|
|
|
|
|
2019-03-08 02:03:19 +00:00
|
|
|
return full_url
|
|
|
|
end function
|
|
|
|
|
|
|
|
function APIRequest(url as String, params={} as Object)
|
|
|
|
req = createObject("roUrlTransfer")
|
|
|
|
|
|
|
|
if server_is_https() then
|
|
|
|
req.setCertificatesFile("common:/certs/ca-bundle.crt")
|
|
|
|
end if
|
|
|
|
|
|
|
|
full_url = buildURL(url, params)
|
|
|
|
|
2019-03-05 04:59:31 +00:00
|
|
|
req.setUrl(full_url)
|
|
|
|
|
|
|
|
req = authorize_request(req)
|
|
|
|
|
|
|
|
return req
|
2019-02-01 02:26:53 +00:00
|
|
|
end function
|
|
|
|
|
2019-03-13 01:43:06 +00:00
|
|
|
function getJson(req)
|
2019-03-05 04:59:31 +00:00
|
|
|
'req.retainBodyOnError(True)
|
|
|
|
'print req.GetToString()
|
|
|
|
json = ParseJson(req.GetToString())
|
|
|
|
return json
|
2019-02-01 02:26:53 +00:00
|
|
|
end function
|
|
|
|
|
2019-03-13 01:43:06 +00:00
|
|
|
function postVoid(req, data="" as string)
|
|
|
|
status = req.PostFromString(data)
|
|
|
|
if status = 200
|
|
|
|
return true
|
|
|
|
else
|
|
|
|
return false
|
|
|
|
end if
|
|
|
|
end function
|
|
|
|
|
|
|
|
function postJson(req, data="" as string)
|
|
|
|
req.setMessagePort(CreateObject("roMessagePort"))
|
|
|
|
req.AsyncPostFromString(data)
|
|
|
|
|
|
|
|
resp = wait(5000, req.GetMessagePort())
|
|
|
|
if type(resp) <> "roUrlEvent"
|
|
|
|
return invalid
|
|
|
|
end if
|
|
|
|
|
|
|
|
if resp.getString() = ""
|
|
|
|
return invalid
|
|
|
|
end if
|
|
|
|
|
|
|
|
json = ParseJson(resp.GetString())
|
|
|
|
|
|
|
|
return json
|
|
|
|
end function
|
|
|
|
|
2019-02-23 03:14:21 +00:00
|
|
|
function get_base_url()
|
|
|
|
base = get_setting("server")
|
|
|
|
port = get_setting("port")
|
|
|
|
if port <> "" and port <> invalid then
|
|
|
|
base = base + ":" + port
|
|
|
|
end if
|
|
|
|
return base
|
|
|
|
end function
|
|
|
|
|
2019-02-01 02:26:53 +00:00
|
|
|
function server_is_https() as Boolean
|
2019-03-05 04:59:31 +00:00
|
|
|
server = get_setting("server")
|
2019-02-01 02:26:53 +00:00
|
|
|
|
2019-03-05 04:59:31 +00:00
|
|
|
i = server.Instr(":")
|
2019-02-01 02:26:53 +00:00
|
|
|
|
2019-03-05 04:59:31 +00:00
|
|
|
' No protocol found
|
|
|
|
if i = 0 then
|
2019-02-01 02:26:53 +00:00
|
|
|
return False
|
2019-03-05 04:59:31 +00:00
|
|
|
end if
|
|
|
|
|
|
|
|
protocol = Left(server, i)
|
|
|
|
if protocol = "https" then
|
|
|
|
return True
|
|
|
|
end if
|
|
|
|
return False
|
2019-02-01 02:26:53 +00:00
|
|
|
end function
|
|
|
|
|
|
|
|
function get_token(user as String, password as String)
|
2019-03-05 04:59:31 +00:00
|
|
|
bytes = createObject("roByteArray")
|
|
|
|
bytes.FromAsciiString(password)
|
|
|
|
digest = createObject("roEVPDigest")
|
|
|
|
digest.setup("sha1")
|
|
|
|
hashed_pass = digest.process(bytes)
|
|
|
|
|
|
|
|
url = "Users/AuthenticateByName?format=json"
|
|
|
|
|
|
|
|
req = APIRequest(url)
|
|
|
|
|
2019-03-13 01:43:06 +00:00
|
|
|
json = postJson(req, "Username=" + user + "&Password=" + hashed_pass)
|
2019-03-12 03:49:17 +00:00
|
|
|
|
2019-03-13 01:43:06 +00:00
|
|
|
if json = invalid then return invalid
|
2019-03-05 04:59:31 +00:00
|
|
|
|
|
|
|
set_setting("active_user", json.User.id)
|
|
|
|
set_user_setting("id", json.User.id) ' redundant, but could come in handy
|
|
|
|
set_user_setting("token", json.AccessToken)
|
|
|
|
return json
|
2019-02-01 02:26:53 +00:00
|
|
|
end function
|
|
|
|
|
|
|
|
function authorize_request(request)
|
2019-03-05 04:59:31 +00:00
|
|
|
auth = "MediaBrowser"
|
|
|
|
auth = auth + " Client=" + Chr(34) + "Jellyfin Roku" + Chr(34)
|
|
|
|
auth = auth + ", Device=" + Chr(34) + "Roku Model" + Chr(34)
|
|
|
|
auth = auth + ", DeviceId=" + Chr(34) + "12345" + Chr(34)
|
|
|
|
auth = auth + ", Version=" + Chr(34) + "10.1.0" + Chr(34)
|
|
|
|
|
|
|
|
user = get_setting("active_user")
|
|
|
|
if user <> invalid and user <> "" then
|
|
|
|
auth = auth + ", UserId=" + Chr(34) + user + Chr(34)
|
|
|
|
end if
|
|
|
|
|
|
|
|
token = get_user_setting("token")
|
|
|
|
if token <> invalid and token <> "" then
|
|
|
|
auth = auth + ", Token=" + Chr(34) + token + Chr(34)
|
|
|
|
end if
|
|
|
|
|
|
|
|
request.AddHeader("X-Emby-Authorization", auth)
|
|
|
|
return request
|
|
|
|
end function
|
|
|
|
|
|
|
|
function AboutMe()
|
|
|
|
url = Substitute("Users/{0}", get_setting("active_user"))
|
|
|
|
resp = APIRequest(url)
|
2019-03-13 01:43:06 +00:00
|
|
|
return getJson(resp)
|
2019-02-01 02:26:53 +00:00
|
|
|
end function
|
|
|
|
|
2019-03-15 00:29:01 +00:00
|
|
|
function ImageURL(id, version="Primary", params={})
|
|
|
|
if params.count() = 0
|
|
|
|
params = {"maxHeight": "384", "maxWidth": "196", "quality": "90"}
|
|
|
|
end if
|
|
|
|
url = Substitute("Items/{0}/Images/{1}", id, version)
|
2019-03-07 05:30:06 +00:00
|
|
|
' ?maxHeight=384&maxWidth=256&tag=<tag>&quality=90"
|
2019-03-15 00:29:01 +00:00
|
|
|
return buildURL(url, params)
|
2019-03-07 05:30:06 +00:00
|
|
|
end function
|
2019-02-03 21:15:17 +00:00
|
|
|
|
|
|
|
' ServerBrowsing
|
|
|
|
|
|
|
|
' List Available Libraries for the current logged in user
|
|
|
|
' Params: None
|
|
|
|
' Returns { Items, TotalRecordCount }
|
|
|
|
function LibraryList()
|
2019-03-05 04:59:31 +00:00
|
|
|
url = Substitute("Users/{0}/Views/", get_setting("active_user"))
|
|
|
|
resp = APIRequest(url)
|
2019-03-13 01:43:06 +00:00
|
|
|
return getJson(resp)
|
2019-02-03 21:15:17 +00:00
|
|
|
end function
|
|
|
|
|
|
|
|
' Search for a string
|
|
|
|
' Params: Search Query
|
|
|
|
' Returns: { SearchHints, TotalRecordCount }
|
|
|
|
function SearchMedia(query as String)
|
2019-03-05 04:59:31 +00:00
|
|
|
resp = APIRequest("Search/Hints", {"searchTerm": query})
|
2019-03-14 22:50:20 +00:00
|
|
|
data = getJson(resp)
|
|
|
|
for each item in data.SearchHints
|
|
|
|
if item.type = "Movie"
|
|
|
|
item.posterURL = ImageURL(item.id)
|
|
|
|
else if item.type = "Person"
|
|
|
|
item.posterURL = ImageURL(item.id)
|
2019-03-15 00:29:01 +00:00
|
|
|
else if item.type = "Episode"
|
|
|
|
item.posterURL = ImageURL(item.id)
|
2019-03-14 22:50:20 +00:00
|
|
|
end if
|
|
|
|
end for
|
|
|
|
return data
|
2019-02-03 21:15:17 +00:00
|
|
|
end function
|
|
|
|
|
|
|
|
' List items from within a Library
|
|
|
|
' Params: Library ID, Limit, Offset, SortBy, SortOrder, IncludeItemTypes, Fields, EnableImageTypes
|
|
|
|
' Returns { Items, TotalRecordCount }
|
2019-03-09 22:09:21 +00:00
|
|
|
function ItemList(library_id=invalid as String, params={})
|
|
|
|
if params["limit"] = invalid
|
|
|
|
params["limit"] = 30
|
|
|
|
end if
|
|
|
|
if params["page"] = invalid
|
|
|
|
params["page"] = 1
|
|
|
|
end if
|
|
|
|
params["parentid"] = library_id
|
2019-03-05 04:59:31 +00:00
|
|
|
url = Substitute("Users/{0}/Items/", get_setting("active_user"))
|
2019-03-09 22:09:21 +00:00
|
|
|
resp = APIRequest(url, params)
|
2019-03-13 17:20:54 +00:00
|
|
|
data = getJson(resp)
|
|
|
|
for each item in data.Items
|
|
|
|
item.posterURL = ImageURL(item.id)
|
|
|
|
end for
|
|
|
|
return data
|
2019-02-03 21:15:17 +00:00
|
|
|
end function
|
|
|
|
|
|
|
|
function ItemMetaData(id as String)
|
2019-03-05 04:59:31 +00:00
|
|
|
url = Substitute("Users/{0}/Items/{1}", get_setting("active_user"), id)
|
|
|
|
resp = APIRequest(url)
|
2019-03-13 17:20:54 +00:00
|
|
|
data = getJson(resp)
|
|
|
|
data.posterURL = ImageURL(data.id)
|
|
|
|
return data
|
2019-02-01 02:26:53 +00:00
|
|
|
end function
|
2019-03-11 02:35:48 +00:00
|
|
|
|
|
|
|
function TVSeasons(id as String)
|
|
|
|
url = Substitute("Shows/{0}/Seasons", id)
|
|
|
|
resp = APIRequest(url, {"UserId": get_setting("active_user")})
|
2019-03-13 17:20:54 +00:00
|
|
|
|
|
|
|
data = getJson(resp)
|
|
|
|
for each item in data.Items
|
|
|
|
item.posterURL = ImageURL(item.id)
|
|
|
|
end for
|
|
|
|
return data
|
2019-03-11 02:35:48 +00:00
|
|
|
end function
|
|
|
|
|
|
|
|
|
|
|
|
function TVNext(id as String)
|
|
|
|
url = Substitute("Shows/NextUp", id)
|
|
|
|
resp = APIRequest(url, {"UserId": get_setting("active_user"), "SeriesId": id})
|
2019-03-13 17:20:54 +00:00
|
|
|
|
|
|
|
data = getJson(resp)
|
|
|
|
for each item in data.Items
|
|
|
|
item.posterURL = ImageURL(item.id)
|
|
|
|
end for
|
|
|
|
return data
|
2019-03-11 02:35:48 +00:00
|
|
|
end function
|