Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
added more robust and universal m3u parser (used by IPTV)
  • Loading branch information
perexg committed Nov 5, 2015
1 parent 0785258 commit 190bdf7
Show file tree
Hide file tree
Showing 8 changed files with 371 additions and 192 deletions.
1 change: 1 addition & 0 deletions Makefile
Expand Up @@ -182,6 +182,7 @@ SRCS-1 = \
src/htsmsg_xml.c \
src/misc/dbl.c \
src/misc/json.c \
src/misc/m3u.c \
src/settings.c \
src/htsbuf.c \
src/trap.c \
Expand Down
5 changes: 3 additions & 2 deletions src/bouquet.c
Expand Up @@ -37,7 +37,7 @@ static void bouquet_remove_service(bouquet_t *bq, service_t *s);
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);
static int bouquet_download_process(void *aux, const char *last_url, const char *host_url, char *data, size_t len);

/**
*
Expand Down Expand Up @@ -1099,7 +1099,8 @@ parse_enigma2(bouquet_t *bq, char *data)
}

static int
bouquet_download_process(void *aux, const char *last_url, char *data, size_t len)
bouquet_download_process(void *aux, const char *last_url, const char *host_url,
char *data, size_t len)
{
bouquet_download_t *bqd = aux;
while (*data) {
Expand Down
27 changes: 24 additions & 3 deletions src/download.c
Expand Up @@ -65,7 +65,7 @@ download_file(download_t *dn, const char *filename)
last_url = strrchr(filename, '/');
if (last_url)
last_url++;
res = dn->process(dn->aux, last_url, data, off);
res = dn->process(dn->aux, last_url, NULL, data, off);
} else {
res = -1;
}
Expand Down Expand Up @@ -95,7 +95,9 @@ download_fetch_complete(http_client_t *hc)
{
download_t *dn = hc->hc_aux;
char *last_url = NULL;
url_t u;
char host_url[512];
char *s, *p;
url_t u, u2;

switch (hc->hc_code) {
case HTTP_STATUS_MOVED:
Expand All @@ -111,14 +113,33 @@ download_fetch_complete(http_client_t *hc)
if (last_url)
last_url++;
}
if ((p = http_arg_get(&hc->hc_args, "Host")) != NULL) {
snprintf(host_url, sizeof(host_url), "%s://%s",
hc->hc_ssl ? "https" : "http", p);
} else if (dn->url) {
s = strdupa(dn->url);
if ((p = strchr(s, '/')) != NULL) {
p++;
if (*p == '/')
p++;
if ((p = strchr(p, '/')) != NULL)
*p = '\0';
}
urlinit(&u2);
if (!urlparse(s, &u2))
snprintf(host_url, sizeof(host_url), "%s", s);
urlreset(&u2);
} else {
host_url[0] = '\0';
}

pthread_mutex_lock(&global_lock);

if (dn->http_client == NULL)
goto out;

if (hc->hc_code == HTTP_STATUS_OK && hc->hc_result == 0 && hc->hc_data_size > 0)
dn->process(dn->aux, last_url, hc->hc_data, hc->hc_data_size);
dn->process(dn->aux, last_url, host_url, hc->hc_data, hc->hc_data_size);
else
tvherror(dn->log, "unable to fetch data from url [%d-%d/%zd]",
hc->hc_code, hc->hc_result, hc->hc_data_size);
Expand Down
3 changes: 2 additions & 1 deletion src/download.h
Expand Up @@ -27,7 +27,8 @@ typedef struct download {
char *url;
void *aux;
int ssl_peer_verify;
int (*process)(void *aux, const char *last_url, char *data, size_t len);
int (*process)(void *aux, const char *last_url, const char *host_url,
char *data, size_t len);
void (*stop)(void *aux);
/* internal members */
http_client_t *http_client;
Expand Down
168 changes: 44 additions & 124 deletions src/input/mpegts/iptv/iptv_auto.c
Expand Up @@ -22,7 +22,7 @@
#include "iptv_private.h"
#include "channels.h"
#include "download.h"
#include "intlconv.h"
#include "misc/m3u.h"

#include <fcntl.h>
#include <sys/stat.h>
Expand All @@ -33,70 +33,15 @@ typedef struct auto_private {
gtimer_t in_auto_timer;
} auto_private_t;

/*
*
*/
static char *get_m3u_str(char *data, char **res)
{
char *p = data, first = *data;

if (first == '"' || first == '\'') {
data++; p++;
while (*data && *data != first)
data++;
} else {
while (*data && *data != ',' && *data > ' ')
data++;
}
if (*data) {
*data = '\0';
data++;
}
*res = data;
return p;
}

/*
*
*/
static char *until_eol(char *d)
{
while (*d && *d != '\r' && *d != '\n') d++;
if (*d) { *d = '\0'; d++; }
while (*d && (*d == '\r' || *d == '\n')) d++;
return d;
}

/*
*
*/
static int replace_string(char **s, const char *n, const char *charset_id)
{
char *c;

if (charset_id && n) {
c = intlconv_to_utf8safestr(charset_id, n, strlen(n)*2);
} else
c = n ? strdup(n) : NULL;
if (strcmp(*s ?: "", n ?: "") == 0) {
free(c);
return 0;
}
free(*s);
*s = c;
return 1;
}

/*
*
*/
static void
iptv_auto_network_process_m3u_item(iptv_network_t *in,
const char *last_url, const char *charset_id,
const char *last_url,
const http_arg_list_t *remove_args,
const char *url, const char *name,
const char *logo, const char *epgid,
int64_t chnum, int *total, int *count)
int64_t chnum, htsmsg_t *item,
int *total, int *count)
{
htsmsg_t *conf;
mpegts_mux_t *mm;
Expand All @@ -108,7 +53,10 @@ iptv_auto_network_process_m3u_item(iptv_network_t *in,
htsbuf_queue_t q;
int delim;
size_t l;
char url2[512], custom[512], name2[128], buf[32], *n, *x = NULL, *y;
const char *url, *name, *logo, *epgid;
char url2[512], custom[512], name2[128], buf[32], *n, *y;

url = htsmsg_get_str(item, "m3u-url");

if (url == NULL ||
(strncmp(url, "file://", 7) &&
Expand All @@ -128,9 +76,16 @@ iptv_auto_network_process_m3u_item(iptv_network_t *in,
chnum += (int64_t)*total * CHANNEL_SPLIT;
}

name = htsmsg_get_str(item, "m3u-name");
if (name == NULL)
name = "";

logo = htsmsg_get_str(item, "tvg-logo");
if (logo == NULL)
logo = htsmsg_get_str(item, "logo");

epgid = htsmsg_get_str(item, "tvg-id");

urlinit(&u);
custom[0] = '\0';

Expand Down Expand Up @@ -199,12 +154,7 @@ iptv_auto_network_process_m3u_item(iptv_network_t *in,
}

skip_url:
x = NULL;
if (last_url) {
if (charset_id) {
x = intlconv_to_utf8safestr(charset_id, name, strlen(name)*2);
name = x;
}
snprintf(n = name2, sizeof(name2), "%s - %s", last_url, name);
} else {
n = (char *)name;
Expand Down Expand Up @@ -234,7 +184,11 @@ iptv_auto_network_process_m3u_item(iptv_network_t *in,
im->mm_iptv_icon = logo ? strdup(logo) : NULL;
change = 1;
}
change |= replace_string(&im->mm_iptv_epgid, epgid, charset_id);
if (strcmp(im->mm_iptv_epgid ?: "", epgid ?: "")) {
free(im->mm_iptv_epgid);
im->mm_iptv_epgid = epgid ? strdup(epgid) : NULL;
change = 1;
}
if (strcmp(im->mm_iptv_hdr ?: "", custom)) {
free(im->mm_iptv_hdr);
im->mm_iptv_hdr = strdup(custom);
Expand Down Expand Up @@ -277,7 +231,6 @@ iptv_auto_network_process_m3u_item(iptv_network_t *in,
}

end:
free(x);
urlreset(&u);
}

Expand All @@ -287,74 +240,40 @@ iptv_auto_network_process_m3u_item(iptv_network_t *in,
static int
iptv_auto_network_process_m3u(iptv_network_t *in, char *data,
const char *last_url,
const char *host_url,
http_arg_list_t *remove_args,
int64_t chnum)
{
char *url, *name = NULL, *logo = NULL, *epgid = NULL;
char *charset_id = intlconv_charset_id(in->in_ctx_charset, 0, 1);
int total = 0, count = 0;

while (*data && *data != '\n') data++;
if (*data) data++;
while (*data) {
if (strncmp(data, "#EXTINF:", 8) == 0) {
name = NULL;
logo = NULL;
epgid = NULL;
data += 8;
while (*data > ' ' && *data != ',') data++;
while (1) {
while (*data && *data <= ' ') data++;
if (*data == ',') break;
if (strncmp(data, "tvg-logo=", 9) == 0) {
logo = get_m3u_str(data + 9, &data); continue;
} else if (strncmp(data, "tvg-id=", 7) == 0) {
epgid = get_m3u_str(data + 7, &data); continue;
} else if (strncmp(data, "logo=", 5) == 0) {
logo = get_m3u_str(data + 5, &data); continue;
} else {
data++;
while (*data && *data != ',' && *data != '=') data++;
if (*data == '=')
get_m3u_str(data + 1, &data);
}
}
if (*data == ',') {
data++;
while (*data && *data <= ' ') data++;
if (*data)
name = data;
}
data = until_eol(data);
continue;
} else if (strncmp(data, "#EXT", 4) == 0) {
data += 4;
while (*data && *data != '\n') data++;
if (*data) data++;
continue;
}
while (*data && *data <= ' ') data++;
url = data;
data = until_eol(data);
if (*url && *url > ' ')
iptv_auto_network_process_m3u_item(in, last_url, charset_id,
remove_args, url, name,
logo, epgid,
chnum, &total, &count);
htsmsg_t *m, *items, *item;
htsmsg_field_t *f;
int ret = 0;

m = parse_m3u(data, in->in_ctx_charset, host_url);
items = htsmsg_get_list(m, "items");
HTSMSG_FOREACH(f, items) {
if ((item = htsmsg_field_get_map(f)) == NULL) continue;
iptv_auto_network_process_m3u_item(in, last_url,
remove_args, chnum,
item,
&total, &count);

}

htsmsg_destroy(m);
if (total == 0)
return -1;
tvhinfo("iptv", "m3u parse: %d new mux(es) in network '%s' (total %d)",
count, in->mn_network_name, total);
return 0;
ret = -1;
else
tvhinfo("iptv", "m3u parse: %d new mux(es) in network '%s' (total %d)",
count, in->mn_network_name, total);
return ret;
}

/*
*
*/
static int
iptv_auto_network_process(void *aux, const char *last_url, char *data, size_t len)
iptv_auto_network_process(void *aux, const char *last_url,
const char *host_url, char *data, size_t len)
{
auto_private_t *ap = aux;
iptv_network_t *in = ap->in_network;
Expand All @@ -381,7 +300,8 @@ iptv_auto_network_process(void *aux, const char *last_url, char *data, size_t le
while (*data && *data <= ' ') data++;

if (!strncmp(data, "#EXTM3U", 7))
r = iptv_auto_network_process_m3u(in, data, last_url, &remove_args, in->in_channel_number);
r = iptv_auto_network_process_m3u(in, data, last_url, host_url,
&remove_args, in->in_channel_number);

http_arg_flush(&remove_args);

Expand Down

0 comments on commit 190bdf7

Please sign in to comment.