summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.lua1
-rw-r--r--osd.lua40
-rw-r--r--rt.lua121
-rw-r--r--rx.lua59
-rw-r--r--state.lua36
5 files changed, 168 insertions, 89 deletions
diff --git a/main.lua b/main.lua
index 1224ec2..67a195d 100644
--- a/main.lua
+++ b/main.lua
@@ -129,6 +129,7 @@ input.set_persistent_mapping({
input.define_mapping('MENU', {
['BS'] = {rt.prev_menu},
['/'] = {rt.start_search},
+ ['E'] = {rt.start_epg_search},
['Ctrl+s'] = {rt.toggle_menu_sort},
['Ctrl+r'] = {rt.reload_option},
['Ctrl+R'] = {rt.reload_data},
diff --git a/osd.lua b/osd.lua
index 2152863..0e06f22 100644
--- a/osd.lua
+++ b/osd.lua
@@ -155,44 +155,14 @@ function mt:menu_lines(state)
end
function mt:menu_title(menu)
- local str = asscape(menu.title)
+ local str, has_tags = menu:get_title()
+ str = asscape(str)
local col = menu.search_active and colour.selected or colour.title
- if menu.type == 'search' then
- local start = #menu.search_text - #menu.search_term
- local prefix = menu.search_text:sub(1, start)
- local term = menu.search_text:sub(start + 1)
-
- if str:find('<text>', 1, true) then
- str = str:gsub('<text>', function()
- return colour.search_prefix ..
- asscape(prefix) .. col .. asscape(term)
- end)
- end
-
- if str:find('<text_with_cursor>', 1, true) then
- local idx = menu.search_cursor
- if idx <= start then
- prefix = asscape(prefix:sub(1, idx - 1)) ..
- col .. cursor_glyph ..
- colour.search_prefix ..
- asscape(prefix:sub(idx))
- term = asscape(term)
- else
- idx = idx - start
- prefix = asscape(prefix)
- term = asscape(term:sub(1, idx - 1)) ..
- cursor_glyph .. asscape(term:sub(idx))
- end
- str = str:gsub('<text_with_cursor>', function()
- return colour.search_prefix .. prefix .. col ..
- term
- end)
- end
-
+ if has_tags then
+ str = str:gsub('<cursor>', cursor_glyph)
str = str:gsub('<colour%.(.-)>', colour)
- str = str:gsub('<num_matches>', #menu.options)
- str = str:gsub('<num_total>', #menu.search_options)
+ str = str:gsub('<reset_colour>', col)
end
if menu:is_sorted() then
diff --git a/rt.lua b/rt.lua
index 8ed3dc9..4a90e6e 100644
--- a/rt.lua
+++ b/rt.lua
@@ -482,49 +482,6 @@ function rt.favourite_option()
osd:dirty()
end
-function rt.goto_option()
- local menu = state:menu()
- local opt = menu.options[menu.cursor]
- if not opt or not opt.path then
- return
- end
-
- if menu.group_id == 'favourites' then
- state.depth = 1
- elseif menu.type == 'search' then
- state.depth = state.depth - 1
- if state:menu().group_id == 'favourites' then
- merge_refreshed_menu_options()
- end
- end
-
- for i = 1, #opt.path do
- cursor_to_id(opt.path[i].id)
- rt.push_group_menu(opt.path[i])
- end
- cursor_to_id(opt.id)
-
- osd:dirty()
-end
-
-function rt.goto_playing()
- local id = state.playing_id
- local obj = id and ctx.catalogue:get(id)
- local path = obj and ctx.catalogue:path_to_root(obj)
- if not path then
- return
- end
-
- state.depth = 1
- for i = #path, 1, -1 do
- cursor_to_id(path[i].id)
- rt.push_group_menu(path[i])
- end
- cursor_to_id(id)
-
- osd:dirty()
-end
-
local function open_option_programme_info(opt, img_url)
local prog = opt.programme
local options = rx.menu_options_programme_info(prog)
@@ -621,6 +578,53 @@ function rt.open_option_info(opt)
end
end
+function rt.goto_option()
+ local menu = state:menu()
+ local opt = menu.options[menu.cursor]
+ if not opt or not opt.path then
+ return
+ end
+
+ if menu.group_id == 'favourites' then
+ state.depth = 1
+ elseif menu.type == 'search' then
+ state.depth = state.depth - 1
+ if state:menu().group_id == 'favourites' then
+ merge_refreshed_menu_options()
+ end
+ end
+
+ for i = 1, #opt.path do
+ cursor_to_id(opt.path[i].id)
+ if i == #opt.path and opt.type == 'programme' then
+ open_option_channel_epg(opt.path[i])
+ else
+ rt.push_group_menu(opt.path[i])
+ end
+ end
+ cursor_to_id(opt.id)
+
+ osd:dirty()
+end
+
+function rt.goto_playing()
+ local id = state.playing_id
+ local obj = id and ctx.catalogue:get(id)
+ local path = obj and ctx.catalogue:path_to_root(obj)
+ if not path then
+ return
+ end
+
+ state.depth = 1
+ for i = #path, 1, -1 do
+ cursor_to_id(path[i].id)
+ rt.push_group_menu(path[i])
+ end
+ cursor_to_id(id)
+
+ osd:dirty()
+end
+
local F_NAME = {name = true}
local F_INFO = {info = true}
local F_BOTH = {name = true, info = true}
@@ -739,14 +743,12 @@ function rt.search_cursor_end()
search_cursor_move(function(str) return #str + 1 end)
end
-function rt.start_search()
+function rt.start_search(options, search_type, title)
local menu = state:menu()
- local title = 'Searching: <text_with_cursor>' ..
- ' <colour.info>(<num_matches>/<num_total>)'
-
- if menu.type == 'search' then
+ if menu.type == 'search' and
+ (not search_type or
+ menu.search_type == search_type) then
menu:save_checkpoint()
- menu.title = title
menu.search_active = true
menu:set_search_cursor(#menu.search_text + 1)
menu:set_cursor(1)
@@ -754,8 +756,10 @@ function rt.start_search()
state:push_menu({
title = title,
type = 'search',
- options = rx.menu_options_search(menu.options),
+ options = options or
+ rx.menu_options_search(menu.options),
search_active = true,
+ search_type = search_type,
})
end
@@ -763,11 +767,20 @@ function rt.start_search()
input.set_mapping('SEARCH')
end
-function rt.end_search()
+function rt.start_epg_search()
local menu = state:menu()
- menu.search_active = false
- menu.title = 'Search results: <text>' ..
- ' <colour.info>(<num_matches>/<num_total>)'
+ local options = menu.search_type ~= 'epg' and
+ rx.menu_options_epg_search(menu.options) or nil
+ if options and not next(options) then
+ osd:flash_error('No EPG data found')
+ return
+ end
+
+ rt.start_search(options, 'epg', 'EPG')
+end
+
+function rt.end_search()
+ state:menu().search_active = false
osd:dirty()
input.set_mapping('MENU')
end
diff --git a/rx.lua b/rx.lua
index d96420f..0c85029 100644
--- a/rx.lua
+++ b/rx.lua
@@ -281,6 +281,7 @@ function rx.menu_options_channel_epg(src_id, ch)
local time = os.time()
for i, v in ipairs(progs) do
local prog = {
+ id = ch .. ':' .. i,
name = os.date('%a %d %b %H:%M', v.start) .. ' ' ..
os.date('%H:%M', v.stop) .. ' ' .. v.title,
type = 'programme',
@@ -315,6 +316,64 @@ function rx.menu_options_programme_info(prog)
return options
end
+local function menu_options_epg_search_build_progs(options, opt, path, time)
+ local ch = opt.epg_channel_id
+ local progs = ctx.src[opt.src_id].epg:channel_programmes(ch)
+ if not progs then
+ return
+ end
+
+ for i, v in ipairs(progs) do
+ if time < v.stop then
+ options[#options+1] = setmetatable({
+ id = ch .. ':' .. i,
+ name = os.date('%a %d %b %H:%M', v.start) ..
+ ' ' .. os.date('%H:%M', v.stop) ..
+ ' ' .. v.title,
+ type = 'programme',
+ programme = v,
+ path = path,
+ }, programme_mt)
+ end
+ end
+end
+
+local function menu_options_epg_search_build(options, opts, path, seen, time)
+ for _, v in ipairs(opts) do
+ if v.id and not seen[v.id] then
+ seen[v.id] = true
+ path[#path+1] = v
+ if v.epg_channel_id then
+ menu_options_epg_search_build_progs(
+ options, v, util.copy_table(path),
+ time)
+ elseif v.type == 'group' and v.children then
+ menu_options_epg_search_build(
+ options, v.children, path, seen, time)
+ end
+ path[#path] = nil
+ end
+ end
+end
+
+function rx.menu_options_epg_search(opts)
+ local options = {}
+ local time = os.time()
+
+ menu_options_epg_search_build(options, opts, {}, {}, time)
+ table.sort(options, function(a, b)
+ if a.programme.start ~= b.programme.start then
+ return a.programme.start < b.programme.start
+ end
+ if a.programme.title ~= b.programme.title then
+ return a.programme.title < b.programme.title
+ end
+ return a.path[#a.path].name < b.path[#b.path].name
+ end)
+
+ return options
+end
+
local function menu_options_search_build(options, t, path)
for _, v in ipairs(options) do
v.path = path
diff --git a/state.lua b/state.lua
index 4db4837..4d97fe3 100644
--- a/state.lua
+++ b/state.lua
@@ -195,6 +195,42 @@ function menu_mt:set_options(options)
self:set_cursor(1)
end
+function menu_mt:get_title()
+ if self.type == 'search' then
+ local str = self.search_active and 'Searching: ' or
+ 'Search results: '
+ if self.title then
+ str = '(' .. self.title .. ') ' .. str
+ end
+
+ local start = #self.search_text - #self.search_term
+ local prefix = self.search_text:sub(1, start)
+ local term = self.search_text:sub(start + 1)
+ if self.search_active then
+ local idx = self.search_cursor
+ if idx <= start then
+ prefix = prefix:sub(1, idx - 1) ..
+ '<reset_colour><cursor>' ..
+ '<colour.search_prefix>' ..
+ prefix:sub(idx)
+ else
+ idx = idx - start
+ term = term:sub(1, idx - 1) .. '<cursor>' ..
+ term:sub(idx)
+ end
+ end
+ str = str .. '<colour.search_prefix>' .. prefix ..
+ '<reset_colour>' .. term
+
+ str = str .. ' <colour.info>(' .. #self.options .. '/' ..
+ #self.search_options .. ')'
+
+ return str, true
+ end
+
+ return self.title
+end
+
function menu_mt:set_search_cursor(pos)
local pos = math.max(1, math.min(#self.search_text + 1, pos))
if pos == self.search_cursor then