started work on epggrab module for pyepg (demo).

This commit is contained in:
Adam Sutton 2012-05-17 12:03:05 +01:00
parent 1a73eecb65
commit 2819dbbf61
5 changed files with 414 additions and 5 deletions

View file

@ -5,11 +5,12 @@
#include "settings.h"
#include "tvheadend.h"
#include "epggrab.h"
#include "epggrab/pyepg.h"
/* Thread protection */
int epggrab_confver;
pthread_mutex_t epggrab_mutex;
pthread_cond_t epggrab_cond;
int epggrab_confver;
pthread_mutex_t epggrab_mutex;
pthread_cond_t epggrab_cond;
/* Config */
uint32_t epggrab_advanced;
@ -18,6 +19,9 @@ uint32_t epggrab_interval;
epggrab_module_t* epggrab_module;
epggrab_sched_list_t epggrab_schedule;
/* Modules */
epggrab_module_t* epggrab_module_pyepg;
/* Internal prototypes */
static void* _epggrab_thread ( void* );
static time_t _epggrab_thread_simple ( void );
@ -37,6 +41,9 @@ void epggrab_init ( void )
epggrab_interval = 12; // hours
epggrab_module = NULL; // disabled
/* Initialise modules */
epggrab_module_pyepg = pyepg_init();
/* Start thread */
pthread_t tid;
pthread_attr_t tattr;
@ -126,6 +133,7 @@ void* _epggrab_thread ( void* p )
epggrab_module_t* epggrab_module_find_by_name ( const char *name )
{
if ( strcmp(name, "pyepg") == 0 ) return epggrab_module_pyepg;
return NULL;
}
@ -156,7 +164,7 @@ void _epggrab_load ( void )
HTSMSG_FOREACH(f, s) {
if ((e = htsmsg_get_map_by_field(f)) != NULL) {
es = calloc(1, sizeof(epggrab_sched_t));
str = htsmsg_get_str(e, "module");
str = htsmsg_get_str(e, "mod");
if (str) es->mod = epggrab_module_find_by_name(str);
str = htsmsg_get_str(e, "opts");
if (str) es->opts = strdup(str);
@ -192,7 +200,7 @@ void _epggrab_save ( void )
s = htsmsg_create_list();
LIST_FOREACH(es, &epggrab_schedule, es_link) {
e = htsmsg_create_map();
if ( es->mod ) htsmsg_add_str(e, "module", es->mod->name());
if ( es->mod ) htsmsg_add_str(e, "mod", es->mod->name());
if ( es->opts ) htsmsg_add_str(e, "opts", es->opts);
c = htsmsg_create_map();
cron_pack(&es->cron, c);

394
src/epggrab/pyepg.c Normal file
View file

@ -0,0 +1,394 @@
/*
* PyEPG grabber
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "htsmsg_xml.h"
#include "tvheadend.h"
#include "spawn.h"
#include "epg.h"
#include "epggrab/pyepg.h"
void _pyepg_grab ( const char **argv );
void _pyepg_parse ( htsmsg_t *data );
void _pyepg_parse_epg ( htsmsg_t *data );
int _pyepg_parse_channel ( htsmsg_t *data );
int _pyepg_parse_brand ( htsmsg_t *data );
int _pyepg_parse_season ( htsmsg_t *data );
int _pyepg_parse_episode ( htsmsg_t *data );
int _pyepg_parse_broadcast ( htsmsg_t *data, epg_channel_t *channel );
int _pyepg_parse_schedule ( htsmsg_t *data );
int _pyepg_parse_time ( const char *str, time_t *tm );
/* ************************************************************************
* Module Setup
* ***********************************************************************/
static epggrab_module_t pyepg_module;
static const char* pyepg_name ( void )
{
return "pyepg";
}
static void pyepg_run ( const char *iopts )
{
int i = 1;
const char *argv[32]; // 32 args max!
char *toksave, *tok;
char *opts = strdup(iopts);
/* TODO: do something better! */
argv[0] = "/usr/bin/pyepg";
if ( opts ) {
tok = strtok_r(opts, " ", &toksave);
while ( tok != NULL ) {
argv[i++] = tok;
tok = strtok_r(NULL, " ", &toksave);
}
argv[i] = NULL;
}
_pyepg_grab(argv);
free(opts);
}
epggrab_module_t* pyepg_init ( void )
{
pyepg_module.enable = NULL;
pyepg_module.disable = NULL;
pyepg_module.name = pyepg_name;
pyepg_module.run = pyepg_run;
return &pyepg_module;
}
/* **************************************************************************
* Grabber
* *************************************************************************/
void _pyepg_grab ( const char **argv )
{
int i = 0, outlen;
char *outbuf;
char cmdstr[1024], errbuf[100];
time_t t1, t2;
htsmsg_t *body;
/* Debug */
cmdstr[0] = '\0';
while ( argv[i] ) {
strcat(cmdstr, argv[i++]);
if ( argv[i] ) strcat(cmdstr, " ");
}
tvhlog(LOG_DEBUG, "pyepg", "grab %s", cmdstr);
/* Grab */
time(&t1);
outlen = spawn_and_store_stdout(argv[0], (char *const*)argv, &outbuf);
if ( outlen < 1 ) {
tvhlog(LOG_ERR, "pyepg", "no output detected");
return;
}
time(&t2);
tvhlog(LOG_DEBUG, "pyepg", "grab took %d seconds", t2 - t1);
/* Extract */
body = htsmsg_xml_deserialize(outbuf, errbuf, sizeof(errbuf));
if ( !body ) {
tvhlog(LOG_ERR, "pyepg", "unable to parse output [e=%s]", errbuf);
return;
}
/* Parse */
pthread_mutex_lock(&global_lock);
_pyepg_parse(body);
pthread_mutex_unlock(&global_lock);
htsmsg_destroy(body);
}
/* **************************************************************************
* Parsing
* *************************************************************************/
void _pyepg_parse ( htsmsg_t *data )
{
htsmsg_t *tags, *epg;
if ((tags = htsmsg_get_map(data, "tags")) == NULL) return;
/* PyEPG format */
if ((epg = htsmsg_get_map(tags, "epg")) != NULL) _pyepg_parse_epg(epg);
/* XMLTV format */
if ((epg = htsmsg_get_map(tags, "tv")) != NULL) return;// TODO: add
}
int _pyepg_parse_channel ( htsmsg_t *data )
{
int save = 0;
htsmsg_t *attr, *tags;
const char *id, *name = NULL;
epg_channel_t *channel;
if ( data == NULL ) return 0;
if ((attr = htsmsg_get_map(data, "attrib")) == NULL) return 0;
if ((id = htsmsg_get_str(attr, "id")) == NULL) return 0;
if ((tags = htsmsg_get_map(data, "tags")) == NULL) return 0;
/* Find channel */
if ((channel = epg_channel_find(id, name, NULL, NULL)) == NULL) return 0;
// TODO: need to save if created
return save;
}
int _pyepg_parse_brand ( htsmsg_t *data )
{
int save = 0;
htsmsg_t *attr, *tags;
epg_brand_t *brand;
const char *str;
uint32_t u32;
if ( data == NULL ) return 0;
if ((attr = htsmsg_get_map(data, "attrib")) == NULL) return 0;
if ((str = htsmsg_get_str(attr, "id")) == NULL) return 0;
if ((tags = htsmsg_get_map(data, "tags")) == NULL) return 0;
/* Find brand */
if ((brand = epg_brand_find_by_id(str, 1)) == NULL) return 0;
// TODO: do we need to save if created?
/* Set title */
if ((str = htsmsg_xml_get_cdata_str(tags, "title"))) {
save |= epg_brand_set_title(brand, str);
}
/* Set summary */
if ((str = htsmsg_xml_get_cdata_str(tags, "summary"))) {
save |= epg_brand_set_summary(brand, str);
}
/* Set icon */
#if TODO
if ((str = htsmsg_xml_get_cdata_str(tags, "icon"))) {
save |= epg_brand_set_icon(brand, str);
}
#endif
/* Set season count */
if (htsmsg_xml_get_cdata_u32(tags, "series-count", &u32)) {
save |= epg_brand_set_season_count(brand, u32);
}
return save;
}
int _pyepg_parse_season ( htsmsg_t *data )
{
int save = 0;
htsmsg_t *attr, *tags;
epg_season_t *season;
epg_brand_t *brand;
const char *str;
uint32_t u32;
if ( data == NULL ) return 0;
if ((attr = htsmsg_get_map(data, "attrib")) == NULL) return 0;
if ((str = htsmsg_get_str(attr, "id")) == NULL) return 0;
if ((tags = htsmsg_get_map(data, "tags")) == NULL) return 0;
/* Find series */
if ((season = epg_season_find_by_id(str, 1)) == NULL) return 0;
// TODO: do we need to save if created?
/* Set brand */
if ((str = htsmsg_xml_get_cdata_str(tags, "brand"))) {
if ((brand = epg_brand_find_by_id(str, 0))) {
save |= epg_season_set_brand(season, brand);
}
}
/* Set title */
#if TODO
if ((str = htsmsg_xml_get_cdata_str(tags, "title"))) {
save |= epg_season_set_title(season, str);
}
/* Set summary */
if ((str = htsmsg_xml_get_cdata_str(tags, "summary"))) {
save |= epg_season_set_summary(season, str);
}
/* Set icon */
if ((str = htsmsg_xml_get_cdata_str(tags, "icon"))) {
save |= epg_season_set_icon(season, str);
}
#endif
/* Set season number */
if (htsmsg_xml_get_cdata_u32(tags, "number", &u32)) {
save |= epg_season_set_number(season, u32);
}
/* Set episode count */
if (htsmsg_xml_get_cdata_u32(tags, "episode-count", &u32)) {
save |= epg_season_set_episode_count(season, u32);
}
return save;
}
int _pyepg_parse_episode ( htsmsg_t *data )
{
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;
if ( data == NULL ) return 0;
if ((attr = htsmsg_get_map(data, "attrib")) == NULL) return 0;
if ((str = htsmsg_get_str(attr, "id")) == NULL) return 0;
if ((tags = htsmsg_get_map(data, "tags")) == NULL) return 0;
/* Find episode */
if ((episode = epg_episode_find_by_id(str, 1)) == NULL) return 0;
// TODO: do we need to save if created?
/* Set brand */
if ((str = htsmsg_xml_get_cdata_str(tags, "brand"))) {
if ((brand = epg_brand_find_by_id(str, 0))) {
save |= epg_episode_set_brand(episode, brand);
}
}
/* Set season */
if ((str = htsmsg_xml_get_cdata_str(tags, "season"))) {
if ((season = epg_season_find_by_id(str, 0))) {
save |= epg_episode_set_season(episode, season);
}
}
/* Set title/subtitle */
if ((str = htsmsg_xml_get_cdata_str(tags, "title"))) {
save |= epg_episode_set_title(episode, str);
}
if ((str = htsmsg_xml_get_cdata_str(tags, "subtitle"))) {
save |= epg_episode_set_subtitle(episode, str);
}
/* Set summary */
if ((str = htsmsg_xml_get_cdata_str(tags, "summary"))) {
save |= epg_episode_set_summary(episode, str);
}
/* Number */
if (htsmsg_xml_get_cdata_u32(tags, "number", &u32)) {
save |= epg_episode_set_number(episode, u32);
}
/* Genre */
// TODO: can actually have multiple!
#if TODO
if ((str = htsmsg_xml_get_cdata_str(tags, "genre"))) {
// TODO: conversion?
save |= epg_episode_set_genre(episode, str);
}
#endif
/* TODO: extra metadata */
return save;
}
int _pyepg_parse_broadcast ( htsmsg_t *data, epg_channel_t *channel )
{
int save = 0;
htsmsg_t *attr;//, *tags;
epg_episode_t *episode;
epg_broadcast_t *broadcast;
const char *id, *start, *stop;
time_t tm_start, tm_stop;
if ( data == NULL || channel == NULL ) return 0;
if ((attr = htsmsg_get_map(data, "attrib")) == NULL) return 0;
if ((id = htsmsg_get_str(attr, "episode")) == NULL) return 0;
if ((start = htsmsg_get_str(attr, "start")) == NULL ) return 0;
if ((stop = htsmsg_get_str(attr, "stop")) == NULL ) return 0;
/* Find episode */
if ((episode = epg_episode_find_by_id(id, 1)) == NULL) return 0;
/* Parse times */
if (!_pyepg_parse_time(start, &tm_start)) return 0;
if (!_pyepg_parse_time(stop, &tm_stop)) return 0;
/* Find broadcast */
// TODO: need to think about this
if ((broadcast = epg_broadcast_find(channel, episode, tm_start, tm_stop, 1)) == NULL) return 0;
save = 1;
/* TODO: extra metadata */
return save;
}
int _pyepg_parse_schedule ( htsmsg_t *data )
{
int save = 0;
htsmsg_t *attr, *tags;
htsmsg_field_t *f;
epg_channel_t *channel;
const char *str;
if ( data == NULL ) return 0;
if ((attr = htsmsg_get_map(data, "attrib")) == NULL) return 0;
if ((str = htsmsg_get_str(attr, "channel")) == NULL) return 0;
if ((channel = epg_channel_find_by_id(str, 0)) == NULL) return 0;
if ((tags = htsmsg_get_map(data, "tags")) == NULL) return 0;
HTSMSG_FOREACH(f, tags) {
if (strcmp(f->hmf_name, "broadcast")) {
save |= _pyepg_parse_broadcast(htsmsg_get_map_by_field(f), channel);
}
}
return save;
}
void _pyepg_parse_epg ( htsmsg_t *data )
{
int save = 0;
htsmsg_t *tags;
htsmsg_field_t *f;
if ((tags = htsmsg_get_map(data, "tags")) == NULL) return;
HTSMSG_FOREACH(f, tags) {
if (strcmp(f->hmf_name, "channel") == 0 ) {
save |= _pyepg_parse_channel(htsmsg_get_map_by_field(f));
} else if (strcmp(f->hmf_name, "brand") == 0 ) {
save |= _pyepg_parse_brand(htsmsg_get_map_by_field(f));
} else if (strcmp(f->hmf_name, "series") == 0 ) {
save |= _pyepg_parse_season(htsmsg_get_map_by_field(f));
} else if (strcmp(f->hmf_name, "episode") == 0 ) {
save |= _pyepg_parse_episode(htsmsg_get_map_by_field(f));
} else if (strcmp(f->hmf_name, "schedule") == 0 ) {
save |= _pyepg_parse_schedule(htsmsg_get_map_by_field(f));
}
}
/* Updated */
if (save) epg_updated();
}

7
src/epggrab/pyepg.h Normal file
View file

@ -0,0 +1,7 @@
/*
* PyEPG grabber module
*/
#include "epggrab.h"
epggrab_module_t* pyepg_init ( void );