Files
jellies-and-jams/main.lua
Squibid b153a46b87 feat: rewrite the whole code
- 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!
2025-10-10 14:55:20 -04:00

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)