WebUI: Add programme duration filtering

This commit is contained in:
Ian 2014-06-10 19:33:06 +01:00
parent c3a3dfef98
commit 812d801a99
10 changed files with 19 additions and 129 deletions

View file

@ -130,10 +130,8 @@ api_epg_grid
const char *ch, *tag, *title, *lang/*, *genre*/;
uint32_t start, limit, end;
htsmsg_t *l = NULL, *e;
//IH
int min_duration;
int max_duration;
//
*resp = htsmsg_create_map();
@ -145,10 +143,8 @@ api_epg_grid
lang = htsmsg_get_str(args, "lang");
// TODO: support multiple tag/genre/channel?
//IH
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);
@ -156,8 +152,6 @@ api_epg_grid
/* Query the EPG */
pthread_mutex_lock(&global_lock);
//IH
// 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

View file

@ -247,10 +247,8 @@ typedef struct dvr_autorec_entry {
epg_serieslink_t *dae_serieslink;
epg_episode_num_t dae_epnum;
//IH
int dae_minduration;
int dae_maxduration;
//
} dvr_autorec_entry_t;
@ -391,9 +389,7 @@ 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,
//IH
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,

View file

@ -26,9 +26,7 @@
#include <stdarg.h>
#include <errno.h>
#include <math.h>
//IH
#include <time.h>
//
#include "tvheadend.h"
#include "settings.h"
@ -73,9 +71,7 @@ autorec_cmp(dvr_autorec_entry_t *dae, epg_broadcast_t *e)
{
channel_tag_mapping_t *ctm;
dvr_config_t *cfg;
//IH
double duration;
//
if (!e->channel) return 0;
if (!e->episode) return 0;
@ -89,10 +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 &&
//IH
&dae->dae_minduration == NULL &&
&dae->dae_maxduration == NULL &&
//
dae->dae_serieslink == NULL)
return 0; // Avoid super wildcard match
@ -146,7 +140,6 @@ autorec_cmp(dvr_autorec_entry_t *dae, epg_broadcast_t *e)
return 0;
}
//IH
duration = difftime(e->stop,e->start);
if(dae->dae_minduration) {
@ -156,7 +149,6 @@ autorec_cmp(dvr_autorec_entry_t *dae, epg_broadcast_t *e)
if(dae->dae_maxduration) {
if(duration > dae->dae_maxduration) return 0;
}
//
if(dae->dae_weekdays != 0x7f) {
struct tm tm;
@ -305,12 +297,10 @@ autorec_record_build(dvr_autorec_entry_t *dae)
build_weekday_tags(l, dae->dae_weekdays);
htsmsg_add_msg(e, "weekdays", l);
//IH
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));
@ -436,13 +426,11 @@ autorec_record_update(void *opaque, const char *id, htsmsg_t *values,
}
}
//IH Updated autorec entry
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);
@ -544,9 +532,7 @@ static void
_dvr_autorec_add(const char *config_name,
const char *title, channel_t *ch,
const char *tag, epg_genre_t *content_type,
//IH
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,
@ -583,13 +569,11 @@ _dvr_autorec_add(const char *config_name,
if (content_type)
dae->dae_content_type.code = content_type->code;
//IH
if (min_duration)
dae->dae_minduration = min_duration;
if (max_duration)
dae->dae_maxduration = max_duration;
//
if(serieslink) {
serieslink->getref(serieslink);
@ -613,17 +597,13 @@ void
dvr_autorec_add(const char *config_name,
const char *title, const char *channel,
const char *tag, epg_genre_t *content_type,
//IH
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,
//IH
min_duration, max_duration,
//
NULL, NULL, NULL, 0, NULL, creator, comment);
}

View file

@ -23,9 +23,7 @@
#include <regex.h>
#include <assert.h>
#include <inttypes.h>
//IH
#include <time.h>
//
#include "tvheadend.h"
#include "queue.h"
@ -2208,8 +2206,6 @@ 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,
//IH
// 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;
@ -2221,11 +2217,8 @@ 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;
//IH
duration = difftime(e->stop,e->start);
// duration = (int)e->stop - (int)e->start;
if ( duration < min_duration || duration > max_duration ) return;
//
/* More space */
if ( eqr->eqr_entries == eqr->eqr_alloced ) {
@ -2240,22 +2233,16 @@ static void _eqr_add
static void _eqr_add_channel
( epg_query_result_t *eqr, channel_t *ch, epg_genre_t *genre,
//IH
// 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) {
//IH
// 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,
//IH
// 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;
@ -2277,24 +2264,18 @@ void epg_query0
/* Single channel */
if (channel && !tag) {
//IH
// _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)
//IH
// _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)
//IH
// _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);
@ -2303,9 +2284,7 @@ void epg_query0
}
void epg_query(epg_query_result_t *eqr, const char *channel, const char *tag,
//IH
// 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)
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;

View file

@ -544,14 +544,6 @@ void epg_query_free(epg_query_result_t *eqr);
void epg_query_sort(epg_query_result_t *eqr);
/* Query routines */
//IH
/*
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);
void epg_query(epg_query_result_t *eqr, const char *channel, const char *tag,
epg_genre_t *genre, const char *title, const char *lang);
*/
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, int min_duration, int max_duration);

View file

@ -57,9 +57,7 @@
#include <sys/statvfs.h>
#include "settings.h"
#include <sys/time.h>
//IH
#include <limits.h>
//
/* **************************************************************************
* Datatypes and variables
@ -1062,10 +1060,8 @@ htsp_method_epgQuery(htsp_connection_t *htsp, htsmsg_t *in)
epg_query_result_t eqr;
epg_genre_t genre, *eg = NULL;
const char *lang;
//IH
int min_duration;
int max_duration;
//
/* Required */
if( (query = htsmsg_get_str(in, "query")) == NULL )
@ -1086,19 +1082,15 @@ 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);
//IH
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
//IH
// epg_query0(&eqr, ch, ct, eg, query, lang);
epg_query0(&eqr, ch, ct, eg, query, lang, min_duration, max_duration);
// create reply

View file

@ -759,15 +759,12 @@ 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");
//IH
int min_duration;
int max_duration;
//
if(channel && !channel[0]) channel = NULL;
if(tag && !tag[0]) tag = NULL;
//IH
if((s = http_arg_get(&hc->hc_req_args, "minduration")) != NULL)
min_duration = atoi(s);
else
@ -777,7 +774,6 @@ extjs_epg(http_connection_t *hc, const char *remain, void *opaque)
max_duration = atoi(s);
else
max_duration = INT_MAX;
//
if((s = http_arg_get(&hc->hc_req_args, "start")) != NULL)
start = atoi(s);
@ -1134,10 +1130,8 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
htsmsg_add_u32(out, "success", 1);
} else if(!strcmp(op, "createAutoRec")) {
//IH
int min_duration;
int max_duration;
//
epg_genre_t genre, *eg = NULL;
if ((s = http_arg_get(&hc->hc_req_args, "contenttype"))) {
@ -1145,7 +1139,6 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
eg = &genre;
}
//IH
if((s = http_arg_get(&hc->hc_req_args, "minduration")) != NULL)
min_duration = atoi(s);
else
@ -1155,16 +1148,12 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
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,
//IH
min_duration,max_duration,
//
eg, min_duration,max_duration,
hc->hc_representative, "Created from EPG query");
out = htsmsg_create_map();

View file

@ -88,9 +88,7 @@ page_simple(http_connection_t *hc,
if(s != NULL) {
//IH
// epg_query(&eqr, NULL, NULL, NULL, s, lang);
//Note: force min/max durations for this interface to 0 and INT_MAX seconds respectively
//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);

View file

@ -510,27 +510,25 @@ tvheadend.dvrschedule = function(title, iconCls, dvrStore) {
/**
*
*/
//IH --------
// Validation function for min/max duration in autorec grid
Ext.apply(Ext.form.VTypes, {
durations: function(val,field) {
var thisvalue = field.getValue();
var othervalue = Ext.getCmp(field.otherfield).getValue();
durations: function(val,field) {
var thisvalue = field.getValue();
var othervalue = Ext.getCmp(field.otherfield).getValue();
// Return if otherfield isn't set yet
if (!othervalue) return true;
if (!othervalue) return true;
// Return if we've changed min and it's <= existing max
if (field.id == 'minfield' && thisvalue <= othervalue) return true;
if (field.id == 'minfield' && thisvalue <= othervalue) return true;
// Return if we've changed max and it's >= existing min
if (field.id == 'maxfield' && thisvalue >= othervalue) return true;
},
if (field.id == 'maxfield' && thisvalue >= othervalue) return true;
},
durationsText: 'Minimum duration must be more than the maximum'
});
//------------
/**
*
@ -613,7 +611,6 @@ tvheadend.autoreceditor = function() {
emptyText: 'Only include content...'
})
},
// IH
{
header: "Min. Duration",
dataIndex: 'minduration',
@ -628,14 +625,12 @@ tvheadend.autoreceditor = function() {
displayField: 'label',
editable: false,
triggerAction: 'all',
//IH ------------------
id: 'minfield',
otherfield: 'maxfield',
vtype: 'durations'
// --------------------
})
},
{
},
{
header: "Max. Duration",
dataIndex: 'maxduration',
width: 75,
@ -649,14 +644,11 @@ tvheadend.autoreceditor = function() {
displayField: 'label',
editable: false,
triggerAction: 'all',
//IH ----------------------
id: 'maxfield',
otherfield: 'minfield',
vtype: 'durations'
// ------------------------
})
},
//
{
header: "Weekdays",
dataIndex: 'weekdays',
@ -856,9 +848,7 @@ tvheadend.dvr = function() {
tvheadend.autorecRecord = Ext.data.Record.create(['enabled', 'title',
'serieslink', 'channel', 'tag', 'creator', 'contenttype', 'comment',
//IH
'minduration', 'maxduration',
//
'weekdays', 'pri', 'approx_time', 'config_name']);
tvheadend.autorecStore = new Ext.data.JsonStore({

View file

@ -29,7 +29,6 @@ tvheadend.contentGroupLookupName = function(code) {
tvheadend.ContentGroupStore.setDefaultSort('code', 'ASC');
//IH
tvheadend.channelLookupName = function(key) {
channelString = "";
@ -53,8 +52,8 @@ tvheadend.durationLookupName = function(value) {
};
tvheadend.DurationStore = new Ext.data.SimpleStore({
storeId: 'durations',
id: 0,
storeId: 'durations',
id: 0,
fields: ['identifier','label','value'],
data: [['0','0 min',0],
['1','20 min', 1200],
@ -65,7 +64,6 @@ tvheadend.DurationStore = new Ext.data.SimpleStore({
['6','12 hrs', 43200],
['7','24 hrs', 86400]]
});
//
tvheadend.epgDetails = function(event) {
@ -446,7 +444,6 @@ tvheadend.epg = function() {
emptyText: 'Filter content type...'
});
//IH
// Slider for duration selection, including tooltip function to display the appropriate string
var tip = new Ext.slider.Tip({
@ -475,26 +472,23 @@ tvheadend.epg = function() {
},
plugins: tip,
listeners: {
change: function(slider, thumb, value){
change: function(slider, thumb, value){
setduration(slider);
}}
}}
});
//
function epgQueryClear() {
//IH
// Reset the pointers before deleting the underlying variables - otherwise they reset to 0/24h not null/null
durationSlider.setValue(0,0);
durationSlider.setValue(1,7);
//
delete epgStore.baseParams.channel;
delete epgStore.baseParams.tag;
delete epgStore.baseParams.contenttype;
delete epgStore.baseParams.title;
//IH
delete epgStore.baseParams.minduration;
delete epgStore.baseParams.maxduration;
//
epgFilterChannels.setValue("");
epgFilterChannelTags.setValue("");
@ -525,9 +519,7 @@ tvheadend.epg = function() {
}
});
//IH
setduration = function(slider) {
setduration = function(slider) {
var min = slider.getValue(0);
var minRec = tvheadend.DurationStore.getById(min);
@ -540,7 +532,6 @@ tvheadend.epg = function() {
epgStore.reload();
};
//
epgFilterTitle.on('valid', function(c) {
var value = c.getValue();
@ -581,11 +572,9 @@ tvheadend.epg = function() {
'-',
epgFilterContentGroup,
'-',
//IH
'Duration: 0h ',
durationSlider,
'24h','-',
//
{
text: 'Reset',
handler: epgQueryClear
@ -628,36 +617,27 @@ tvheadend.epg = function() {
var title = epgStore.baseParams.title ? epgStore.baseParams.title
: "<i>Don't care</i>";
//IH - correct to display content type as a string as opposed to the underlying (lookup) code
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>";
//IH - correct to display content type as a string as opposed to the underlying (lookup) code
var contenttype = epgStore.baseParams.contenttype ? tvheadend.contentGroupLookupName(epgStore.baseParams.contenttype)
//
: "<i>Don't care</i>";
//IH
var minduration = epgStore.baseParams.minduration ? tvheadend.durationLookupName(epgStore.baseParams.minduration)
: "<i>Don't care</i>";
var maxduration = epgStore.baseParams.maxduration ? tvheadend.durationLookupName(epgStore.baseParams.maxduration)
: "<i>Don't care</i>";
//
Ext.MessageBox.confirm('Auto Recorder', 'This will create an automatic rule that '
+ 'continuously scans the EPG for programmes '
//IH - correct typo
+ '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>'
//IH
+ '<div class="x-smallhdr">Min duration:</div>' + minduration + '<br>'
+ '<div class="x-smallhdr">Max duration:</div>' + maxduration + '<br>'
//
+ '<br><br>' + 'Currently this will match (and record) '
+ epgStore.getTotalCount() + ' events. ' + 'Are you sure?',
function(button) {