Merge branch 'epg-rewrite' into initialscan

This commit is contained in:
Adam Sutton 2012-07-06 15:36:23 +01:00
commit 140796a889
18 changed files with 406 additions and 362 deletions

View file

@ -164,6 +164,8 @@ channel_create(const char *name, int number)
channel_t *ch, *x;
int id;
if (!name || !*name) return NULL;
ch = RB_LAST(&channel_identifier_tree);
if(ch == NULL) {
id = 1;
@ -330,6 +332,8 @@ channel_rename(channel_t *ch, const char *newname)
lock_assert(&global_lock);
if (!newname || !*newname) return 0;
if(channel_find_by_name(newname, 0, 0))
return -1;

View file

@ -132,7 +132,7 @@ typedef struct dvr_entry {
char *de_ititle; /* Internal title optionally with channelname
date and time pre/post/fixed */
char *de_desc; /* Description in UTF-8 (from EPG) */
uint8_t de_content_type; /* Content type (from EPG) */
epg_genre_t de_content_type; /* Content type (from EPG) */
dvr_prio_t de_pri;
@ -205,7 +205,7 @@ typedef struct dvr_autorec_entry {
char *dae_title;
regex_t dae_title_preg;
uint8_t dae_content_type;
epg_genre_t dae_content_type;
int dae_approx_time; /* Minutes from midnight */
@ -259,7 +259,7 @@ dvr_entry_t *dvr_entry_create(const char *dvr_config_name,
channel_t *ch, time_t start, time_t stop,
time_t start_extra, time_t stop_extra,
const char *title, const char *description,
uint8_t content_type,
epg_genre_t *content_type,
const char *creator, dvr_autorec_entry_t *dae,
dvr_prio_t pri);
@ -327,7 +327,7 @@ void dvr_query_sort(dvr_query_result_t *dqr);
*/
void dvr_autorec_add(const char *dvr_config_name,
const char *title, const char *channel,
const char *tag, uint8_t content_type,
const char *tag, epg_genre_t *content_type,
const char *creator, const char *comment);
void dvr_autorec_add_series_link(const char *dvr_config_name,

View file

@ -74,7 +74,7 @@ autorec_cmp(dvr_autorec_entry_t *dae, epg_broadcast_t *e)
if(dae->dae_channel == NULL &&
dae->dae_channel_tag == NULL &&
dae->dae_content_type == 0 &&
dae->dae_content_type.code == 0 &&
(dae->dae_title == NULL ||
dae->dae_title[0] == '\0') &&
dae->dae_brand == NULL &&
@ -91,7 +91,7 @@ autorec_cmp(dvr_autorec_entry_t *dae, epg_broadcast_t *e)
if(dae->dae_title != NULL && dae->dae_title[0] != '\0') {
if(e->episode->title == NULL ||
regexec(&dae->dae_title_preg, e->episode->title, 0, NULL, 0))
return 0;
return 0;
}
// Note: ignore channel test if we allow quality unlocking
@ -109,15 +109,9 @@ autorec_cmp(dvr_autorec_entry_t *dae, epg_broadcast_t *e)
return 0;
}
if(dae->dae_content_type != 0) {
int i, ok = 0;
for (i = 0; i < e->episode->genre_cnt; i++) {
if (e->episode->genre[i] == dae->dae_content_type) {
ok = 1;
break;
}
}
if (!ok) return 0;
if(dae->dae_content_type.code != 0) {
if (!epg_genre_list_contains(&e->episode->genre, &dae->dae_content_type, 1))
return 0;
}
if(dae->dae_approx_time != 0) {
@ -275,7 +269,7 @@ autorec_record_build(dvr_autorec_entry_t *dae)
if(dae->dae_channel_tag != NULL)
htsmsg_add_str(e, "tag", dae->dae_channel_tag->ct_name);
htsmsg_add_u32(e, "contenttype",dae->dae_content_type);
htsmsg_add_u32(e, "contenttype",dae->dae_content_type.code);
htsmsg_add_str(e, "title", dae->dae_title ?: "");
@ -389,7 +383,7 @@ autorec_record_update(void *opaque, const char *id, htsmsg_t *values,
}
}
dae->dae_content_type = htsmsg_get_u32_or_default(values, "contenttype", 0);
dae->dae_content_type.code = htsmsg_get_u32_or_default(values, "contenttype", 0);
if((s = htsmsg_get_str(values, "approx_time")) != NULL) {
if(strchr(s, ':') != NULL) {
@ -470,7 +464,7 @@ dvr_autorec_init(void)
static void
_dvr_autorec_add(const char *config_name,
const char *title, channel_t *ch,
const char *tag, uint8_t content_type,
const char *tag, epg_genre_t *content_type,
epg_brand_t *brand, epg_season_t *season,
int approx_time, epg_episode_num_t *epnum,
const char *creator, const char *comment)
@ -503,7 +497,8 @@ _dvr_autorec_add(const char *config_name,
}
dae->dae_enabled = 1;
dae->dae_content_type = content_type;
if (content_type)
dae->dae_content_type.code = content_type->code;
if(brand) {
dae->dae_brand = brand;
@ -535,7 +530,7 @@ _dvr_autorec_add(const char *config_name,
void
dvr_autorec_add(const char *config_name,
const char *title, const char *channel,
const char *tag, uint8_t content_type,
const char *tag, epg_genre_t *content_type,
const char *creator, const char *comment)
{
channel_t *ch = NULL;

View file

@ -249,7 +249,7 @@ static dvr_entry_t *_dvr_entry_create (
channel_t *ch, time_t start, time_t stop,
time_t start_extra, time_t stop_extra,
const char *title, const char *description,
uint8_t content_type,
epg_genre_t *content_type,
const char *creator, dvr_autorec_entry_t *dae,
dvr_prio_t pri)
{
@ -301,7 +301,7 @@ static dvr_entry_t *_dvr_entry_create (
de->de_creator = strdup(creator);
de->de_title = strdup(title);
de->de_desc = description ? strdup(description) : NULL;
de->de_content_type = content_type;
if (content_type) de->de_content_type = *content_type;
de->de_bcast = e;
if (e) e->getref((epg_object_t*)e);
@ -334,7 +334,7 @@ dvr_entry_create(const char *config_name,
channel_t *ch, time_t start, time_t stop,
time_t start_extra, time_t stop_extra,
const char *title, const char *description,
uint8_t content_type,
epg_genre_t *content_type,
const char *creator, dvr_autorec_entry_t *dae,
dvr_prio_t pri)
{
@ -363,7 +363,7 @@ dvr_entry_create_by_event(const char *config_name,
e->episode->title,
e->episode->description ? e->episode->description
: e->episode->summary,
e->episode->genre_cnt ? e->episode->genre[0] : 0,
LIST_FIRST(&e->episode->genre),
creator, dae, pri);
}
@ -530,7 +530,7 @@ dvr_db_load_one(htsmsg_t *c, int id)
}
de->de_content_type = htsmsg_get_u32_or_default(c, "contenttype", 0);
de->de_content_type.code = htsmsg_get_u32_or_default(c, "contenttype", 0);
if (!htsmsg_get_u32(c, "broadcast", &bcid)) {
de->de_bcast = epg_broadcast_find_by_id(bcid, ch);
@ -606,8 +606,8 @@ dvr_entry_save(dvr_entry_t *de)
if(de->de_autorec != NULL)
htsmsg_add_str(m, "autorec", de->de_autorec->dae_id);
if(de->de_content_type)
htsmsg_add_u32(m, "contenttype", de->de_content_type);
if(de->de_content_type.code)
htsmsg_add_u32(m, "contenttype", de->de_content_type.code);
if(de->de_bcast)
htsmsg_add_u32(m, "broadcast", de->de_bcast->id);
@ -666,10 +666,12 @@ static dvr_entry_t *_dvr_entry_update
}
if (e) {
if (e->episode &&
e->episode->genre_cnt && e->episode->genre_cnt != de->de_content_type) {
de->de_content_type = e->episode->genre[0];
save = 1;
epg_genre_t *g;
if (e->episode && (g = LIST_FIRST(&e->episode->genre))) {
if (g->code != de->de_content_type.code) {
de->de_content_type.code = g->code;
save = 1;
}
}
if (de->de_bcast != e) {
de->de_bcast->putref((epg_object_t*)de->de_bcast);

View file

@ -464,9 +464,9 @@ static htsbuf_queue_t *
_mk_build_metadata(const dvr_entry_t *de, const epg_broadcast_t *ebc)
{
htsbuf_queue_t *q = htsbuf_queue_alloc(0);
char datestr[64];
char datestr[64], ctype[100];
const epg_genre_t *eg = NULL;
struct tm tm;
const char *ctype = NULL;
localtime_r(de ? &de->de_start : &ebc->start, &tm);
epg_episode_t *ee = NULL;
channel_t *ch;
@ -490,12 +490,12 @@ _mk_build_metadata(const dvr_entry_t *de, const epg_broadcast_t *ebc)
addtag(q, build_tag_string("ORIGINAL_MEDIA_TYPE", "TV", 0, NULL));
if(de && de->de_content_type) {
ctype = epg_genre_get_name(de->de_content_type, 0);
} else if (ee && ee->genre_cnt) {
ctype = epg_genre_get_name(ee->genre[0], 0);
if(de && de->de_content_type.code) {
eg = &de->de_content_type;
} else if (ee) {
eg = LIST_FIRST(&ee->genre);
}
if(ctype != NULL)
if(eg && epg_genre_get_str(eg, 1, 0, ctype, 100))
addtag(q, build_tag_string("CONTENT_TYPE", ctype, 0, NULL));
if(ch)

250
src/epg.c
View file

@ -343,33 +343,33 @@ int epg_brand_set_season_count ( epg_brand_t *brand, uint16_t count )
static void _epg_brand_add_season
( epg_brand_t *brand, epg_season_t *season )
{
LIST_INSERT_SORTED(&brand->seasons, season, blink, _season_order);
_epg_object_getref(brand);
_epg_object_set_updated(brand);
LIST_INSERT_SORTED(&brand->seasons, season, blink, _season_order);
}
static void _epg_brand_rem_season
( epg_brand_t *brand, epg_season_t *season )
{
LIST_REMOVE(season, blink);
_epg_object_putref(brand);
_epg_object_set_updated(brand);
_epg_object_putref(brand);
}
static void _epg_brand_add_episode
( epg_brand_t *brand, epg_episode_t *episode )
{
LIST_INSERT_SORTED(&brand->episodes, episode, blink, _episode_order);
_epg_object_getref(brand);
_epg_object_set_updated(brand);
LIST_INSERT_SORTED(&brand->episodes, episode, blink, _episode_order);
}
static void _epg_brand_rem_episode
( epg_brand_t *brand, epg_episode_t *episode )
{
LIST_REMOVE(episode, blink);
_epg_object_putref(brand);
_epg_object_set_updated(brand);
_epg_object_putref(brand);
}
htsmsg_t *epg_brand_serialize ( epg_brand_t *brand )
@ -509,17 +509,17 @@ int epg_season_set_brand ( epg_season_t *season, epg_brand_t *brand, int u )
static void _epg_season_add_episode
( epg_season_t *season, epg_episode_t *episode )
{
LIST_INSERT_SORTED(&season->episodes, episode, slink, _episode_order);
_epg_object_getref(season);
_epg_object_set_updated(season);
LIST_INSERT_SORTED(&season->episodes, episode, slink, _episode_order);
}
static void _epg_season_rem_episode
( epg_season_t *season, epg_episode_t *episode )
{
LIST_REMOVE(episode, slink);
_epg_object_putref(season);
_epg_object_set_updated(season);
_epg_object_putref(season);
}
htsmsg_t *epg_season_serialize ( epg_season_t *season )
@ -618,6 +618,7 @@ static epg_episode_num_t *epg_episode_num_deserialize
static void _epg_episode_destroy ( void *eo )
{
epg_genre_t *g;
epg_episode_t *ee = eo;
if (LIST_FIRST(&ee->broadcasts)) {
tvhlog(LOG_CRIT, "epg", "attempt to destroy episode with broadcasts");
@ -630,7 +631,10 @@ static void _epg_episode_destroy ( void *eo )
if (ee->subtitle) free(ee->subtitle);
if (ee->summary) free(ee->summary);
if (ee->description) free(ee->description);
if (ee->genre) free(ee->genre);
while ((g = LIST_FIRST(&ee->genre))) {
LIST_REMOVE(g, link);
free(g);
}
if (ee->image) free(ee->image);
if (ee->epnum.text) free(ee->epnum.text);
free(ee);
@ -761,69 +765,52 @@ int epg_episode_set_season ( epg_episode_t *episode, epg_season_t *season )
return save;
}
int epg_episode_set_genre ( epg_episode_t *ee, const uint8_t *genre, int cnt )
int epg_episode_set_genre ( epg_episode_t *ee, epg_genre_list_t *genre )
{
int i, save = 0;
if (!ee || !genre || !cnt) return 0;
if (cnt != ee->genre_cnt)
save = 1;
else {
for (i = 0; i < cnt; i++ ) {
if (genre[i] != ee->genre[i]) {
save = 1;
break;
}
}
}
if (save) {
if (cnt > ee->genre_cnt)
ee->genre = realloc(ee->genre, cnt * sizeof(uint8_t));
memcpy(ee->genre, genre, cnt * sizeof(uint8_t));
ee->genre_cnt = cnt;
}
return save;
}
int save = 0;
epg_genre_t *g1, *g2;
// Note: only works for the EN 300 468 defined names
int epg_episode_set_genre_str ( epg_episode_t *ee, const char **gstr )
{
static int gcnt = 0;
static uint8_t *genre;
int cnt = 0;
while (gstr[cnt]) cnt++;
if (!cnt) return 0;
if (cnt > gcnt) {
genre = realloc(genre, sizeof(uint8_t) * cnt);
gcnt = cnt;
/* Remove old */
g1 = LIST_FIRST(&ee->genre);
while (g1) {
g2 = LIST_NEXT(g1, link);
if (!epg_genre_list_contains(genre, g1, 0)) {
LIST_REMOVE(g1, link);
save = 1;
}
g1 = g2;
}
cnt = 0;
while (gstr[cnt]) {
genre[cnt] = epg_genre_find_by_name(gstr[cnt]);
cnt++;
/* Insert all entries */
LIST_FOREACH(g1, genre, link) {
save |= epg_genre_list_add(&ee->genre, g1);
}
return epg_episode_set_genre(ee, genre, gcnt);
return save;
}
int epg_episode_set_is_bw ( epg_episode_t *e, uint8_t bw )
{
int save = 0;
if (!e) return 0;
return _epg_object_set_u8(e, &e->is_bw, bw);
return save;
}
static void _epg_episode_add_broadcast
( epg_episode_t *episode, epg_broadcast_t *broadcast )
{
LIST_INSERT_SORTED(&episode->broadcasts, broadcast, ep_link, _ebc_start_cmp);
_epg_object_getref(episode);
_epg_object_set_updated(episode);
LIST_INSERT_SORTED(&episode->broadcasts, broadcast, ep_link, _ebc_start_cmp);
}
static void _epg_episode_rem_broadcast
( epg_episode_t *episode, epg_broadcast_t *broadcast )
{
LIST_REMOVE(broadcast, ep_link);
_epg_object_putref(episode);
_epg_object_set_updated(episode);
_epg_object_putref(episode);
}
size_t epg_episode_number_format
@ -893,7 +880,8 @@ int epg_episode_fuzzy_match
htsmsg_t *epg_episode_serialize ( epg_episode_t *episode )
{
htsmsg_t *m;
epg_genre_t *eg;
htsmsg_t *m, *a = NULL;
if (!episode || !episode->uri) return NULL;
if (!(m = _epg_object_serialize((epg_object_t*)episode))) return NULL;
htsmsg_add_str(m, "uri", episode->uri);
@ -905,7 +893,12 @@ htsmsg_t *epg_episode_serialize ( epg_episode_t *episode )
htsmsg_add_str(m, "summary", episode->summary);
if (episode->description)
htsmsg_add_str(m, "description", episode->description);
htsmsg_add_msg(m, "epnum", epg_episode_num_serialize(&episode->epnum));
htsmsg_add_msg(m, "epnum", epg_episode_num_serialize(&episode->epnum));
LIST_FOREACH(eg, &episode->genre, link) {
if (!a) a = htsmsg_create_list();
htsmsg_add_u32(a, NULL, eg->code);
}
if (a) htsmsg_add_msg(m, "genre", a);
if (episode->brand)
htsmsg_add_str(m, "brand", episode->brand->uri);
if (episode->season)
@ -924,6 +917,7 @@ epg_episode_t *epg_episode_deserialize ( htsmsg_t *m, int create, int *save )
const char *str;
epg_episode_num_t num;
htsmsg_t *sub;
htsmsg_field_t *f;
if ( !_epg_object_deserialize(m, *skel) ) return NULL;
if ( !(ee = epg_episode_find_by_uri((*skel)->uri, create, save)) ) return NULL;
@ -941,6 +935,17 @@ epg_episode_t *epg_episode_deserialize ( htsmsg_t *m, int create, int *save )
*save |= epg_episode_set_epnum(ee, &num);
if (num.text) free(num.text);
}
if ( (sub = htsmsg_get_list(m, "genre")) ) {
epg_genre_list_t *egl = calloc(1, sizeof(epg_genre_list_t));
HTSMSG_FOREACH(f, sub) {
epg_genre_t genre;
genre.code = (uint8_t)f->hmf_s64;
epg_genre_list_add(egl, &genre);
}
*save |= epg_episode_set_genre(ee, egl);
epg_genre_list_destroy(egl);
}
if ( (str = htsmsg_get_str(m, "season")) )
if ( (es = epg_season_find_by_uri(str, 0, NULL)) )
*save |= epg_episode_set_season(ee, es);
@ -1045,6 +1050,7 @@ static epg_broadcast_t *_epg_channel_add_broadcast
ret = *bcast;
*bcast = NULL;
_epg_object_create(ret);
// Note: sets updated
_epg_object_getref(ret);
/* No change */
@ -1054,6 +1060,7 @@ static epg_broadcast_t *_epg_channel_add_broadcast
/* Extend in time */
} else {
ret->stop = (*bcast)->stop;
_epg_object_set_updated(ret);
}
}
@ -1334,11 +1341,12 @@ epg_broadcast_t *epg_broadcast_deserialize
* Genre
* *************************************************************************/
// TODO: make this configurable
// FULL(ish) list from EN 300 468, I've excluded the last category
// that relates more to broadcast content than what I call a "genre"
// these will be handled elsewhere as broadcast metadata
static const char *_epg_genre_names[16][16] = {
{},
{ "" },
{
"Movie/Drama",
"detective/thriller",
@ -1505,7 +1513,7 @@ static int _genre_str_match ( const char *a, const char *b )
return (a[i] == '\0' && b[j] == '\0'); // end of string(both)
}
uint8_t epg_genre_find_by_name ( const char *name )
static uint8_t _epg_genre_find_by_name ( const char *name )
{
uint8_t a, b;
for ( a = 1; a < 11; a++ ) {
@ -1517,12 +1525,131 @@ uint8_t epg_genre_find_by_name ( const char *name )
return 0; // undefined
}
const char *epg_genre_get_name ( uint8_t genre, int full )
uint8_t epg_genre_get_eit ( const epg_genre_t *genre )
{
int a, b = 0;
a = (genre >> 4) & 0xF;
if (full) b = (genre & 0xF);
return _epg_genre_names[a][b];
if (!genre) return 0;
return genre->code;
}
size_t epg_genre_get_str ( const epg_genre_t *genre, int major_only,
int major_prefix, char *buf, size_t len )
{
int maj, min;
size_t ret = 0;
if (!genre || !buf) return 0;
maj = (genre->code >> 4) & 0xf;
if (!_epg_genre_names[maj][0]) return 0;
min = major_only ? 0 : (genre->code & 0xf);
if (!min || major_prefix ) {
ret = snprintf(buf, len, "%s", _epg_genre_names[maj][0]);
if (min) ret += snprintf(buf+ret, len-ret, " : ");
}
if (min && _epg_genre_names[maj][min]) {
ret += snprintf(buf+ret, len-ret, "%s", _epg_genre_names[maj][min]);
}
return ret;
}
int epg_genre_list_add ( epg_genre_list_t *list, epg_genre_t *genre )
{
epg_genre_t *g1, *g2;
if (!list || !genre || !genre->code) return 0;
g1 = LIST_FIRST(list);
if (!g1) {
g2 = calloc(1, sizeof(epg_genre_t));
g2->code = genre->code;
LIST_INSERT_HEAD(list, g2, link);
} else {
while (g1) {
/* Already exists */
if (g1->code == genre->code) return 0;
/* Update a major only entry */
if (g1->code == (genre->code & 0xF0)) {
g1->code = genre->code;
break;
}
/* Insert before */
if (g1->code > genre->code) {
g2 = calloc(1, sizeof(epg_genre_t));
g2->code = genre->code;
LIST_INSERT_BEFORE(g1, g2, link);
break;
}
/* Insert after (end) */
if (!(g2 = LIST_NEXT(g1, link))) {
g2 = calloc(1, sizeof(epg_genre_t));
g2->code = genre->code;
LIST_INSERT_AFTER(g1, g2, link);
break;
}
/* Next */
g1 = g2;
}
}
return 1;
}
int epg_genre_list_add_by_eit ( epg_genre_list_t *list, uint8_t eit )
{
epg_genre_t g;
g.code = eit;
return epg_genre_list_add(list, &g);
}
int epg_genre_list_add_by_str ( epg_genre_list_t *list, const char *str )
{
epg_genre_t g;
g.code = _epg_genre_find_by_name(str);
return epg_genre_list_add(list, &g);
}
// Note: if partial=1 and genre is a major only category then all minor
// entries will also match
int epg_genre_list_contains
( epg_genre_list_t *list, epg_genre_t *genre, int partial )
{
uint8_t mask = 0xFF;
epg_genre_t *g;
if (!list || !genre) return 0;
if (partial && !(genre->code & 0x0F)) mask = 0xF0;
LIST_FOREACH(g, list, link) {
if ((g->code & mask) == genre->code) break;
}
return g ? 1 : 0;
}
void epg_genre_list_destroy ( epg_genre_list_t *list )
{
epg_genre_t *g;
while ((g = LIST_FIRST(list))) {
LIST_REMOVE(g, link);
free(g);
}
free(list);
}
htsmsg_t *epg_genres_list_all ( int major_only, int major_prefix )
{
int i, j;
htsmsg_t *e, *m;
m = htsmsg_create_list();
for (i = 0; i < 16; i++ ) {
for (j = 0; j < (major_only ? 1 : 16); j++) {
if (_epg_genre_names[i][j]) {
e = htsmsg_create_map();
htsmsg_add_u32(e, "code", i << 4 | j);
htsmsg_add_str(e, "name", _epg_genre_names[i][j]);
// TODO: use major_prefix
htsmsg_add_msg(m, NULL, e);
}
}
}
return m;
}
/* **************************************************************************
@ -1531,12 +1658,12 @@ const char *epg_genre_get_name ( uint8_t genre, int full )
static void _eqr_add
( epg_query_result_t *eqr, epg_broadcast_t *e,
uint8_t genre, regex_t *preg, time_t start )
epg_genre_t *genre, regex_t *preg, time_t start )
{
/* Ignore */
if ( e->stop < start ) return;
if ( genre && e->episode->genre_cnt && e->episode->genre[0] != genre ) return;
if ( !e->episode->title ) return;
if ( genre && !epg_genre_list_contains(&e->episode->genre, genre, 1) ) return;
if ( preg && regexec(preg, e->episode->title, 0, NULL, 0) ) return;
/* More space */
@ -1551,7 +1678,7 @@ static void _eqr_add
}
static void _eqr_add_channel
( epg_query_result_t *eqr, channel_t *ch, uint8_t genre,
( epg_query_result_t *eqr, channel_t *ch, epg_genre_t *genre,
regex_t *preg, time_t start )
{
epg_broadcast_t *ebc;
@ -1562,7 +1689,7 @@ static void _eqr_add_channel
void epg_query0
( epg_query_result_t *eqr, channel_t *channel, channel_tag_t *tag,
uint8_t genre, const char *title )
epg_genre_t *genre, const char *title )
{
time_t now;
channel_tag_mapping_t *ctm;
@ -1604,12 +1731,11 @@ void epg_query0
}
void epg_query(epg_query_result_t *eqr, const char *channel, const char *tag,
const char *genre, const char *title)
epg_genre_t *genre, const char *title)
{
channel_t *ch = channel ? channel_find_by_name(channel, 0, 0) : NULL;
channel_tag_t *ct = tag ? channel_tag_find_by_name(tag, 0) : NULL;
uint8_t ge = genre ? epg_genre_find_by_name(genre) : 0;
epg_query0(eqr, ch, ct, ge, title);
epg_query0(eqr, ch, ct, genre, title);
}
void epg_query_free(epg_query_result_t *eqr)

View file

@ -28,7 +28,7 @@ struct channel;
struct channel_tag;
/*
* Map types
* Map/List types
*/
LIST_HEAD(epg_object_list, epg_object);
RB_HEAD (epg_object_tree, epg_object);
@ -37,10 +37,12 @@ LIST_HEAD(epg_season_list, epg_season);
LIST_HEAD(epg_episode_list, epg_episode);
LIST_HEAD(epg_broadcast_list, epg_broadcast);
RB_HEAD (epg_broadcast_tree, epg_broadcast);
LIST_HEAD(epg_genre_list, epg_genre);
/*
* Typedefs (most are redundant!)
*/
typedef struct epg_genre epg_genre_t;
typedef struct epg_object epg_object_t;
typedef struct epg_brand epg_brand_t;
typedef struct epg_season epg_season_t;
@ -52,6 +54,38 @@ typedef struct epg_broadcast_list epg_broadcast_list_t;
typedef struct epg_broadcast_tree epg_broadcast_tree_t;
typedef struct epg_object_list epg_object_list_t;
typedef struct epg_object_tree epg_object_tree_t;
typedef struct epg_genre_list epg_genre_list_t;
/* ************************************************************************
* Genres
* ***********************************************************************/
/* Genre object */
struct epg_genre
{
LIST_ENTRY(epg_genre) link;
uint8_t code;
};
/* Accessors */
uint8_t epg_genre_get_eit ( const epg_genre_t *genre );
size_t epg_genre_get_str ( const epg_genre_t *genre, int major_only,
int major_prefix, char *buf, size_t len );
/* Delete */
void epg_genre_list_destroy ( epg_genre_list_t *list );
/* Add to list */
int epg_genre_list_add ( epg_genre_list_t *list, epg_genre_t *genre );
int epg_genre_list_add_by_eit ( epg_genre_list_t *list, uint8_t eit );
int epg_genre_list_add_by_str ( epg_genre_list_t *list, const char *str );
/* Search */
int epg_genre_list_contains
( epg_genre_list_t *list, epg_genre_t *genre, int partial );
/* List all available genres */
htsmsg_t *epg_genres_list_all ( int major_only, int major_prefix );
/* ************************************************************************
* Generic Object
@ -198,11 +232,10 @@ struct epg_episode
char *subtitle; ///< Sub-title
char *summary; ///< Summary
char *description; ///< An extended description
uint8_t *genre; ///< Episode genre(s)
int genre_cnt; ///< Genre count
char *image; ///< Episode image
epg_genre_list_t genre; ///< Episode genre(s)
epg_episode_num_t epnum; ///< Episode numbering
// Note: do not use epnum directly! use the accessor routine
char *image; ///< Episode image
uint8_t is_bw; ///< Is black and white
// TODO: certification and rating
@ -213,7 +246,6 @@ struct epg_episode
epg_brand_t *brand; ///< (Grand-)Parent brand
epg_season_t *season; ///< Parent season
epg_broadcast_list_t broadcasts; ///< Broadcast list
};
/* Lookup */
@ -241,7 +273,7 @@ int epg_episode_set_brand ( epg_episode_t *e, epg_brand_t *b )
__attribute__((warn_unused_result));
int epg_episode_set_season ( epg_episode_t *e, epg_season_t *s )
__attribute__((warn_unused_result));
int epg_episode_set_genre ( epg_episode_t *e, const uint8_t *g, int c )
int epg_episode_set_genre ( epg_episode_t *e, epg_genre_list_t *g )
__attribute__((warn_unused_result));
int epg_episode_set_genre_str ( epg_episode_t *e, const char **s )
__attribute__((warn_unused_result));
@ -359,13 +391,6 @@ epg_broadcast_t *epg_broadcast_deserialize
/* Unlink */
void epg_channel_unlink ( struct channel *ch );
/* ************************************************************************
* Genre
* ***********************************************************************/
uint8_t epg_genre_find_by_name ( const char *name );
const char *epg_genre_get_name ( uint8_t genre, int full );
/* ************************************************************************
* Querying
* ***********************************************************************/
@ -387,9 +412,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, uint8_t type, const char *title);
struct channel_tag *ct, epg_genre_t *genre, const char *title);
void epg_query(epg_query_result_t *eqr, const char *channel, const char *tag,
const char *contentgroup, const char *title);
epg_genre_t *genre, const char *title);
/* ************************************************************************

View file

@ -61,12 +61,18 @@ typedef struct epggrab_stats
* Grabber Channels
* *************************************************************************/
/*
* Lists
*/
RB_HEAD(epggrab_channel_tree, epggrab_channel);
typedef struct epggrab_channel_tree epggrab_channel_tree_t;
/*
* Grab channel
*/
typedef struct epggrab_channel
{
RB_ENTRY(epggrab_channel) link; ///< Global link
RB_ENTRY(epggrab_channel) link; ///< Global link
epggrab_module_t *mod; ///< Linked module
char *id; ///< Grabber's ID
@ -74,19 +80,10 @@ typedef struct epggrab_channel
char *name; ///< Channel name
char *icon; ///< Channel icon
int number; ///< Channel number
char **sname; ///< Service name's
uint16_t *sid; ///< Service ID's
struct channel *channel; ///< Mapped channel
} epggrab_channel_t;
/*
* Channel list structure
*/
RB_HEAD(epggrab_channel_tree, epggrab_channel);
typedef struct epggrab_channel_tree epggrab_channel_tree_t;
/*
* Access functions
*/
@ -95,11 +92,9 @@ htsmsg_t* epggrab_channel_list ( void );
/*
* Mutators
*/
int epggrab_channel_set_name ( epggrab_channel_t *ch, const char *name );
int epggrab_channel_set_icon ( epggrab_channel_t *ch, const char *icon );
int epggrab_channel_set_number ( epggrab_channel_t *ch, int number );
int epggrab_channel_set_sname ( epggrab_channel_t *ch, const char **sname );
int epggrab_channel_set_sid ( epggrab_channel_t *ch, const uint16_t *sid );
int epggrab_channel_set_name ( epggrab_channel_t *ch, const char *name );
int epggrab_channel_set_icon ( epggrab_channel_t *ch, const char *icon );
int epggrab_channel_set_number ( epggrab_channel_t *ch, int number );
/*
* Updated/link

View file

@ -36,39 +36,13 @@
// returns 1 if link made
int epggrab_channel_link ( epggrab_channel_t *ec, channel_t *ch )
{
service_t *sv;
int match = 0, i;
int match = 0;
if (!ec || !ch) return 0;
if (ec->channel) return 0;
if (ec->name && !strcmp(ec->name, ch->ch_name))
match = 1;
else {
LIST_FOREACH(sv, &ch->ch_services, s_ch_link) {
if (ec->sid) {
i = 0;
while (ec->sid[i]) {
if (sv->s_dvb_service_id == ec->sid[i]) {
match = 1;
break;
}
i++;
}
}
if (!match && ec->sname) {
i = 0;
while (ec->sname[i]) {
if (!strcmp(ec->sname[i], sv->s_svcname)) {
match = 1;
break;
}
i++;
}
}
if (match) break;
}
}
if (match) {
tvhlog(LOG_INFO, ec->mod->id, "linking %s to %s",
@ -129,63 +103,6 @@ int epggrab_channel_set_number ( epggrab_channel_t *ec, int number )
return save;
}
/* Set service IDs */
int epggrab_channel_set_sid
( epggrab_channel_t *ec, const uint16_t *sid )
{
int save = 0, i;
if ( !ec || !sid ) return 0;
if (!ec->sid) save = 1;
else {
i = 0;
while ( ec->sid[i] && sid[i] ) {
if ( ec->sid[i] != sid[i] ) break;
i++;
}
if (ec->sid[i] || sid[i]) save = 1;
}
if (save) {
i = 0;
while (ec->sid[i++]);
if (ec->sid) free(ec->sid);
ec->sid = calloc(i, sizeof(uint16_t));
memcpy(ec->sid, sid, i * sizeof(uint16_t));
}
return save;
}
/* Set names */
int epggrab_channel_set_sname ( epggrab_channel_t *ec, const char **sname )
{
int save = 0, i = 0;
if ( !ec || !sname ) return 0;
if (!ec->sname) save = 1;
else {
while ( ec->sname[i] && sname[i] ) {
if (strcmp(ec->sname[i], sname[i])) break;
i++;
}
if (ec->sname[i] || sname[i]) save = 1;
}
if (save) {
if (ec->sname) {
i = 0;
while (ec->sname[i])
free(ec->sname[i++]);
free(ec->sname);
}
i = 0;
while (sname[i++]);
ec->sname = calloc(i+1, sizeof(char*));
i = 0;
while (sname[i]) {
ec->sname[i] = strdup(sname[i]);
i++;
}
}
return save;
}
/* Channel settings updated */
void epggrab_channel_updated ( epggrab_channel_t *ec )
{

View file

@ -142,9 +142,7 @@ void epggrab_module_parse
void epggrab_module_ch_save ( void *_m, epggrab_channel_t *ch )
{
int i;
htsmsg_t *m = htsmsg_create_map();
htsmsg_t *a;
epggrab_module_t *mod = _m;
if (ch->name)
@ -153,24 +151,6 @@ void epggrab_module_ch_save ( void *_m, epggrab_channel_t *ch )
htsmsg_add_str(m, "icon", ch->icon);
if (ch->channel)
htsmsg_add_u32(m, "channel", ch->channel->ch_id);
if (ch->sid) {
a = htsmsg_create_list();
i = 0;
while (ch->sid[i]) {
htsmsg_add_u32(a, NULL, ch->sid[i]);
i++;
}
htsmsg_add_msg(m, "sid", a);
}
if (ch->sname) {
a = htsmsg_create_list();
i = 0;
while (ch->sname[i]) {
htsmsg_add_str(a, NULL, ch->sname[i]);
i++;
}
htsmsg_add_msg(m, "sname", a);
}
if (ch->number)
htsmsg_add_u32(m, "number", ch->number);
@ -210,11 +190,9 @@ void epggrab_module_ch_mod ( void *mod, channel_t *ch )
static void _epggrab_module_channel_load
( epggrab_module_t *mod, htsmsg_t *m, const char *id )
{
int save = 0, i;
int save = 0;
const char *str;
uint32_t u32;
htsmsg_t *a;
htsmsg_field_t *f;
epggrab_channel_t *ch = epggrab_channel_find(mod->channels, id, 1, &save, mod);
@ -222,28 +200,6 @@ static void _epggrab_module_channel_load
ch->name = strdup(str);
if ((str = htsmsg_get_str(m, "icon")))
ch->icon = strdup(str);
if ((a = htsmsg_get_list(m, "sid"))) {
i = 0;
HTSMSG_FOREACH(f, a) i++;
if (i) {
ch->sid = calloc(i+1, sizeof(uint16_t));
i = 0;
HTSMSG_FOREACH(f, a) {
ch->sid[i++] = (uint16_t)f->hmf_s64;
}
}
}
if ((a = htsmsg_get_list(m, "sname"))) {
i = 0;
HTSMSG_FOREACH(f, a) i++;
if (i) {
ch->sname = calloc(i+1, sizeof(char*));
i = 0;
HTSMSG_FOREACH(f, a) {
ch->sname[i++] = strdup(f->hmf_str);
}
}
}
if(!htsmsg_get_u32(m, "number", &u32))
ch->number = u32;

View file

@ -152,13 +152,12 @@ static int _eit_callback
channel_t *ch;
epg_broadcast_t *ebc;
epg_episode_t *ee;
epg_genre_list_t *egl = NULL;
eit_status_t *sta;
int resched = 0, save = 0, save2 = 0, dllen, dtag, dlen;
uint16_t tsid, sid, eid;
uint8_t bw, hd, ws, ad, ds, st;
time_t start, stop;
int genre_idx = 0;
uint8_t genre[10];
char title[256];
char summary[256];
char desc[5000];
@ -260,7 +259,6 @@ static int _eit_callback
/* Process tags */
*title = *summary = *desc = 0;
extra = NULL;
genre_idx = 0;
hd = ws = bw = ad = st = ds = 0;
while(dllen > 0) {
dtag = ptr[0];
@ -296,8 +294,10 @@ static int _eit_callback
dlen -= 2;
if ( *ptr == 0xb1 )
bw = 1;
else if ( *ptr < 0xb0 && genre_idx < sizeof(genre) )
genre[genre_idx++] = *ptr;
else if ( *ptr < 0xb0 ) {
if (!egl) egl = calloc(1, sizeof(epg_genre_list_t));
epg_genre_list_add_by_eit(egl, *ptr);
}
}
break;
@ -376,8 +376,8 @@ static int _eit_callback
char *uri;
uri = epg_hash(title, summary, desc);
if (uri) {
ee = epg_episode_find_by_uri(uri, 1, &save2);
save |= epg_broadcast_set_episode(ebc, ee);
if ((ee = epg_episode_find_by_uri(uri, 1, &save2)))
save |= epg_broadcast_set_episode(ebc, ee);
free(uri);
}
}
@ -392,14 +392,17 @@ static int _eit_callback
save |= epg_episode_set_summary(ee, summary);
if ( !ee->description && *desc )
save |= epg_episode_set_description(ee, desc);
if ( !ee->genre_cnt && genre_idx )
save |= epg_episode_set_genre(ee, genre, genre_idx);
if ( !LIST_FIRST(&ee->genre) && egl )
save |= epg_episode_set_genre(ee, egl);
#if TODO_ADD_EXTRA
if ( extra )
save |= epg_episode_set_extra(ee, extra);
#endif
}
/* Tidy up */
if (extra) free(extra);
if (egl) epg_genre_list_destroy(egl);
}
/* Update EPG */

View file

@ -405,8 +405,12 @@ static int _opentv_parse_event_section
save |= epg_episode_set_summary(ee, ev.summary);
if (ev.desc)
save |= epg_episode_set_description(ee, ev.desc);
if (ev.cat)
save |= epg_episode_set_genre(ee, &ev.cat, 1);
if (ev.cat) {
epg_genre_list_t *egl = calloc(1, sizeof(epg_genre_list_t));
epg_genre_list_add_by_eit(egl, ev.cat);
save |= epg_episode_set_genre(ee, egl);
epg_genre_list_destroy(egl);
}
// Note: don't override the season (since the ID is channel specific
// it'll keep changing!
if (ev.series && !ee->season) {

View file

@ -55,23 +55,29 @@ static int _pyepg_parse_time ( const char *str, time_t *out )
return ret;
}
static const uint8_t *_pyepg_parse_genre ( htsmsg_t *tags, int *cnt )
static epg_genre_list_t
*_pyepg_parse_genre ( htsmsg_t *tags )
{
// TODO: implement this
return NULL;
htsmsg_t *e;
htsmsg_field_t *f;
epg_genre_list_t *egl = NULL;
HTSMSG_FOREACH(f, tags) {
if (!strcmp(f->hmf_name, "genre") && (e = htsmsg_get_map_by_field(f))) {
if (!egl) { egl = calloc(1, sizeof(epg_genre_list_t)); printf("alloc %p\n", egl); }
printf("GENRE %s\n", htsmsg_get_str(e, "cdata"));
epg_genre_list_add_by_str(egl, htsmsg_get_str(e, "cdata"));
}
}
return egl;
}
static int _pyepg_parse_channel ( htsmsg_t *data, epggrab_stats_t *stats )
{
int save = 0;
epggrab_channel_t *ch;
htsmsg_t *attr, *tags, *e;
htsmsg_field_t *f;
htsmsg_t *attr, *tags;
const char *str;
uint32_t u32;
const char *sname[11];
uint16_t sid[11];
int sid_idx = 0, sname_idx = 0;
if ( data == NULL ) return 0;
@ -90,34 +96,6 @@ static int _pyepg_parse_channel ( htsmsg_t *data, epggrab_stats_t *stats )
if ((!htsmsg_xml_get_cdata_u32(tags, "number", &u32)))
save |= epggrab_channel_set_number(ch, u32);
HTSMSG_FOREACH(f, tags) {
if (!strcmp(f->hmf_name, "sid")) {
if (sid_idx < 10) {
e = htsmsg_get_map_by_field(f);
if (!htsmsg_get_u32(e, "cdata", &u32)) {
sid[sid_idx] = (uint16_t)u32;
sid_idx++;
}
}
} else if (!strcmp(f->hmf_name, "sname")) {
if (sname_idx < 10) {
e = htsmsg_get_map_by_field(f);
if ((str = htsmsg_get_str(e, "cdata"))) {
sname[sname_idx] = str;
sname_idx++;
}
}
}
}
if (sid_idx) {
sid[sid_idx] = 0;
save |= epggrab_channel_set_sid(ch, sid);
}
if (sname_idx) {
sname[sname_idx] = NULL;
save |= epggrab_channel_set_sname(ch, sname);
}
/* Update */
if (save) {
epggrab_channel_updated(ch);
@ -229,14 +207,14 @@ static int _pyepg_parse_season ( htsmsg_t *data, epggrab_stats_t *stats )
static int _pyepg_parse_episode ( htsmsg_t *data, epggrab_stats_t *stats )
{
int genre_cnt, save = 0;
int save = 0;
htsmsg_t *attr, *tags;
epg_episode_t *episode;
epg_season_t *season;
epg_brand_t *brand;
const char *str;
uint32_t u32, pc, pn;
const uint8_t *genre;
epg_genre_list_t *egl;
if ( data == NULL ) return 0;
@ -294,8 +272,9 @@ static int _pyepg_parse_episode ( htsmsg_t *data, epggrab_stats_t *stats )
}
/* Genre */
if ((genre = _pyepg_parse_genre(tags, &genre_cnt))) {
save |= epg_episode_set_genre(episode, genre, genre_cnt);
if ((egl = _pyepg_parse_genre(tags))) {
save |= epg_episode_set_genre(episode, egl);
epg_genre_list_destroy(egl);
}
/* Content */

View file

@ -286,6 +286,24 @@ xmltv_parse_accessibility ( epg_broadcast_t *ebc, htsmsg_t *m )
return save;
}
/*
* Parse category list
*/
static epg_genre_list_t
*_xmltv_parse_categories ( htsmsg_t *tags )
{
htsmsg_t *e;
htsmsg_field_t *f;
epg_genre_list_t *egl = NULL;
HTSMSG_FOREACH(f, tags) {
if (!strcmp(f->hmf_name, "category") && (e = htsmsg_get_map_by_field(f))) {
if (!egl) egl = calloc(1, sizeof(epg_genre_list_t));
epg_genre_list_add_by_str(egl, htsmsg_get_str(e, "cdata"));
}
}
return egl;
}
/**
* Parse tags inside of a programme
*/
@ -296,12 +314,12 @@ _xmltv_parse_programme_tags(channel_t *ch, htsmsg_t *tags,
int save = 0, save2 = 0;
epg_episode_t *ee;
epg_broadcast_t *ebc;
epg_genre_list_t *egl;
int sn = 0, sc = 0, en = 0, ec = 0, pn = 0, pc = 0;
const char *onscreen = NULL;
char *uri;
const char *title = htsmsg_xml_get_cdata_str(tags, "title");
const char *desc = htsmsg_xml_get_cdata_str(tags, "desc");
const char *category[2];
const char *title = htsmsg_xml_get_cdata_str(tags, "title");
const char *desc = htsmsg_xml_get_cdata_str(tags, "desc");
get_episode_info(tags, &onscreen, &sn, &sc, &en, &ec, &pn, &pc);
/* Ignore */
@ -315,11 +333,12 @@ _xmltv_parse_programme_tags(channel_t *ch, htsmsg_t *tags,
stats->episodes.total++;
if (save) stats->episodes.created++;
category[0] = htsmsg_xml_get_cdata_str(tags, "category");
category[1] = NULL;
if (title) save |= epg_episode_set_title(ee, title);
if (desc) save |= epg_episode_set_description(ee, desc);
if (*category) save |= epg_episode_set_genre_str(ee, category);
if ((egl = _xmltv_parse_categories(tags))) {
save |= epg_episode_set_genre(ee, egl);
epg_genre_list_destroy(egl);
}
if (pn) save |= epg_episode_set_part(ee, pn, pc);
if (en) save |= epg_episode_set_number(ee, en);
if (save) stats->episodes.modified++;

View file

@ -709,10 +709,11 @@ htsp_method_epgQuery(htsp_connection_t *htsp, htsmsg_t *in)
htsmsg_t *out, *eventIds;
const char *query;
int c, i;
uint32_t channelid, tagid, epg_content_dvbcode = 0;
uint32_t channelid, tagid, epg_content_dvbcode;
channel_t *ch = NULL;
channel_tag_t *ct = NULL;
epg_query_result_t eqr;
epg_genre_t genre, *eg = NULL;
//only mandatory parameter is the query
if( (query = htsmsg_get_str(in, "query")) == NULL )
@ -724,10 +725,13 @@ htsp_method_epgQuery(htsp_connection_t *htsp, htsmsg_t *in)
if( !(htsmsg_get_u32(in, "tagId", &tagid)) )
ct = channel_tag_find_by_identifier(tagid);
htsmsg_get_u32(in, "contentType", &epg_content_dvbcode);
if (!htsmsg_get_u32(in, "contentType", &epg_content_dvbcode)) {
genre.code = epg_content_dvbcode;
eg = &genre;
}
//do the query
epg_query0(&eqr, ch, ct, epg_content_dvbcode, query);
epg_query0(&eqr, ch, ct, eg, query);
c = eqr.eqr_entries;
// create reply
@ -754,6 +758,7 @@ htsp_build_event(epg_broadcast_t *e)
htsmsg_t *out;
epg_broadcast_t *n;
dvr_entry_t *de;
epg_genre_t *g;
out = htsmsg_create_map();
@ -769,9 +774,8 @@ htsp_build_event(epg_broadcast_t *e)
else if(e->episode->summary != NULL)
htsmsg_add_str(out, "description", e->episode->summary);
// TODO: only supports one entry!
if(e->episode->genre_cnt)
htsmsg_add_u32(out, "contentType", e->episode->genre[0]);
if((g = LIST_FIRST(&e->episode->genre)))
htsmsg_add_u32(out, "contentType", g->code);
}
if((de = dvr_entry_find_by_event(e)) != NULL) {

View file

@ -414,24 +414,11 @@ static int
extjs_ecglist(http_connection_t *hc, const char *remain, void *opaque)
{
htsbuf_queue_t *hq = &hc->hc_reply;
htsmsg_t *out, *array, *c;
const char *s;
int i;
out = htsmsg_create_map();
array = htsmsg_create_list();
for(i = 0; i < 16; i++) {
if((s = epg_genre_get_name(i<<4, 0)) == NULL)
continue;
c = htsmsg_create_map();
htsmsg_add_str(c, "name", s);
htsmsg_add_msg(array, NULL, c);
}
htsmsg_t *out, *array;
out = htsmsg_create_map();
array = epg_genres_list_all(1, 0);
htsmsg_add_msg(out, "entries", array);
htsmsg_json_serialize(out, hq, 0);
htsmsg_destroy(out);
http_output_content(hc, "text/x-json; charset=UTF-8");
@ -658,13 +645,13 @@ extjs_epg(http_connection_t *hc, const char *remain, void *opaque)
epg_query_result_t eqr;
epg_broadcast_t *e;
epg_episode_t *ee = NULL;
epg_genre_t *eg = NULL, genre;
channel_t *ch;
int start = 0, end, limit, i;
const char *s;
char buf[100];
const char *channel = http_arg_get(&hc->hc_req_args, "channel");
const char *tag = http_arg_get(&hc->hc_req_args, "tag");
const char *cgrp = http_arg_get(&hc->hc_req_args, "contentgrp");
const char *title = http_arg_get(&hc->hc_req_args, "title");
if(channel && !channel[0]) channel = NULL;
@ -678,12 +665,17 @@ extjs_epg(http_connection_t *hc, const char *remain, void *opaque)
else
limit = 20; /* XXX */
if ((s = http_arg_get(&hc->hc_req_args, "contenttype"))) {
genre.code = atoi(s);
eg = &genre;
}
out = htsmsg_create_map();
array = htsmsg_create_list();
pthread_mutex_lock(&global_lock);
epg_query(&eqr, channel, tag, cgrp, title);
epg_query(&eqr, channel, tag, eg, title);
epg_query_sort(&eqr);
@ -724,9 +716,9 @@ extjs_epg(http_connection_t *hc, const char *remain, void *opaque)
htsmsg_add_u32(m, "end", e->stop);
htsmsg_add_u32(m, "duration", e->stop - e->start);
if(ee->genre_cnt)
if((s = epg_genre_get_name(ee->genre[0], 0)))
htsmsg_add_str(m, "contentgrp", s);
if((eg = LIST_FIRST(&ee->genre))) {
htsmsg_add_u32(m, "contenttype", eg->code);
}
dvr_entry_t *de;
if((de = dvr_entry_find_by_event(e)) != NULL)
@ -1000,13 +992,17 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
htsmsg_add_u32(out, "success", 1);
} else if(!strcmp(op, "createAutoRec")) {
const char *cgrp = http_arg_get(&hc->hc_req_args, "contentgrp");
epg_genre_t genre, *eg = NULL;
if ((s = http_arg_get(&hc->hc_req_args, "contenttype"))) {
genre.code = atoi(s);
eg = &genre;
}
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"),
cgrp ? epg_genre_find_by_name(cgrp) : 0,
eg,
hc->hc_representative, "Created from EPG query");
out = htsmsg_create_map();

View file

@ -470,9 +470,13 @@ tvheadend.autoreceditor = function() {
emptyText: 'Only include tag...'
})
},{
header: "Content Group",
dataIndex: 'contentgrp',
header: "Genre",
dataIndex: 'contenttype',
renderer: function(v) {
return tvheadend.contentGroupLookupName(v);
},
editor: new Ext.form.ComboBox({
valueField: 'code',
displayField:'name',
store: tvheadend.ContentGroupStore,
mode: 'local',
@ -635,7 +639,7 @@ tvheadend.dvr = function() {
tvheadend.autorecRecord = Ext.data.Record.create([
'enabled','title', 'brand', 'channel','tag','creator','contentgrp','comment',
'enabled','title', 'brand', 'channel','tag','creator','contenttype','comment',
'weekdays', 'pri', 'approx_time', 'config_name'
]);

View file

@ -9,12 +9,25 @@ tvheadend.brands = new Ext.data.JsonStore({
tvheadend.ContentGroupStore = new Ext.data.JsonStore({
root:'entries',
fields: [{name: 'name'}],
fields: ['name', 'code'],
autoLoad: true,
url:'ecglist'
});
tvheadend.ContentGroupStore.setDefaultSort('name', 'ASC');
tvheadend.contentGroupLookupName = function(code)
{
ret = "";
tvheadend.ContentGroupStore.each(function(r)
{
if (r.data.code == code)
ret = r.data.name;
else if (ret == "" && r.data.code == code & 0xF0)
ret = r.data.name;
});
return ret;
}
tvheadend.ContentGroupStore.setDefaultSort('code', 'ASC');
tvheadend.epgDetails = function(event) {
@ -29,7 +42,7 @@ tvheadend.epgDetails = function(event) {
content += '<div class="x-epg-desc">' + event.episode + '</div>';
content += '<div class="x-epg-desc">' + event.description + '</div>';
content += '<div class="x-epg-meta">' + event.contentgrp + '</div>';
content += '<div class="x-epg-meta">' + tvheadend.contentGroupLookupName(event.contenttype) + '</div>';
if(event.ext_desc != null)
content += '<div class="x-epg-meta">' + event.ext_desc + '</div>';
@ -206,7 +219,7 @@ tvheadend.epg = function() {
{name: 'start', type: 'date', dateFormat: 'U' /* unix time */},
{name: 'end', type: 'date', dateFormat: 'U' /* unix time */},
{name: 'duration'},
{name: 'contentgrp'},
{name: 'contenttype'},
{name: 'schedstate'}
])
});
@ -298,10 +311,12 @@ tvheadend.epg = function() {
renderer: renderText
},{
width: 250,
id:'contentgrp',
id:'contenttype',
header: "Content Type",
dataIndex: 'contentgrp',
renderer: renderText
dataIndex: 'contenttype',
renderer: function(v) {
return tvheadend.contentGroupLookupName(v);
}
}
]);
@ -357,7 +372,7 @@ tvheadend.epg = function() {
function epgQueryClear() {
epgStore.baseParams.channel = null;
epgStore.baseParams.tag = null;
epgStore.baseParams.contentgrp = null;
epgStore.baseParams.contenttype = null;
epgStore.baseParams.title = null;
epgFilterChannels.setValue("");
@ -383,8 +398,8 @@ tvheadend.epg = function() {
});
epgFilterContentGroup.on('select', function(c, r) {
if(epgStore.baseParams.contentgrp != r.data.name) {
epgStore.baseParams.contentgrp = r.data.name;
if(epgStore.baseParams.contenttype != r.data.code) {
epgStore.baseParams.contenttype = r.data.code;
epgStore.reload();
}
});
@ -477,8 +492,8 @@ tvheadend.epg = function() {
epgStore.baseParams.channel : "<i>Don't care</i>";
var tag = epgStore.baseParams.tag ?
epgStore.baseParams.tag : "<i>Don't care</i>";
var contentgrp = epgStore.baseParams.contentgrp ?
epgStore.baseParams.contentgrp : "<i>Don't care</i>";
var contenttype = epgStore.baseParams.contenttype ?
epgStore.baseParams.contenttype : "<i>Don't care</i>";
Ext.MessageBox.confirm('Auto Recorder',
'This will create an automatic rule that ' +
@ -488,7 +503,7 @@ tvheadend.epg = function() {
'<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">Content Group:</div>' + contentgrp + '<br>' +
'<div class="x-smallhdr">Genre:</div>' + contenttype + '<br>' +
'<br>' +
'Currently this will match (and record) ' +
epgStore.getTotalCount() + ' events. ' +