Complete update to the EPG genre setup. Mostly this is now achieved using an listable structure (to remove the ugly array implementation) however some code still deals directly with the uint8_t code value.
This commit is contained in:
parent
c07fd8d59f
commit
b361262d6b
14 changed files with 373 additions and 184 deletions
|
@ -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,
|
||||
|
|
|
@ -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 &&
|
||||
|
@ -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) {
|
||||
|
@ -256,7 +250,6 @@ build_weekday_mask(const char *str)
|
|||
static htsmsg_t *
|
||||
autorec_record_build(dvr_autorec_entry_t *dae)
|
||||
{
|
||||
const char *s;
|
||||
char str[30];
|
||||
htsmsg_t *e = htsmsg_create_map();
|
||||
|
||||
|
@ -276,11 +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);
|
||||
|
||||
// Note: Mixed usage creates problems, for now we have to store
|
||||
// both values!
|
||||
htsmsg_add_u32(e, "contenttype",dae->dae_content_type);
|
||||
if ((s = epg_content_group_get_name(dae->dae_content_type)))
|
||||
htsmsg_add_str(e, "contentgrp", s);
|
||||
htsmsg_add_u32(e, "contenttype",dae->dae_content_type.code);
|
||||
|
||||
htsmsg_add_str(e, "title", dae->dae_title ?: "");
|
||||
|
||||
|
@ -351,6 +340,8 @@ autorec_record_update(void *opaque, const char *id, htsmsg_t *values,
|
|||
channel_t *ch;
|
||||
channel_tag_t *ct;
|
||||
uint32_t u32;
|
||||
printf("autorec_record_update()\n");
|
||||
htsmsg_print(values);
|
||||
|
||||
if((dae = autorec_entry_find(id, maycreate)) == NULL)
|
||||
return NULL;
|
||||
|
@ -394,15 +385,7 @@ autorec_record_update(void *opaque, const char *id, htsmsg_t *values,
|
|||
}
|
||||
}
|
||||
|
||||
// Note: unfortunately there is a mixed usage here, DVR code uses
|
||||
// contenttype however UI code uses contentgrp. so we test for both!
|
||||
if (htsmsg_get_u32(values, "contenttype", &u32)) {
|
||||
if ((s = htsmsg_get_str(values, "contentgrp")))
|
||||
u32 = epg_content_group_find_by_name(s);
|
||||
else
|
||||
u32 = 0;
|
||||
}
|
||||
dae->dae_content_type = u32;
|
||||
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) {
|
||||
|
@ -483,7 +466,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)
|
||||
|
@ -516,7 +499,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;
|
||||
|
@ -548,7 +532,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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
232
src/epg.c
232
src/epg.c
|
@ -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,53 +765,36 @@ 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
|
||||
|
@ -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);
|
||||
|
@ -1336,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",
|
||||
|
@ -1507,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++ ) {
|
||||
|
@ -1519,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;
|
||||
}
|
||||
|
||||
/* **************************************************************************
|
||||
|
@ -1533,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 */
|
||||
|
@ -1553,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;
|
||||
|
@ -1564,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;
|
||||
|
@ -1606,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)
|
||||
|
|
55
src/epg.h
55
src/epg.h
|
@ -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);
|
||||
|
||||
|
||||
/* ************************************************************************
|
||||
|
|
|
@ -152,13 +152,12 @@ static int _eit_callback
|
|||
channel_t *ch;
|
||||
epg_broadcast_t *ebc;
|
||||
epg_episode_t *ee;
|
||||
epg_genre_list_t genre;
|
||||
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,8 @@ 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 )
|
||||
epg_genre_list_add_by_eit(&genre, *ptr);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -392,14 +390,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) && LIST_FIRST(&genre) )
|
||||
save |= epg_episode_set_genre(ee, &genre);
|
||||
#if TODO_ADD_EXTRA
|
||||
if ( extra )
|
||||
save |= epg_episode_set_extra(ee, extra);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Tidy up */
|
||||
if (extra) free(extra);
|
||||
epg_genre_list_destroy(&genre);
|
||||
}
|
||||
|
||||
/* Update EPG */
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -55,10 +55,20 @@ 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 )
|
||||
|
@ -197,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;
|
||||
|
||||
|
@ -262,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 */
|
||||
|
|
|
@ -302,6 +302,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
|
||||
*/
|
||||
|
@ -313,12 +331,12 @@ _xmltv_parse_programme_tags(channel_t *ch, htsmsg_t *tags,
|
|||
epg_episode_t *ee;
|
||||
epg_broadcast_t *ebc;
|
||||
epg_season_t *es;
|
||||
epg_genre_list_t *egl;
|
||||
int sn = 0, sc = 0, en = 0, ec = 0, pn = 0, pc = 0;
|
||||
char *uri = NULL, *suri = NULL;
|
||||
const char *onscreen = NULL;
|
||||
const char *title = htsmsg_xml_get_cdata_str(tags, "title");
|
||||
const char *desc = htsmsg_xml_get_cdata_str(tags, "desc");
|
||||
const char *category[2];
|
||||
get_episode_info(tags, &uri, &suri, &onscreen, &sn, &sc, &en, &ec, &pn, &pc);
|
||||
|
||||
/* Ignore */
|
||||
|
@ -339,11 +357,12 @@ _xmltv_parse_programme_tags(channel_t *ch, htsmsg_t *tags,
|
|||
free(suri);
|
||||
}
|
||||
|
||||
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++;
|
||||
|
|
16
src/htsp.c
16
src/htsp.c
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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'
|
||||
]);
|
||||
|
||||
|
|
|
@ -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. ' +
|
||||
|
|
Loading…
Add table
Reference in a new issue