1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
-- Copyright 2025 David Vazgenovich Shakaryan
local util = require('util')
local catalogue = {}
local mt = {}
mt.__index = mt
function catalogue.new()
local t = setmetatable({data = {}}, mt)
t:add({
type = 'group',
id = 'root',
name = '/',
})
t:add({
type = 'group',
id = 'favourites',
parent_id = 'root',
name = 'Favourites',
lazy = true, -- prevent infinite recursion on search
})
return t
end
function mt:get(id)
return self.data[id]
end
function mt:_ensure_catchall(section_id)
local id = section_id .. ':category:catchall'
local entry = self.data[id]
if entry then
return entry
end
return self:add({
section = section_id,
type = 'group',
group_type = 'category',
id = id,
parent_id = section_id .. ':category:0',
-- non-ascii symbol to sort near end
name = '∗CATCHALL∗',
})
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 entry
end
local parent = self.data[entry.parent_id]
-- dump any entries referencing nonexistent categories into a single
-- catchall category
if not parent then
parent = self:_ensure_catchall(entry.section)
entry.parent_id = parent.id
end
if parent.id == entry.id then
entry.parent_id = nil
else
parent.children[#parent.children+1] = entry
end
return 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.img_url = util.strip_ne(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.img_url = util.strip_ne(v.stream_icon)
vv.epg_channel_id = util.strip_ne(v.epg_channel_id)
end
self:add(vv)
end
end
function mt:path_to_root(entry)
local path = {}
local curr = entry
while curr.parent_id and curr.parent_id ~= 'root' do
curr = self:get(curr.parent_id)
if not curr then
return
end
path[#path+1] = curr
end
if curr.parent_id ~= 'root' then
return
end
return path
end
function mt:path_from_root(entry)
local path = self:path_to_root(entry)
if path then
util.reverse(path)
end
return path
end
return catalogue
|