Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
bouquet: add enigma2 parser, fixes #2994
  • Loading branch information
perexg committed Oct 19, 2015
1 parent 1ca4f29 commit ffd995c
Show file tree
Hide file tree
Showing 9 changed files with 247 additions and 14 deletions.
2 changes: 1 addition & 1 deletion src/api/api_bouquet.c
Expand Up @@ -64,7 +64,7 @@ api_bouquet_create
htsmsg_t *conf;
bouquet_t *bq;

if (!(conf = htsmsg_get_map(args, "conf")))
if (!(conf = htsmsg_get_map(args, "conf")))
return EINVAL;

pthread_mutex_lock(&global_lock);
Expand Down
176 changes: 168 additions & 8 deletions src/bouquet.c
Expand Up @@ -23,10 +23,20 @@
#include "service.h"
#include "channels.h"
#include "service_mapper.h"
#include "download.h"

typedef struct bouquet_download {
bouquet_t *bq;
download_t download;
gtimer_t timer;
} bouquet_download_t;

bouquet_tree_t bouquets;

static uint64_t bouquet_get_channel_number0(bouquet_t *bq, service_t *t);
static void bouquet_download_trigger(bouquet_t *bq);
static void bouquet_download_stop(void *aux);
static int bouquet_download_process(void *aux, const char *last_url, char *data, size_t len);

/**
*
Expand All @@ -45,13 +55,16 @@ bouquet_create(const char *uuid, htsmsg_t *conf,
const char *name, const char *src)
{
bouquet_t *bq, *bq2;
bouquet_download_t *bqd;
char buf[128];
int i;

lock_assert(&global_lock);

bq = calloc(1, sizeof(bouquet_t));
bq->bq_services = idnode_set_create(1);
bq->bq_active_services = idnode_set_create(1);
bq->bq_ext_url_period = 60;

if (idnode_insert(&bq->bq_id, uuid, &bouquet_class, 0)) {
if (uuid)
Expand All @@ -78,11 +91,26 @@ bouquet_create(const char *uuid, htsmsg_t *conf,
bq->bq_src = strdup(src);
}

if (bq->bq_ext_url) {
free(bq->bq_src);
snprintf(buf, sizeof(buf), "exturl://%s", idnode_uuid_as_sstr(&bq->bq_id));
bq->bq_src = strdup(buf);
bq->bq_download = bqd = calloc(1, sizeof(*bqd));
bqd->bq = bq;
download_init(&bqd->download, "bouquet");
bqd->download.process = bouquet_download_process;
bqd->download.stop = bouquet_download_stop;
bouquet_change_comment(bq, bq->bq_ext_url, 0);
}

bq2 = RB_INSERT_SORTED(&bouquets, bq, bq_link, _bq_cmp);
assert(bq2 == NULL);

bq->bq_saveflag = 1;

if (bq->bq_ext_url)
bouquet_download_trigger(bq);

return bq;
}

Expand All @@ -92,17 +120,25 @@ bouquet_create(const char *uuid, htsmsg_t *conf,
static void
bouquet_destroy(bouquet_t *bq)
{
bouquet_download_t *bqd;

if (!bq)
return;

RB_REMOVE(&bouquets, bq, bq_link);
idnode_unlink(&bq->bq_id);

if ((bqd = bq->bq_download) != NULL) {
download_done(&bqd->download);
free(bqd);
}

idnode_set_free(bq->bq_active_services);
idnode_set_free(bq->bq_services);
assert(bq->bq_services_waiting == NULL);
free((char *)bq->bq_chtag_waiting);
free(bq->bq_name);
free(bq->bq_ext_url);
free(bq->bq_src);
free(bq->bq_comment);
free(bq);
Expand Down Expand Up @@ -254,7 +290,7 @@ bouquet_map_channel(bouquet_t *bq, service_t *t)
*
*/
void
bouquet_add_service(bouquet_t *bq, service_t *s, uint64_t lcn, uint32_t tag)
bouquet_add_service(bouquet_t *bq, service_t *s, uint64_t lcn, const char *tag)
{
service_lcn_t *tl;
idnode_list_mapping_t *ilm;
Expand Down Expand Up @@ -494,8 +530,8 @@ bouquet_get_channel_number(bouquet_t *bq, service_t *t)
/*
*
*/
static uint32_t
bouquet_get_tag_number(bouquet_t *bq, service_t *t)
static const char *
bouquet_get_tag_name(bouquet_t *bq, service_t *t)
{
return 0;
}
Expand Down Expand Up @@ -763,7 +799,7 @@ bouquet_class_services_get ( void *obj )
bouquet_t *bq = obj;
service_t *t;
int64_t lcn;
uint32_t tag;
const char *tag;
size_t z;

/* Add all */
Expand All @@ -772,8 +808,8 @@ bouquet_class_services_get ( void *obj )
e = htsmsg_create_map();
if ((lcn = bouquet_get_channel_number0(bq, t)) != 0)
htsmsg_add_s64(e, "lcn", lcn);
if ((tag = bouquet_get_tag_number(bq, t)) != 0)
htsmsg_add_s64(e, "tag", lcn);
if ((tag = bouquet_get_tag_name(bq, t)) != NULL)
htsmsg_add_str(e, "tag", tag);
htsmsg_add_msg(m, idnode_uuid_as_sstr(&t->s_id), e);
}

Expand Down Expand Up @@ -813,6 +849,12 @@ bouquet_class_services_count_get ( void *obj )
return &u32;
}

static void
bouquet_class_ext_url_notify ( void *obj, const char *lang )
{
bouquet_download_trigger((bouquet_t *)obj);
}

const idclass_t bouquet_class = {
.ic_class = "bouquet",
.ic_caption = N_("Bouquet"),
Expand Down Expand Up @@ -887,6 +929,30 @@ const idclass_t bouquet_class = {
.name = N_("Name"),
.off = offsetof(bouquet_t, bq_name),
},
{
.type = PT_STR,
.id = "ext_url",
.name = N_("External URL"),
.off = offsetof(bouquet_t, bq_ext_url),
.opts = PO_HIDDEN | PO_MULTILINE,
.notify = bouquet_class_ext_url_notify,
},
{
.type = PT_BOOL,
.id = "ssl_peer_verify",
.name = N_("ssl_peer_verify"),
.off = offsetof(bouquet_t, bq_ssl_peer_verify),
.opts = PO_ADVANCED | PO_HIDDEN,
.notify = bouquet_class_ext_url_notify,
},
{
.type = PT_U32,
.id = "ext_url_period",
.name = N_("Re-fetch period (mins)"),
.off = offsetof(bouquet_t, bq_ext_url_period),
.opts = PO_ADVANCED | PO_HIDDEN,
.def.i = 60
},
{
.type = PT_STR,
.id = "source",
Expand Down Expand Up @@ -935,6 +1001,100 @@ const idclass_t bouquet_class = {
}
};

/**
*
*/
static void
bouquet_download_trigger0(void *aux)
{
bouquet_download_t *bqd = aux;
bouquet_t *bq = bqd->bq;

download_start(&bqd->download, bq->bq_ext_url, bqd);
gtimer_arm(&bqd->timer, bouquet_download_trigger0, bqd,
MAX(1, bq->bq_ext_url_period) * 60);
}

static void
bouquet_download_trigger(bouquet_t *bq)
{
bouquet_download_t *bqd = bq->bq_download;
if (bqd) {
bqd->download.ssl_peer_verify = bq->bq_ssl_peer_verify;
bouquet_download_trigger0(bqd);
}
}

static void
bouquet_download_stop(void *aux)
{
bouquet_download_t *bqd = aux;
gtimer_disarm(&bqd->timer);
}

static int
parse_enigma2(bouquet_t *bq, char *data)
{
extern service_t *mpegts_service_find_e2(uint32_t stype, uint32_t sid,
uint32_t tsid, uint32_t onid,
uint32_t hash);
char *argv[11], *p, *tagname = NULL, *name;
long lv, stype, sid, tsid, onid, hash;
uint32_t seen = 0;
int n;

while (*data) {
if (strncmp(data, "#NAME ", 6) == 0) {
for (data += 6, p = data; *data && *data != '\r' && *data != '\n'; data++);
if (*data) { *data = '\0'; data++; }
if (bq->bq_name == NULL || bq->bq_name[0] == '\0')
bq->bq_name = strdup(p);
} if (strncmp(data, "#SERVICE ", 9) == 0) {
data += 9, p = data;
while (*data && *data != '\r' && *data != '\n') data++;
if (*data) { *data = '\0'; data++; }
n = http_tokenize(p, argv, ARRAY_SIZE(argv), ':');
if (n >= 10) {
if (strtol(argv[0], NULL, 0) != 1) goto next; /* item type */
lv = strtol(argv[1], NULL, 16); /* service flags? */
if (lv != 0 && lv != 0x64) goto next;
stype = strtol(argv[2], NULL, 16); /* DVB service type */
sid = strtol(argv[3], NULL, 16); /* DVB service ID */
tsid = strtol(argv[4], NULL, 16);
onid = strtol(argv[5], NULL, 16);
hash = strtol(argv[6], NULL, 16);
name = n > 10 ? argv[10] : NULL;
if (lv == 0) {
service_t *s = mpegts_service_find_e2(stype, sid, tsid, onid, hash);
if (s)
bouquet_add_service(bq, s, ++seen, tagname);
} else if (lv == 64) {
tagname = name;
}
}
} else {
while (*data && *data != '\r' && *data != '\n') data++;
}
next:
while (*data && (*data == '\r' || *data == '\n')) data++;
}
bouquet_completed(bq, seen);
tvhinfo("bouquet", "parsed Enigma2 bouquet %s (%d services)", bq->bq_name, seen);
return 0;
}

static int
bouquet_download_process(void *aux, const char *last_url, char *data, size_t len)
{
bouquet_download_t *bqd = aux;
while (*data) {
while (*data && *data < ' ') data++;
if (*data && !strncmp(data, "#NAME ", 6))
return parse_enigma2(bqd->bq, data);
}
return 0;
}

/**
*
*/
Expand Down Expand Up @@ -966,7 +1126,7 @@ bouquet_service_resolve(void)
htsmsg_field_t *f;
service_t *s;
int64_t lcn;
uint32_t tag;
const char *tag;
int saveflag;

lock_assert(&global_lock);
Expand All @@ -979,7 +1139,7 @@ bouquet_service_resolve(void)
HTSMSG_FOREACH(f, bq->bq_services_waiting) {
if ((e = htsmsg_field_get_map(f)) == NULL) continue;
lcn = htsmsg_get_s64_or_default(e, "lcn", 0);
tag = htsmsg_get_u32_or_default(e, "tag", 0);
tag = htsmsg_get_str(e, "tag");
s = service_find_by_identifier(f->hmf_name);
if (s)
bouquet_add_service(bq, s, lcn, tag);
Expand Down
7 changes: 6 additions & 1 deletion src/bouquet.h
Expand Up @@ -44,6 +44,9 @@ typedef struct bouquet {
channel_tag_t*bq_chtag_ptr;
const char *bq_chtag_waiting;
char *bq_name;
char *bq_ext_url;
int bq_ssl_peer_verify;
int bq_ext_url_period;
char *bq_src;
char *bq_comment;
idnode_set_t *bq_services;
Expand All @@ -53,6 +56,8 @@ typedef struct bouquet {
uint32_t bq_lcn_offset;
uint64_t bq_last_lcn;

void *bq_download;

} bouquet_t;

typedef RB_HEAD(,bouquet) bouquet_tree_t;
Expand Down Expand Up @@ -85,7 +90,7 @@ bouquet_t * bouquet_find_by_source(const char *name, const char *src, int create

void bouquet_map_to_channels(bouquet_t *bq);
void bouquet_notify_channels(bouquet_t *bq);
void bouquet_add_service(bouquet_t *bq, service_t *s, uint64_t lcn, uint32_t tag);
void bouquet_add_service(bouquet_t *bq, service_t *s, uint64_t lcn, const char *tag);
void bouquet_completed(bouquet_t *bq, uint32_t seen);
void bouquet_change_comment(bouquet_t *bq, const char *comment, int replace);

Expand Down
1 change: 0 additions & 1 deletion src/htsbuf.c
Expand Up @@ -475,4 +475,3 @@ htsbuf_to_string(htsbuf_queue_t *hq)
htsbuf_read(hq, r, hq->hq_size);
return r;
}

4 changes: 4 additions & 0 deletions src/input/mpegts.h
Expand Up @@ -1008,6 +1008,10 @@ mpegts_service_t *mpegts_service_create_raw(mpegts_mux_t *mm);
mpegts_service_t *mpegts_service_find
( mpegts_mux_t *mm, uint16_t sid, uint16_t pmt_pid, int create, int *save );

service_t *
mpegts_service_find_e2
( uint32_t stype, uint32_t sid, uint32_t tsid, uint32_t onid, uint32_t hash);

mpegts_service_t *
mpegts_service_find_by_pid ( mpegts_mux_t *mm, int pid );

Expand Down
4 changes: 2 additions & 2 deletions src/input/mpegts/dvb_psi.c
Expand Up @@ -589,7 +589,7 @@ dvb_freesat_add_service
snprintf(name, sizeof(name), "%s: %s", bi->name, fr->name);
fr->bouquet = bouquet_find_by_source(name, src, 1);
}
bouquet_add_service(fr->bouquet, (service_t *)s, (int64_t)lcn * CHANNEL_SPLIT, 0);
bouquet_add_service(fr->bouquet, (service_t *)s, (int64_t)lcn * CHANNEL_SPLIT, NULL);
return fr->bouquet->bq_enabled;
}

Expand Down Expand Up @@ -1088,7 +1088,7 @@ dvb_bat_completed
services_count++;
if (bq->bq_enabled)
bouquet_add_service(bq, (service_t *)bs->svc,
(int64_t)bs->lcn * CHANNEL_SPLIT, 0);
(int64_t)bs->lcn * CHANNEL_SPLIT, NULL);
}

bouquet_completed(bq, services_count);
Expand Down
2 changes: 1 addition & 1 deletion src/input/mpegts/iptv/iptv.c
Expand Up @@ -107,7 +107,7 @@ iptv_bouquet_update(void *aux)
bouquet_change_comment(bq, in->in_url, 1);
LIST_FOREACH(mm, &in->mn_muxes, mm_network_link)
LIST_FOREACH(ms, &mm->mm_services, s_dvb_mux_link) {
bouquet_add_service(bq, (service_t *)ms, ((iptv_mux_t *)mm)->mm_iptv_chnum, 0);
bouquet_add_service(bq, (service_t *)ms, ((iptv_mux_t *)mm)->mm_iptv_chnum, NULL);
seen++;
}
bouquet_completed(bq, seen);
Expand Down

4 comments on commit ffd995c

@mario-tux
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting feature but I'm not sure how to use. I've tried to download the file 'Vhannibal E1 Hot Bird 13 ott.zip' from http://www.vhannibal.net/. I've added a bouquet with a url like 'file:///home/.../userbouquet.dbe00.tv'. Is it the right way?
The number of services on the new row remains zero. I observed locks and crashs. I can provide details on them if needed.

@perexg
Copy link
Contributor Author

@perexg perexg commented on ffd995c Oct 19, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, .tv file should be the source. Which file exactly ? userbouquet.vh04.tv is fine..

@perexg
Copy link
Contributor Author

@perexg perexg commented on ffd995c Oct 19, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ohh. E2 and E1 .... Actually, E2 parser is implemeted only.

@perexg
Copy link
Contributor Author

@perexg perexg commented on ffd995c Oct 19, 2015

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enigma1 parser was added in a8a29d2 .

Please sign in to comment.