- Now stores the different lists in a tree which caches each path to enable the minimum amount of re-fetching - Every request is async allowing input while waiting for the server to respond - No longer requires a list library as a list implementation is built in Currently I've yet to implement the video handling, but that's next!
173 lines
3.9 KiB
Lua
173 lines
3.9 KiB
Lua
local mp = require("mp")
|
|
local msg = require("mp.msg")
|
|
local utils = require("mp.utils")
|
|
|
|
local list = require("src.list")
|
|
local auth = require("src.auth")
|
|
local api = require("src.api")
|
|
local cache = require("src.cache")
|
|
local tree = require("src.utils.tree")
|
|
|
|
---@type auth
|
|
local jf = nil
|
|
|
|
-- keeps track of all the info available
|
|
local state = {
|
|
---@type tree<cache> the currently selected node in the tree
|
|
pos = nil,
|
|
---@type tree<cache> the head of the tree
|
|
tree = nil,
|
|
|
|
-- when we're navigating (in the middle of loading) we shouldn't allow more
|
|
-- navigations
|
|
navigating = false
|
|
}
|
|
|
|
-- create the main list
|
|
local l = list:new()
|
|
l:update()
|
|
local timer = l:set_fade_animation(0.02, "Authenticating")
|
|
|
|
coroutine.wrap(function()
|
|
-- attempt to authenticate with the server
|
|
jf = auth:new(
|
|
"http://192.168.50.159:8096",
|
|
"zachary",
|
|
"qwerty1"
|
|
)
|
|
if not jf.available then
|
|
timer:kill()
|
|
l:log({
|
|
style = [[{\c&H0000ff&}]],
|
|
ass = string.format(
|
|
"The jellyfin server at '%s' is not available",
|
|
jf.url
|
|
)
|
|
})
|
|
mp.add_timeout(5, function()
|
|
l:close()
|
|
end)
|
|
return
|
|
end
|
|
|
|
-- we've connected kill the auth animation and clear the list
|
|
timer:kill()
|
|
l:set()
|
|
|
|
if not jf.authenticated then
|
|
l:log({
|
|
style = [[{\c&H0000ff&}]],
|
|
ass = "Failed to authenticate with jellyfin server. Check your credentials.",
|
|
})
|
|
mp.add_timeout(5, function()
|
|
l:close()
|
|
end)
|
|
return
|
|
end
|
|
|
|
msg.trace("Welcome to jellyfin. Everything's working so far.")
|
|
-- show the first list
|
|
state.tree = tree:new(cache:new(nil, function(self)
|
|
return api.async_request(self, "head", l, jf, "/Items/", { method = "GET" })
|
|
end))
|
|
state.pos = state.tree
|
|
|
|
l:set(api.items_to_list(state.pos.data:get().items))
|
|
l.selected = 1
|
|
l:update()
|
|
end)()
|
|
|
|
-- add keys
|
|
l:addkey("k", "up", function()
|
|
if state.navigating then
|
|
return
|
|
end
|
|
l:up()
|
|
end)
|
|
l:addkey("j", "down", function()
|
|
if state.navigating then
|
|
return
|
|
end
|
|
l:down()
|
|
end)
|
|
l:addkey("l", "enter", function()
|
|
if state.navigating then
|
|
return
|
|
end
|
|
state.navigating = true
|
|
coroutine.resume(coroutine.create(function()
|
|
if #state.pos.data:get().items < 1 then
|
|
state.navigating = false
|
|
return
|
|
end
|
|
|
|
local cur_item = state.pos.data:get().items[l.selected]
|
|
if cur_item.MediaType == "Video" then
|
|
print(cur_item.Name)
|
|
-- TODO: handle playing videos
|
|
state.navigating = false
|
|
return
|
|
end
|
|
|
|
local new_pos = nil
|
|
for _, child in ipairs(state.pos.children) do
|
|
if child.data:get().id == cur_item.Name then
|
|
new_pos = child
|
|
break
|
|
end
|
|
end
|
|
|
|
if not new_pos then
|
|
new_pos = tree:new(cache:new(nil, function(self)
|
|
return api.async_request(self, cur_item.Name, l, jf, "/Items/", {
|
|
method = "GET",
|
|
paramaters = {
|
|
["parentId"] = cur_item.Id,
|
|
["sortBy"] = "SortName"
|
|
}
|
|
})
|
|
end))
|
|
state.pos:addchild(new_pos)
|
|
end
|
|
|
|
state.pos.data.data.selected = l.selected
|
|
state.pos = new_pos
|
|
l:set(api.items_to_list(state.pos.data:get().items))
|
|
l.selected = state.pos.data:get().selected
|
|
l:update()
|
|
state.navigating = false
|
|
end))
|
|
end)
|
|
l:addkey("h", "leave", function()
|
|
if state.navigating then
|
|
return
|
|
end
|
|
state.navigating = true
|
|
|
|
if not state.pos.parent then
|
|
state.navigating = false
|
|
return
|
|
end
|
|
|
|
state.pos.data.data.selected = l.selected
|
|
state.pos = state.pos.parent
|
|
|
|
coroutine.resume(coroutine.create(function()
|
|
l:set(api.items_to_list(state.pos.data:get().items))
|
|
l.selected = state.pos.data:get().selected
|
|
l:update()
|
|
state.navigating = false
|
|
end))
|
|
end)
|
|
l:addkey("esc", "close", function() l:close() end)
|
|
mp.add_key_binding("Ctrl+j", "open", function()
|
|
coroutine.resume(coroutine.create(function()
|
|
if not l.open then
|
|
if not jf:ping() then
|
|
print("hi")
|
|
end
|
|
l:update()
|
|
end
|
|
end))
|
|
end)
|