* Add parsing of episode information from XMLTV and display it in the
WebUI EPG
This commit is contained in:
parent
197af300b9
commit
7d38bc1943
6 changed files with 183 additions and 0 deletions
3
debian/changelog
vendored
3
debian/changelog
vendored
|
@ -15,6 +15,9 @@ hts-tvheadend (2.11-WIP) hts; urgency=low
|
|||
to understand what is happening. It also makes (more) correct
|
||||
wakeup from suspend hard to do.
|
||||
|
||||
* Add parsing of episode information from XMLTV and display it in the
|
||||
WebUI EPG
|
||||
|
||||
hts-tvheadend (2.10) hts; urgency=high
|
||||
|
||||
* Fix a crash in HTSP server.
|
||||
|
|
14
src/epg.c
14
src/epg.c
|
@ -242,6 +242,19 @@ epg_event_set_content_type(event_t *e, epg_content_type_t *ect)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
epg_event_set_episode(event_t *e, epg_episode_t *ee)
|
||||
{
|
||||
e->e_episode.ee_season = ee->ee_season;
|
||||
e->e_episode.ee_episode = ee->ee_episode;
|
||||
e->e_episode.ee_part = ee->ee_part;
|
||||
|
||||
tvh_str_set(&e->e_episode.ee_onscreen, ee->ee_onscreen);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -254,6 +267,7 @@ epg_event_destroy(event_t *e)
|
|||
|
||||
free(e->e_title);
|
||||
free(e->e_desc);
|
||||
free(e->e_episode.ee_onscreen);
|
||||
LIST_REMOVE(e, e_global_link);
|
||||
free(e);
|
||||
}
|
||||
|
|
14
src/epg.h
14
src/epg.h
|
@ -41,6 +41,16 @@ typedef struct epg_content_type {
|
|||
uint8_t ect_dvbcode;
|
||||
} epg_content_type_t;
|
||||
|
||||
typedef struct epg_episode {
|
||||
|
||||
uint16_t ee_season;
|
||||
uint16_t ee_episode;
|
||||
uint16_t ee_part;
|
||||
|
||||
char *ee_onscreen;
|
||||
} epg_episode_t;
|
||||
|
||||
|
||||
/*
|
||||
* EPG event
|
||||
*/
|
||||
|
@ -67,6 +77,8 @@ typedef struct event {
|
|||
|
||||
int e_dvb_id;
|
||||
|
||||
epg_episode_t e_episode;
|
||||
|
||||
} event_t;
|
||||
|
||||
|
||||
|
@ -87,6 +99,8 @@ void epg_event_set_ext_text(event_t *e, int ext_dn, const char *text);
|
|||
|
||||
void epg_event_set_content_type(event_t *e, epg_content_type_t *ect);
|
||||
|
||||
void epg_event_set_episode(event_t *e, epg_episode_t *ee);
|
||||
|
||||
event_t *epg_event_create(channel_t *ch, time_t start, time_t stop,
|
||||
int dvb_id, int *created);
|
||||
|
||||
|
|
|
@ -660,6 +660,9 @@ extjs_epg(http_connection_t *hc, const char *remain, void *opaque)
|
|||
if(e->e_desc != NULL)
|
||||
htsmsg_add_str(m, "description", e->e_desc);
|
||||
|
||||
if(e->e_episode.ee_onscreen != NULL)
|
||||
htsmsg_add_str(m, "episode", e->e_episode.ee_onscreen);
|
||||
|
||||
if(e->e_ext_desc != NULL)
|
||||
htsmsg_add_str(m, "ext_desc", e->e_ext_desc);
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ tvheadend.epgDetails = function(event) {
|
|||
content += '<img class="x-epg-chicon" src="' + event.chicon + '">';
|
||||
|
||||
content += '<div class="x-epg-title">' + event.title + '</div>';
|
||||
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>';
|
||||
|
@ -89,6 +90,7 @@ tvheadend.epg = function() {
|
|||
{name: 'id'},
|
||||
{name: 'channel'},
|
||||
{name: 'title'},
|
||||
{name: 'episode'},
|
||||
{name: 'description'},
|
||||
{name: 'ext_desc'},
|
||||
{name: 'ext_item'},
|
||||
|
@ -148,6 +150,12 @@ tvheadend.epg = function() {
|
|||
header: "Title",
|
||||
dataIndex: 'title',
|
||||
renderer: renderText
|
||||
},{
|
||||
width: 250,
|
||||
id:'episode',
|
||||
header: "Episode",
|
||||
dataIndex: 'episode',
|
||||
renderer: renderText
|
||||
},{
|
||||
width: 100,
|
||||
id:'start',
|
||||
|
|
141
src/xmltv.c
141
src/xmltv.c
|
@ -336,6 +336,141 @@ xmltv_parse_channel(htsmsg_t *body)
|
|||
xmltv_save(xc);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This is probably the most obscure formating there is. From xmltv.dtd:
|
||||
*
|
||||
*
|
||||
* xmltv_ns: This is intended to be a general way to number episodes and
|
||||
* parts of multi-part episodes. It is three numbers separated by dots,
|
||||
* the first is the series or season, the second the episode number
|
||||
* within that series, and the third the part number, if the programme is
|
||||
* part of a two-parter. All these numbers are indexed from zero, and
|
||||
* they can be given in the form 'X/Y' to show series X out of Y series
|
||||
* made, or episode X out of Y episodes in this series, or part X of a
|
||||
* Y-part episode. If any of these aren't known they can be omitted.
|
||||
* You can put spaces whereever you like to make things easier to read.
|
||||
*
|
||||
* (NB 'part number' is not used when a whole programme is split in two
|
||||
* for purely scheduling reasons; it's intended for cases where there
|
||||
* really is a 'Part One' and 'Part Two'. The format doesn't currently
|
||||
* have a way to represent a whole programme that happens to be split
|
||||
* across two or more timeslots.)
|
||||
*
|
||||
* Some examples will make things clearer. The first episode of the
|
||||
* second series is '1.0.0/1' . If it were a two-part episode, then the
|
||||
* first half would be '1.0.0/2' and the second half '1.0.1/2'. If you
|
||||
* know that an episode is from the first season, but you don't know
|
||||
* which episode it is or whether it is part of a multiparter, you could
|
||||
* give the episode-num as '0..'. Here the second and third numbers have
|
||||
* been omitted. If you know that this is the first part of a three-part
|
||||
* episode, which is the last episode of the first series of thirteen,
|
||||
* its number would be '0 . 12/13 . 0/3'. The series number is just '0'
|
||||
* because you don't know how many series there are in total - perhaps
|
||||
* the show is still being made!
|
||||
*
|
||||
*/
|
||||
|
||||
static const char *
|
||||
xmltv_ns_get_parse_num(const char *s, int *ap, int *bp)
|
||||
{
|
||||
int a = -1, b = -1;
|
||||
|
||||
while(1) {
|
||||
if(!*s)
|
||||
goto out;
|
||||
|
||||
if(*s == '.') {
|
||||
s++;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if(*s == '/')
|
||||
break;
|
||||
|
||||
if(*s >= '0' && *s <= '9') {
|
||||
if(a == -1)
|
||||
a = 0;
|
||||
a = a * 10 + *s - '0';
|
||||
}
|
||||
s++;
|
||||
}
|
||||
|
||||
s++; // slash
|
||||
|
||||
while(1) {
|
||||
if(!*s)
|
||||
break;
|
||||
|
||||
if(*s == '.') {
|
||||
s++;
|
||||
break;
|
||||
}
|
||||
|
||||
if(*s >= '0' && *s <= '9') {
|
||||
if(b == -1)
|
||||
b = 0;
|
||||
b = b * 10 + *s - '0';
|
||||
}
|
||||
s++;
|
||||
}
|
||||
|
||||
|
||||
out:
|
||||
if(ap) *ap = a;
|
||||
if(bp) *bp = b;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static void
|
||||
parse_xmltv_ns_episode(const char *s, epg_episode_t *ee)
|
||||
{
|
||||
int season;
|
||||
int episode;
|
||||
int part;
|
||||
|
||||
s = xmltv_ns_get_parse_num(s, &season, NULL);
|
||||
s = xmltv_ns_get_parse_num(s, &episode, NULL);
|
||||
xmltv_ns_get_parse_num(s, &part, NULL);
|
||||
|
||||
if(season != -1)
|
||||
ee->ee_season = season + 1;
|
||||
if(episode != -1)
|
||||
ee->ee_episode = episode + 1;
|
||||
if(part != -1)
|
||||
ee->ee_part = part + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
get_episode_info(htsmsg_t *tags, epg_episode_t *ee)
|
||||
{
|
||||
htsmsg_field_t *f;
|
||||
htsmsg_t *c, *a;
|
||||
const char *sys, *cdata;
|
||||
|
||||
memset(ee, 0, sizeof(epg_episode_t));
|
||||
|
||||
HTSMSG_FOREACH(f, tags) {
|
||||
if((c = htsmsg_get_map_by_field(f)) == NULL ||
|
||||
strcmp(f->hmf_name, "episode-num") ||
|
||||
(a = htsmsg_get_map(c, "attrib")) == NULL ||
|
||||
(cdata = htsmsg_get_str(c, "cdata")) == NULL ||
|
||||
(sys = htsmsg_get_str(a, "system")) == NULL)
|
||||
continue;
|
||||
|
||||
if(!strcmp(sys, "onscreen"))
|
||||
tvh_str_set(&ee->ee_onscreen, cdata);
|
||||
else if(!strcmp(sys, "xmltv_ns"))
|
||||
parse_xmltv_ns_episode(cdata, ee);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse tags inside of a programme
|
||||
*/
|
||||
|
@ -348,6 +483,9 @@ xmltv_parse_programme_tags(xmltv_channel_t *xc, htsmsg_t *tags,
|
|||
const char *title = xmltv_get_cdata_by_tag(tags, "title");
|
||||
const char *desc = xmltv_get_cdata_by_tag(tags, "desc");
|
||||
int created;
|
||||
epg_episode_t episode;
|
||||
|
||||
get_episode_info(tags, &episode);
|
||||
|
||||
LIST_FOREACH(ch, &xc->xc_channels, ch_xc_link) {
|
||||
if((e = epg_event_create(ch, start, stop, -1, &created)) == NULL)
|
||||
|
@ -358,7 +496,10 @@ xmltv_parse_programme_tags(xmltv_channel_t *xc, htsmsg_t *tags,
|
|||
|
||||
if(title != NULL) epg_event_set_title(e, title);
|
||||
if(desc != NULL) epg_event_set_desc(e, desc);
|
||||
epg_event_set_episode(e, &episode);
|
||||
}
|
||||
|
||||
free(episode.ee_onscreen);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue