summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--catalogue.lua119
-rw-r--r--main.lua138
2 files changed, 147 insertions, 110 deletions
diff --git a/catalogue.lua b/catalogue.lua
new file mode 100644
index 0000000..eecd73b
--- /dev/null
+++ b/catalogue.lua
@@ -0,0 +1,119 @@
+-- Copyright 2025 David Vazgenovich Shakaryan
+
+local util = require('util')
+
+local catalogue = {}
+local mt = {}
+mt.__index = mt
+
+function catalogue.new()
+ o = setmetatable({data = {}}, mt)
+
+ o:add({
+ type = 'group',
+ id = 'root',
+ })
+ o:add({
+ type = 'group',
+ id = 'favourites',
+ parent_id = 'root',
+ name = 'Favourites',
+ lazy = true, -- prevent infinite recursion on search
+ })
+
+ return o
+end
+
+function mt:get(id)
+ return self.data[id]
+end
+
+function mt:add(entry)
+ self.data[entry.id] = entry
+
+ if entry.type == 'group' then
+ entry.children = {}
+ end
+
+ if not entry.parent_id then
+ return
+ end
+
+ -- dump any entries referencing nonexistent categories into a single
+ -- catchall category
+ if not self.data[entry.parent_id] then
+ entry.parent_id = entry.section .. ':category:catchall'
+ if not self.data[entry.parent_id] then
+ self:add({
+ section = entry.section,
+ type = 'group',
+ group_type = 'category',
+ id = entry.parent_id,
+ parent_id = entry.section .. ':category:0',
+ -- non-ascii symbol to sort near end
+ name = '🞷CATCHALL🞷',
+ })
+ end
+ end
+
+ local parent_children = self.data[entry.parent_id].children
+ parent_children[#parent_children+1] = entry
+end
+
+function mt:load_xc_section(section)
+ self:add({
+ section = section.id,
+ type = 'group',
+ group_type = 'category',
+ id = section.id .. ':category:0',
+ parent_id = 'root',
+ name = section.name,
+ })
+
+ -- currently, this will not correctly handle subcategories which come
+ -- before their parent category
+ for _, v in ipairs(section.categories) do
+ self:add({
+ section = section.id,
+ type = 'group',
+ group_type = 'category',
+ id = section.id .. ':category:' .. v.category_id,
+ parent_id = section.id .. ':category:' .. v.parent_id,
+ name = util.strip(v.category_name),
+ })
+ end
+
+ for _, v in ipairs(section.elements) do
+ local vv = {
+ section = section.id,
+ parent_id = section.id .. ':category:' .. v.category_id,
+ name = util.strip(v.name),
+ }
+
+ if section.type == 'series' then
+ vv.type = 'group'
+ vv.group_type = 'series'
+ vv.id = section.id .. ':series:' .. v.series_id
+ vv.series_id = v.series_id
+ vv.image = v.cover
+ vv.lazy = true -- avoid API calls on search
+ else
+ vv.type = 'stream'
+ vv.id = section.id .. ':stream:' .. v.stream_id
+ vv.stream_type = v.stream_type
+ vv.stream_id = v.stream_id
+ vv.image = v.stream_icon
+ vv.epg_channel_id = v.epg_channel_id
+ end
+
+ self:add(vv)
+ end
+end
+
+function mt:load_xc_data(sections)
+ for _, v in ipairs(sections) do
+ self:load_xc_section(v)
+ end
+end
+
+return catalogue
diff --git a/main.lua b/main.lua
index 4805c10..f80e35f 100644
--- a/main.lua
+++ b/main.lua
@@ -1,6 +1,7 @@
-- Copyright 2025 David Vazgenovich Shakaryan
local util = require('util')
+local _catalogue = require('catalogue')
local _downloader = require('downloader')
local _epg = require('epg')
local _xc = require('xc')
@@ -53,7 +54,7 @@ osd_bg.data = '{\\pos(0,0)}' .. colours.bg ..
'{\\p1}m 0 0 l 7680 0 7680 720 0 720{\\p0}'
local osd_img
-local objects = {}
+local catalogue = _catalogue.new()
local epg = _epg.new()
local favourites
local playing_id
@@ -83,38 +84,6 @@ local function get_image_path(url, dl)
end
end
-local function add_object(obj)
- objects[obj.id] = obj
-
- if obj.type == 'group' then
- obj.children = {}
- end
-
- if not obj.parent_id then
- return
- end
-
- -- dump any objects referencing nonexistent categories into a single
- -- catchall category
- if not objects[obj.parent_id] then
- obj.parent_id = obj.section .. ':category:catchall'
- if not objects[obj.parent_id] then
- add_object({
- section = obj.section,
- type = 'group',
- group_type = 'category',
- id = obj.parent_id,
- parent_id = obj.section .. ':category:0',
- -- non-ascii symbol to sort near end
- name = '🞷CATCHALL🞷',
- })
- end
- end
-
- local parent_children = objects[obj.parent_id].children
- parent_children[#parent_children+1] = obj
-end
-
local function cached_xc_call(method, ...)
local id = xc.server:gsub('%W', '_') .. '.' .. method
if select('#', ...) ~= 0 then
@@ -140,73 +109,20 @@ local function cached_xc_call(method, ...)
return data
end
-local function load_section(section, name, section_type)
- add_object({
- section = section,
- type = 'group',
- group_type = 'category',
- id = section .. ':category:0',
- parent_id = 'root',
- name = name,
- })
-
- local tmp = cached_xc_call('get_' .. section_type .. '_categories')
- for _, v in ipairs(tmp) do
- add_object({
- section = section,
- type = 'group',
- group_type = 'category',
- id = section .. ':category:' .. v.category_id,
- parent_id = section .. ':category:' .. v.parent_id,
- name = util.strip(v.category_name),
- })
- end
-
- tmp = cached_xc_call(
- section_type == 'series' and 'get_series' or
- ('get_' .. section_type .. '_streams'))
- for _, v in ipairs(tmp) do
- local vv = {
- section = section,
- parent_id = section .. ':category:' .. v.category_id,
- name = util.strip(v.name),
- }
-
- if section_type == 'series' then
- vv.type = 'group'
- vv.group_type = 'series'
- vv.id = section .. ':series:' .. v.series_id
- vv.series_id = v.series_id
- vv.stream_icon = v.cover
- vv.lazy = true
- else
- vv.type = 'stream'
- vv.id = section .. ':stream:' .. v.stream_id
- vv.stream_type = v.stream_type
- vv.stream_id = v.stream_id
- vv.stream_icon = v.stream_icon
- vv.epg_channel_id = v.epg_channel_id
- end
- add_object(vv)
- end
-end
-
local function load_data()
- add_object({
- type = 'group',
- id = 'root',
- })
- add_object({
- type = 'group',
- id = 'favourites',
- parent_id = 'root',
- name = 'Favourites',
- lazy = true,
- })
+ local arr = {
+ {id = 'live', name = 'Live TV', type = 'live'},
+ {id = 'movie', name = 'Movies', type = 'vod'},
+ {id = 'series', name = 'Series', type = 'series'},
+ }
+ for _, v in ipairs(arr) do
+ v.categories = cached_xc_call('get_' .. v.type .. '_categories')
+ v.elements = cached_xc_call(
+ v.type == 'series' and 'get_series' or
+ ('get_' .. v.type .. '_streams'))
+ end
+ catalogue:load_xc_data(arr)
- load_section('live', 'Live TV', 'live')
- load_section('movie', 'Movies', 'vod')
- load_section('series', 'Series', 'series')
epg:load_xc_data(cached_xc_call('get_epg'))
favourites = util.read_json_file(
@@ -443,8 +359,8 @@ function update_osd()
osd_option_text(opt, info) ..
osd_option_path(opt, info)
- if selected and opt.stream_icon and opt.stream_icon ~= '' then
- img = get_image_path(opt.stream_icon, true)
+ if selected and opt.image and opt.image ~= '' then
+ img = get_image_path(opt.image, true)
end
end
@@ -623,13 +539,13 @@ local function favourites_group_menu_options(group)
local options = {}
local time = os.time()
for id in pairs(favourites) do
- local obj = objects[id]
+ local obj = catalogue:get(id)
if obj then
local path = {}
local curr = obj
while curr.parent_id and curr.parent_id ~= 'root' and
- objects[curr.parent_id] do
- curr = objects[curr.parent_id]
+ catalogue:get(curr.parent_id) do
+ curr = catalogue:get(curr.parent_id)
path[#path+1] = curr
end
@@ -686,7 +602,7 @@ local function series_group_menu_options(series)
seasons[#seasons+1] = {
type = 'group',
group_type = 'season',
- id = series.section .. 'series:season:' .. season.id,
+ id = series.id .. ':season:' .. season.id,
children = episodes,
name = util.strip(season.name),
info = count,
@@ -734,7 +650,7 @@ local function prev_menu()
if depth == 0 then
-- reset main menu
- push_group_menu(objects[menus[1].group_id])
+ push_group_menu(catalogue:get(menus[1].group_id))
else
update_osd()
end
@@ -743,7 +659,9 @@ end
local function play_stream(stream)
local url = stream.stream_url or
xc:stream_url(stream.stream_type, stream.stream_id)
- if not url then return end
+ if not url then
+ return
+ end
-- add a per-file option containing the stream id, allowing it to be
-- retrieved when a start-file event is received
@@ -810,7 +728,7 @@ local function goto_playing()
return
end
- local obj = objects[playing_id]
+ local obj = catalogue:get(playing_id)
if not obj then
return
end
@@ -818,8 +736,8 @@ local function goto_playing()
local path = {}
local curr = obj
while curr.parent_id and curr.parent_id ~= 'root' and
- objects[curr.parent_id] do
- curr = objects[curr.parent_id]
+ catalogue:get(curr.parent_id) do
+ curr = catalogue:get(curr.parent_id)
path[#path+1] = curr
end
if #path == 0 or curr.parent_id ~= 'root' then
@@ -1341,7 +1259,7 @@ mp.register_event('end-file', function()
end)
load_data()
-push_group_menu(objects['root'])
+push_group_menu(catalogue:get('root'))
-- keys added via bind_key() are unbound when the OSD is closed, but we want
-- toggle-menu to work regardless of setting.