Floatplane channel plugin for Jellyfin 10.10.x: browse, HLS proxy, cookie session, CI release
Some checks failed
release / build-release (push) Has been cancelled

- IChannel: creators -> sub-channels -> video posts (public listing API, search mapped)
- IRequiresMediaInfoCallback -> signed proxy URLs; stream controller rewrites HLS so the
  AES-128 key is fetched server-side with the session cookie, segments stay on the CDN
- delivery/info cached per token lifetime and throttled (~2/min)
- config page: paste sails.sid + validate, extra creators, quality, search test
- scripts/package.sh -> plugin folder + zip + md5 + manifest.json; Gitea release workflow
- research docs, HAR analysis (HAR itself gitignored), install-pi5.sh

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-10-25 09:42:27 +01:00
commit 9e33a343ab
162 changed files with 52004 additions and 0 deletions

View File

@@ -0,0 +1,74 @@
function init()
m.category_list = m.top.findNode("category_list")
m.channel_list = m.top.findNode("channel_list")
m.chevron_right = m.top.findNode("chevron-right")
m.background = m.top.findNode("background")
m.category_list.setFocus(true)
m.top.observeField("visible", "onVisibleChange")
m.category_list.observeField("itemFocused", "onFocusChanged")
end function
sub onVisibleChange()
if m.top.visible = true then
m.category_list.setFocus(true)
end if
end sub
sub onFocusChanged()
if m.category_list.visible = true
index = m.category_list.itemFocused
if index <> -1
m.background.uri = m.category_list.content.getChild(index).HDPosterURL
m.highlighted = m.category_list.content.getChild(index)
getChannels(m.highlighted.creatorGUID)
end if
end if
end sub
sub getChannels(id)
m.subs_task = CreateObject("roSGNode", "urlTask")
apiConfigObj = ApiConfig()
url = apiConfigObj.buildApiUrl("/api/v3/creator/info?id=" + id)
m.subs_task.setField("url", url)
m.subs_task.observeField("response", "gotChannels")
m.subs_task.control = "RUN"
end sub
sub gotChannels(obj)
m.feed_task = createObject("roSGNode", "setupChannelsTask")
m.feed_task.setField("unparsed", obj.getData())
m.feed_task.observeField("category_node", "onChannelsSetup")
m.feed_task.control = "RUN"
end sub
sub onChannelsSetup(obj)
m.channel_list.content = obj.getData()
if obj.getData().getChildCount() < 2
m.channel_list.visible = false
m.chevron_right.visible = false
else
m.channel_list.visible = true
m.chevron_right.visible = true
m.channel_list.drawFocusFeedback = false
m.channel_list.opacity = 0.5
end if
end sub
function onKeyEvent(key as string, press as boolean) as boolean
if not press then return false
if key = "right" and m.category_list.hasFocus()
m.channel_list.drawFocusFeedback = true
m.channel_list.opacity = 1
m.channel_list.setFocus(true)
return true
else if key = "left" OR key = "back"
if m.channel_list.hasFocus()
m.channel_list.opacity = 1
m.category_list.setFocus(true)
return true
end if
end if
return false
end function