");
if(!simple) {
tcp_qprintf(&tq, "
");
if(ch->ch_icon) {
tcp_qprintf(&tq, "
"
"
"
"",
ch->ch_tag,
refstr_get(ch->ch_icon));
}
tcp_qprintf(&tq, "
");
}
tcp_qprintf(&tq, "
");
tcp_qprintf(&tq,
"
"
"%s",
ch->ch_tag, ch->ch_name);
si = (struct sockaddr_in *)&hc->hc_tcp_session.tcp_self_addr;
tcp_qprintf(&tq,
"
Watch live",
inet_ntoa(si->sin_addr), ntohs(si->sin_port),
ch->ch_sname);
e = epg_event_find_current_or_upcoming(ch);
for(i = 0; i < 3 && e != NULL; i++) {
output_event(hc, &tq, ch, e, simple, 0, 1, 580);
e = TAILQ_NEXT(e, e_link);
}
tcp_qprintf(&tq, "
");
box_bottom(&tq);
tcp_qprintf(&tq, "");
tcp_qprintf(&tq, "
%s",
ch->ch_tag, ch->ch_name);
e = epg_event_find_current_or_upcoming(ch);
if(e != NULL) {
localtime_r(&e->e_start, &a);
wday = a.tm_wday;
for(w = 0; w < 7; w++) {
tcp_qprintf(&tq,
"
"
"%s",
ch->ch_tag, w,
days[(wday + w) % 7]);
while(e != NULL) {
localtime_r(&e->e_start, &a);
if(a.tm_wday != wday + w)
break;
if(a.tm_wday == wday + doff) {
output_event(hc, &tq, ch, e, simple, 0, 1, 580);
}
e = TAILQ_NEXT(e, e_link);
}
}
}
tcp_qprintf(&tq, "
");
box_bottom(&tq);
tcp_qprintf(&tq, "\r\n");
html_footer(&tq);
http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0);
epg_unlock();
return 0;
}
static int
pvrcmp(const void *A, const void *B)
{
const pvr_rec_t *a = *(const pvr_rec_t **)A;
const pvr_rec_t *b = *(const pvr_rec_t **)B;
return a->pvrr_start - b->pvrr_start;
}
/**
* PVR main page
*/
static int
page_pvr(http_connection_t *hc, const char *remain, void *opaque)
{
tcp_queue_t tq;
int simple = is_client_simple(hc);
pvr_rec_t *pvrr, *pvrr_tgt;
char escapebuf[4000];
char title[100];
char channel[100];
struct tm a, b, day;
const char *pvr_txt, *pvr_color, *buttontxt, *cmd, *txt;
char buttonname[100];
int c, i;
pvr_rec_t **pv;
int divid = 1;
int size = 600;
http_arg_t *ra;
autorec_t *ar, *ar_show = NULL;
if(!html_verify_access(hc, "record-events"))
return HTTP_STATUS_UNAUTHORIZED;
if(http_arg_get(&hc->hc_req_args, "clearall")) {
pvr_clear_all_completed();
}
pvrr_tgt = NULL;
TAILQ_FOREACH(ra, &hc->hc_req_args, link) {
c = 0;
if(!strncmp(ra->key, "ardel_", 6)) {
txt = ra->key + 6;
autorec_delete_by_id(atoi(txt));
/* Redirect back to ourself, to get rid of URL cruft */
http_redirect(hc, "/pvr");
return 0;
} else if(!strncmp(ra->key, "clear_", 6)) {
txt = ra->key + 6;
} else if(!strncmp(ra->key, "desched_", 8)) {
txt = ra->key + 8;
} else if(!strncmp(ra->key, "abort_", 6)) {
c = 1;
txt = ra->key + 6;
} else {
continue;
}
pvrr_tgt = pvr_get_tag_entry(atoi(txt));
if(pvrr_tgt != NULL) {
if(c)
pvr_abort(pvrr_tgt);
else
pvr_clear(pvrr_tgt);
}
break;
}
tcp_init_queue(&tq, -1);
html_header(&tq, "HTS/tvheadend", 0, MAIN_WIDTH, 0,
"\n");
top_menu(hc, &tq);
tcp_qprintf(&tq, "");
tcp_qprintf(&tq, "
");
box_top(&tq, "box");
tcp_qprintf(&tq, "
");
tcp_qprintf(&tq, "
Input devices
");
tcp_qprintf(&tq, "");
box_bottom(&tq);
tcp_qprintf(&tq, "
");
/* DVB adapters */
box_top(&tq, "box");
tcp_qprintf(&tq, "
");
tcp_qprintf(&tq, "
DVB adapters");
if(LIST_FIRST(&dvb_adapters_running) == NULL) {
tcp_qprintf(&tq, "No DVB adapters configured
");
} else {
LIST_FOREACH(tda, &dvb_adapters_running, tda_link) {
tcp_qprintf(&tq, "
%s
%s
",
tda->tda_rootpath, tda->tda_info);
LIST_FOREACH(tdmi, &tda->tda_muxes_active, tdmi_adapter_link) {
tcp_qprintf(&tq,
""
"%s"
"",
tdmi->tdmi_shortname);
txt = tdmi->tdmi_status ?: "Ok";
v = vv = 0;
for(i = 0; i < TDMI_FEC_ERR_HISTOGRAM_SIZE; i++) {
if(tdmi->tdmi_fec_err_histogram[i] > DVB_FEC_ERROR_LIMIT)
v++;
vv += tdmi->tdmi_fec_err_histogram[i];
}
vv /= TDMI_FEC_ERR_HISTOGRAM_SIZE;
if(v == TDMI_FEC_ERR_HISTOGRAM_SIZE)
txt = "Constant high FEC rate";
else if(v > 0)
txt = "Bursty FEC rate";
tcp_qprintf(&tq,
""
"%s"
"",
txt);
switch(tdmi->tdmi_state) {
default:
txt = "???";
break;
case TDMI_IDLE:
txt = "Idle";
break;
case TDMI_RUNNING:
txt = "Running";
break;
case TDMI_IDLESCAN:
txt = "IdleScan";
break;
}
tcp_qprintf(&tq,
""
"%s"
"",
txt);
tcp_qprintf(&tq,
""
"%d"
"
",
vv);
}
}
}
tcp_qprintf(&tq, "");
box_bottom(&tq);
tcp_qprintf(&tq, "
");
/* IPTV adapters */
box_top(&tq, "box");
tcp_qprintf(&tq, "
");
tcp_qprintf(&tq, "
IPTV sources");
LIST_FOREACH(t, &all_transports, tht_global_link) {
if(t->tht_type != TRANSPORT_IPTV)
continue;
html_iptv_status(&tq, t,
t->tht_status == TRANSPORT_IDLE ? "Idle" : "Running");
}
LIST_FOREACH(t, &iptv_stale_transports, tht_adapter_link)
html_iptv_status(&tq, t, "Probe failed");
tcp_qprintf(&tq, "");
box_bottom(&tq);
tcp_qprintf(&tq, "
");
/* Video4Linux adapters */
box_top(&tq, "box");
tcp_qprintf(&tq, "
");
tcp_qprintf(&tq, "
Video4Linux adapters");
LIST_FOREACH(tva, &v4l_adapters, tva_link) {
tcp_qprintf(&tq,
""
"%s"
"",
tva->tva_path);
if(tva->tva_dispatch_handle == NULL) {
snprintf(tmptxt, sizeof(tmptxt), "Idle");
} else {
snprintf(tmptxt, sizeof(tmptxt), "Tuned to %.3f MHz",
(float)tva->tva_frequency/1000000.0);
}
tcp_qprintf(&tq,
""
"%s"
"
",
tmptxt);
}
tcp_qprintf(&tq, "");
box_bottom(&tq);
tcp_qprintf(&tq, "
");
/* Active transports */
tcp_qprintf(&tq, "
");
box_top(&tq, "box");
tcp_qprintf(&tq, "
");
tcp_qprintf(&tq, "
Active transports
");
tcp_qprintf(&tq, "");
box_bottom(&tq);
tcp_qprintf(&tq, "
");
LIST_FOREACH(t, &all_transports, tht_global_link) {
if(t->tht_status != TRANSPORT_RUNNING)
continue;
box_top(&tq, "box");
tcp_qprintf(&tq, "
");
tcp_qprintf(&tq,
""
"%s"
""
""
"%s"
"
",
t->tht_name,
t->tht_channel->ch_name);
switch(t->tht_type) {
case TRANSPORT_IPTV:
t1 = tmptxt;
snprintf(tmptxt, sizeof(tmptxt), "IPTV: %s",
inet_ntoa(t->tht_iptv_group_addr));
t2 = "";
break;
case TRANSPORT_V4L:
t1 = tmptxt;
snprintf(tmptxt, sizeof(tmptxt), "V4L: %.3f MHz",
(float)t->tht_v4l_frequency / 1000000.0f);
t2 = t->tht_v4l_adapter->tva_path;
break;
case TRANSPORT_DVB:
t1 = t->tht_dvb_mux_instance->tdmi_shortname;
t2 = t->tht_dvb_mux_instance->tdmi_adapter->tda_rootpath;
break;
case TRANSPORT_AVGEN:
t1 = "A/V Generator";
t2 = "";
break;
default:
continue;
}
tcp_qprintf(&tq,
""
"%s"
""
""
"%s"
"
",
t1, t2);
LIST_FOREACH(st, &t->tht_streams, st_link) {
tcp_qprintf(&tq,
""
"%s"
"",
htstvstreamtype2txt(st->st_type));
tcp_qprintf(&tq,
""
"%d kb/s"
"",
avgstat_read_and_expire(&st->st_rate, dispatch_clock)
/ 1000);
tcp_qprintf(&tq,
""
"%d errors/s"
"
",
avgstat_read_and_expire(&st->st_cc_errors, dispatch_clock));
}
tcp_qprintf(&tq, "
");
box_bottom(&tq);
tcp_qprintf(&tq, "
");
}
tcp_qprintf(&tq, "
");
/* Subscribers */
tcp_qprintf(&tq, "
");
box_top(&tq, "box");
tcp_qprintf(&tq, "
");
tcp_qprintf(&tq, "
Subscriptions
");
tcp_qprintf(&tq, "");
box_bottom(&tq);
tcp_qprintf(&tq, "
");
LIST_FOREACH(s, &subscriptions, ths_global_link) {
box_top(&tq, "box");
tcp_qprintf(&tq, "
");
tcp_qprintf(&tq,
""
"%s"
"",
s->ths_title);
tcp_qprintf(&tq,
""
"%s"
"
",
s->ths_channel->ch_name);
if((t = s->ths_transport) == NULL) {
tcp_qprintf(&tq,
"No transport available
");
} else {
tcp_qprintf(&tq,
"Using transport \"%s\"
",
t->tht_name);
}
tcp_qprintf(&tq, "
");
box_bottom(&tq);
tcp_qprintf(&tq, "
");
}
tcp_qprintf(&tq, "
");
tcp_qprintf(&tq, "
");
html_footer(&tq);
http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0);
return 0;
}
/**
* Manage channel groups
*/
static int
page_chgroups(http_connection_t *hc, const char *remain, void *opaque)
{
tcp_queue_t tq;
th_channel_group_t *tcg;
th_channel_t *ch;
int cnt;
const char *grp;
http_arg_t *ra;
if(!html_verify_access(hc, "admin"))
return HTTP_STATUS_UNAUTHORIZED;
if((grp = http_arg_get(&hc->hc_req_args, "newgrpname")) != NULL)
channel_group_find(grp, 1);
TAILQ_FOREACH(ra, &hc->hc_req_args, link) {
if(!strncmp(ra->key, "delgroup", 8)) {
tcg = channel_group_by_tag(atoi(ra->key + 8));
if(tcg != NULL)
channel_group_destroy(tcg);
break;
}
if(!strncmp(ra->key, "up", 2)) {
tcg = channel_group_by_tag(atoi(ra->key + 2));
if(tcg != NULL)
channel_group_move_prev(tcg);
break;
}
if(!strncmp(ra->key, "down", 4)) {
tcg = channel_group_by_tag(atoi(ra->key + 4));
if(tcg != NULL)
channel_group_move_next(tcg);
break;
}
}
tcp_init_queue(&tq, -1);
html_header(&tq, "HTS/tvheadend", 0, MAIN_WIDTH, 0, NULL);
top_menu(hc, &tq);
TAILQ_FOREACH(tcg, &all_channel_groups, tcg_global_link) {
if(tcg->tcg_hidden)
continue;
tcp_qprintf(&tq, "");
}
html_footer(&tq);
http_output_queue(hc, &tq, "text/html; charset=UTF-8", 0);
return 0;
}
/**
* XML output
*/
static int
xml_channellist(http_connection_t *hc, const char *remain, void *opaque)
{
tcp_queue_t tq;
th_channel_t *ch;
th_channel_group_t *tcg;
struct sockaddr_in *si;
char escapebuf[100];
if(!html_verify_access(hc, "browse-events"))
return HTTP_STATUS_UNAUTHORIZED;
tcp_init_queue(&tq, -1);
si = (struct sockaddr_in *)&hc->hc_tcp_session.tcp_self_addr;
tcp_qprintf(&tq,
"\n"
"