/* * tvheadend, EXTJS based interface * Copyright (C) 2008 Andreas Ă–man * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include "htsmsg.h" #include "htsmsg_json.h" #include "tvheadend.h" #include "http.h" #include "webui.h" #include "access.h" #include "dtable.h" #include "channels.h" #include "dvr/dvr.h" #include "epggrab.h" #include "epg.h" #include "muxer.h" #include "epggrab/private.h" #include "config2.h" #include "lang_codes.h" #include "subscriptions.h" #include "imagecache.h" #include "timeshift.h" #include "tvhtime.h" #include "input.h" #if ENABLE_LIBAV #include "plumbing/transcoding.h" #endif /** * */ static void extjs_load(htsbuf_queue_t *hq, const char *script) { htsbuf_qprintf(hq, "\n", script); } /** * */ static void extjs_exec(htsbuf_queue_t *hq, const char *fmt, ...) { va_list ap; htsbuf_qprintf(hq, "\r\n"); } /** * PVR info, deliver info about the given PVR entry */ static int extjs_root(http_connection_t *hc, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hc->hc_reply; #define EXTJSPATH "static/extjs" htsbuf_qprintf(hq, "\n"); htsbuf_qprintf(hq, "\n"); // Issue #1504 - IE9 temporary fix htsbuf_qprintf(hq, "\n"); htsbuf_qprintf(hq, "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n", tvheadend_webui_debug ? "-debug" : "", tvheadend_webui_debug ? "-debug" : "", "");//tvheadend_webui_debug ? "" : "-min"); extjs_exec(hq, "Ext.BLANK_IMAGE_URL = " "'"EXTJSPATH"/resources/images/default/s.gif';"); /** * Load extjs extensions */ extjs_load(hq, "static/app/extensions.js"); extjs_load(hq, "static/livegrid/livegrid-all.js"); extjs_load(hq, "static/lovcombo/lovcombo-all.js"); extjs_load(hq, "static/multiselect/multiselect.js"); extjs_load(hq, "static/multiselect/ddview.js"); extjs_load(hq, "static/checkcolumn/CheckColumn.js"); extjs_load(hq, "static/extjs/examples/ux/gridfilters/GridFilters.js"); extjs_load(hq, "static/extjs/examples/ux/gridfilters/filter/Filter.js"); extjs_load(hq, "static/extjs/examples/ux/gridfilters/filter/BooleanFilter.js"); extjs_load(hq, "static/extjs/examples/ux/gridfilters/filter/DateFilter.js"); extjs_load(hq, "static/extjs/examples/ux/gridfilters/filter/ListFilter.js"); extjs_load(hq, "static/extjs/examples/ux/gridfilters/filter/NumericFilter.js"); extjs_load(hq, "static/extjs/examples/ux/gridfilters/filter/StringFilter.js"); extjs_load(hq, "static/extjs/examples/ux/gridfilters/menu/ListMenu.js"); extjs_load(hq, "static/extjs/examples/ux/gridfilters/menu/RangeMenu.js"); /** * Create a namespace for our app */ extjs_exec(hq, "Ext.namespace('tvheadend');"); /** * Load all components */ extjs_load(hq, "static/app/comet.js"); extjs_load(hq, "static/app/tableeditor.js"); extjs_load(hq, "static/app/cteditor.js"); extjs_load(hq, "static/app/acleditor.js"); extjs_load(hq, "static/app/cwceditor.js"); extjs_load(hq, "static/app/capmteditor.js"); extjs_load(hq, "static/app/tvadapters.js"); extjs_load(hq, "static/app/idnode.js"); #if ENABLE_LINUXDVB extjs_load(hq, "static/app/dvb.js"); extjs_load(hq, "static/app/dvb_networks.js"); extjs_load(hq, "static/app/mpegts.js"); #endif extjs_load(hq, "static/app/iptv.js"); #if ENABLE_V4L extjs_load(hq, "static/app/v4l.js"); #endif #if ENABLE_TIMESHIFT extjs_load(hq, "static/app/timeshift.js"); #endif 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/epggrab.js"); extjs_load(hq, "static/app/config.js"); extjs_load(hq, "static/app/tvhlog.js"); extjs_load(hq, "static/app/status.js"); /** * Finally, the app itself */ extjs_load(hq, "static/app/tvheadend.js"); extjs_exec(hq, "Ext.onReady(tvheadend.app.init, tvheadend.app);"); htsbuf_qprintf(hq, "\n" "HTS Tvheadend %s\n" "\n" "\n" "
\n" "\n", tvheadend_version); http_output_html(hc); return 0; } /** * */ static int extjs_livetv(http_connection_t *hc, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hc->hc_reply; htsbuf_qprintf(hq, "\n"); htsbuf_qprintf(hq, "\n"); htsbuf_qprintf(hq, "\n"); htsbuf_qprintf(hq, "HTS Tvheadend %s\n", tvheadend_version); htsbuf_qprintf(hq, "\n"); if(tvheadend_webui_debug) { extjs_load(hq, "static/extjs/adapter/ext/ext-base-debug.js"); extjs_load(hq, "static/extjs/ext-all-debug.js"); } else { extjs_load(hq, "static/extjs/adapter/ext/ext-base.js"); extjs_load(hq, "static/extjs/ext-all.js"); } extjs_load(hq, "static/tv.js"); extjs_exec(hq, "Ext.onReady(tv.app.init, tv.app);"); htsbuf_qprintf(hq, "\n"); htsbuf_qprintf(hq, "\n"); htsbuf_qprintf(hq, "\n"); http_output_html(hc); return 0; } /** * */ static int page_about(http_connection_t *hc, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hc->hc_reply; htsbuf_qprintf(hq, "
" "
" "HTS Tvheadend %s" "

" "© 2006 - 2013 Andreas \303\226man, et al.

" "
" "" "https://tvheadend.org

" "Based on software from " "ExtJS. " "Icons from " "" "FamFamFam" "

" "Build: %s" "

" "If you'd like to support the project, please consider a donation." "
" "All proceeds are used to support server infrastructure and buy test " "equipment." "
" "" "

", tvheadend_version, tvheadend_version); http_output_html(hc); return 0; } /** * */ static int extjs_tablemgr(http_connection_t *hc, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hc->hc_reply; dtable_t *dt; htsmsg_t *out = NULL, *in, *array; const char *tablename = http_arg_get(&hc->hc_req_args, "table"); const char *op = http_arg_get(&hc->hc_req_args, "op"); const char *entries = http_arg_get(&hc->hc_req_args, "entries"); if(op == NULL) return 400; if(tablename == NULL || (dt = dtable_find(tablename)) == NULL) return 404; if(http_access_verify(hc, dt->dt_dtc->dtc_read_access)) return HTTP_STATUS_UNAUTHORIZED; in = entries != NULL ? htsmsg_json_deserialize(entries) : NULL; pthread_mutex_lock(dt->dt_dtc->dtc_mutex); if(!strcmp(op, "create")) { if(http_access_verify(hc, dt->dt_dtc->dtc_write_access)) goto noaccess; out = dtable_record_create(dt); } else if(!strcmp(op, "get")) { array = dtable_record_get_all(dt); out = htsmsg_create_map(); htsmsg_add_msg(out, "entries", array); } else if(!strcmp(op, "update")) { if(http_access_verify(hc, dt->dt_dtc->dtc_write_access)) goto noaccess; if(in == NULL) goto bad; dtable_record_update_by_array(dt, in); } else if(!strcmp(op, "delete")) { if(http_access_verify(hc, dt->dt_dtc->dtc_write_access)) goto noaccess; if(in == NULL) goto bad; dtable_record_delete_by_array(dt, in); } else { bad: pthread_mutex_unlock(dt->dt_dtc->dtc_mutex); return HTTP_STATUS_BAD_REQUEST; noaccess: pthread_mutex_unlock(dt->dt_dtc->dtc_mutex); return HTTP_STATUS_BAD_REQUEST; } pthread_mutex_unlock(dt->dt_dtc->dtc_mutex); if(in != NULL) htsmsg_destroy(in); if(out == NULL) out = htsmsg_create_map(); htsmsg_json_serialize(out, hq, 0); htsmsg_destroy(out); http_output_content(hc, "text/x-json; charset=UTF-8"); return 0; } /** * EPG Content Groups */ static int extjs_ecglist(http_connection_t *hc, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hc->hc_reply; htsmsg_t *out, *array; out = htsmsg_create_map(); array = epg_genres_list_all(1, 0); htsmsg_add_msg(out, "entries", array); htsmsg_json_serialize(out, hq, 0); htsmsg_destroy(out); http_output_content(hc, "text/x-json; charset=UTF-8"); return 0; } /** * */ static htsmsg_t * json_single_record(htsmsg_t *rec, const char *root) { htsmsg_t *out, *array; out = htsmsg_create_map(); array = htsmsg_create_list(); htsmsg_add_msg(array, NULL, rec); htsmsg_add_msg(out, root, array); return out; } /** * */ static int extjs_epggrab(http_connection_t *hc, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hc->hc_reply; const char *op = http_arg_get(&hc->hc_req_args, "op"); htsmsg_t *out, *array, *r, *e; htsmsg_field_t *f; const char *str; uint32_t u32; if(op == NULL) return 400; pthread_mutex_lock(&global_lock); if(http_access_verify(hc, ACCESS_ADMIN)) { pthread_mutex_unlock(&global_lock); return HTTP_STATUS_UNAUTHORIZED; } pthread_mutex_unlock(&global_lock); /* Basic settings (not the advanced schedule) */ if(!strcmp(op, "loadSettings")) { pthread_mutex_lock(&epggrab_mutex); r = htsmsg_create_map(); if (epggrab_module) htsmsg_add_str(r, "module", epggrab_module->id); htsmsg_add_u32(r, "interval", epggrab_interval); htsmsg_add_u32(r, "channel_rename", epggrab_channel_rename); htsmsg_add_u32(r, "channel_renumber", epggrab_channel_renumber); htsmsg_add_u32(r, "channel_reicon", epggrab_channel_reicon); htsmsg_add_u32(r, "epgdb_periodicsave", epggrab_epgdb_periodicsave / 3600); pthread_mutex_unlock(&epggrab_mutex); out = json_single_record(r, "epggrabSettings"); /* List of modules and currently states */ } else if (!strcmp(op, "moduleList")) { out = htsmsg_create_map(); pthread_mutex_lock(&epggrab_mutex); array = epggrab_module_list(); pthread_mutex_unlock(&epggrab_mutex); htsmsg_add_msg(out, "entries", array); /* Channel list */ } else if (!strcmp(op, "channelList")) { out = htsmsg_create_map(); pthread_mutex_lock(&global_lock); array = epggrab_channel_list(); pthread_mutex_unlock(&global_lock); htsmsg_add_msg(out, "entries", array); /* Save settings */ } else if (!strcmp(op, "saveSettings") ) { int save = 0; pthread_mutex_lock(&epggrab_mutex); str = http_arg_get(&hc->hc_req_args, "channel_rename"); save |= epggrab_set_channel_rename(str ? 1 : 0); str = http_arg_get(&hc->hc_req_args, "channel_renumber"); save |= epggrab_set_channel_renumber(str ? 1 : 0); str = http_arg_get(&hc->hc_req_args, "channel_reicon"); save |= epggrab_set_channel_reicon(str ? 1 : 0); if ( (str = http_arg_get(&hc->hc_req_args, "epgdb_periodicsave")) ) save |= epggrab_set_periodicsave(atoi(str) * 3600); if ( (str = http_arg_get(&hc->hc_req_args, "interval")) ) save |= epggrab_set_interval(atoi(str)); if ( (str = http_arg_get(&hc->hc_req_args, "module")) ) save |= epggrab_set_module_by_id(str); if ( (str = http_arg_get(&hc->hc_req_args, "external")) ) { if ( (array = htsmsg_json_deserialize(str)) ) { HTSMSG_FOREACH(f, array) { if ( (e = htsmsg_get_map_by_field(f)) ) { str = htsmsg_get_str(e, "id"); u32 = 0; htsmsg_get_u32(e, "enabled", &u32); if ( str ) save |= epggrab_enable_module_by_id(str, u32); } } htsmsg_destroy(array); } } if (save) epggrab_save(); pthread_mutex_unlock(&epggrab_mutex); out = htsmsg_create_map(); htsmsg_add_u32(out, "success", 1); } else { return HTTP_STATUS_BAD_REQUEST; } htsmsg_json_serialize(out, hq, 0); htsmsg_destroy(out); http_output_content(hc, "text/x-json; charset=UTF-8"); return 0; } /** * */ static int extjs_channeltags(http_connection_t *hc, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hc->hc_reply; const char *op = http_arg_get(&hc->hc_req_args, "op"); htsmsg_t *out, *array, *e; channel_tag_t *ct; pthread_mutex_lock(&global_lock); if(op != NULL && !strcmp(op, "listTags")) { out = htsmsg_create_map(); array = htsmsg_create_list(); TAILQ_FOREACH(ct, &channel_tags, ct_link) { if(!ct->ct_enabled) continue; e = htsmsg_create_map(); htsmsg_add_u32(e, "identifier", ct->ct_identifier); htsmsg_add_str(e, "name", ct->ct_name); htsmsg_add_msg(array, NULL, e); } htsmsg_add_msg(out, "entries", array); } else { pthread_mutex_unlock(&global_lock); return HTTP_STATUS_BAD_REQUEST; } pthread_mutex_unlock(&global_lock); htsmsg_json_serialize(out, hq, 0); htsmsg_destroy(out); http_output_content(hc, "text/x-json; charset=UTF-8"); return 0; } /** * */ static int extjs_confignames(http_connection_t *hc, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hc->hc_reply; const char *op = http_arg_get(&hc->hc_req_args, "op"); htsmsg_t *out, *array, *e; dvr_config_t *cfg; pthread_mutex_lock(&global_lock); if(op != NULL && !strcmp(op, "list")) { out = htsmsg_create_map(); array = htsmsg_create_list(); if (http_access_verify(hc, ACCESS_RECORDER_ALL)) goto skip; LIST_FOREACH(cfg, &dvrconfigs, config_link) { e = htsmsg_create_map(); htsmsg_add_str(e, "identifier", cfg->dvr_config_name); if (strlen(cfg->dvr_config_name) == 0) htsmsg_add_str(e, "name", "(default)"); else htsmsg_add_str(e, "name", cfg->dvr_config_name); htsmsg_add_msg(array, NULL, e); } skip: htsmsg_add_msg(out, "entries", array); } else { pthread_mutex_unlock(&global_lock); return HTTP_STATUS_BAD_REQUEST; } pthread_mutex_unlock(&global_lock); htsmsg_json_serialize(out, hq, 0); htsmsg_destroy(out); http_output_content(hc, "text/x-json; charset=UTF-8"); return 0; } /** * */ static int extjs_dvr_containers(http_connection_t *hc, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hc->hc_reply; const char *op = http_arg_get(&hc->hc_req_args, "op"); htsmsg_t *out, *array; pthread_mutex_lock(&global_lock); if(op != NULL && !strcmp(op, "list")) { out = htsmsg_create_map(); array = htsmsg_create_list(); if (http_access_verify(hc, ACCESS_RECORDER_ALL)) goto skip; muxer_container_list(array); skip: htsmsg_add_msg(out, "entries", array); } else { pthread_mutex_unlock(&global_lock); return HTTP_STATUS_BAD_REQUEST; } pthread_mutex_unlock(&global_lock); htsmsg_json_serialize(out, hq, 0); htsmsg_destroy(out); http_output_content(hc, "text/x-json; charset=UTF-8"); return 0; } /** * */ static int extjs_languages(http_connection_t *hc, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hc->hc_reply; const char *op = http_arg_get(&hc->hc_req_args, "op"); htsmsg_t *out, *array, *e; pthread_mutex_lock(&global_lock); if(op != NULL && !strcmp(op, "list")) { out = htsmsg_create_map(); array = htsmsg_create_list(); const lang_code_t *c = lang_codes; while (c->code2b) { e = htsmsg_create_map(); htsmsg_add_str(e, "identifier", c->code2b); htsmsg_add_str(e, "name", c->desc); htsmsg_add_msg(array, NULL, e); c++; } } else if(op != NULL && !strcmp(op, "config")) { out = htsmsg_create_map(); array = htsmsg_create_list(); const lang_code_t **c = lang_code_split2(NULL); if(c) { int i = 0; while (c[i]) { e = htsmsg_create_map(); htsmsg_add_str(e, "identifier", c[i]->code2b); htsmsg_add_str(e, "name", c[i]->desc); htsmsg_add_msg(array, NULL, e); i++; } free(c); } } else { pthread_mutex_unlock(&global_lock); return HTTP_STATUS_BAD_REQUEST; } pthread_mutex_unlock(&global_lock); htsmsg_add_msg(out, "entries", array); htsmsg_json_serialize(out, hq, 0); htsmsg_destroy(out); http_output_content(hc, "text/x-json; charset=UTF-8"); return 0; } /** * */ static int extjs_epg(http_connection_t *hc, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hc->hc_reply; htsmsg_t *out, *array, *m; epg_query_result_t eqr; epg_broadcast_t *e; epg_episode_t *ee = NULL; epg_genre_t *eg = NULL, genre; channel_t *ch; int start = 0, end, limit, i; const char *s; char buf[100]; const char *channel = http_arg_get(&hc->hc_req_args, "channel"); const char *tag = http_arg_get(&hc->hc_req_args, "tag"); const char *title = http_arg_get(&hc->hc_req_args, "title"); const char *lang = http_arg_get(&hc->hc_args, "Accept-Language"); if(channel && !channel[0]) channel = NULL; if(tag && !tag[0]) tag = NULL; if((s = http_arg_get(&hc->hc_req_args, "start")) != NULL) start = atoi(s); if((s = http_arg_get(&hc->hc_req_args, "limit")) != NULL) limit = atoi(s); else limit = 20; /* XXX */ if ((s = http_arg_get(&hc->hc_req_args, "contenttype"))) { genre.code = atoi(s); eg = &genre; } out = htsmsg_create_map(); array = htsmsg_create_list(); pthread_mutex_lock(&global_lock); epg_query(&eqr, channel, tag, eg, title, lang); epg_query_sort(&eqr); htsmsg_add_u32(out, "totalCount", eqr.eqr_entries); start = MIN(start, eqr.eqr_entries); end = MIN(start + limit, eqr.eqr_entries); for(i = start; i < end; i++) { e = eqr.eqr_array[i]; ee = e->episode; ch = e->channel; if (!ch||!ee) continue; m = htsmsg_create_map(); htsmsg_add_str(m, "channel", channel_get_name(ch)); htsmsg_add_u32(m, "channelid", channel_get_id(ch)); if(ch->ch_icon != NULL) htsmsg_add_imageurl(m, "chicon", "imagecache/%d", ch->ch_icon); if((s = epg_episode_get_title(ee, lang))) htsmsg_add_str(m, "title", s); if((s = epg_episode_get_subtitle(ee, lang))) htsmsg_add_str(m, "subtitle", s); if((s = epg_broadcast_get_description(e, lang))) htsmsg_add_str(m, "description", s); else if((s = epg_broadcast_get_summary(e, lang))) htsmsg_add_str(m, "description", s); if (epg_episode_number_format(ee, buf, 100, NULL, "Season %d", ".", "Episode %d", "/%d")) htsmsg_add_str(m, "episode", buf); htsmsg_add_u32(m, "id", e->id); htsmsg_add_u32(m, "start", e->start); htsmsg_add_u32(m, "end", e->stop); htsmsg_add_u32(m, "duration", e->stop - e->start); if(e->serieslink) htsmsg_add_str(m, "serieslink", e->serieslink->uri); if((eg = LIST_FIRST(&ee->genre))) { htsmsg_add_u32(m, "contenttype", eg->code); } dvr_entry_t *de; if((de = dvr_entry_find_by_event(e)) != NULL) htsmsg_add_str(m, "schedstate", dvr_entry_schedstatus(de)); htsmsg_add_msg(array, NULL, m); } epg_query_free(&eqr); pthread_mutex_unlock(&global_lock); htsmsg_add_msg(out, "entries", array); htsmsg_json_serialize(out, hq, 0); htsmsg_destroy(out); http_output_content(hc, "text/x-json; charset=UTF-8"); return 0; } static int extjs_epgrelated(http_connection_t *hc, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hc->hc_reply; htsmsg_t *out, *array, *m; epg_broadcast_t *e, *ebc; epg_episode_t *ee, *ee2; channel_t *ch; uint32_t count = 0; const char *s; char buf[100]; const char *lang = http_arg_get(&hc->hc_args, "Accept-Language"); const char *id = http_arg_get(&hc->hc_req_args, "id"); const char *type = http_arg_get(&hc->hc_req_args, "type"); out = htsmsg_create_map(); array = htsmsg_create_list(); pthread_mutex_lock(&global_lock); if ( id && type ) { e = epg_broadcast_find_by_id(atoi(id), NULL); if ( e && e->episode ) { ee = e->episode; /* Alternative broadcasts */ if (!strcmp(type, "alternative")) { LIST_FOREACH(ebc, &ee->broadcasts, ep_link) { ch = ebc->channel; if ( !ch ) continue; // skip something not viewable if ( ebc == e ) continue; // skip self count++; m = htsmsg_create_map(); htsmsg_add_u32(m, "id", ebc->id); htsmsg_add_str(m, "channel", channel_get_name(ch)); if (ch->ch_icon) htsmsg_add_imageurl(m, "chicon", "imagecache/%d", ch->ch_icon); htsmsg_add_u32(m, "start", ebc->start); htsmsg_add_msg(array, NULL, m); } /* Related */ } else if (!strcmp(type, "related")) { if (ee->brand) { LIST_FOREACH(ee2, &ee->brand->episodes, blink) { if (ee2 == ee) continue; if (!ee2->title) continue; count++; m = htsmsg_create_map(); htsmsg_add_str(m, "uri", ee2->uri); if ((s = epg_episode_get_title(ee2, lang))) htsmsg_add_str(m, "title", s); if ((s = epg_episode_get_subtitle(ee2, lang))) htsmsg_add_str(m, "subtitle", s); if (epg_episode_number_format(ee2, buf, 100, NULL, "Season %d", ".", "Episode %d", "/%d")) htsmsg_add_str(m, "episode", buf); htsmsg_add_msg(array, NULL, m); } } else if (ee->season) { LIST_FOREACH(ee2, &ee->season->episodes, slink) { if (ee2 == ee) continue; if (!ee2->title) continue; count++; m = htsmsg_create_map(); htsmsg_add_str(m, "uri", ee2->uri); if ((s = epg_episode_get_title(ee2, lang))) htsmsg_add_str(m, "title", s); if ((s = epg_episode_get_subtitle(ee2, lang))) htsmsg_add_str(m, "subtitle", s); if (epg_episode_number_format(ee2, buf, 100, NULL, "Season %d", ".", "Episode %d", "/%d")) htsmsg_add_str(m, "episode", buf); htsmsg_add_msg(array, NULL, m); } } } } } pthread_mutex_unlock(&global_lock); htsmsg_add_u32(out, "totalCount", count); htsmsg_add_msg(out, "entries", array); htsmsg_json_serialize(out, hq, 0); htsmsg_destroy(out); http_output_content(hc, "text/x-json; charset=UTF-8"); return 0; } /** * */ static int extjs_epgobject(http_connection_t *hc, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hc->hc_reply; const char *op = http_arg_get(&hc->hc_req_args, "op"); htsmsg_t *out, *array; if(op == NULL) return 400; if (!strcmp(op, "brandList")) { out = htsmsg_create_map(); pthread_mutex_lock(&global_lock); array = epg_brand_list(); pthread_mutex_unlock(&global_lock); htsmsg_add_msg(out, "entries", array); } else { return HTTP_STATUS_BAD_REQUEST; } htsmsg_json_serialize(out, hq, 0); htsmsg_destroy(out); http_output_content(hc, "text/x-json; charset=UTF-8"); return 0; } /** * */ static int extjs_dvr(http_connection_t *hc, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hc->hc_reply; const char *op = http_arg_get(&hc->hc_req_args, "op"); htsmsg_t *out, *r; dvr_entry_t *de; const char *s; int flags = 0; dvr_config_t *cfg; epg_broadcast_t *e; if(op == NULL) op = "loadSettings"; pthread_mutex_lock(&global_lock); if(http_access_verify(hc, ACCESS_RECORDER)) { pthread_mutex_unlock(&global_lock); return HTTP_STATUS_UNAUTHORIZED; } if(!strcmp(op, "recordEvent") || !strcmp(op, "recordSeries")) { const char *config_name = http_arg_get(&hc->hc_req_args, "config_name"); s = http_arg_get(&hc->hc_req_args, "eventId"); if((e = epg_broadcast_find_by_id(atoi(s), NULL)) == NULL) { pthread_mutex_unlock(&global_lock); return HTTP_STATUS_BAD_REQUEST; } if (http_access_verify(hc, ACCESS_RECORDER_ALL)) { config_name = NULL; LIST_FOREACH(cfg, &dvrconfigs, config_link) { if (cfg->dvr_config_name && hc->hc_username && strcmp(cfg->dvr_config_name, hc->hc_username) == 0) { config_name = cfg->dvr_config_name; break; } } if (config_name == NULL && hc->hc_username) tvhlog(LOG_INFO,"dvr","User '%s' has no dvr config with identical name, using default...", hc->hc_username); } if (!strcmp(op, "recordEvent")) dvr_entry_create_by_event(config_name, e, 0, 0, hc->hc_representative, NULL, DVR_PRIO_NORMAL); else dvr_autorec_add_series_link(config_name, e, hc->hc_representative, "Created from EPG query"); out = htsmsg_create_map(); htsmsg_add_u32(out, "success", 1); } else if(!strcmp(op, "cancelEntry")) { s = http_arg_get(&hc->hc_req_args, "entryId"); if((de = dvr_entry_find_by_id(atoi(s))) == NULL) { pthread_mutex_unlock(&global_lock); return HTTP_STATUS_BAD_REQUEST; } dvr_entry_cancel(de); out = htsmsg_create_map(); htsmsg_add_u32(out, "success", 1); } else if(!strcmp(op, "deleteEntry")) { s = http_arg_get(&hc->hc_req_args, "entryId"); if((de = dvr_entry_find_by_id(atoi(s))) == NULL) { pthread_mutex_unlock(&global_lock); return HTTP_STATUS_BAD_REQUEST; } dvr_entry_delete(de); out = htsmsg_create_map(); htsmsg_add_u32(out, "success", 1); } else if(!strcmp(op, "createEntry")) { const char *config_name = http_arg_get(&hc->hc_req_args, "config_name"); const char *title = http_arg_get(&hc->hc_req_args, "title"); const char *datestr = http_arg_get(&hc->hc_req_args, "date"); const char *startstr = http_arg_get(&hc->hc_req_args, "starttime"); const char *stopstr = http_arg_get(&hc->hc_req_args, "stoptime"); const char *channel = http_arg_get(&hc->hc_req_args, "channelid"); const char *pri = http_arg_get(&hc->hc_req_args, "pri"); channel_t *ch = channel ? channel_find_by_id(atoi(channel)) : NULL; if(ch == NULL || title == NULL || datestr == NULL || strlen(datestr) != 10 || startstr == NULL || strlen(startstr) != 5 || stopstr == NULL || strlen(stopstr) != 5) { pthread_mutex_unlock(&global_lock); return HTTP_STATUS_BAD_REQUEST; } struct tm t = {0}; t.tm_year = atoi(datestr + 6) - 1900; t.tm_mon = atoi(datestr) - 1; t.tm_mday = atoi(datestr + 3); t.tm_isdst = -1; t.tm_hour = atoi(startstr); t.tm_min = atoi(startstr + 3); time_t start = mktime(&t); t.tm_hour = atoi(stopstr); t.tm_min = atoi(stopstr + 3); time_t stop = mktime(&t); if(stop < start) stop += 86400; if (http_access_verify(hc, ACCESS_RECORDER_ALL)) { config_name = NULL; LIST_FOREACH(cfg, &dvrconfigs, config_link) { if (cfg->dvr_config_name && hc->hc_username && strcmp(cfg->dvr_config_name, hc->hc_username) == 0) { config_name = cfg->dvr_config_name; break; } } if (config_name == NULL && hc->hc_username) tvhlog(LOG_INFO,"dvr","User '%s' has no dvr config with identical name, using default...", hc->hc_username); } dvr_entry_create(config_name, ch, start, stop, 0, 0, title, NULL, NULL, 0, hc->hc_representative, NULL, dvr_pri2val(pri)); out = htsmsg_create_map(); htsmsg_add_u32(out, "success", 1); } else if(!strcmp(op, "createAutoRec")) { epg_genre_t genre, *eg = NULL; if ((s = http_arg_get(&hc->hc_req_args, "contenttype"))) { genre.code = atoi(s); eg = &genre; } dvr_autorec_add(http_arg_get(&hc->hc_req_args, "config_name"), http_arg_get(&hc->hc_req_args, "title"), http_arg_get(&hc->hc_req_args, "channel"), http_arg_get(&hc->hc_req_args, "tag"), eg, hc->hc_representative, "Created from EPG query"); out = htsmsg_create_map(); htsmsg_add_u32(out, "success", 1); } else if(!strcmp(op, "loadSettings")) { s = http_arg_get(&hc->hc_req_args, "config_name"); if (s == NULL) s = ""; cfg = dvr_config_find_by_name_default(s); r = htsmsg_create_map(); htsmsg_add_str(r, "storage", cfg->dvr_storage); htsmsg_add_str(r, "container", muxer_container_type2txt(cfg->dvr_mc)); if(cfg->dvr_postproc != NULL) htsmsg_add_str(r, "postproc", cfg->dvr_postproc); htsmsg_add_u32(r, "retention", cfg->dvr_retention_days); htsmsg_add_u32(r, "preExtraTime", cfg->dvr_extra_time_pre); htsmsg_add_u32(r, "postExtraTime", cfg->dvr_extra_time_post); htsmsg_add_u32(r, "dayDirs", !!(cfg->dvr_flags & DVR_DIR_PER_DAY)); htsmsg_add_u32(r, "channelDirs", !!(cfg->dvr_flags & DVR_DIR_PER_CHANNEL)); htsmsg_add_u32(r, "channelInTitle", !!(cfg->dvr_flags & DVR_CHANNEL_IN_TITLE)); htsmsg_add_u32(r, "dateInTitle", !!(cfg->dvr_flags & DVR_DATE_IN_TITLE)); htsmsg_add_u32(r, "timeInTitle", !!(cfg->dvr_flags & DVR_TIME_IN_TITLE)); htsmsg_add_u32(r, "whitespaceInTitle", !!(cfg->dvr_flags & DVR_WHITESPACE_IN_TITLE)); htsmsg_add_u32(r, "titleDirs", !!(cfg->dvr_flags & DVR_DIR_PER_TITLE)); htsmsg_add_u32(r, "episodeInTitle", !!(cfg->dvr_flags & DVR_EPISODE_IN_TITLE)); htsmsg_add_u32(r, "cleanTitle", !!(cfg->dvr_flags & DVR_CLEAN_TITLE)); htsmsg_add_u32(r, "tagFiles", !!(cfg->dvr_flags & DVR_TAG_FILES)); htsmsg_add_u32(r, "commSkip", !!(cfg->dvr_flags & DVR_SKIP_COMMERCIALS)); out = json_single_record(r, "dvrSettings"); } else if(!strcmp(op, "saveSettings")) { s = http_arg_get(&hc->hc_req_args, "config_name"); cfg = dvr_config_find_by_name(s); if (cfg == NULL) cfg = dvr_config_create(s); tvhlog(LOG_INFO,"dvr","Saving configuration '%s'", cfg->dvr_config_name); if((s = http_arg_get(&hc->hc_req_args, "storage")) != NULL) dvr_storage_set(cfg,s); if((s = http_arg_get(&hc->hc_req_args, "container")) != NULL) dvr_container_set(cfg,s); if((s = http_arg_get(&hc->hc_req_args, "postproc")) != NULL) dvr_postproc_set(cfg,s); if((s = http_arg_get(&hc->hc_req_args, "retention")) != NULL) dvr_retention_set(cfg,atoi(s)); if((s = http_arg_get(&hc->hc_req_args, "preExtraTime")) != NULL) dvr_extra_time_pre_set(cfg,atoi(s)); if((s = http_arg_get(&hc->hc_req_args, "postExtraTime")) != NULL) dvr_extra_time_post_set(cfg,atoi(s)); if(http_arg_get(&hc->hc_req_args, "dayDirs") != NULL) flags |= DVR_DIR_PER_DAY; if(http_arg_get(&hc->hc_req_args, "channelDirs") != NULL) flags |= DVR_DIR_PER_CHANNEL; if(http_arg_get(&hc->hc_req_args, "channelInTitle") != NULL) flags |= DVR_CHANNEL_IN_TITLE; if(http_arg_get(&hc->hc_req_args, "cleanTitle") != NULL) flags |= DVR_CLEAN_TITLE; if(http_arg_get(&hc->hc_req_args, "dateInTitle") != NULL) flags |= DVR_DATE_IN_TITLE; if(http_arg_get(&hc->hc_req_args, "timeInTitle") != NULL) flags |= DVR_TIME_IN_TITLE; if(http_arg_get(&hc->hc_req_args, "whitespaceInTitle") != NULL) flags |= DVR_WHITESPACE_IN_TITLE; if(http_arg_get(&hc->hc_req_args, "titleDirs") != NULL) flags |= DVR_DIR_PER_TITLE; if(http_arg_get(&hc->hc_req_args, "episodeInTitle") != NULL) flags |= DVR_EPISODE_IN_TITLE; if(http_arg_get(&hc->hc_req_args, "tagFiles") != NULL) flags |= DVR_TAG_FILES; if(http_arg_get(&hc->hc_req_args, "commSkip") != NULL) flags |= DVR_SKIP_COMMERCIALS; dvr_flags_set(cfg,flags); out = htsmsg_create_map(); htsmsg_add_u32(out, "success", 1); } else if(!strcmp(op, "deleteSettings")) { s = http_arg_get(&hc->hc_req_args, "config_name"); dvr_config_delete(s); out = htsmsg_create_map(); htsmsg_add_u32(out, "success", 1); } else { pthread_mutex_unlock(&global_lock); return HTTP_STATUS_BAD_REQUEST; } pthread_mutex_unlock(&global_lock); htsmsg_json_serialize(out, hq, 0); htsmsg_destroy(out); http_output_content(hc, "text/x-json; charset=UTF-8"); return 0; } /** * */ static int extjs_dvrlist(http_connection_t *hc, const char *remain, void *opaque, dvr_entry_filter filter, dvr_entry_comparator cmp) { htsbuf_queue_t *hq = &hc->hc_reply; htsmsg_t *out, *array, *m; dvr_query_result_t dqr; dvr_entry_t *de; int start = 0, end, limit, i; const char *s; int64_t fsize = 0; char buf[100]; if((s = http_arg_get(&hc->hc_req_args, "start")) != NULL) start = atoi(s); if((s = http_arg_get(&hc->hc_req_args, "limit")) != NULL) limit = atoi(s); else limit = 20; /* XXX */ pthread_mutex_lock(&global_lock); if(http_access_verify(hc, ACCESS_RECORDER)) { pthread_mutex_unlock(&global_lock); return HTTP_STATUS_UNAUTHORIZED; } out = htsmsg_create_map(); array = htsmsg_create_list(); dvr_query_filter(&dqr, filter); dvr_query_sort_cmp(&dqr, cmp); htsmsg_add_u32(out, "totalCount", dqr.dqr_entries); start = MIN(start, dqr.dqr_entries); end = MIN(start + limit, dqr.dqr_entries); for(i = start; i < end; i++) { de = dqr.dqr_array[i]; m = htsmsg_create_map(); htsmsg_add_str(m, "channel", DVR_CH_NAME(de)); if(de->de_channel != NULL) { if (de->de_channel->ch_icon) htsmsg_add_imageurl(m, "chicon", "imagecache/%d", de->de_channel->ch_icon); } htsmsg_add_str(m, "config_name", de->de_config_name); if(de->de_title != NULL) htsmsg_add_str(m, "title", lang_str_get(de->de_title, NULL)); if(de->de_desc != NULL) htsmsg_add_str(m, "description", lang_str_get(de->de_desc, NULL)); if (de->de_bcast && de->de_bcast->episode) if (epg_episode_number_format(de->de_bcast->episode, buf, 100, NULL, "Season %d", ".", "Episode %d", "/%d")) htsmsg_add_str(m, "episode", buf); htsmsg_add_u32(m, "id", de->de_id); htsmsg_add_u32(m, "start", de->de_start); htsmsg_add_u32(m, "end", de->de_stop); htsmsg_add_u32(m, "duration", de->de_stop - de->de_start); htsmsg_add_str(m, "creator", de->de_creator); htsmsg_add_str(m, "pri", dvr_val2pri(de->de_pri)); htsmsg_add_str(m, "status", dvr_entry_status(de)); htsmsg_add_str(m, "schedstate", dvr_entry_schedstatus(de)); if(de->de_sched_state == DVR_COMPLETED) { fsize = dvr_get_filesize(de); if (fsize > 0) { char url[100]; htsmsg_add_s64(m, "filesize", fsize); snprintf(url, sizeof(url), "dvrfile/%d", de->de_id); htsmsg_add_str(m, "url", url); } } htsmsg_add_msg(array, NULL, m); } dvr_query_free(&dqr); pthread_mutex_unlock(&global_lock); htsmsg_add_msg(out, "entries", array); htsmsg_json_serialize(out, hq, 0); htsmsg_destroy(out); http_output_content(hc, "text/x-json; charset=UTF-8"); return 0; } static int is_dvr_entry_finished(dvr_entry_t *entry) { dvr_entry_sched_state_t state = entry->de_sched_state; return state == DVR_COMPLETED && !entry->de_last_error && dvr_get_filesize(entry) != -1; } static int is_dvr_entry_upcoming(dvr_entry_t *entry) { dvr_entry_sched_state_t state = entry->de_sched_state; return state == DVR_RECORDING || state == DVR_SCHEDULED; } static int is_dvr_entry_failed(dvr_entry_t *entry) { if (is_dvr_entry_finished(entry)) return 0; if (is_dvr_entry_upcoming(entry)) return 0; return 1; } static int extjs_dvrlist_finished(http_connection_t *hc, const char *remain, void *opaque) { return extjs_dvrlist(hc, remain, opaque, is_dvr_entry_finished, dvr_sort_start_descending); } static int extjs_dvrlist_upcoming(http_connection_t *hc, const char *remain, void *opaque) { return extjs_dvrlist(hc, remain, opaque, is_dvr_entry_upcoming, dvr_sort_start_ascending); } static int extjs_dvrlist_failed(http_connection_t *hc, const char *remain, void *opaque) { return extjs_dvrlist(hc, remain, opaque, is_dvr_entry_failed, dvr_sort_start_descending); } /** * */ static int extjs_subscriptions(http_connection_t *hc, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hc->hc_reply; htsmsg_t *out, *array; th_subscription_t *s; pthread_mutex_lock(&global_lock); if(http_access_verify(hc, ACCESS_ADMIN)) { pthread_mutex_unlock(&global_lock); return HTTP_STATUS_UNAUTHORIZED; } out = htsmsg_create_map(); array = htsmsg_create_list(); LIST_FOREACH(s, &subscriptions, ths_global_link) htsmsg_add_msg(array, NULL, subscription_create_msg(s)); pthread_mutex_unlock(&global_lock); htsmsg_add_msg(out, "entries", array); htsmsg_json_serialize(out, hq, 0); htsmsg_destroy(out); http_output_content(hc, "text/x-json; charset=UTF-8"); return 0; } /** * */ void extjs_service_delete(htsmsg_t *in) { htsmsg_field_t *f; service_t *t; const char *id; TAILQ_FOREACH(f, &in->hm_fields, hmf_link) { if((id = htsmsg_field_get_string(f)) != NULL && (t = service_find_by_identifier(id)) != NULL) service_destroy(t); } } /** * */ static int extjs_servicedetails(http_connection_t *hc, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hc->hc_reply; htsmsg_t *out, *streams, *c; service_t *t; elementary_stream_t *st; caid_t *ca; char buf[128]; pthread_mutex_lock(&global_lock); if(remain == NULL || (t = service_find_by_identifier(remain)) == NULL) { pthread_mutex_unlock(&global_lock); return 404; } streams = htsmsg_create_list(); TAILQ_FOREACH(st, &t->s_components, es_link) { c = htsmsg_create_map(); htsmsg_add_u32(c, "pid", st->es_pid); htsmsg_add_str(c, "type", streaming_component_type2txt(st->es_type)); switch(st->es_type) { default: htsmsg_add_str(c, "details", ""); break; case SCT_CA: buf[0] = 0; LIST_FOREACH(ca, &st->es_caids, link) { snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s (0x%04x) [0x%08x]", "TODO"/*psi_caid2name(ca->caid)*/, ca->caid, ca->providerid); } htsmsg_add_str(c, "details", buf); break; case SCT_AC3: case SCT_MP4A: case SCT_AAC: case SCT_MPEG2AUDIO: if (st->es_audio_type) { snprintf(buf, sizeof(buf), "%s (%s)", st->es_lang, streaming_component_audio_type2desc(st->es_audio_type)); htsmsg_add_str(c, "details", buf); } else { htsmsg_add_str(c, "details", st->es_lang); } break; case SCT_DVBSUB: snprintf(buf, sizeof(buf), "%s (%04x %04x)", st->es_lang, st->es_composition_id, st->es_ancillary_id); htsmsg_add_str(c, "details", buf); break; case SCT_MPEG2VIDEO: case SCT_H264: buf[0] = 0; if(st->es_frame_duration) snprintf(buf, sizeof(buf), "%2.2f Hz", 90000.0 / st->es_frame_duration); htsmsg_add_str(c, "details", buf); break; } htsmsg_add_msg(streams, NULL, c); } out = htsmsg_create_map(); #ifdef TODO_FIX_THIS htsmsg_add_str(out, "title", t->s_svcname ?: "unnamed service"); #endif htsmsg_add_msg(out, "streams", streams); #ifdef TODO_FIX_THIS if(t->s_dvb_charset != NULL) htsmsg_add_str(out, "dvb_charset", t->s_dvb_charset); htsmsg_add_u32(out, "dvb_eit_enable", t->s_dvb_eit_enable); #endif pthread_mutex_unlock(&global_lock); htsmsg_json_serialize(out, hq, 0); htsmsg_destroy(out); http_output_content(hc, "text/x-json; charset=UTF-8"); return 0; } /** * */ static int extjs_config(http_connection_t *hc, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hc->hc_reply; const char *op = http_arg_get(&hc->hc_req_args, "op"); htsmsg_t *out, *m; const char *str; if(op == NULL) return 400; pthread_mutex_lock(&global_lock); if(http_access_verify(hc, ACCESS_ADMIN)) { pthread_mutex_unlock(&global_lock); return HTTP_STATUS_UNAUTHORIZED; } pthread_mutex_unlock(&global_lock); /* Basic settings */ if(!strcmp(op, "loadSettings")) { /* Misc */ pthread_mutex_lock(&global_lock); m = config_get_all(); /* Time */ htsmsg_add_u32(m, "tvhtime_update_enabled", tvhtime_update_enabled); htsmsg_add_u32(m, "tvhtime_ntp_enabled", tvhtime_ntp_enabled); htsmsg_add_u32(m, "tvhtime_tolerance", tvhtime_tolerance); /* Transcoding */ #if ENABLE_LIBAV htsmsg_add_u32(m, "transcoding_enabled", transcoding_enabled); #endif pthread_mutex_unlock(&global_lock); /* Image cache */ #if ENABLE_IMAGECACHE pthread_mutex_lock(&imagecache_mutex); htsmsg_add_u32(m, "imagecache_enabled", imagecache_enabled); htsmsg_add_u32(m, "imagecache_ok_period", imagecache_ok_period); htsmsg_add_u32(m, "imagecache_fail_period", imagecache_fail_period); htsmsg_add_u32(m, "imagecache_ignore_sslcert", imagecache_ignore_sslcert); pthread_mutex_unlock(&imagecache_mutex); #endif if (!m) return HTTP_STATUS_BAD_REQUEST; out = json_single_record(m, "config"); /* Save settings */ } else if (!strcmp(op, "saveSettings") ) { int save = 0; /* Misc settings */ pthread_mutex_lock(&global_lock); if ((str = http_arg_get(&hc->hc_req_args, "muxconfpath"))) save |= config_set_muxconfpath(str); if ((str = http_arg_get(&hc->hc_req_args, "language"))) save |= config_set_language(str); if (save) config_save(); /* Time */ if ((str = http_arg_get(&hc->hc_req_args, "tvhtime_update_enabled"))) tvhtime_set_update_enabled(!!str); if ((str = http_arg_get(&hc->hc_req_args, "tvhtime_ntp_enabled"))) tvhtime_set_ntp_enabled(!!str); if ((str = http_arg_get(&hc->hc_req_args, "tvhtime_tolerance"))) tvhtime_set_tolerance(atoi(str)); /* Transcoding */ #if ENABLE_LIBAV str = http_arg_get(&hc->hc_req_args, "transcoding_enabled"); save = transcoding_set_enabled(!!str); if (save) transcoding_save(); #endif pthread_mutex_unlock(&global_lock); /* Image Cache */ #if ENABLE_IMAGECACHE pthread_mutex_lock(&imagecache_mutex); str = http_arg_get(&hc->hc_req_args, "imagecache_enabled"); save = imagecache_set_enabled(!!str); if ((str = http_arg_get(&hc->hc_req_args, "imagecache_ok_period"))) save |= imagecache_set_ok_period(atoi(str)); if ((str = http_arg_get(&hc->hc_req_args, "imagecache_fail_period"))) save |= imagecache_set_fail_period(atoi(str)); str = http_arg_get(&hc->hc_req_args, "imagecache_ignore_sslcert"); save |= imagecache_set_ignore_sslcert(!!str); if (save) imagecache_save(); pthread_mutex_unlock(&imagecache_mutex); #endif out = htsmsg_create_map(); htsmsg_add_u32(out, "success", 1); } else { return HTTP_STATUS_BAD_REQUEST; } htsmsg_json_serialize(out, hq, 0); htsmsg_destroy(out); http_output_content(hc, "text/x-json; charset=UTF-8"); return 0; } /** * */ static int extjs_tvhlog(http_connection_t *hc, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hc->hc_reply; const char *op = http_arg_get(&hc->hc_req_args, "op"); htsmsg_t *out, *m; if(op == NULL) return 400; pthread_mutex_lock(&global_lock); if(http_access_verify(hc, ACCESS_ADMIN)) { pthread_mutex_unlock(&global_lock); return HTTP_STATUS_UNAUTHORIZED; } pthread_mutex_unlock(&global_lock); /* Basic settings */ if(!strcmp(op, "loadSettings")) { char str[2048]; /* Get config */ pthread_mutex_lock(&tvhlog_mutex); m = htsmsg_create_map(); htsmsg_add_u32(m, "tvhlog_level", tvhlog_level); htsmsg_add_u32(m, "tvhlog_trace_on", tvhlog_level > LOG_DEBUG); tvhlog_get_trace(str, sizeof(str)); htsmsg_add_str(m, "tvhlog_trace", str); tvhlog_get_debug(str, sizeof(str)); htsmsg_add_str(m, "tvhlog_debug", str); htsmsg_add_str(m, "tvhlog_path", tvhlog_path ?: ""); htsmsg_add_u32(m, "tvhlog_options", tvhlog_options); htsmsg_add_u32(m, "tvhlog_dbg_syslog", tvhlog_options & TVHLOG_OPT_DBG_SYSLOG); pthread_mutex_unlock(&tvhlog_mutex); if (!m) return HTTP_STATUS_BAD_REQUEST; out = json_single_record(m, "config"); /* Save settings */ } else if (!strcmp(op, "saveSettings") ) { const char *str; pthread_mutex_lock(&tvhlog_mutex); if ((str = http_arg_get(&hc->hc_req_args, "tvhlog_level"))) tvhlog_level = atoi(str); if ((str = http_arg_get(&hc->hc_req_args, "tvhlog_trace_on"))) tvhlog_level = LOG_TRACE; else tvhlog_level = LOG_DEBUG; if ((str = http_arg_get(&hc->hc_req_args, "tvhlog_path"))) { free(tvhlog_path); if (*str) tvhlog_path = strdup(str); else tvhlog_path = NULL; } if ((str = http_arg_get(&hc->hc_req_args, "tvhlog_options"))) tvhlog_options = atoi(str); if ((str = http_arg_get(&hc->hc_req_args, "tvhlog_dbg_syslog"))) tvhlog_options |= TVHLOG_OPT_DBG_SYSLOG; else tvhlog_options &= ~TVHLOG_OPT_DBG_SYSLOG; tvhlog_set_trace(http_arg_get(&hc->hc_req_args, "tvhlog_trace")); tvhlog_set_debug(http_arg_get(&hc->hc_req_args, "tvhlog_debug")); pthread_mutex_unlock(&tvhlog_mutex); out = htsmsg_create_map(); htsmsg_add_u32(out, "success", 1); } else { return HTTP_STATUS_BAD_REQUEST; } htsmsg_json_serialize(out, hq, 0); htsmsg_destroy(out); http_output_content(hc, "text/x-json; charset=UTF-8"); return 0; } /** * Capability check */ static int extjs_capabilities(http_connection_t *hc, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hc->hc_reply; htsmsg_t *l = tvheadend_capabilities_list(0); htsmsg_json_serialize(l, hq, 0); htsmsg_destroy(l); http_output_content(hc, "text/x-json; charset=UTF-8"); return 0; } /** * */ #if ENABLE_TIMESHIFT static int extjs_timeshift(http_connection_t *hc, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hc->hc_reply; const char *op = http_arg_get(&hc->hc_req_args, "op"); htsmsg_t *out, *m; const char *str; if(op == NULL) return 400; pthread_mutex_lock(&global_lock); if(http_access_verify(hc, ACCESS_ADMIN)) { pthread_mutex_unlock(&global_lock); return HTTP_STATUS_UNAUTHORIZED; } pthread_mutex_unlock(&global_lock); /* Basic settings (not the advanced schedule) */ if(!strcmp(op, "loadSettings")) { pthread_mutex_lock(&global_lock); m = htsmsg_create_map(); htsmsg_add_u32(m, "timeshift_enabled", timeshift_enabled); htsmsg_add_u32(m, "timeshift_ondemand", timeshift_ondemand); if (timeshift_path) htsmsg_add_str(m, "timeshift_path", timeshift_path); htsmsg_add_u32(m, "timeshift_unlimited_period", timeshift_unlimited_period); htsmsg_add_u32(m, "timeshift_max_period", timeshift_max_period / 60); htsmsg_add_u32(m, "timeshift_unlimited_size", timeshift_unlimited_size); htsmsg_add_u32(m, "timeshift_max_size", timeshift_max_size / 1048576); pthread_mutex_unlock(&global_lock); out = json_single_record(m, "config"); /* Save settings */ } else if (!strcmp(op, "saveSettings") ) { pthread_mutex_lock(&global_lock); timeshift_enabled = http_arg_get(&hc->hc_req_args, "timeshift_enabled") ? 1 : 0; timeshift_ondemand = http_arg_get(&hc->hc_req_args, "timeshift_ondemand") ? 1 : 0; if ((str = http_arg_get(&hc->hc_req_args, "timeshift_path"))) { if (timeshift_path) free(timeshift_path); timeshift_path = strdup(str); } timeshift_unlimited_period = http_arg_get(&hc->hc_req_args, "timeshift_unlimited_period") ? 1 : 0; if ((str = http_arg_get(&hc->hc_req_args, "timeshift_max_period"))) timeshift_max_period = (uint32_t)atol(str) * 60; timeshift_unlimited_size = http_arg_get(&hc->hc_req_args, "timeshift_unlimited_size") ? 1 : 0; if ((str = http_arg_get(&hc->hc_req_args, "timeshift_max_size"))) timeshift_max_size = atol(str) * 1048576LL; timeshift_save(); pthread_mutex_unlock(&global_lock); out = htsmsg_create_map(); htsmsg_add_u32(out, "success", 1); } else { return HTTP_STATUS_BAD_REQUEST; } htsmsg_json_serialize(out, hq, 0); htsmsg_destroy(out); http_output_content(hc, "text/x-json; charset=UTF-8"); return 0; } #endif /** * WEB user interface */ void extjs_start(void) { http_path_add("/about.html", NULL, page_about, ACCESS_WEB_INTERFACE); http_path_add("/extjs.html", NULL, extjs_root, ACCESS_WEB_INTERFACE); http_path_add("/tv.html", NULL, extjs_livetv, ACCESS_WEB_INTERFACE); http_path_add("/capabilities", NULL, extjs_capabilities, ACCESS_WEB_INTERFACE); http_path_add("/tablemgr", NULL, extjs_tablemgr, 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); http_path_add("/epgrelated", NULL, extjs_epgrelated, ACCESS_WEB_INTERFACE); http_path_add("/epgobject", NULL, extjs_epgobject, ACCESS_WEB_INTERFACE); http_path_add("/dvr", NULL, extjs_dvr, ACCESS_WEB_INTERFACE); http_path_add("/dvrlist_upcoming", NULL, extjs_dvrlist_upcoming, ACCESS_WEB_INTERFACE); http_path_add("/dvrlist_finished", NULL, extjs_dvrlist_finished, ACCESS_WEB_INTERFACE); http_path_add("/dvrlist_failed", NULL, extjs_dvrlist_failed, ACCESS_WEB_INTERFACE); http_path_add("/dvr_containers", NULL, extjs_dvr_containers, ACCESS_WEB_INTERFACE); http_path_add("/subscriptions", NULL, extjs_subscriptions, ACCESS_WEB_INTERFACE); http_path_add("/ecglist", NULL, extjs_ecglist, ACCESS_WEB_INTERFACE); http_path_add("/config", NULL, extjs_config, ACCESS_WEB_INTERFACE); http_path_add("/languages", NULL, extjs_languages, ACCESS_WEB_INTERFACE); http_path_add("/servicedetails", NULL, extjs_servicedetails, ACCESS_ADMIN); #if ENABLE_TIMESHIFT http_path_add("/timeshift", NULL, extjs_timeshift, ACCESS_ADMIN); #endif http_path_add("/tvhlog", NULL, extjs_tvhlog, ACCESS_ADMIN); #if ENABLE_V4L extjs_start_v4l(); #endif }