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 the currently selected node in the tree pos = nil, ---@type tree 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)