summaryrefslogtreecommitdiff
path: root/rt.lua
diff options
context:
space:
mode:
Diffstat (limited to 'rt.lua')
-rw-r--r--rt.lua349
1 files changed, 211 insertions, 138 deletions
diff --git a/rt.lua b/rt.lua
index 3cc2aa8..67d18a5 100644
--- a/rt.lua
+++ b/rt.lua
@@ -29,7 +29,148 @@ local function cache_miss_status_msg(str)
}
end
+local function series_children(series)
+ local info = ctx.xc:with_opts('get_series_info', series.series_id,
+ cache_miss_status_msg('Loading series info...'))
+ if not info or not info.seasons then
+ return {}
+ end
+
+ local seasons = {}
+ for _, season in pairs(info.seasons) do
+ local episodes = {}
+ local season_num = tostring(season.season_number)
+ if info.episodes and info.episodes[season_num] then
+ for i, episode in pairs(info.episodes[season_num]) do
+ local epinfo = episode.info or {}
+ local t = {
+ name = util.strip(episode.title),
+ type = 'stream',
+ stream_type = 'series',
+ id = series.section .. ':stream:' ..
+ episode.id,
+ stream_id = episode.id,
+ img_url = util.strip_ne(
+ epinfo.movie_image),
+ }
+ t.info_data = {
+ name = t.name,
+ cover = t.img_url,
+ description = epinfo.plot,
+ releasedate = epinfo.releasedate,
+ duration = epinfo.duration,
+ video = epinfo.video,
+ audio = epinfo.audio,
+ }
+ episodes[#episodes+1] = t
+ end
+ end
+
+ local count = tostring(#episodes)
+ local tmp = util.strip_ne(season.episode_count)
+ if tmp then
+ count = count .. '/' .. tmp
+ end
+ local t = {
+ type = 'group',
+ group_type = 'season',
+ id = series.id .. ':season:' .. season.id,
+ children = episodes,
+ name = util.strip(season.name),
+ info = count,
+ img_url = util.strip_ne(season.cover_big) or
+ util.strip_ne(season.cover),
+ }
+ t.info_data = {
+ name = t.name,
+ cover = t.img_url,
+ description = season.overview,
+ releasedate = season.air_date,
+ num_episodes = count,
+ }
+ seasons[#seasons+1] = t
+ end
+
+ return seasons
+end
+
+local function catalogue_add_section(sect, cats, elems)
+ ctx.catalogue:add({
+ section = sect.id,
+ type = 'group',
+ group_type = 'category',
+ id = sect.id .. ':category:0',
+ parent_id = 'root',
+ name = sect.name,
+ })
+
+ -- currently, this will not correctly handle subcategories which come
+ -- before their parent category
+ for _, v in ipairs(cats) do
+ ctx.catalogue:add({
+ section = sect.id,
+ type = 'group',
+ group_type = 'category',
+ id = sect.id .. ':category:' .. v.category_id,
+ parent_id = sect.id .. ':category:' .. v.parent_id,
+ name = util.strip(v.category_name),
+ })
+ end
+
+ for _, v in ipairs(elems) do
+ local vv = {
+ section = sect.id,
+ parent_id = sect.id .. ':category:' .. v.category_id,
+ name = util.strip(v.name),
+ }
+
+ if sect.type == 'series' then
+ vv.type = 'group'
+ vv.group_type = 'series'
+ vv.id = sect.id .. ':series:' .. v.series_id
+ vv.series_id = v.series_id
+ vv.img_url = util.strip_ne(v.cover)
+ vv.count = 1
+ vv.hide_count = true
+ vv.children_f = series_children
+ else
+ vv.type = 'stream'
+ vv.id = sect.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
+
+ ctx.catalogue:add(vv)
+ end
+end
+
function rt.load_data(force)
+ ctx.catalogue:add({
+ type = 'group',
+ id = 'favourites',
+ parent_id = 'root',
+ name = 'Favourites',
+ count_f = function()
+ return #state.favourites
+ end,
+ children_f = function()
+ local options = {}
+ for i, id in ipairs(state.favourites) do
+ -- missing favourites are displayed so that
+ -- they can be removed
+ options[i] = ctx.catalogue:get(id) or
+ {
+ id = id,
+ name = id,
+ missing = true,
+ }
+ end
+ return options
+ end,
+ })
+
local arr = {
{id = 'live', name = 'Live TV', type = 'live'},
{id = 'movie', name = 'Movies', type = 'vod'},
@@ -56,15 +197,15 @@ function rt.load_data(force)
end
end,
}
- for _, v in ipairs(arr) do
- sect_str = base_str .. ' » ' .. v.name
- v.categories = ctx.xc:with_opts(
- 'get_' .. v.type .. '_categories', call_opts)
- v.elements = ctx.xc:with_opts(
- v.type == 'series' and 'get_series' or
- ('get_' .. v.type .. '_streams'),
+ for _, sect in ipairs(arr) do
+ sect_str = base_str .. ' » ' .. sect.name
+ local cats = ctx.xc:with_opts(
+ 'get_' .. sect.type .. '_categories', call_opts)
+ local elems = ctx.xc:with_opts(
+ sect.type == 'series' and 'get_series' or
+ ('get_' .. sect.type .. '_streams'),
call_opts)
- ctx.catalogue:load_xc_section(v)
+ catalogue_add_section(sect, cats, elems)
end
osd:set_status('Loading EPG...')
@@ -257,140 +398,65 @@ local function add_programme(opt, time)
end
end
-local function group_count(group)
- if group.children and not group.lazy then
- local count = 0
- for _, v in ipairs(group.children) do
- if v.type == 'stream' or v.group_type == 'series' then
- count = count + 1
- elseif v.type == 'group' then
- local c = group_count(v)
- if c then
- count = count + c
- end
- end
- end
- return count
- elseif group.id == 'favourites' then
- -- not recursive
- return #state.favourites
- end
-end
+local menu_option_mt_count = 0
+local menu_option_mt = {
+ __index = function(t, k)
+ local v = t._v
-local function favourites_group_menu_options(group)
- local options = {}
- local time = os.time()
- for _, id in ipairs(state.favourites) do
- local obj = ctx.catalogue:get(id)
- if obj then
- obj = util.copy_table(obj)
- add_programme(obj, time)
- local c = group_count(obj)
- if c then
- obj.info = tostring(c)
- end
- local path = ctx.catalogue:path_from_root(obj)
- if path then
- obj.path = path
- end
- options[#options+1] = obj
- else
- -- display missing favourites so that they can be
- -- removed
- options[#options+1] = {
- id = id,
- name = id,
- missing = true,
- }
- end
- end
- return options
-end
+ if k == 'info' then
+ if v.type == 'group' and not v.hide_count then
+ local c = ctx.catalogue:group_count(v)
+ local ret = c and tostring(c) or ''
+ rawset(t, 'info', ret)
+ return ret
+ elseif v.epg_channel_id then
+ if t._info_exp and
+ osd.redraw_time <
+ t._info_exp then
+ return t._info
+ end
-local function series_group_menu_options(series)
- local info = ctx.xc:with_opts('get_series_info', series.series_id,
- cache_miss_status_msg('Loading series info...'))
- if not info or not info.seasons then
- return {}
- end
+ local prog = ctx.epg:scheduled_programme(
+ v.epg_channel_id,
+ osd.redraw_time)
+ local ret = prog and prog.title or ''
+ local exp = prog and prog.stop
+
+ if not prog then
+ prog = ctx.epg:next_programme(
+ v.epg_channel_id,
+ osd.redraw_time)
+ exp = prog and prog.start
+
+ if not prog then
+ rawset(t, 'info', ret)
+ return ret
+ end
+ end
- local seasons = {}
- for _, season in pairs(info.seasons) do
- local episodes = {}
- local season_num = tostring(season.season_number)
- if info.episodes and info.episodes[season_num] then
- for i, episode in pairs(info.episodes[season_num]) do
- local epinfo = episode.info or {}
- local t = {
- name = util.strip(episode.title),
- type = 'stream',
- stream_type = 'series',
- id = series.section .. ':stream:' ..
- episode.id,
- stream_id = episode.id,
- img_url = util.strip_ne(
- epinfo.movie_image),
- }
- t.info_data = {
- name = t.name,
- cover = t.img_url,
- description = epinfo.plot,
- releasedate = epinfo.releasedate,
- duration = epinfo.duration,
- video = epinfo.video,
- audio = epinfo.audio,
- }
- episodes[#episodes+1] = t
+ rawset(t, '_info_exp', exp)
+ rawset(t, '_info', ret)
+ return ret
end
end
- local count = tostring(#episodes)
- local tmp = util.strip_ne(season.episode_count)
- if tmp then
- count = count .. '/' .. tmp
- end
- local t = {
- type = 'group',
- group_type = 'season',
- id = series.id .. ':season:' .. season.id,
- children = episodes,
- name = util.strip(season.name),
- info = count,
- img_url = util.strip_ne(season.cover_big) or
- util.strip_ne(season.cover),
- }
- t.info_data = {
- name = t.name,
- cover = t.img_url,
- description = season.overview,
- releasedate = season.air_date,
- num_episodes = count,
- }
- seasons[#seasons+1] = t
- end
-
- return seasons
-end
+ return v[k]
+ end,
+}
local function group_menu_options(group)
- if group.id == 'favourites' then
- return favourites_group_menu_options(group)
- end
-
- if group.group_type == 'series' then
- return series_group_menu_options(group)
- end
-
local options = {}
- local time = os.time()
- for i, v in ipairs(group.children) do
- v = util.copy_table(v)
- add_programme(v, time)
- local c = group_count(v)
- if c then
- v.info = tostring(c)
+ for i, v in ipairs(ctx.catalogue:group_children(group)) do
+ local t = setmetatable({_v = v}, menu_option_mt)
+
+ if group.id == 'favourites' then
+ local path = ctx.catalogue:path_from_root(v)
+ if path then
+ t.path = path
+ end
end
- options[i] = v
+
+ options[i] = t
end
return options
end
@@ -784,12 +850,9 @@ function rt.open_option_info(opt)
end
local function search_menu_options_build(options, t, path)
- local menu = state:menu()
- local path = path or {}
-
for _, v in ipairs(options) do
- local v = util.copy_table(v)
v.path = path
+
if v.type == 'group' and v.group_type ~= 'series' then
t.categories[#t.categories+1] = v
else
@@ -797,7 +860,7 @@ local function search_menu_options_build(options, t, path)
end
-- contents of lazy-loaded groups should not be searchable
- if v.type == 'group' and not v.lazy then
+ if v.type == 'group' and v.children then
local path = util.copy_table(path)
path[#path+1] = v
search_menu_options_build(
@@ -808,7 +871,17 @@ end
local function search_menu_options(options)
local t = {categories = {}, elements = {}}
- search_menu_options_build(options, t)
+
+ local opts = {}
+ for i, v in ipairs(options) do
+ -- menu options may contain dynamic data that is updated on
+ -- redraw. using a proxy table instead of copying allows a
+ -- single update to target both the source and search menus.
+ opts[i] = setmetatable({}, {__index = v})
+ end
+
+ -- empty table is needed to shadow existing path from proxied table
+ search_menu_options_build(opts, t, {})
-- display categories first
local ret = t.categories