From 134e3b880e61209bdc73e4d73146f4d51d1cf8cc Mon Sep 17 00:00:00 2001 From: Adam Sutton Date: Thu, 17 May 2012 12:05:45 +0100 Subject: [PATCH] Initial hack in of new epg data structures, xmltv refs hacked out and some code left in for compat. this will not compile/run. --- Makefile | 5 +- src/channels.c | 20 ++- src/channels.h | 8 - src/epg.c | 3 + src/epg.h | 278 +++++++++++++++++++++++++----- src/main.c | 4 +- src/webui/extjs.c | 16 +- src/webui/statedump.c | 3 +- src/webui/static/app/epggrab.js | 194 +++++++++++++++++++++ src/webui/static/app/tvheadend.js | 2 +- 10 files changed, 467 insertions(+), 66 deletions(-) create mode 100644 src/webui/static/app/epggrab.js diff --git a/Makefile b/Makefile index 100c71f0..76d32e4c 100644 --- a/Makefile +++ b/Makefile @@ -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 \ diff --git a/src/channels.c b/src/channels.c index f13e0ed4..c7e16479 100644 --- a/src/channels.c +++ b/src/channels.c @@ -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 /** diff --git a/src/channels.h b/src/channels.h index 6dfbc73e..0ccd3349 100644 --- a/src/channels.h +++ b/src/channels.h @@ -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 */ diff --git a/src/epg.c b/src/epg.c index c43248a6..6137a50b 100644 --- a/src/epg.c +++ b/src/epg.c @@ -33,6 +33,9 @@ #include "htsp.h" #include "htsmsg_binary.h" + + + #define EPG_MAX_AGE 86400 #define EPG_GLOBAL_HASH_WIDTH 1024 diff --git a/src/epg.h b/src/epg.h index ebd7b0c9..69b1a9dc 100644 --- a/src/epg.h +++ b/src/epg.h @@ -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 */ diff --git a/src/main.c b/src/main.c index 370bb2ae..c2461ce5 100644 --- a/src/main.c +++ b/src/main.c @@ -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(); diff --git a/src/webui/extjs.c b/src/webui/extjs.c index 3ed9f8b4..c2d8083d 100644 --- a/src/webui/extjs.c +++ b/src/webui/extjs.c @@ -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); diff --git a/src/webui/statedump.c b/src/webui/statedump.c index 911a31ec..a638e7a6 100644 --- a/src/webui/statedump.c +++ b/src/webui/statedump.c @@ -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 : "", +#endif ch->ch_icon ?: ""); } } diff --git a/src/webui/static/app/epggrab.js b/src/webui/static/app/epggrab.js new file mode 100644 index 00000000..b4baa0fc --- /dev/null +++ b/src/webui/static/app/epggrab.js @@ -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.
'+ + '
' + + 'To configure manually execute the ' + + 'following command in a shell on the ' + + 'server:
' + + '$ ' + r.data.identifier + + ' --configure
' + + '
' + + '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.'+ + '
' + + '
' + + '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).
' + + 'Make sure that the grabber is properly ' + + 'configured before saving configuration.
'+ + '
' + + 'To configure manually execute the ' + + 'following command in a shell on the ' + + 'server:
' + + '$ ' + r.data.identifier + + ' --configure
' + + '
' + + '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.'+ + '
' + + '
' + + '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; +} + diff --git a/src/webui/static/app/tvheadend.js b/src/webui/static/app/tvheadend.js index 5835b3f1..1b70dcb5 100644 --- a/src/webui/static/app/tvheadend.js +++ b/src/webui/static/app/tvheadend.js @@ -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,