Initial hack in of new epg data structures, xmltv refs hacked out and some code left in for compat. this will not compile/run.

This commit is contained in:
Adam Sutton 2012-05-17 12:05:45 +01:00
parent 214677a4f5
commit 134e3b880e
10 changed files with 467 additions and 66 deletions

View file

@ -40,8 +40,9 @@ SRCS = src/main.c \
src/tcp.c \
src/http.c \
src/notify.c \
src/cron.c \
src/epg.c \
src/xmltv.c \
src/epggrab.c\
src/spawn.c \
src/packet.c \
src/streaming.c \
@ -70,6 +71,8 @@ SRCS = src/main.c \
src/iptv_input.c \
src/avc.c \
SRCS += src/epggrab/pyepg.c
SRCS += src/plumbing/tsfix.c \
src/plumbing/globalheaders.c \

View file

@ -34,13 +34,13 @@
#include "psi.h"
#include "channels.h"
#include "epg.h"
#include "xmltv.h"
//#include "xmltv.h"
#include "dtable.h"
#include "notify.h"
#include "dvr/dvr.h"
#include "htsp.h"
struct channel_list channels_not_xmltv_mapped;
//struct channel_list channels_not_xmltv_mapped;
struct channel_tree channel_name_tree;
static struct channel_tree channel_identifier_tree;
@ -164,7 +164,7 @@ static channel_t *
channel_create(const char *name, int number)
{
channel_t *ch, *x;
xmltv_channel_t *xc;
//xmltv_channel_t *xc;
int id;
ch = RB_LAST(&channel_identifier_tree);
@ -176,7 +176,7 @@ channel_create(const char *name, int number)
ch = calloc(1, sizeof(channel_t));
RB_INIT(&ch->ch_epg_events);
LIST_INSERT_HEAD(&channels_not_xmltv_mapped, ch, ch_xc_link);
//LIST_INSERT_HEAD(&channels_not_xmltv_mapped, ch, ch_xc_link);
channel_set_name(ch, name);
ch->ch_number = number;
@ -186,11 +186,13 @@ channel_create(const char *name, int number)
assert(x == NULL);
#if 0
if((xc = xmltv_channel_find_by_displayname(name)) != NULL) {
channel_set_xmltv_source(ch, xc);
if(xc->xc_icon != NULL)
channel_set_icon(ch, xc->xc_icon);
}
#endif
htsp_channel_add(ch);
return ch;
@ -236,7 +238,7 @@ static void
channel_load_one(htsmsg_t *c, int id)
{
channel_t *ch;
const char *s;
//const char *s;
const char *name = htsmsg_get_str(c, "name");
htsmsg_t *tags;
htsmsg_field_t *f;
@ -260,6 +262,7 @@ channel_load_one(htsmsg_t *c, int id)
channel_set_name(ch, name);
#if 0
if((s = htsmsg_get_str(c, "xmltv-channel")) != NULL &&
(ch->ch_xc = xmltv_channel_find(s, 0)) != NULL) {
LIST_INSERT_HEAD(&ch->ch_xc->xc_channels, ch, ch_xc_link);
@ -267,6 +270,7 @@ channel_load_one(htsmsg_t *c, int id)
} else {
LIST_INSERT_HEAD(&channels_not_xmltv_mapped, ch, ch_xc_link);
}
#endif
tvh_str_update(&ch->ch_icon, htsmsg_get_str(c, "icon"));
@ -322,8 +326,10 @@ channel_save(channel_t *ch)
htsmsg_add_str(m, "name", ch->ch_name);
#if 0
if(ch->ch_xc != NULL)
htsmsg_add_str(m, "xmltv-channel", ch->ch_xc->xc_identifier);
#endif
if(ch->ch_icon != NULL)
htsmsg_add_str(m, "icon", ch->ch_icon);
@ -408,7 +414,7 @@ channel_delete(channel_t *ch)
RB_REMOVE(&channel_name_tree, ch, ch_name_link);
RB_REMOVE(&channel_identifier_tree, ch, ch_identifier_link);
LIST_REMOVE(ch, ch_xc_link);
//LIST_REMOVE(ch, ch_xc_link);
free(ch->ch_name);
free(ch->ch_sname);
@ -505,6 +511,7 @@ channel_set_number(channel_t *ch, int number)
/**
*
*/
#if 0
void
channel_set_xmltv_source(channel_t *ch, xmltv_channel_t *xc)
{
@ -527,6 +534,7 @@ channel_set_xmltv_source(channel_t *ch, xmltv_channel_t *xc)
channel_save(ch);
}
#endif
/**

View file

@ -58,9 +58,6 @@ typedef struct channel {
struct dvr_autorec_entry_list ch_autorecs;
struct xmltv_channel *ch_xc;
LIST_ENTRY(channel) ch_xc_link;
struct channel_tag_mapping_list ch_ctms;
} channel_t;
@ -122,9 +119,6 @@ void channel_set_number(channel_t *ch, int number);
void channel_set_icon(channel_t *ch, const char *icon);
struct xmltv_channel;
void channel_set_xmltv_source(channel_t *ch, struct xmltv_channel *xc);
void channel_set_tags_from_list(channel_t *ch, const char *maplist);
channel_tag_t *channel_tag_find_by_name(const char *name, int create);
@ -135,6 +129,4 @@ int channel_tag_map(channel_t *ch, channel_tag_t *ct, int check);
void channel_save(channel_t *ch);
extern struct channel_list channels_not_xmltv_mapped;
#endif /* CHANNELS_H */

View file

@ -33,6 +33,9 @@
#include "htsp.h"
#include "htsmsg_binary.h"
#define EPG_MAX_AGE 86400
#define EPG_GLOBAL_HASH_WIDTH 1024

278
src/epg.h
View file

@ -22,16 +22,247 @@
#include "channels.h"
#include "settings.h"
/* ************************************************************************
* Type definitions
* ***********************************************************************/
/*
* Forward declarations
*/
struct epg_brand;
struct epg_season;
struct epg_episode;
struct epg_broadcast;
struct epg_channel;
/*
* Represents a specific show
* e.g. The Simpsons, 24, Eastenders, etc...
*/
typedef struct epg_brand
{
uint32_t eb_id; ///< Internal ID
char *eb_uri; ///< Grabber URI
char *eb_title; ///< Brand name
char *eb_summary; ///< Brand summary
uint16_t eb_season_count; ///< Total number of seasons
LIST_HEAD(, epg_season_t) eb_seasons; ///< Attached seasons
LIST_HEAD(, epg_episode_t) eb_episodes; ///< Un(-seasoned) episodes??
// TODO: should this only include unattached episodes?
int eb_refcount; ///< Reference counting
} epg_brand_t;
/*
* Represents a season
*/
typedef struct epg_season
{
uint32_t es_id; ///< Internal ID
char *es_uri; ///< Grabber URI
char *es_summary; ///< Season summary
uint16_t es_number; ///< The season number
uint16_t es_episode_count; ///< Total number of episodes
epg_brand_t *es_brand; ///< Parent brand
LIST_HEAD(, epg_episode_t) es_episodes; ///< Child episodes
int es_refcount; ///< Reference counting
} epg_season_t;
/*
* Represents a particular episode
*/
typedef struct epg_episode
{
uint32_t ee_id; ///< Internal ID
char *ee_uri; ///< Grabber URI
char *ee_title; ///< Title
char *ee_subtitle; ///< Sub-title
char *ee_summary; ///< Summary
char *ee_description; ///< An extended description
uint8_t ee_genre; ///< Episode genre (TODO: need a list?)
uint16_t ee_number; ///< The episode number
uint16_t ee_part_number; ///< For multipart episodes
uint16_t ee_part_count; ///< For multipart episodes
epg_brand_t *ee_brand; ///< (Grand-)Parent brand
epg_season_t *ee_season; ///< Parent season
int ee_refcount; ///< Reference counting
} epg_episode_t;
/*
* A specific broadcast of an episode
*/
typedef struct epg_broadcast
{
int eb_id; ///< Internal ID
int eb_dvb_id; ///< DVB identifier
time_t eb_start; ///< Start time
time_t eb_stop; ///< End time
epg_episode_t *eb_episode; ///< Episode shown
channel_t* eb_channel; ///< Channel being broadcast on
/* Some quality info */
uint8_t eb_widescreen; ///< Is widescreen
uint8_t eb_hd; ///< Is HD
uint16_t eb_lines; ///< Lines in image (quality)
uint16_t eb_aspect; ///< Aspect ratio (*100)
/* Some accessibility support */
uint8_t eb_deafsigned; ///< In screen signing
uint8_t eb_subtitled; ///< Teletext subtitles
uint8_t eb_audio_desc; ///< Audio description
/* Misc flags */
uint8_t eb_new; ///< New series / file premiere
uint8_t eb_repeat; ///< Repeat screening
} epg_broadcast_t;
/*
* Channel for mappings
*/
typedef struct epg_channel
{
} epg_channel_t;
/*
* Query result
*/
typedef struct epg_query_result {
epg_broadcast_t **eqr_array;
int eqr_entries;
int eqr_alloced;
} epg_query_result_t;
/* ************************************************************************
* Function prototypes
* ***********************************************************************/
/*
* Load/Save
*/
void epg_init(void);
void epg_save(void);
/**
* All the epg_X_set_ function return 1 if it actually changed
* the EPG records. otherwise it returns 0.
*
* If the caller detects that something has changed, it should call
* epg_event_updated().
*
* There reason to put the burden on the caller is that the caller
* can combine multiple set()'s into one update
*
*/
/* Brand set() calls */
int epg_brand_set_uri ( epg_brand_t *b, const char *uri )
__attribute__((warn_unused_result));
int epg_brand_set_title ( epg_brand_t *b, const char *title )
__attribute__((warn_unused_result));
int epg_brand_set_summary ( epg_brand_t *b, const char *summary )
__attribute__((warn_unused_result));
int epg_brand_set_season_count ( epg_brand_t *b, uint16_t season_count )
__attribute__((warn_unused_result));
/* Season set() calls */
int epg_season_set_uri ( epg_season_t *s, const char *uri )
__attribute__((warn_unused_result));
int epg_season_set_summary ( epg_season_t *s, const char *summary )
__attribute__((warn_unused_result));
int epg_season_set_number ( epg_season_t *s, uint16_t number )
__attribute__((warn_unused_result));
int epg_season_set_episode_count ( epg_season_t *s, uint16_t episode_count )
__attribute__((warn_unused_result));
int epg_season_set_brand ( epg_season_t *s, const epg_brand_t *b )
__attribute__((warn_unused_result));
/* Episode set() calls */
int epg_episode_set_uri ( epg_episode_t *e, const char *uri )
__attribute__((warn_unused_result));
int epg_episode_set_title ( epg_episode_t *e, const char *title )
__attribute__((warn_unused_result));
int epg_episode_set_subtitle ( epg_episode_t *e, const char *subtitle )
__attribute__((warn_unused_result));
int epg_episode_set_summary ( epg_episode_t *e, const char *summary )
__attribute__((warn_unused_result));
int epg_episode_set_description ( epg_episode_t *e, const char *description )
__attribute__((warn_unused_result));
int epg_episode_set_number ( epg_episode_t *e, uint16_t number )
__attribute__((warn_unused_result));
int epg_episode_set_part ( epg_episode_t *e,
uint16_t number, uint16_t count )
__attribute__((warn_unused_result));
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));
// Note: you don't need to call set_brand() if you set_season() using a season
// on which you've called set_brand()
/* Broadcast set() calls */
// TODO: need to think how this will work with the new hierarchy
void epg_updated ( void );
void epg_brand_updated ( epg_brand_t *b );
void epg_season_updated ( epg_season_t *s );
void epg_episode_updated ( epg_episode_t *e );
void epg_broadcast_updated ( epg_broadcast_t *b );
/*
* Simple lookup
*/
epg_brand_t *epg_brand_find_by_id ( const char *id, int create );
epg_season_t *epg_season_find_by_id ( const char *id, int create );
epg_episode_t *epg_episode_find_by_id ( const char *id, int create );
epg_channel_t *epg_channel_find_by_id ( const char *id, int create );
epg_channel_t *epg_channel_find ( const char *id, const char *name, const char **sname, const int **sid );
epg_broadcast_t *epg_broadcast_find ( epg_channel_t *ch, epg_episode_t *ep, time_t start, time_t stop, int create );
epg_broadcast_t *epg_event_find_by_time(channel_t *ch, time_t t);
epg_broadcast_t *epg_event_find_by_id(int eventid);
/*
* Advanced Query
*/
void epg_query0(epg_query_result_t *eqr, channel_t *ch, channel_tag_t *ct,
uint8_t type, const char *title);
void epg_query(epg_query_result_t *eqr, const char *channel, const char *tag,
const char *contentgroup, const char *title);
void epg_query_free(epg_query_result_t *eqr);
void epg_query_sort(epg_query_result_t *eqr);
/*
* Genres?
*/
uint8_t epg_content_group_find_by_name(const char *name);
const char *epg_content_group_get_name(uint8_t type);
typedef struct epg_episode {
/* ************************************************************************
* Compatibility code
* ***********************************************************************/
typedef struct _epg_episode {
uint16_t ee_season;
uint16_t ee_episode;
uint16_t ee_part;
char *ee_onscreen;
} epg_episode_t;
} _epg_episode_t;
/*
@ -59,47 +290,10 @@ typedef struct event {
int e_dvb_id;
epg_episode_t e_episode;
_epg_episode_t e_episode;
} event_t;
/**
* Prototypes
*/
void epg_init(void);
void epg_save(void);
/**
* All the epg_event_set_ function return 1 if it actually changed
* the EPG records. otherwise it returns 0.
*
* If the caller detects that something has changed, it should call
* epg_event_updated().
*
* There reason to put the burden on the caller is that the caller
* can combine multiple set()'s into one update
*
*/
int epg_event_set_title(event_t *e, const char *title);
int epg_event_set_desc(event_t *e, const char *desc);
int epg_event_set_ext_desc(event_t *e, int ext_dn, const char *desc)
__attribute__ ((warn_unused_result));
int epg_event_set_ext_item(event_t *e, int ext_dn, const char *item)
__attribute__ ((warn_unused_result));
int epg_event_set_ext_text(event_t *e, int ext_dn, const char *text)
__attribute__ ((warn_unused_result));
int epg_event_set_content_type(event_t *e, uint8_t type)
__attribute__ ((warn_unused_result));
int epg_event_set_episode(event_t *e, epg_episode_t *ee)
__attribute__ ((warn_unused_result));
#if 0
void epg_event_updated(event_t *e);
@ -135,5 +329,5 @@ void epg_query(epg_query_result_t *eqr, const char *channel, const char *tag,
const char *contentgroup, const char *title);
void epg_query_free(epg_query_result_t *eqr);
void epg_query_sort(epg_query_result_t *eqr);
#endif
#endif /* EPG_H */

View file

@ -42,7 +42,7 @@
#include "http.h"
#include "webui/webui.h"
#include "dvb/dvb.h"
#include "xmltv.h"
#include "epggrab.h"
#include "spawn.h"
#include "subscriptions.h"
#include "serviceprobe.h"
@ -369,7 +369,7 @@ main(int argc, char **argv)
/**
* Initialize subsystems
*/
xmltv_init(); /* Must be initialized before channels */
epggrab_init(); /* Must be initialized before channels */
service_init();

View file

@ -39,7 +39,7 @@
#include "dvr/dvr.h"
#include "serviceprobe.h"
#include "xmltv.h"
#include "epggrab.h"
#include "epg.h"
#include "iptv_input.h"
@ -133,7 +133,7 @@ extjs_root(http_connection_t *hc, const char *remain, void *opaque)
extjs_load(hq, "static/app/chconf.js");
extjs_load(hq, "static/app/epg.js");
extjs_load(hq, "static/app/dvr.js");
extjs_load(hq, "static/app/xmltv.js");
extjs_load(hq, "static/app/epggrab.js");
/**
* Finally, the app itself
@ -325,8 +325,10 @@ extjs_channels_update(htsmsg_t *in)
if((s = htsmsg_get_str(c, "name")) != NULL)
channel_rename(ch, s);
#if TODO_XMLTV
if((s = htsmsg_get_str(c, "xmltvsrc")) != NULL)
channel_set_xmltv_source(ch, xmltv_channel_find_by_displayname(s));
#endif
if((s = htsmsg_get_str(c, "ch_icon")) != NULL)
channel_set_icon(ch, s);
@ -377,8 +379,10 @@ extjs_channels(http_connection_t *hc, const char *remain, void *opaque)
htsmsg_add_str(c, "name", ch->ch_name);
htsmsg_add_u32(c, "chid", ch->ch_id);
#if TODO_XMLTV
if(ch->ch_xc != NULL)
htsmsg_add_str(c, "xmltvsrc", ch->ch_xc->xc_displayname);
#endif
if(ch->ch_icon != NULL)
htsmsg_add_str(c, "ch_icon", ch->ch_icon);
@ -469,8 +473,9 @@ json_single_record(htsmsg_t *rec, const char *root)
*
*/
static int
extjs_xmltv(http_connection_t *hc, const char *remain, void *opaque)
extjs_epggrab(http_connection_t *hc, const char *remain, void *opaque)
{
#if TODO_EPGGRAB
htsbuf_queue_t *hq = &hc->hc_reply;
const char *op = http_arg_get(&hc->hc_req_args, "op");
xmltv_channel_t *xc;
@ -557,8 +562,9 @@ extjs_xmltv(http_connection_t *hc, const char *remain, void *opaque)
htsmsg_json_serialize(out, hq, 0);
htsmsg_destroy(out);
http_output_content(hc, "text/x-json; charset=UTF-8");
return 0;
#endif
return 0;
}
@ -1516,7 +1522,7 @@ extjs_start(void)
http_path_add("/extjs.html", NULL, extjs_root, ACCESS_WEB_INTERFACE);
http_path_add("/tablemgr", NULL, extjs_tablemgr, ACCESS_WEB_INTERFACE);
http_path_add("/channels", NULL, extjs_channels, ACCESS_WEB_INTERFACE);
http_path_add("/xmltv", NULL, extjs_xmltv, ACCESS_WEB_INTERFACE);
http_path_add("/epggrab", NULL, extjs_epggrab, ACCESS_WEB_INTERFACE);
http_path_add("/channeltags", NULL, extjs_channeltags, ACCESS_WEB_INTERFACE);
http_path_add("/confignames", NULL, extjs_confignames, ACCESS_WEB_INTERFACE);
http_path_add("/epg", NULL, extjs_epg, ACCESS_WEB_INTERFACE);

View file

@ -28,7 +28,6 @@
#include "webui.h"
#include "access.h"
#include "epg.h"
#include "xmltv.h"
#include "psi.h"
#if ENABLE_LINUXDVB
#include "dvr/dvr.h"
@ -74,7 +73,9 @@ dumpchannels(htsbuf_queue_t *hq)
ch->ch_refcount,
ch->ch_zombie,
ch->ch_number,
#if TODO_XMLTV
ch->ch_xc ? ch->ch_xc->xc_displayname : "<none set>",
#endif
ch->ch_icon ?: "<none set>");
}
}

View file

@ -0,0 +1,194 @@
tvheadend.grabberStore = new Ext.data.JsonStore({
root:'entries',
fields: ['identifier','name','version','apiconfig'],
url:'xmltv',
baseParams: {
op: 'listGrabbers'
}
});
tvheadend.epggrab = function() {
var confreader = new Ext.data.JsonReader(
{ root: 'epggrabSettings' },
[ 'module', 'eitenable', 'advanced' ]
);
var grabberSelect = new Ext.form.ComboBox({
loadingText: 'Loading, please wait...',
fieldLabel: 'XML-TV Source',
name: 'grabber',
width: 350,
displayField:'name',
valueField:'identifier',
store: tvheadend.grabberStore,
forceSelection: true,
editable: false,
triggerAction: 'all',
mode: 'remote',
emptyText: 'Select grabber'
});
grabberSelect.setVisible(false);
var advancedCheck = new Ext.form.Checkbox({
fieldLabel : 'Advanced Config',
name : 'advanced',
});
var moduleSelect = new Ext.form.ComboBox({
fieldLabel : 'Grab Module',
name : 'module',
width : 150,
valueField : 'key',
displayField : 'value',
forceSelection : true,
editable : false,
triggerAction : 'all',
mode : 'local',
store : new Ext.data.SimpleStore({
fields : [ 'key', 'value' ],
data : [
[ 'xmltv', 'XMLTV' ],
[ 'pyepg', 'PyEPG' ],
]
})
});
var confpanel = new Ext.FormPanel(
{
title : 'EPG Grabber',
iconCls : 'xml',
border : false,
bodyStyle : 'padding:15px',
labelAlign : 'right',
labelWidth : 200,
waitMsgTarget : true,
reader : confreader,
layout : 'form',
defaultType : 'textfield',
items : [
moduleSelect,
new Ext.form.Checkbox({
fieldLabel : 'Enable EIT',
name : 'eitenable'
}),
advancedCheck,
grabberSelect
],
tbar: [
{
tooltip: 'Save changes made to configuration below',
iconCls:'save',
text: "Save configuration",
handler: saveChanges
},
'->',
{
text: 'Help',
handler: function() {
new tvheadend.help('XMLTV configuration', 'config_xmltv.html');
}
}
]
}
);
/*
* Event handlers
*/
advancedCheck.on('enable', function(e) {
Ext.MessageBox.alert('Test', 'testing');
});
moduleSelect.on('select', function(c,r,i) {
alert('select module');
});
confpanel.on('render', function() {
confpanel.getForm().load({
url:'xmltv',
params:{'op':'loadSettings'},
success:function(form, action) {
confpanel.enable();
}
});
});
grabberSelect.on('select', function(c,r,i) {
Ext.MessageBox.alert('XMLTV',
'Make sure that the grabber is properly ' +
'configured before saving configuration.<br>'+
'<br>' +
'To configure manually execute the ' +
'following command in a shell on the ' +
'server:<br>' +
'$ ' + r.data.identifier +
' --configure<br>' +
'<br>' +
'Note: It is important to configure the ' +
'grabber using the same userid as tvheadend '+
'since most grabbers save their '+
'configuration in the users home directory.'+
'<br>' +
'<br>' +
'Grabber version: ' + r.data.version
);
/*
if(r.data.apiconfig) {
Ext.MessageBox.confirm('XMLTV',
'Configure grabber? ' +
'If you know that the grabber is already '+
'set up or if you want to configure it '+
'manually you may skip this step',
function(button) {
Ext.MessageBox.alert('XMLTV',
'oops, embedded '+
'config not '+
'implemeted yet');
}
);
} else {
Ext.MessageBox.alert('XMLTV',
'This grabber does not support being ' +
'configured from external application ' +
'(such as Tvheadend).<br>' +
'Make sure that the grabber is properly ' +
'configured before saving configuration.<br>'+
'<br>' +
'To configure manually execute the ' +
'following command in a shell on the ' +
'server:<br>' +
'$ ' + r.data.identifier +
' --configure<br>' +
'<br>' +
'Note: It is important to configure the ' +
'grabber using the same userid as tvheadend '+
'since most grabbers save their '+
'configuration in the users home directory.'+
'<br>' +
'<br>' +
'Grabber version: ' + r.data.version
);
}
*/
});
function saveChanges() {
confpanel.getForm().submit({
url:'xmltv',
params:{'op':'saveSettings'},
waitMsg:'Saving Data...',
failure: function(form, action) {
Ext.Msg.alert('Save failed', action.result.errormsg);
}
});
}
return confpanel;
}

View file

@ -234,7 +234,7 @@ function accessUpdate(o) {
title: 'Configuration',
iconCls: 'wrench',
items: [new tvheadend.chconf,
new tvheadend.xmltv,
new tvheadend.epggrab,
new tvheadend.cteditor,
new tvheadend.dvrsettings,
new tvheadend.tvadapters,