static int xmlrpc_parse_value(htsmsg_t *dst, htsmsg_field_t *g, const char *name, char *errbuf, size_t errlen) { const char *cdata; htsmsg_t *c; htsmsg_t *sub; if(!strcmp(g->hmf_name, "struct") && (c = htsmsg_get_map_by_field(g)) != NULL) { sub = htsmsg_create_map(); if(xmlrpc_parse_struct(sub, c, errbuf, errlen)) { htsmsg_release(sub); return -1; } htsmsg_add_msg(dst, name, sub); return 0; } else if(!strcmp(g->hmf_name, "array") && (c = htsmsg_get_map_by_field(g)) != NULL) { sub = htsmsg_create_list(); if(xmlrpc_parse_array(sub, c, errbuf, errlen)) { htsmsg_release(sub); return -1; } htsmsg_add_msg(dst, name, sub); return 0; } cdata = g->hmf_type == HMF_STR ? g->hmf_str : NULL; if(!strcmp(g->hmf_name, "string")) { if(cdata != NULL) htsmsg_add_str(dst, name, cdata); } else if(!strcmp(g->hmf_name, "boolean")) { if(cdata != NULL) htsmsg_add_u32(dst, name, atoi(cdata)); } else if(!strcmp(g->hmf_name, "double")) { if(cdata != NULL) htsmsg_add_dbl(dst, name, my_str2double(cdata, NULL)); } else if(!strcmp(g->hmf_name, "int")) { if(cdata != NULL) htsmsg_add_s64(dst, name, atoll(cdata)); } else { snprintf(errbuf, errlen, "Unknown field type \"%s\" %s = %s", g->hmf_name, name, cdata); return -1; } return 0; }
static void keyring_clear(void *opaque, prop_event_t event, ...) { hts_mutex_lock(&keyring_mutex); htsmsg_release(persistent_keyring); htsmsg_release(temporary_keyring); persistent_keyring = htsmsg_create_map(); temporary_keyring = htsmsg_create_map(); htsmsg_store_save(persistent_keyring, "keyring"); hts_mutex_unlock(&keyring_mutex); notify_add(NULL, NOTIFY_WARNING, NULL, 3, _("Rembered passwords erased")); }
static htsmsg_t * xmlrpc_convert_response(htsmsg_t *xml, char *errbuf, size_t errlen) { htsmsg_t *dst, *params; htsmsg_field_t *f, *g; htsmsg_t *c; if((params = htsmsg_get_map_multi(xml, "methodResponse", "params", NULL)) == NULL) { snprintf(errbuf, errlen, "No params in reply found"); return NULL; } dst = htsmsg_create_list(); HTSMSG_FOREACH(f, params) { if(strcmp(f->hmf_name, "param") || (c = htsmsg_get_map_by_field(f)) == NULL) continue; if((c = htsmsg_get_map(c, "value")) == NULL) continue; g = TAILQ_FIRST(&c->hm_fields); if(g == NULL || g->hmf_type != HMF_MAP) continue; if(xmlrpc_parse_value(dst, g, NULL, errbuf, errlen)) { htsmsg_release(dst); return NULL; } } return dst; }
static htsmsg_t * avt_SetAVTransportURI(http_connection_t *hc, htsmsg_t *args, const char *myhost, int myport) { const char *uri = htsmsg_get_str(args, "CurrentURI"); const char *metaxml = htsmsg_get_str(args, "CurrentURIMetaData"); char errbuf[200]; htsmsg_t *meta; if(uri == NULL) return NULL; if(metaxml == NULL) { playqueue_play(uri, prop_create_root(NULL), 1); return NULL; } meta = htsmsg_xml_deserialize_cstr(metaxml, errbuf, sizeof(errbuf)); if(meta == NULL) { TRACE(TRACE_ERROR, "UPNP", "SetAVTransportURI: Unable to parse metadata -- %s", errbuf); return NULL; } if(play_with_context(uri, meta)) { // Failed to play from context // TODO: Fix metadata here playqueue_play(uri, prop_create_root(NULL), 1); } htsmsg_release(meta); return NULL; }
void htsmsg_store_save(htsmsg_t *record, const char *key) { loaded_msg_t *lm; hts_mutex_lock(&loaded_msg_mutex); LIST_FOREACH(lm, &loaded_msgs, lm_link) if(!strcmp(lm->lm_key, key)) break; if(lm == NULL) { lm = calloc(1, sizeof(loaded_msg_t)); atomic_set(&lm->lm_refcount, 1); lm->lm_key = strdup(key); LIST_INSERT_HEAD(&loaded_msgs, lm, lm_link); } else { htsmsg_release(lm->lm_msg); } lm->lm_msg = htsmsg_copy(record); lm->lm_dirty = 1; callout_arm_managed(&lm->lm_timer, htsmsg_store_timer_cb, lm, SETTINGS_CACHE_DELAY, htsmsg_store_lockmgr); hts_mutex_unlock(&loaded_msg_mutex); }
static void audio_mastervol_init(void) { htsmsg_t *m = htsmsg_store_load("audiomixer"); int32_t i32; prop_t *pa, *mv, *mm; pa = prop_create(prop_get_global(), "audio"); mv = prop_create(pa, "mastervolume"); mm = prop_create(pa, "mastermute"); prop_set_float_clipping_range(mv, -75, 12); if(m != NULL && !htsmsg_get_s32(m, "master-volume", &i32)) prop_set_float(mv, (float)i32 / 1000); prop_set_int(mm, 0); htsmsg_release(m); prop_subscribe(PROP_SUB_NO_INITIAL_UPDATE, PROP_TAG_CALLBACK_FLOAT, save_matervol, NULL, PROP_TAG_ROOT, mv, NULL); prop_subscribe(PROP_SUB_NO_INITIAL_UPDATE, PROP_TAG_SET_INT, &audio_master_mute, PROP_TAG_ROOT, mm, NULL); }
void notifications_fini(void) { hts_mutex_lock(&news_mutex); htsmsg_store_save(dismissed_news_out, "dismissed_news"); htsmsg_release(dismissed_news_out); dismissed_news_out = NULL; hts_mutex_unlock(&news_mutex); }
void glw_settings_fini(void) { setting_destroy(glw_settings.gs_setting_screensaver); setting_destroy(glw_settings.gs_setting_underscan_v); setting_destroy(glw_settings.gs_setting_underscan_h); setting_destroy(glw_settings.gs_setting_size); setting_destroy(glw_settings.gs_setting_wrap); prop_destroy(glw_settings.gs_settings); htsmsg_release(glw_settings.gs_settings_store); }
static void save_matervol(void *opaque, float value) { audio_master_volume = pow(10, (value / 20)); htsmsg_t *m = htsmsg_create_map(); TRACE(TRACE_DEBUG, "audio", "Master volume set to %f dB", value); htsmsg_add_s32(m, "master-volume", value * 1000); htsmsg_store_save(m, "audiomixer"); htsmsg_release(m); }
static void save_order(prop_reorder_t *pr) { htsmsg_t *out = htsmsg_create_list(); prop_t *p; if(pr->pr_dst->hp_type == PROP_DIR) TAILQ_FOREACH(p, &pr->pr_dst->hp_childs, hp_parent_link) htsmsg_add_str(out, NULL, get_id(p)); htsmsg_store_save(out, pr->pr_store); if(pr->pr_order) htsmsg_release(pr->pr_order); pr->pr_order = out; }
/** * TTML docs here: http://www.w3.org/TR/ttaf1-dfxp/ */ static ext_subtitles_t * load_ttml(const char *url, buf_t *buf) { char errbuf[256]; htsmsg_t *subs; htsmsg_field_t *f; htsmsg_t *xml = htsmsg_xml_deserialize_buf(buf, errbuf, sizeof(errbuf)); if(xml == NULL) { TRACE(TRACE_INFO, "Subtitles", "Unable to load TTML: %s", errbuf); return NULL; } subs = htsmsg_get_map_multi(xml, "tt", "body", "div", NULL); if(subs == NULL) { htsmsg_release(xml); return NULL; } ext_subtitles_t *es = calloc(1, sizeof(ext_subtitles_t)); TAILQ_INIT(&es->es_entries); HTSMSG_FOREACH(f, subs) { if(f->hmf_type == HMF_STR && f->hmf_childs != NULL) { htsmsg_t *n = f->hmf_childs; const char *str, *txt; int64_t start, end; txt = f->hmf_str; if((str = htsmsg_get_str(n, "begin")) == NULL) continue; if((start = ttml_time_expression(str)) == -1) continue; if((str = htsmsg_get_str(n, "end")) == NULL) continue; if((end = ttml_time_expression(str)) == -1) continue; es_insert_text(es, txt, start, end, 0); } } return es; }
int cfg_load(const char *filename, const char *defconf) { int err; static char *lastfilename; if(filename == NULL) { filename = lastfilename; } else { free(lastfilename); lastfilename = strdup(filename); } if(filename == NULL) filename = defconf; trace(LOG_NOTICE, "About to load config form %s", filename); char *cfgtxt = readfile(filename, &err, NULL); if(cfgtxt == NULL) { trace(LOG_ERR, "Unable to read file %s -- %s", filename, strerror(err)); trace(LOG_ERR, "Config not updated"); return -1; } char errbuf[256]; htsmsg_t *m = htsmsg_json_deserialize(cfgtxt, errbuf, sizeof(errbuf)); free(cfgtxt); if(m == NULL) { trace(LOG_ERR, "Unable to parse file %s -- %s", filename, errbuf); trace(LOG_ERR, "Config not updated"); return -1; } pthread_mutex_lock(&cfg_mutex); if(cfgroot != NULL) htsmsg_release(cfgroot); cfgroot = m; htsmsg_retain(m); pthread_mutex_unlock(&cfg_mutex); trace(LOG_NOTICE, "Config updated"); return 0; }
void usage_fini(void) { if(gconf.device_id[0] == 0) return; hts_mutex_lock(&usage_mutex); int runtime = arch_get_ts() / 1000000LL - usage_time_base; htsmsg_s32_inc(usage_counters, "runtime", runtime); htsmsg_t *r = make_usage_report(); hts_mutex_unlock(&usage_mutex); htsmsg_store_save(r, "usage"); htsmsg_release(r); }
static void jsg_release(js_setting_group_t *jsg) { if(atomic_dec(&jsg->jsg_refcount)) return; if(jsg->jsg_root_owner) if(jsg->jsg_root != NULL) prop_destroy(jsg->jsg_root); if(jsg->jsg_store != NULL) htsmsg_release(jsg->jsg_store); free(jsg->jsg_spath); prop_ref_dec(jsg->jsg_root); free(jsg->jsg_kv_url); free(jsg); }
static int lm_destroy(loaded_msg_t *lm, int dosync) { int x = 0; if(lm->lm_dirty) { loaded_msg_write(lm); if(dosync) persistent_store_sync(); else x = 1; } htsmsg_release(lm->lm_msg); lm->lm_msg = NULL; LIST_REMOVE(lm, lm_link); callout_disarm(&lm->lm_timer); loaded_msg_release(lm); return x; }
static ext_subtitles_t * load_timedtext(const char *url, buf_t *buf) { char errbuf[256]; htsmsg_field_t *f; htsmsg_t *xml = htsmsg_xml_deserialize_buf(buf, errbuf, sizeof(errbuf)); if(xml == NULL) { TRACE(TRACE_INFO, "Subtitles", "Unable to load timed text: %s", errbuf); return NULL; } htsmsg_t *transcript = htsmsg_get_map_multi(xml, "transcript", NULL); if(transcript == NULL) { htsmsg_release(xml); return NULL; } ext_subtitles_t *es = calloc(1, sizeof(ext_subtitles_t)); TAILQ_INIT(&es->es_entries); HTSMSG_FOREACH(f, transcript) { if(f->hmf_type == HMF_STR && f->hmf_childs != NULL) { htsmsg_t *n = f->hmf_childs; const char *str; int64_t start, end; if((str = htsmsg_get_str(n, "start")) == NULL) continue; start = my_str2double(str, NULL) * 1000000.0; if((str = htsmsg_get_str(n, "dur")) == NULL) continue; end = start + my_str2double(str, NULL) * 1000000.0; char *txt = strdup(f->hmf_str); html_entities_decode(txt); es_insert_text(es, txt, start, end, 0); free(txt); } } return es; }
static void * send_report(void *aux) { htsmsg_t *m = aux; htsbuf_queue_t hq; htsbuf_queue_init(&hq, 0); htsmsg_add_msg(m, "plugins", plugins_get_installed_list()); htsmsg_json_serialize(m, &hq, 0); http_req("https://movian.tv/movian/status/v1/usage", HTTP_POSTDATA(&hq, "application/json"), NULL); htsmsg_release(m); return NULL; }
void htsmsg_field_destroy(htsmsg_t *msg, htsmsg_field_t *f) { TAILQ_REMOVE(&msg->hm_fields, f, hmf_link); htsmsg_release(f->hmf_childs); switch(f->hmf_type) { case HMF_STR: case HMF_BIN: if(f->hmf_flags & HMF_ALLOCED) free(f->hmf_str); break; default: break; } if(f->hmf_flags & HMF_NAME_ALLOCED) free(f->hmf_name); rstr_release(f->hmf_namespace); free(f); }
static int tmdb_configure(void) { hts_mutex_lock(&tmdb_mutex); if(!tmdb_configured) { buf_t *result; char errbuf[256]; result = fa_load("http://api.themoviedb.org/3/configuration", FA_LOAD_ERRBUF(errbuf, sizeof(errbuf)), FA_LOAD_QUERY_ARG("api_key", TMDB_APIKEY), FA_LOAD_QUERY_ARG("language", getlang()), FA_LOAD_FLAGS(FA_COMPRESSION | FA_IMPORTANT), NULL); if(result == NULL) { TRACE(TRACE_INFO, "TMDB", "Unable to get configuration -- %s", errbuf); goto done; } htsmsg_t *doc = htsmsg_json_deserialize2(buf_cstr(result), errbuf, sizeof(errbuf)); buf_release(result); if(doc == NULL) { TRACE(TRACE_ERROR, "TMDB", "Got bad JSON from config -- %s", errbuf); goto done; } tmdb_parse_config(doc); htsmsg_release(doc); tmdb_configured = 1; } done: hts_mutex_unlock(&tmdb_mutex); return !tmdb_configured; }
static void screenshot_process(void *task) { pixmap_t *pm = task; if(pm == NULL) { screenshot_response(NULL, "Screenshot not supported on this platform"); return; } TRACE(TRACE_DEBUG, "Screenshot", "Processing image %d x %d", pm->pm_width, pm->pm_height); int codecid = AV_CODEC_ID_PNG; if(screenshot_connection) codecid = AV_CODEC_ID_MJPEG; buf_t *b = screenshot_compress(pm, codecid); pixmap_release(pm); if(b == NULL) { screenshot_response(NULL, "Unable to compress image"); return; } if(!screenshot_connection) { char path[512]; char errbuf[512]; snprintf(path, sizeof(path), "%s/screenshot.png", gconf.cache_path); fa_handle_t *fa = fa_open_ex(path, errbuf, sizeof(errbuf), FA_WRITE, NULL); if(fa == NULL) { TRACE(TRACE_ERROR, "SCREENSHOT", "Unable to open %s -- %s", path, errbuf); buf_release(b); return; } fa_write(fa, buf_data(b), buf_len(b)); fa_close(fa); TRACE(TRACE_INFO, "SCREENSHOT", "Written to %s", path); buf_release(b); return; } buf_t *result = NULL; htsbuf_queue_t hq; htsbuf_queue_init(&hq, 0); htsbuf_append(&hq, "image=", 6); htsbuf_append_and_escape_url_len(&hq, buf_cstr(b), buf_len(b)); char errbuf[256]; int ret = http_req("https://api.imgur.com/3/upload", HTTP_FLAGS(FA_CONTENT_ON_ERROR), HTTP_REQUEST_HEADER("Authorization", "Client-ID 7c79b311d4797ed"), HTTP_RESULT_PTR(&result), HTTP_POSTDATA(&hq, "application/x-www-form-urlencoded"), HTTP_ERRBUF(errbuf, sizeof(errbuf)), NULL); if(ret) { screenshot_response(NULL, errbuf); } else { htsmsg_t *response = htsmsg_json_deserialize(buf_cstr(result)); if(response == NULL) { screenshot_response(NULL, "Unable to parse imgur response"); } else { if(htsmsg_get_u32_or_default(response, "success", 0)) { const char *url = htsmsg_get_str_multi(response, "data", "link", NULL); screenshot_response(url, "No link in imgur response"); } else { const char *msg = htsmsg_get_str_multi(response, "data", "error", NULL); if(msg == NULL) { screenshot_response(NULL, "Unkown imgur error"); } else { snprintf(errbuf, sizeof(errbuf), "Imgur error: %s", msg); screenshot_response(NULL, errbuf); } } htsmsg_release(response); } buf_release(result); } buf_release(b); }
void cfg_releasep(cfg_t **p) { if(*p) htsmsg_release(*p); }
void load_site_news(void) { #if ENABLE_WEBPOPUP struct http_header_list response_headers; buf_t *b; char errbuf[512]; b = fa_load("https://movian.tv/projects/movian/news.json", FA_LOAD_FLAGS(FA_DISABLE_AUTH | FA_COMPRESSION), FA_LOAD_RESPONSE_HEADERS(&response_headers), FA_LOAD_ERRBUF(errbuf, sizeof(errbuf)), NULL); if(b == NULL) { TRACE(TRACE_DEBUG, "News", "Unable to load news -- %s", errbuf); return; } const char *dateheader = http_header_get(&response_headers, "date"); if(dateheader == NULL) { buf_release(b); http_headers_free(&response_headers); return; } dateheader = mystrdupa(dateheader); http_headers_free(&response_headers); htsmsg_t *newsinfo = htsmsg_store_load("sitenews"); time_t no_news_before; if(newsinfo == NULL) newsinfo = htsmsg_create_map(); no_news_before = htsmsg_get_u32_or_default(newsinfo, "nothingbefore", 0); if(no_news_before == 0) { if(http_ctime(&no_news_before, dateheader)) { buf_release(b); htsmsg_release(newsinfo); return; } htsmsg_add_u32(newsinfo, "nothingbefore", no_news_before); htsmsg_store_save(newsinfo, "sitenews"); htsmsg_release(newsinfo); } htsmsg_t *doc = htsmsg_json_deserialize(buf_cstr(b)); buf_release(b); if(doc == NULL) { return; } hts_mutex_lock(&news_mutex); htsmsg_t *news = htsmsg_get_list(doc, "news"); if(news != NULL) { htsmsg_field_t *f; HTSMSG_FOREACH(f, news) { htsmsg_t *entry; if((entry = htsmsg_get_map_by_field(f)) == NULL) continue; const char *title = htsmsg_get_str(entry, "title"); const char *created_on = htsmsg_get_str(entry, "created_on"); int id = htsmsg_get_u32_or_default(entry, "id", 0); if(created_on == NULL || title == NULL || id == 0) continue; time_t t; if(parse_created_on_time(&t, created_on)) continue; if(t < no_news_before) continue; char idstr[64]; snprintf(idstr, sizeof(idstr), "sitenews:%d", id); prop_t *p = add_news_locked(idstr, title, NULL, "Read more", idstr); if(p != NULL) { prop_subscribe(PROP_SUB_TRACK_DESTROY, PROP_TAG_CALLBACK, open_news, p, PROP_TAG_ROOT, prop_create(p, "eventSink"), PROP_TAG_MUTEX, &news_mutex, NULL); } }