Merge pull request #408 from ProfYaffle/durationfilter
Concept of filtering EPG on duration
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 21 KiB |
BIN
docs/docresources/dvrlog2.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
docs/docresources/dvrlog3.png
Normal file
After Width: | Height: | Size: 27 KiB |
BIN
docs/docresources/dvrlog4.png
Normal file
After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 123 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 14 KiB |
BIN
docs/docresources/epg3.png
Normal file
After Width: | Height: | Size: 18 KiB |
|
@ -1,5 +1,5 @@
|
|||
<div class="hts-doc-text">
|
||||
The 'Automatic Recorder' is used to create rules that will trig
|
||||
The 'Automatic Recorder' is used to create rules that will trigger
|
||||
automatic recording of events. You can use this to record you favorite
|
||||
TV show(s), record all movies on a specific channel, etc.
|
||||
<p>
|
||||
|
@ -62,6 +62,10 @@ The columns have the following functions:
|
|||
<dd>
|
||||
Only match events belonging to the given content group.
|
||||
|
||||
<dt>Duration
|
||||
<dd>
|
||||
Only match events that fall within the specified duration range.
|
||||
|
||||
<dt>Weekdays
|
||||
<dd>
|
||||
Only record events if they occur on one of these days. By default all days
|
||||
|
|
|
@ -1,27 +1,45 @@
|
|||
<div class="hts-doc-text">
|
||||
The DVR log is split into a series of paged grids:
|
||||
|
||||
<p></p>
|
||||
|
||||
<ul>
|
||||
<li>Upcoming Recordings - stuff scheduled to be recorded in the future
|
||||
<li>Finished Recordings - stuff that has succesfully finished recording
|
||||
<li>Failed Recordings - stuff that failed to record
|
||||
</ul>
|
||||
<li><b>Upcoming Recordings</b> - events that are scheduled to be recorded in the future</li>
|
||||
|
||||
<img src="docresources/dvrlog.png">
|
||||
|
||||
<li><b>Finished Recordings</b> - events that have succesfully finished recording</li>
|
||||
|
||||
<img src="docresources/dvrlog2.png">
|
||||
|
||||
<p>
|
||||
Use the bottom toolbar (not displayed in this manual) to navigate
|
||||
between pages in the grid.
|
||||
<img src="docresources/dvrlog.png">
|
||||
Once the recording is completed there will be a clickable link to a playlist
|
||||
for the recorded file (XSPF or M3U as per your startup options) so you can watch
|
||||
it.</p>
|
||||
|
||||
|
||||
<li><b>Failed Recordings</b> - events that failed to record</li>
|
||||
|
||||
<img src="docresources/dvrlog3.png">
|
||||
</ul>
|
||||
|
||||
|
||||
<p>
|
||||
Use the bottom toolbar to navigate between pages in the grid.</p>
|
||||
|
||||
<img src="docresources/dvrlog4.png">
|
||||
|
||||
<p>Note that the columns are sortable, but only the current view will be sorted (by
|
||||
default, this will be the first page of the most recent events). Select more events
|
||||
per page if you want to sort a longer selection.</p>
|
||||
<p>
|
||||
To see more details about a recorded event, just click on it and a pop
|
||||
up will appear:
|
||||
<p>
|
||||
up will appear:</p>
|
||||
<p></p>
|
||||
<img src="docresources/dvrlogentry.png">
|
||||
<p></p>
|
||||
<p>
|
||||
In this pop up you can cancel a scheduled recording or abort a
|
||||
recording in progress. To close the pop up, just close it with the
|
||||
[X] window button.
|
||||
<p>
|
||||
Once the recording is completed there will be a clickable link to the
|
||||
recorded matroska file so you can download it directly from the
|
||||
interface.
|
||||
[X] window button.</p>
|
||||
</div>
|
||||
|
|
|
@ -1,95 +1,130 @@
|
|||
<div class="hts-doc-text">
|
||||
Tvheadend has a built in Electronic Program Guide. The EPG is an in memory
|
||||
<p>Tvheadend has a built-in Electronic Program Guide. The EPG is an in-memory
|
||||
database populated with all the information about events received from
|
||||
the DVB networks or from XMLTV.
|
||||
<p>
|
||||
The EPG tab displays a filterable paged grid containing all the events
|
||||
sorted based on start time.
|
||||
the DVB networks over-the-air or from external grabbers such as XMLTV.</p>
|
||||
<p></p>
|
||||
<p>The EPG tab displays a filterable grid containing all events,
|
||||
sorted based on start time.</p>
|
||||
<img src="docresources/epg.png">
|
||||
<p>
|
||||
<dl>
|
||||
<dt>Filtering (or searching)
|
||||
<dd>
|
||||
In the EPG top tool bar you can access four input fields.
|
||||
<p></p>
|
||||
<hr>
|
||||
<b>Filtering (or searching)</b>
|
||||
<hr>
|
||||
<p>In the EPG top tool bar you can access five input fields.
|
||||
These are used to filter/search for events. The form uses implicit AND
|
||||
between the input fields. This means that all filters must match
|
||||
for an event to be displayed.
|
||||
for an event to be displayed.</p>
|
||||
<dl>
|
||||
<dt>[Search title...]
|
||||
<dd>
|
||||
Filter on the event title. The filter uses case insensitive regular
|
||||
expression. If you don't know what a regular expression is this means
|
||||
that you can type just parts of the title and filter on that too.
|
||||
(No need for exact matching).
|
||||
<dt>[Filter channel...]
|
||||
Only display events that match the given title. The filter uses case-insensitive
|
||||
regular expressions. If you don't know what a regular expression is, this simply
|
||||
means that you can type just parts of the title and filter on that - there's no need
|
||||
for full, exact matching.</dd>
|
||||
<dt>[Filter channel...]</dt>
|
||||
<dd>
|
||||
Only display events from the selected channel. Channels in the drop down are
|
||||
ordered by channel number and can be filtered (by name) by typing in the box.
|
||||
<dt>[Filter tag...]
|
||||
ordered by channel number and can be filtered (by name) by typing in the box.</dd>
|
||||
<dt>[Filter tag...]</dt>
|
||||
<dd>
|
||||
Only display events from the channels which are included in the selected tag.
|
||||
Tags are used for grouping channels and is configured by the administrator.
|
||||
<dt>[Filter content type...]
|
||||
Only display events from channels which are included in the selected tag.
|
||||
Tags are used for grouping channels together - such as 'Radio' or 'HDTV' - and are
|
||||
configured by the administrator. You can start typing a tag name to filter the list.</dd>
|
||||
<dt>[Filter content type...]</dt>
|
||||
<dd>
|
||||
Most DVB networks classify their events into content groups. This field
|
||||
allows you to filter based on content type.
|
||||
Only display events that match the given content type tag. Most DVB networks
|
||||
classify their events into content groups. This field allows you to filter based
|
||||
on content type (e.g. "Sports" or "Game Show"). Supported tags are determined by
|
||||
your broadcaster. Again, simply start typing to filter the entries if you have a
|
||||
long list to choose from.</dd>
|
||||
<dt>[Filter duration...]</dt>
|
||||
<dd>
|
||||
Only display events that fall between the given minimum and maximum durations.
|
||||
This allows you to filter for or against, say, a daily broadcast and a weekly omnibus
|
||||
edition of a programme, or only look for short news bulletins and not the 24-hour
|
||||
rolling broadcasts.</dd>
|
||||
<dd> </dd>
|
||||
<dd>Options are:</dd>
|
||||
|
||||
<table class="hts-doc-text" border="0">
|
||||
<tr><td>00:00:01 to 00:15:00 - for very short news bulletins, children's programmes, etc.</td></tr>
|
||||
<tr><td>00:15:01 to 00:30:00 - for short programmes, e.g. daily soap operas</td></tr>
|
||||
<tr><td>00:30:01 to 01:30:00 - for medium-length programmes, e.g. documentaries</td></tr>
|
||||
<tr><td>01:30:01 to 03:00:00 - for longer programmes, e.g. films</td></tr>
|
||||
<tr><td>03:00:00 to no maximum - for very long programmes, e.g. major sporting events</td></tr>
|
||||
</table>
|
||||
|
||||
</dl>
|
||||
Thus, if you only would like to browse Movies from your HD-channels you
|
||||
would select 'HDTV' in the [Filter tag...]-field, and select
|
||||
'Movie / Drama' in the [Only include content...]-field.
|
||||
<p>
|
||||
Notice that you don't have to press a 'Search' button, the grid immediately
|
||||
updates itself as you change the filters.
|
||||
<p>
|
||||
If you would like to clear all filters, just press the [Reset] button.
|
||||
|
||||
<dt>Paging
|
||||
<p>So, if you only want to see Movies from your available HD channels, you
|
||||
would select 'HDTV' in the <i>[Filter tag...]</i> field, and select
|
||||
'Movie / Drama' in the <i>[Filter content type...]</i> field. If you wish, you
|
||||
could then further limit the search to programmes of between 90 minutes and 3 hours by
|
||||
selecting '01:30:01 to 03:00:00' in the <i>[Filter duration...]</i> field.</p>
|
||||
<p></p>
|
||||
<p>Note that you don't have to press a 'Search' button: the grid immediately
|
||||
updates itself as you change the filters.</p>
|
||||
<p></p>
|
||||
<p>You can clear an individual filter by simply deleting its contents, or by selecting
|
||||
<i>'(Clear filter)'</i> as appropriate on all except the title filter. If you want to
|
||||
clear all filters, just press the <i>[Reset All]</i> button.</p>
|
||||
<br> </br>
|
||||
|
||||
<dd>
|
||||
In large installations with many channels and full EPG feed there could be
|
||||
tens of thousands of events in the database.
|
||||
Therefore the EPG display employs a paging bar at the bottom of the grid.
|
||||
Use it to browse backwards and forwards in the EPG. It also displays the
|
||||
total amount of events matched by the current query.
|
||||
<hr>
|
||||
<b>Event details and recording</b>
|
||||
<hr>
|
||||
|
||||
<dt>Event details and recording
|
||||
<dd>
|
||||
If you click on a single event, a popup will display detailed information
|
||||
about the event. It also allows the user to schedule the event for recording
|
||||
by clicking on the [Record program] button.
|
||||
<p>If you click on a single event, a popup will display detailed information
|
||||
about the event. It also allows you to schedule the event for recording
|
||||
by clicking on the <i>[Record program]</i> button.</p>
|
||||
<p>
|
||||
For EPG providers that supply series link information there will also be a
|
||||
[Record series] button that will record all entries in the series.
|
||||
<i>[Record series]</i> button that will record all entries in the series.</p>
|
||||
<p>
|
||||
For events without any series link information, a [Autorec] button will be
|
||||
provided to create a pseudo series link using the Autorec feature.
|
||||
<p>
|
||||
<img src="docresources/epg2.png">
|
||||
<p>
|
||||
To close the popup, just close it with the [X] window button.
|
||||
The popup is not modal and you can open as many detailed information popups
|
||||
as you want.
|
||||
For events without any series link information, an <i>[Autorec]</i> button will be
|
||||
provided to create a pseudo-series link using the autorec feature.</p>
|
||||
<p></p>
|
||||
<img src="docresources/epg2.png"> <img src="docresources/epg3.png">
|
||||
<p></p>
|
||||
<p>If you schedule any kind of recording from this point, you can choose a specific
|
||||
DVR profile that will apply to the recording or autorec rule. This will normally show
|
||||
as <i>(default)</i>, but you can define different profiles in the <b>Configuration ->
|
||||
Recording -> Digital Video Recorder</b> tab. This allows you to set, for example, more post-
|
||||
broadcast padding for a channel that always runs late, or perhaps define a different
|
||||
post-processing command to strip adverts out on a commercial channel.</p>
|
||||
<p>You will also see a <i>Search IMDB</i> link to look for the programme by name on
|
||||
imdb.com, and a <i>Play</i> link to watch a programme that's already in progress. This
|
||||
second link downloads a playlist file (XSPF or M3U depending on your startup options);
|
||||
if your system is configured for it, this will automatically launch an appropriate
|
||||
player, otherwise you will need to manually open the playlist to start watching (normally a
|
||||
double-click on the downloaded file).</p>
|
||||
<p></p>
|
||||
<p>To close the popup, just click on the [X] window button.
|
||||
The popup isn't modal, so you don't have to close it before doing something else,
|
||||
and you can open as many detailed information popups as you want.</p>
|
||||
<br> </br>
|
||||
|
||||
|
||||
<dt>Autorecordings
|
||||
<dd>
|
||||
Should you wish to record all events matching a specific query. (Record
|
||||
your favorite TV-show, etc) you can press the [Create Autorec] button
|
||||
in the top toolbar.
|
||||
<p>
|
||||
A popup with details about the to-be-created autorecording rule needs to
|
||||
be confirmed before the rule takes effect.
|
||||
<p>
|
||||
<hr>
|
||||
<b>Autorecordings</b>
|
||||
<hr>
|
||||
<p>Should you wish to record all events matching a specific query (to record
|
||||
your favourite show every week, for example) you can press the <i>[Create AutoRec]</i>
|
||||
button in the top toolbar.</p>
|
||||
<p></p>
|
||||
<p>A popup with details about the to-be-created autorecording rule needs to
|
||||
be confirmed before the rule takes effect.</p>
|
||||
<p></p>
|
||||
<img src="docresources/autorecpopup.png">
|
||||
<p>
|
||||
The autorecordings can later be changed/deleted in under the
|
||||
'Digital Video Recorder'-tag. Use that editor if you temporary want
|
||||
to disable an autorecording or make adjustments, etc.
|
||||
<p></p>
|
||||
<p>You can change or delete the autorec rules in the
|
||||
<b>Digital Video Recorder</b> tab. Use that editor if you temporarily want
|
||||
to disable an autorecording or make adjustments to the channel, tag, or similar.</p>
|
||||
<br> </br>
|
||||
|
||||
<dt>Watch TV
|
||||
<dd>
|
||||
If you want to watch live TV in the web UI, the [Watch TV] button will pop-up
|
||||
<hr>
|
||||
<b>Watch TV</b>
|
||||
<hr>
|
||||
<p>If you want to watch live TV in the web UI, the <i>[Watch TV]</i> button will pop up
|
||||
a VLC plugin window (if you don't have the plugin installed a direct URL should be
|
||||
provided to load into your preferred media player).
|
||||
</dl>
|
||||
provided to load into your preferred media player).</p>
|
||||
</div>
|
||||
|
|
|
@ -130,6 +130,8 @@ api_epg_grid
|
|||
const char *ch, *tag, *title, *lang/*, *genre*/;
|
||||
uint32_t start, limit, end;
|
||||
htsmsg_t *l = NULL, *e;
|
||||
int min_duration;
|
||||
int max_duration;
|
||||
|
||||
*resp = htsmsg_create_map();
|
||||
|
||||
|
@ -141,13 +143,16 @@ api_epg_grid
|
|||
lang = htsmsg_get_str(args, "lang");
|
||||
// TODO: support multiple tag/genre/channel?
|
||||
|
||||
min_duration = htsmsg_get_u32_or_default(args, "minduration", 0);
|
||||
max_duration = htsmsg_get_u32_or_default(args, "maxduration", INT_MAX);
|
||||
|
||||
/* Pagination settings */
|
||||
start = htsmsg_get_u32_or_default(args, "start", 0);
|
||||
limit = htsmsg_get_u32_or_default(args, "limit", 50);
|
||||
|
||||
/* Query the EPG */
|
||||
pthread_mutex_lock(&global_lock);
|
||||
epg_query(&eqr, ch, tag, NULL, /*genre,*/ title, lang);
|
||||
epg_query(&eqr, ch, tag, NULL, /*genre,*/ title, lang, min_duration, max_duration);
|
||||
epg_query_sort(&eqr);
|
||||
// TODO: optional sorting
|
||||
|
||||
|
|
|
@ -247,6 +247,8 @@ typedef struct dvr_autorec_entry {
|
|||
epg_serieslink_t *dae_serieslink;
|
||||
epg_episode_num_t dae_epnum;
|
||||
|
||||
int dae_minduration;
|
||||
int dae_maxduration;
|
||||
} dvr_autorec_entry_t;
|
||||
|
||||
|
||||
|
@ -386,12 +388,13 @@ int dvr_sort_start_ascending(const void *A, const void *B);
|
|||
*/
|
||||
void dvr_autorec_add(const char *dvr_config_name,
|
||||
const char *title, const char *channel,
|
||||
const char *tag, epg_genre_t *content_type,
|
||||
const char *creator, const char *comment);
|
||||
const char *tag, epg_genre_t *content_type,
|
||||
const int min_duration, const int max_duration,
|
||||
const char *creator, const char *comment);
|
||||
|
||||
void dvr_autorec_add_series_link(const char *dvr_config_name,
|
||||
epg_broadcast_t *event,
|
||||
const char *creator, const char *comment);
|
||||
const char *creator, const char *comment);
|
||||
|
||||
void dvr_autorec_check_event(epg_broadcast_t *e);
|
||||
void dvr_autorec_check_brand(epg_brand_t *b);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "settings.h"
|
||||
|
@ -70,6 +71,7 @@ autorec_cmp(dvr_autorec_entry_t *dae, epg_broadcast_t *e)
|
|||
{
|
||||
channel_tag_mapping_t *ctm;
|
||||
dvr_config_t *cfg;
|
||||
double duration;
|
||||
|
||||
if (!e->channel) return 0;
|
||||
if (!e->episode) return 0;
|
||||
|
@ -83,6 +85,8 @@ autorec_cmp(dvr_autorec_entry_t *dae, epg_broadcast_t *e)
|
|||
dae->dae_title[0] == '\0') &&
|
||||
dae->dae_brand == NULL &&
|
||||
dae->dae_season == NULL &&
|
||||
&dae->dae_minduration == NULL &&
|
||||
&dae->dae_maxduration == NULL &&
|
||||
dae->dae_serieslink == NULL)
|
||||
return 0; // Avoid super wildcard match
|
||||
|
||||
|
@ -136,6 +140,16 @@ autorec_cmp(dvr_autorec_entry_t *dae, epg_broadcast_t *e)
|
|||
return 0;
|
||||
}
|
||||
|
||||
duration = difftime(e->stop,e->start);
|
||||
|
||||
if(dae->dae_minduration) {
|
||||
if(duration < dae->dae_minduration) return 0;
|
||||
}
|
||||
|
||||
if(dae->dae_maxduration) {
|
||||
if(duration > dae->dae_maxduration) return 0;
|
||||
}
|
||||
|
||||
if(dae->dae_weekdays != 0x7f) {
|
||||
struct tm tm;
|
||||
localtime_r(&e->start, &tm);
|
||||
|
@ -283,6 +297,11 @@ autorec_record_build(dvr_autorec_entry_t *dae)
|
|||
build_weekday_tags(l, dae->dae_weekdays);
|
||||
htsmsg_add_msg(e, "weekdays", l);
|
||||
|
||||
if (dae->dae_minduration)
|
||||
htsmsg_add_u32(e, "minduration", dae->dae_minduration);
|
||||
if (dae->dae_maxduration)
|
||||
htsmsg_add_u32(e, "maxduration", dae->dae_maxduration);
|
||||
|
||||
htsmsg_add_str(e, "pri", dvr_val2pri(dae->dae_pri));
|
||||
|
||||
if (dae->dae_brand)
|
||||
|
@ -407,6 +426,12 @@ autorec_record_update(void *opaque, const char *id, htsmsg_t *values,
|
|||
}
|
||||
}
|
||||
|
||||
if(!htsmsg_get_u32(values, "minduration", &u32))
|
||||
dae->dae_minduration = u32;
|
||||
|
||||
if(!htsmsg_get_u32(values, "maxduration", &u32))
|
||||
dae->dae_maxduration = u32;
|
||||
|
||||
if((l = htsmsg_get_list(values, "weekdays")) != NULL)
|
||||
dae->dae_weekdays = build_weekday_mask(l);
|
||||
|
||||
|
@ -506,7 +531,8 @@ dvr_autorec_update(void)
|
|||
static void
|
||||
_dvr_autorec_add(const char *config_name,
|
||||
const char *title, channel_t *ch,
|
||||
const char *tag, epg_genre_t *content_type,
|
||||
const char *tag, epg_genre_t *content_type,
|
||||
const int min_duration, const int max_duration,
|
||||
epg_brand_t *brand, epg_season_t *season,
|
||||
epg_serieslink_t *serieslink,
|
||||
int approx_time, epg_episode_num_t *epnum,
|
||||
|
@ -543,6 +569,12 @@ _dvr_autorec_add(const char *config_name,
|
|||
if (content_type)
|
||||
dae->dae_content_type.code = content_type->code;
|
||||
|
||||
if (min_duration)
|
||||
dae->dae_minduration = min_duration;
|
||||
|
||||
if (max_duration)
|
||||
dae->dae_maxduration = max_duration;
|
||||
|
||||
if(serieslink) {
|
||||
serieslink->getref(serieslink);
|
||||
dae->dae_serieslink = serieslink;
|
||||
|
@ -564,12 +596,14 @@ _dvr_autorec_add(const char *config_name,
|
|||
void
|
||||
dvr_autorec_add(const char *config_name,
|
||||
const char *title, const char *channel,
|
||||
const char *tag, epg_genre_t *content_type,
|
||||
const char *creator, const char *comment)
|
||||
const char *tag, epg_genre_t *content_type,
|
||||
const int min_duration, const int max_duration,
|
||||
const char *creator, const char *comment)
|
||||
{
|
||||
channel_t *ch = NULL;
|
||||
if(channel != NULL) ch = channel_find(channel);
|
||||
_dvr_autorec_add(config_name, title, ch, tag, content_type,
|
||||
min_duration, max_duration,
|
||||
NULL, NULL, NULL, 0, NULL, creator, comment);
|
||||
}
|
||||
|
||||
|
@ -584,6 +618,7 @@ void dvr_autorec_add_series_link
|
|||
title,
|
||||
event->channel,
|
||||
NULL, 0, // tag/content type
|
||||
0,INT_MAX,
|
||||
NULL,
|
||||
NULL,
|
||||
event->serieslink,
|
||||
|
|
24
src/epg.c
|
@ -23,6 +23,7 @@
|
|||
#include <regex.h>
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "queue.h"
|
||||
|
@ -2205,9 +2206,10 @@ htsmsg_t *epg_genres_list_all ( int major_only, int major_prefix )
|
|||
|
||||
static void _eqr_add
|
||||
( epg_query_result_t *eqr, epg_broadcast_t *e,
|
||||
epg_genre_t *genre, regex_t *preg, time_t start, const char *lang )
|
||||
epg_genre_t *genre, regex_t *preg, time_t start, const char *lang, int min_duration, int max_duration )
|
||||
{
|
||||
const char *title;
|
||||
double duration;
|
||||
|
||||
/* Ignore */
|
||||
if ( e->stop < start ) return;
|
||||
|
@ -2215,6 +2217,9 @@ static void _eqr_add
|
|||
if ( genre && !epg_genre_list_contains(&e->episode->genre, genre, 1) ) return;
|
||||
if ( preg && regexec(preg, title, 0, NULL, 0)) return;
|
||||
|
||||
duration = difftime(e->stop,e->start);
|
||||
if ( duration < min_duration || duration > max_duration ) return;
|
||||
|
||||
/* More space */
|
||||
if ( eqr->eqr_entries == eqr->eqr_alloced ) {
|
||||
eqr->eqr_alloced = MAX(100, eqr->eqr_alloced * 2);
|
||||
|
@ -2228,17 +2233,17 @@ static void _eqr_add
|
|||
|
||||
static void _eqr_add_channel
|
||||
( epg_query_result_t *eqr, channel_t *ch, epg_genre_t *genre,
|
||||
regex_t *preg, time_t start, const char *lang )
|
||||
regex_t *preg, time_t start, const char *lang, int min_duration, int max_duration )
|
||||
{
|
||||
epg_broadcast_t *ebc;
|
||||
RB_FOREACH(ebc, &ch->ch_epg_schedule, sched_link) {
|
||||
if ( ebc->episode ) _eqr_add(eqr, ebc, genre, preg, start, lang);
|
||||
if ( ebc->episode ) _eqr_add(eqr, ebc, genre, preg, start, lang, min_duration, max_duration);
|
||||
}
|
||||
}
|
||||
|
||||
void epg_query0
|
||||
( epg_query_result_t *eqr, channel_t *channel, channel_tag_t *tag,
|
||||
epg_genre_t *genre, const char *title, const char *lang )
|
||||
epg_genre_t *genre, const char *title, const char *lang, int min_duration, int max_duration )
|
||||
{
|
||||
time_t now;
|
||||
channel_tag_mapping_t *ctm;
|
||||
|
@ -2259,19 +2264,19 @@ void epg_query0
|
|||
|
||||
/* Single channel */
|
||||
if (channel && !tag) {
|
||||
_eqr_add_channel(eqr, channel, genre, preg, now, lang);
|
||||
_eqr_add_channel(eqr, channel, genre, preg, now, lang, min_duration, max_duration);
|
||||
|
||||
/* Tag based */
|
||||
} else if ( tag ) {
|
||||
LIST_FOREACH(ctm, &tag->ct_ctms, ctm_tag_link) {
|
||||
if(channel == NULL || ctm->ctm_channel == channel)
|
||||
_eqr_add_channel(eqr, ctm->ctm_channel, genre, preg, now, lang);
|
||||
_eqr_add_channel(eqr, ctm->ctm_channel, genre, preg, now, lang, min_duration, max_duration);
|
||||
}
|
||||
|
||||
/* All channels */
|
||||
} else {
|
||||
CHANNEL_FOREACH(channel)
|
||||
_eqr_add_channel(eqr, channel, genre, preg, now, lang);
|
||||
_eqr_add_channel(eqr, channel, genre, preg, now, lang, min_duration, max_duration);
|
||||
}
|
||||
if (preg) regfree(preg);
|
||||
|
||||
|
@ -2279,11 +2284,12 @@ void epg_query0
|
|||
}
|
||||
|
||||
void epg_query(epg_query_result_t *eqr, const char *channel, const char *tag,
|
||||
epg_genre_t *genre, const char *title, const char *lang)
|
||||
epg_genre_t *genre, const char *title, const char *lang, int min_duration, int max_duration)
|
||||
{
|
||||
channel_t *ch = channel ? channel_find(channel) : NULL;
|
||||
channel_tag_t *ct = tag ? channel_tag_find_by_name(tag, 0) : NULL;
|
||||
epg_query0(eqr, ch, ct, genre, title, lang);
|
||||
|
||||
epg_query0(eqr, ch, ct, genre, title, lang, min_duration, max_duration);
|
||||
}
|
||||
|
||||
void epg_query_free(epg_query_result_t *eqr)
|
||||
|
|
|
@ -546,9 +546,9 @@ void epg_query_sort(epg_query_result_t *eqr);
|
|||
/* Query routines */
|
||||
void epg_query0(epg_query_result_t *eqr, struct channel *ch,
|
||||
struct channel_tag *ct, epg_genre_t *genre, const char *title,
|
||||
const char *lang);
|
||||
const char *lang, int min_duration, int max_duration);
|
||||
void epg_query(epg_query_result_t *eqr, const char *channel, const char *tag,
|
||||
epg_genre_t *genre, const char *title, const char *lang);
|
||||
epg_genre_t *genre, const char *title, const char *lang, int min_duration, int max_duration);
|
||||
|
||||
|
||||
/* ************************************************************************
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
#include <sys/statvfs.h>
|
||||
#include "settings.h"
|
||||
#include <sys/time.h>
|
||||
#include <limits.h>
|
||||
|
||||
/* **************************************************************************
|
||||
* Datatypes and variables
|
||||
|
@ -1059,7 +1060,9 @@ htsp_method_epgQuery(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
epg_query_result_t eqr;
|
||||
epg_genre_t genre, *eg = NULL;
|
||||
const char *lang;
|
||||
|
||||
int min_duration;
|
||||
int max_duration;
|
||||
|
||||
/* Required */
|
||||
if( (query = htsmsg_get_str(in, "query")) == NULL )
|
||||
return htsp_error("Missing argument 'query'");
|
||||
|
@ -1079,12 +1082,16 @@ htsp_method_epgQuery(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
lang = htsmsg_get_str(in, "language") ?: htsp->htsp_language;
|
||||
full = htsmsg_get_u32_or_default(in, "full", 0);
|
||||
|
||||
min_duration = htsmsg_get_u32_or_default(in, "minduration", 0);
|
||||
max_duration = htsmsg_get_u32_or_default(in, "maxduration", INT_MAX);
|
||||
tvhtrace("htsp", "min_duration %d and max_duration %d", min_duration, max_duration);
|
||||
|
||||
/* Check access */
|
||||
if (!htsp_user_access_channel(htsp, ch))
|
||||
return htsp_error("User does not have access");
|
||||
|
||||
//do the query
|
||||
epg_query0(&eqr, ch, ct, eg, query, lang);
|
||||
epg_query0(&eqr, ch, ct, eg, query, lang, min_duration, max_duration);
|
||||
|
||||
// create reply
|
||||
out = htsmsg_create_map();
|
||||
|
|
|
@ -759,9 +759,22 @@ extjs_epg(http_connection_t *hc, const char *remain, void *opaque)
|
|||
const char *title = http_arg_get(&hc->hc_req_args, "title");
|
||||
const char *lang = http_arg_get(&hc->hc_args, "Accept-Language");
|
||||
|
||||
int min_duration;
|
||||
int max_duration;
|
||||
|
||||
if(channel && !channel[0]) channel = NULL;
|
||||
if(tag && !tag[0]) tag = NULL;
|
||||
|
||||
if((s = http_arg_get(&hc->hc_req_args, "minduration")) != NULL)
|
||||
min_duration = atoi(s);
|
||||
else
|
||||
min_duration = 0;
|
||||
|
||||
if((s = http_arg_get(&hc->hc_req_args, "maxduration")) != NULL)
|
||||
max_duration = atoi(s);
|
||||
else
|
||||
max_duration = INT_MAX;
|
||||
|
||||
if((s = http_arg_get(&hc->hc_req_args, "start")) != NULL)
|
||||
start = atoi(s);
|
||||
|
||||
|
@ -780,7 +793,7 @@ extjs_epg(http_connection_t *hc, const char *remain, void *opaque)
|
|||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
epg_query(&eqr, channel, tag, eg, title, lang);
|
||||
epg_query(&eqr, channel, tag, eg, title, lang, min_duration, max_duration);
|
||||
|
||||
epg_query_sort(&eqr);
|
||||
|
||||
|
@ -1117,18 +1130,31 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
|
|||
htsmsg_add_u32(out, "success", 1);
|
||||
|
||||
} else if(!strcmp(op, "createAutoRec")) {
|
||||
int min_duration;
|
||||
int max_duration;
|
||||
epg_genre_t genre, *eg = NULL;
|
||||
|
||||
if ((s = http_arg_get(&hc->hc_req_args, "contenttype"))) {
|
||||
genre.code = atoi(s);
|
||||
eg = &genre;
|
||||
}
|
||||
|
||||
if((s = http_arg_get(&hc->hc_req_args, "minduration")) != NULL)
|
||||
min_duration = atoi(s);
|
||||
else
|
||||
min_duration = 0;
|
||||
|
||||
if((s = http_arg_get(&hc->hc_req_args, "maxduration")) != NULL)
|
||||
max_duration = atoi(s);
|
||||
else
|
||||
max_duration = INT_MAX;
|
||||
|
||||
dvr_autorec_add(http_arg_get(&hc->hc_req_args, "config_name"),
|
||||
http_arg_get(&hc->hc_req_args, "title"),
|
||||
http_arg_get(&hc->hc_req_args, "channel"),
|
||||
http_arg_get(&hc->hc_req_args, "tag"),
|
||||
eg,
|
||||
hc->hc_representative, "Created from EPG query");
|
||||
http_arg_get(&hc->hc_req_args, "channel"),
|
||||
http_arg_get(&hc->hc_req_args, "tag"),
|
||||
eg, min_duration,max_duration,
|
||||
hc->hc_representative, "Created from EPG query");
|
||||
|
||||
out = htsmsg_create_map();
|
||||
htsmsg_add_u32(out, "success", 1);
|
||||
|
|
|
@ -87,8 +87,9 @@ page_simple(http_connection_t *hc,
|
|||
|
||||
|
||||
if(s != NULL) {
|
||||
|
||||
epg_query(&eqr, NULL, NULL, NULL, s, lang);
|
||||
|
||||
//Note: force min/max durations for this interface to 0 and INT_MAX seconds respectively
|
||||
epg_query(&eqr, NULL, NULL, NULL, s, lang, 0, INT_MAX);
|
||||
epg_query_sort(&eqr);
|
||||
|
||||
c = eqr.eqr_entries;
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
/**
|
||||
* Channel tags
|
||||
*/
|
||||
insertChannelTagsClearOption = function( scope, records, options ){
|
||||
var placeholder = Ext.data.Record.create(['identifier', 'name']);
|
||||
scope.insert(0,new placeholder({identifier: '-1', name: '(Clear filter)'}));
|
||||
};
|
||||
|
||||
tvheadend.channelTags = new Ext.data.JsonStore({
|
||||
autoLoad: true,
|
||||
root: 'entries',
|
||||
|
@ -9,6 +14,9 @@ tvheadend.channelTags = new Ext.data.JsonStore({
|
|||
url: 'channeltags',
|
||||
baseParams: {
|
||||
op: 'listTags'
|
||||
},
|
||||
listeners: {
|
||||
'load': insertChannelTagsClearOption
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -26,6 +34,11 @@ tvheadend.channelrec = new Ext.data.Record.create(
|
|||
['name', 'chid', 'epggrabsrc', 'tags', 'ch_icon', 'epg_pre_start',
|
||||
'epg_post_end', 'number']);
|
||||
|
||||
insertChannelClearOption = function( scope, records, options ){
|
||||
var placeholder = Ext.data.Record.create(['key', 'val']);
|
||||
scope.insert(0,new placeholder({key: '-1', val: '(Clear filter)'}));
|
||||
};
|
||||
|
||||
tvheadend.channels = new Ext.data.JsonStore({
|
||||
url: 'api/channel/list',
|
||||
root: 'entries',
|
||||
|
@ -35,6 +48,9 @@ tvheadend.channels = new Ext.data.JsonStore({
|
|||
sortInfo: {
|
||||
field: 'val',
|
||||
direction: 'ASC'
|
||||
},
|
||||
listeners: {
|
||||
'load': insertChannelClearOption
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -507,10 +507,6 @@ tvheadend.dvrschedule = function(title, iconCls, dvrStore) {
|
|||
return panel;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -543,16 +539,15 @@ tvheadend.autoreceditor = function() {
|
|||
valueField: 'key',
|
||||
store: tvheadend.channels,
|
||||
mode: 'local',
|
||||
editable: false,
|
||||
editable: true,
|
||||
forceSelection: true,
|
||||
typeAhead: true,
|
||||
triggerAction: 'all',
|
||||
emptyText: 'Only include channel...'
|
||||
}),
|
||||
renderer: function(v, m, r) {
|
||||
var i = tvheadend.channels.find('key', v);
|
||||
if (i !== -1)
|
||||
v = tvheadend.channels.getAt(i).get('val');
|
||||
return v;
|
||||
}
|
||||
renderer: function(v) {
|
||||
return tvheadend.channelLookupName(v);
|
||||
},
|
||||
},
|
||||
{
|
||||
header: "SeriesLink",
|
||||
|
@ -568,7 +563,9 @@ tvheadend.autoreceditor = function() {
|
|||
displayField: 'name',
|
||||
store: tvheadend.channelTags,
|
||||
mode: 'local',
|
||||
editable: false,
|
||||
editable: true,
|
||||
forceSelection: true,
|
||||
typeAhead: true,
|
||||
triggerAction: 'all',
|
||||
emptyText: 'Only include tag...'
|
||||
})
|
||||
|
@ -584,11 +581,31 @@ tvheadend.autoreceditor = function() {
|
|||
displayField: 'name',
|
||||
store: tvheadend.ContentGroupStore,
|
||||
mode: 'local',
|
||||
editable: false,
|
||||
editable: true,
|
||||
forceSelection: true,
|
||||
typeAhead: true,
|
||||
triggerAction: 'all',
|
||||
emptyText: 'Only include content...'
|
||||
})
|
||||
},
|
||||
{
|
||||
header: "Duration",
|
||||
dataIndex: 'minduration',
|
||||
renderer: function(v) {
|
||||
return tvheadend.durationLookupRange(v);
|
||||
},
|
||||
editor: durationCombo = new Ext.form.ComboBox({
|
||||
store: tvheadend.DurationStore,
|
||||
mode: 'local',
|
||||
valueField: 'minvalue',
|
||||
displayField: 'label',
|
||||
editable: true,
|
||||
forceSelection: true,
|
||||
typeAhead: true,
|
||||
triggerAction: 'all',
|
||||
id: 'minfield'
|
||||
})
|
||||
},
|
||||
{
|
||||
header: "Weekdays",
|
||||
dataIndex: 'weekdays',
|
||||
|
@ -685,10 +702,35 @@ tvheadend.autoreceditor = function() {
|
|||
})
|
||||
}]});
|
||||
|
||||
tvheadend.autorecStore.on('update', function (store, record, operation) {
|
||||
if (operation == 'edit') {
|
||||
if (record.isModified('minduration')) {
|
||||
if (record.data.minduration == "")
|
||||
record.set('maxduration',"");
|
||||
else {
|
||||
var index = tvheadend.DurationStore.find('minvalue', record.data.minduration);
|
||||
|
||||
if (index !== -1)
|
||||
record.set('maxduration', tvheadend.DurationStore.getById(index).data.maxvalue);
|
||||
}
|
||||
}
|
||||
|
||||
if (record.isModified('channel') && record.data.channel == -1)
|
||||
record.set('channel',"");
|
||||
|
||||
if (record.isModified('tag') && record.data.tag == '(Clear filter)')
|
||||
record.set('tag',"");
|
||||
|
||||
if (record.isModified('contenttype') && record.data.contenttype == -1)
|
||||
record.set('contenttype',"");
|
||||
}
|
||||
});
|
||||
|
||||
return new tvheadend.tableEditor('Automatic Recorder', 'autorec', cm,
|
||||
tvheadend.autorecRecord, [], tvheadend.autorecStore,
|
||||
'autorec.html', 'wand');
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -786,6 +828,7 @@ tvheadend.dvr = function() {
|
|||
|
||||
tvheadend.autorecRecord = Ext.data.Record.create(['enabled', 'title',
|
||||
'serieslink', 'channel', 'tag', 'creator', 'contenttype', 'comment',
|
||||
'minduration', 'maxduration',
|
||||
'weekdays', 'pri', 'approx_time', 'config_name']);
|
||||
|
||||
tvheadend.autorecStore = new Ext.data.JsonStore({
|
||||
|
|
|
@ -7,13 +7,22 @@ tvheadend.brands = new Ext.data.JsonStore({
|
|||
op: 'brandList'
|
||||
}
|
||||
});
|
||||
|
||||
insertContentGroupClearOption = function( scope, records, options ){
|
||||
var placeholder = Ext.data.Record.create(['name', 'code']);
|
||||
scope.insert(0,new placeholder({name: '(Clear filter)', code: '-1'}));
|
||||
};
|
||||
|
||||
//WIBNI: might want this store to periodically update
|
||||
|
||||
tvheadend.ContentGroupStore = new Ext.data.JsonStore({
|
||||
root: 'entries',
|
||||
fields: ['name', 'code'],
|
||||
autoLoad: true,
|
||||
url: 'ecglist'
|
||||
url: 'ecglist',
|
||||
listeners: {
|
||||
'load': insertContentGroupClearOption
|
||||
}
|
||||
});
|
||||
|
||||
tvheadend.contentGroupLookupName = function(code) {
|
||||
|
@ -29,6 +38,45 @@ tvheadend.contentGroupLookupName = function(code) {
|
|||
|
||||
tvheadend.ContentGroupStore.setDefaultSort('code', 'ASC');
|
||||
|
||||
tvheadend.channelLookupName = function(key) {
|
||||
channelString = "";
|
||||
|
||||
var index = tvheadend.channels.find('key', key);
|
||||
|
||||
if (index !== -1)
|
||||
var channelString = tvheadend.channels.getAt(index).get('val');
|
||||
|
||||
return channelString;
|
||||
};
|
||||
|
||||
// Store for duration filters - EPG, autorec dialog and autorec rules in the DVR grid
|
||||
// NB: 'no max' is defined as 9999999s, or about 3 months...
|
||||
|
||||
tvheadend.DurationStore = new Ext.data.SimpleStore({
|
||||
storeId: 'durationnames',
|
||||
idIndex: 0,
|
||||
fields: ['identifier','label','minvalue','maxvalue'],
|
||||
data: [['-1', '(Clear filter)',"",""],
|
||||
['1','00:00:01 - 00:15:00',1, 900],
|
||||
['2','00:15:01 - 00:30:00', 901, 1800],
|
||||
['3','00:30:01 - 01:30:00', 1801, 5400],
|
||||
['4','01:30:01 - 03:00:00', 5401, 10800],
|
||||
['5','03:00:01 - No maximum', 10801, 9999999]]
|
||||
});
|
||||
|
||||
// Function to convert numeric duration to corresponding label string
|
||||
// Note: triggered by minimum duration only. This would fail if ranges
|
||||
// had the same minimum (e.g. 15-30 mins and 15-60 minutes) (which we don't have).
|
||||
|
||||
tvheadend.durationLookupRange = function(value) {
|
||||
durationString = "";
|
||||
var index = tvheadend.DurationStore.find('minvalue', value);
|
||||
if (index !== -1)
|
||||
var durationString = tvheadend.DurationStore.getAt(index).data.label;
|
||||
|
||||
return durationString;
|
||||
};
|
||||
|
||||
tvheadend.epgDetails = function(event) {
|
||||
|
||||
var content = '';
|
||||
|
@ -378,7 +426,16 @@ tvheadend.epg = function() {
|
|||
editable: true,
|
||||
forceSelection: true,
|
||||
triggerAction: 'all',
|
||||
emptyText: 'Filter channel...'
|
||||
typeAhead: true,
|
||||
emptyText: 'Filter channel...',
|
||||
listeners: {
|
||||
blur: function () {
|
||||
if(this.getRawValue() == "" ) {
|
||||
clearChannelFilter();
|
||||
epgStore.reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Tags, uses global store
|
||||
|
@ -391,7 +448,17 @@ tvheadend.epg = function() {
|
|||
editable: true,
|
||||
forceSelection: true,
|
||||
triggerAction: 'all',
|
||||
emptyText: 'Filter tag...'
|
||||
typeAhead: true,
|
||||
emptyText: 'Filter tag...',
|
||||
listeners: {
|
||||
blur: function () {
|
||||
if(this.getRawValue() == "" ) {
|
||||
clearChannelTagsFilter();
|
||||
epgStore.reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Content groups
|
||||
|
@ -405,42 +472,115 @@ tvheadend.epg = function() {
|
|||
editable: true,
|
||||
forceSelection: true,
|
||||
triggerAction: 'all',
|
||||
emptyText: 'Filter content type...'
|
||||
typeAhead: true,
|
||||
emptyText: 'Filter content type...',
|
||||
listeners: {
|
||||
blur: function () {
|
||||
if(this.getRawValue() == "" ) {
|
||||
clearContentGroupFilter();
|
||||
epgStore.reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function epgQueryClear() {
|
||||
delete epgStore.baseParams.channel;
|
||||
delete epgStore.baseParams.tag;
|
||||
delete epgStore.baseParams.contenttype;
|
||||
var epgFilterDuration = new Ext.form.ComboBox({
|
||||
loadingText: 'Loading...',
|
||||
width: 150,
|
||||
displayField: 'label',
|
||||
store: tvheadend.DurationStore,
|
||||
mode: 'local',
|
||||
editable: true,
|
||||
forceSelection: true,
|
||||
triggerAction: 'all',
|
||||
typeAhead: true,
|
||||
emptyText: 'Filter duration...',
|
||||
listeners: {
|
||||
blur: function () {
|
||||
if(this.getRawValue() == "" ) {
|
||||
clearDurationFilter();
|
||||
epgStore.reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
/*
|
||||
* Clear filter functions
|
||||
*/
|
||||
|
||||
clearTitleFilter = function() {
|
||||
delete epgStore.baseParams.title;
|
||||
|
||||
epgFilterChannels.setValue("");
|
||||
epgFilterChannelTags.setValue("");
|
||||
epgFilterContentGroup.setValue("");
|
||||
epgFilterTitle.setValue("");
|
||||
};
|
||||
|
||||
clearChannelFilter = function() {
|
||||
delete epgStore.baseParams.channel;
|
||||
epgFilterChannels.setValue("");
|
||||
};
|
||||
|
||||
clearChannelTagsFilter = function() {
|
||||
delete epgStore.baseParams.tag;
|
||||
epgFilterChannelTags.setValue("");
|
||||
};
|
||||
|
||||
clearContentGroupFilter = function() {
|
||||
delete epgStore.baseParams.contenttype;
|
||||
epgFilterContentGroup.setValue("");
|
||||
};
|
||||
|
||||
clearDurationFilter = function() {
|
||||
delete epgStore.baseParams.minduration;
|
||||
delete epgStore.baseParams.maxduration;
|
||||
epgFilterDuration.setValue("");
|
||||
};
|
||||
|
||||
function epgQueryClear() {
|
||||
clearTitleFilter();
|
||||
clearChannelFilter();
|
||||
clearChannelTagsFilter();
|
||||
clearDurationFilter();
|
||||
clearContentGroupFilter();
|
||||
epgStore.reload();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Filter selection event handlers
|
||||
*/
|
||||
|
||||
epgFilterChannels.on('select', function(c, r) {
|
||||
if (epgStore.baseParams.channel !== r.data.key) {
|
||||
if (r.data.key == -1)
|
||||
clearChannelFilter();
|
||||
else if (epgStore.baseParams.channel !== r.data.key)
|
||||
epgStore.baseParams.channel = r.data.key;
|
||||
epgStore.reload();
|
||||
}
|
||||
epgStore.reload();
|
||||
});
|
||||
|
||||
epgFilterChannelTags.on('select', function(c, r) {
|
||||
if (epgStore.baseParams.tag !== r.data.name) {
|
||||
if (r.data.identifier == -1)
|
||||
clearChannelTagsFilter();
|
||||
else if (epgStore.baseParams.tag !== r.data.name)
|
||||
epgStore.baseParams.tag = r.data.name;
|
||||
epgStore.reload();
|
||||
}
|
||||
epgStore.reload();
|
||||
});
|
||||
|
||||
epgFilterContentGroup.on('select', function(c, r) {
|
||||
if (epgStore.baseParams.contenttype !== r.data.code) {
|
||||
if (r.data.code == -1)
|
||||
clearContentGroupFilter();
|
||||
else if (epgStore.baseParams.contenttype !== r.data.code)
|
||||
epgStore.baseParams.contenttype = r.data.code;
|
||||
epgStore.reload();
|
||||
epgStore.reload();
|
||||
});
|
||||
|
||||
epgFilterDuration.on('select', function(c, r) {
|
||||
if (r.data.identifier == -1)
|
||||
clearDurationFilter();
|
||||
else if (epgStore.baseParams.minduration !== r.data.minvalue) {
|
||||
epgStore.baseParams.minduration = r.data.minvalue;
|
||||
epgStore.baseParams.maxduration = r.data.maxvalue;
|
||||
}
|
||||
epgStore.reload();
|
||||
});
|
||||
|
||||
epgFilterTitle.on('valid', function(c) {
|
||||
|
@ -482,8 +622,10 @@ tvheadend.epg = function() {
|
|||
'-',
|
||||
epgFilterContentGroup,
|
||||
'-',
|
||||
epgFilterDuration,
|
||||
'-',
|
||||
{
|
||||
text: 'Reset',
|
||||
text: 'Reset All',
|
||||
handler: epgQueryClear
|
||||
},
|
||||
'->',
|
||||
|
@ -524,28 +666,31 @@ tvheadend.epg = function() {
|
|||
|
||||
var title = epgStore.baseParams.title ? epgStore.baseParams.title
|
||||
: "<i>Don't care</i>";
|
||||
var channel = epgStore.baseParams.channel ? epgStore.baseParams.channel
|
||||
var channel = epgStore.baseParams.channel ? tvheadend.channelLookupName(epgStore.baseParams.channel)
|
||||
: "<i>Don't care</i>";
|
||||
var tag = epgStore.baseParams.tag ? epgStore.baseParams.tag
|
||||
: "<i>Don't care</i>";
|
||||
var contenttype = epgStore.baseParams.contenttype ? epgStore.baseParams.contenttype
|
||||
var contenttype = epgStore.baseParams.contenttype ? tvheadend.contentGroupLookupName(epgStore.baseParams.contenttype)
|
||||
: "<i>Don't care</i>";
|
||||
var duration = epgStore.baseParams.minduration ? tvheadend.durationLookupRange(epgStore.baseParams.minduration)
|
||||
: "<i>Don't care</i>";
|
||||
|
||||
Ext.MessageBox.confirm('Auto Recorder',
|
||||
'This will create an automatic rule that '
|
||||
|
||||
Ext.MessageBox.confirm('Auto Recorder', 'This will create an automatic rule that '
|
||||
+ 'continuously scans the EPG for programmes '
|
||||
+ 'to record that matches this query: ' + '<br><br>'
|
||||
+ 'to record that match this query: ' + '<br><br>'
|
||||
+ '<div class="x-smallhdr">Title:</div>' + title + '<br>'
|
||||
+ '<div class="x-smallhdr">Channel:</div>' + channel + '<br>'
|
||||
+ '<div class="x-smallhdr">Tag:</div>' + tag + '<br>'
|
||||
+ '<div class="x-smallhdr">Genre:</div>' + contenttype + '<br>'
|
||||
+ '<br>' + 'Currently this will match (and record) '
|
||||
+ '<div class="x-smallhdr">Duration:</div>' + duration + '<br>'
|
||||
+ '<br><br>' + 'Currently this will match (and record) '
|
||||
+ epgStore.getTotalCount() + ' events. ' + 'Are you sure?',
|
||||
function(button) {
|
||||
if (button === 'no')
|
||||
return;
|
||||
createAutoRec2(epgStore.baseParams);
|
||||
});
|
||||
function(button) {
|
||||
if (button === 'no')
|
||||
return;
|
||||
createAutoRec2(epgStore.baseParams);
|
||||
});
|
||||
}
|
||||
|
||||
function createAutoRec2(params) {
|
||||
|
|