static htsmsg_t * make_usage_report(void) { extern const char *htsversion_full; htsmsg_t *out = htsmsg_create_map(); htsmsg_add_str(out, "deviceid", gconf.device_id); htsmsg_add_str(out, "version", htsversion_full); htsmsg_add_str(out, "arch", arch_get_system_type()); htsmsg_add_u32(out, "verint", app_get_version_int()); htsmsg_add_u32(out, "generated", time(NULL)); if(gconf.os_info[0]) htsmsg_add_str(out, "os" , gconf.os_info); time_t now = arch_get_ts() / 1000000LL; int runtime = now - usage_time_base; htsmsg_s32_inc(usage_counters, "runtime", runtime); usage_time_base = now; htsmsg_add_msg(out, "counters", usage_counters); usage_counters = htsmsg_create_map(); htsmsg_add_msg(out, "plugincounters", plugin_counters); plugin_counters = htsmsg_create_map(); return out; }
static htsmsg_t * tvh_codec_audio_get_list_sample_fmts(TVHAudioCodec *self) { htsmsg_t *list = NULL, *map = NULL; const enum AVSampleFormat *sample_fmts = self->sample_fmts; enum AVSampleFormat f = AV_SAMPLE_FMT_NONE; const char *f_str = NULL; int i; if (sample_fmts && (list = htsmsg_create_list())) { if (!(map = htsmsg_create_map())) { htsmsg_destroy(list); list = NULL; } else { ADD_ENTRY(list, map, s32, f, str, AUTO_STR); for (i = 0; (f = sample_fmts[i]) != AV_SAMPLE_FMT_NONE; i++) { if (!(f_str = av_get_sample_fmt_name(f)) || !(map = htsmsg_create_map())) { htsmsg_destroy(list); list = NULL; break; } ADD_ENTRY(list, map, s32, f, str, f_str); } } } return list; }
static htsmsg_t * tvh_codec_audio_get_list_sample_rates(TVHAudioCodec *self) { htsmsg_t *list = NULL, *map = NULL; const int *sample_rates = self->sample_rates; int r = 0, i; if (sample_rates && (list = htsmsg_create_list())) { if (!(map = htsmsg_create_map())) { htsmsg_destroy(list); list = NULL; } else { ADD_ENTRY(list, map, s32, r, str, AUTO_STR); for (i = 0; (r = sample_rates[i]); i++) { if (!(map = htsmsg_create_map())) { htsmsg_destroy(list); list = NULL; break; } ADD_S32_VAL(list, map, r); } } } return list; }
static htsmsg_t * tvh_codec_audio_get_list_channel_layouts(TVHAudioCodec *self) { htsmsg_t *list = NULL, *map = NULL; const uint64_t *channel_layouts = self->channel_layouts; uint64_t l = 0; char l_buf[16]; int i; if (channel_layouts && (list = htsmsg_create_list())) { if (!(map = htsmsg_create_map())) { htsmsg_destroy(list); list = NULL; } else { ADD_ENTRY(list, map, s64, l, str, AUTO_STR); for (i = 0; (l = channel_layouts[i]); i++) { if (l < INT64_MAX) { if (!(map = htsmsg_create_map())) { htsmsg_destroy(list); list = NULL; break; } l_buf[0] = '\0'; av_get_channel_layout_string(l_buf, sizeof(l_buf), 0, l); ADD_ENTRY(list, map, s64, l, str, l_buf); } } } } return list; }
/** * Get a list of supported containers */ int muxer_container_list(htsmsg_t *array) { htsmsg_t *mc; int c = 0; mc = htsmsg_create_map(); htsmsg_add_str(mc, "name", muxer_container_type2txt(MC_MATROSKA)); htsmsg_add_str(mc, "description", "Matroska"); htsmsg_add_msg(array, NULL, mc); c++; mc = htsmsg_create_map(); htsmsg_add_str(mc, "name", muxer_container_type2txt(MC_PASS)); htsmsg_add_str(mc, "description", "Same as source (pass through)"); htsmsg_add_msg(array, NULL, mc); c++; #if ENABLE_LIBAV mc = htsmsg_create_map(); htsmsg_add_str(mc, "name", muxer_container_type2txt(MC_MPEGTS)); htsmsg_add_str(mc, "description", "MPEG-TS"); htsmsg_add_msg(array, NULL, mc); c++; mc = htsmsg_create_map(); htsmsg_add_str(mc, "name", muxer_container_type2txt(MC_MPEGPS)); htsmsg_add_str(mc, "description", "MPEG-PS (DVD)"); htsmsg_add_msg(array, NULL, mc); c++; #endif return c; }
void keyring_init(void) { hts_mutex_init(&keyring_mutex); if((persistent_keyring = htsmsg_store_load("keyring")) == NULL) persistent_keyring = htsmsg_create_map(); temporary_keyring = htsmsg_create_map(); }
void usage_init(void) { hts_mutex_init(&usage_mutex); usage_time_base = arch_get_ts() / 1000000LL; usage_counters = htsmsg_create_map(); plugin_counters = htsmsg_create_map(); }
void keyring_init(void) { hts_mutex_init(&keyring_mutex); if((persistent_keyring = htsmsg_store_load("keyring")) == NULL) persistent_keyring = htsmsg_create_map(); temporary_keyring = htsmsg_create_map(); settings_create_action(settings_general, _p("Forget remembered passwords"), keyring_clear, NULL, NULL); }
void notifications_init(void) { hts_mutex_init(&news_mutex); prop_t *root = prop_create(prop_get_global(), "notifications"); if((dismissed_news_in = htsmsg_store_load("dismissed_news")) == NULL) dismissed_news_in = htsmsg_create_map(); dismissed_news_out = htsmsg_create_map(); notify_prop_entries = prop_create(root, "nodes"); }
static int api_dvr_entry_create ( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp ) { dvr_entry_t *de; dvr_config_t *cfg; htsmsg_t *conf, *m; char *s, *lang; const char *s1; int res = EPERM; if (!(conf = htsmsg_get_map(args, "conf"))) return EINVAL; pthread_mutex_lock(&global_lock); s1 = htsmsg_get_str(conf, "config_name"); cfg = dvr_config_find_by_list(perm->aa_dvrcfgs, s1); if (cfg) { htsmsg_set_str(conf, "config_name", idnode_uuid_as_str(&cfg->dvr_id)); htsmsg_set_str(conf, "owner", perm->aa_username ?: ""); htsmsg_set_str(conf, "creator", perm->aa_representative ?: ""); lang = access_get_lang(perm, htsmsg_get_str(conf, "lang")); if (lang) { for (s = (char *)lang; *s && *s != ','; s++); *s = '\0'; } else { lang = strdup(lang_code_preferred()); } s1 = htsmsg_get_str(conf, "disp_title"); if (s1 && !htsmsg_get_map(conf, "title")) { m = htsmsg_create_map(); htsmsg_add_str(m, lang, s1); htsmsg_add_msg(conf, "title", m); } s1 = htsmsg_get_str(conf, "disp_subtitle"); if (s1 && !htsmsg_get_map(conf, "subtitle")) { m = htsmsg_create_map(); htsmsg_add_str(m, lang, s1); htsmsg_add_msg(conf, "subtitle", m); } if ((de = dvr_entry_create(NULL, conf))) dvr_entry_save(de); res = 0; free(lang); } pthread_mutex_unlock(&global_lock); return res; }
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")); }
JSBool js_createStore(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { const char *id; char spath[URL_MAX]; JSBool per_user = 0; if(!JS_ConvertArguments(cx, argc, argv, "s/b", &id, &per_user)) return JS_FALSE; js_plugin_t *jsp = JS_GetPrivate(cx, obj); snprintf(spath, sizeof(spath), "jsstore/%s-%s", jsp->jsp_id, id); js_setting_group_t *jsg = calloc(1, sizeof(js_setting_group_t)); JSObject *robj; jsg->jsg_refcount = 1; jsg->jsg_frozen = 1; jsg->jsg_spath = strdup(spath); jsg->jsg_store = htsmsg_store_load(spath) ?: htsmsg_create_map(); robj = JS_NewObjectWithGivenProto(cx, &setting_group_class, NULL, obj); *rval = OBJECT_TO_JSVAL(robj); JS_SetPrivate(cx, robj, jsg); jsg->jsg_frozen = 0; return JS_TRUE; }
void opensub_init(void) { prop_t *s; hts_mutex_init(&opensub_mutex); s = subtitle_settings_dir; settings_create_divider(s, _p("Settings for opensubtitles.org")); htsmsg_t *store = htsmsg_store_load("opensubtitles"); if(store == NULL) store = htsmsg_create_map(); settings_create_bool(s, "enable", _p("Use opensubtitles.org"), 0, store, set_enable, NULL, SETTINGS_INITIAL_UPDATE, NULL, settings_generic_save_settings, (void *)"opensubtitles"); settings_create_string(s, "username", _p("Username"), NULL, store, set_username, NULL, SETTINGS_INITIAL_UPDATE, NULL, settings_generic_save_settings, (void *)"opensubtitles"); settings_create_string(s, "password", _p("Password"), NULL, store, set_password, NULL, SETTINGS_INITIAL_UPDATE | SETTINGS_PASSWORD, NULL, settings_generic_save_settings, (void *)"opensubtitles"); }
bool cHTSPData::GetTime(time_t *localTime, int *gmtOffset) { XBMC->Log(LOG_DEBUG, "%s", __FUNCTION__); htsmsg_t *msg = htsmsg_create_map(); htsmsg_add_str(msg, "method", "getSysTime"); if ((msg = ReadResult(msg)) == NULL) { XBMC->Log(LOG_ERROR, "%s - failed to get sysTime", __FUNCTION__); return false; } unsigned int secs; if (htsmsg_get_u32(msg, "time", &secs) != 0) return false; int offset; if (htsmsg_get_s32(msg, "timezone", &offset) != 0) return false; XBMC->Log(LOG_DEBUG, "%s - tvheadend reported time=%u, timezone=%d, correction=%d" , __FUNCTION__, secs, offset, g_iEpgOffsetCorrection * 60); /* XBMC needs the timezone difference in seconds from GMT */ offset = (offset - (g_iEpgOffsetCorrection * 60)) * 60; *localTime = secs + offset; *gmtOffset = -offset; return true; }
static int api_channel_tag_list ( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp ) { channel_tag_t *ct; htsmsg_t *l; int cfg = api_channel_is_all(perm, args); char buf[128], ubuf[UUID_HEX_SIZE]; l = htsmsg_create_list(); pthread_mutex_lock(&global_lock); TAILQ_FOREACH(ct, &channel_tags, ct_link) if (cfg || channel_tag_access(ct, perm, 0)) { if (ct->ct_enabled) { api_channel_key_val(l, idnode_uuid_as_str(&ct->ct_id, ubuf), ct->ct_name); } else { snprintf(buf, sizeof(buf), "{%s}", ct->ct_name); api_channel_key_val(l, idnode_uuid_as_str(&ct->ct_id, ubuf), buf); } } pthread_mutex_unlock(&global_lock); *resp = htsmsg_create_map(); htsmsg_add_msg(*resp, "entries", l); return 0; }
PVR_ERROR cHTSPData::AddTimer(const PVR_TIMERINFO &timerinfo) { XBMC->Log(LOG_DEBUG, "%s - id=%d", __FUNCTION__, timerinfo.index); htsmsg_t *msg = htsmsg_create_map(); htsmsg_add_str(msg, "method", "addDvrEntry"); htsmsg_add_u32(msg, "eventId", timerinfo.index); htsmsg_add_str(msg, "title", timerinfo.title); htsmsg_add_u32(msg, "starttime", timerinfo.starttime); htsmsg_add_u32(msg, "endtime", timerinfo.endtime); if ((msg = ReadResult(msg)) == NULL) { XBMC->Log(LOG_DEBUG, "%s - Failed to get addDvrEntry", __FUNCTION__); return PVR_ERROR_SERVER_ERROR; } unsigned int success; if (htsmsg_get_u32(msg, "success", &success) != 0) { XBMC->Log(LOG_DEBUG, "%s - Failed to parse param", __FUNCTION__); return PVR_ERROR_SERVER_ERROR; } return success > 0 ? PVR_ERROR_NO_ERROR : PVR_ERROR_NOT_DELETED; }
// TODO: this will need converting to an idnode system static int api_channel_list ( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp ) { channel_t *ch; htsmsg_t *l; int cfg = api_channel_is_all(perm, args); char buf[128], ubuf[UUID_HEX_SIZE]; l = htsmsg_create_list(); pthread_mutex_lock(&global_lock); CHANNEL_FOREACH(ch) { if (!cfg && !channel_access(ch, perm, 0)) continue; if (!ch->ch_enabled) { snprintf(buf, sizeof(buf), "{%s}", channel_get_name(ch)); api_channel_key_val(l, idnode_uuid_as_str(&ch->ch_id, ubuf), buf); } else { api_channel_key_val(l, idnode_uuid_as_str(&ch->ch_id, ubuf), channel_get_name(ch)); } } pthread_mutex_unlock(&global_lock); *resp = htsmsg_create_map(); htsmsg_add_msg(*resp, "entries", l); return 0; }
bool CHTSPData::GetEvent(SEvent& event, uint32_t id) { if(id == 0) { event.Clear(); return false; } SEvents::iterator it = m_events.find(id); if(it != m_events.end()) { event = it->second; return true; } htsmsg_t *msg = htsmsg_create_map(); htsmsg_add_str(msg, "method", "getEvent"); htsmsg_add_u32(msg, "eventId", id); if((msg = ReadResult(msg)) == NULL) { XBMC->Log(LOG_DEBUG, "%s - failed to get event %d", __FUNCTION__, id); return false; } if (m_session->ParseEvent(msg, id, event)) { m_events[id] = event; return true; } return false; }
PVR_ERROR CHTSPData::UpdateTimer(const PVR_TIMER &timer) { XBMC->Log(LOG_DEBUG, "%s - channelUid=%d title=%s epgid=%d", __FUNCTION__, timer.iClientChannelUid, timer.strTitle, timer.iEpgUid); htsmsg_t *msg = htsmsg_create_map(); htsmsg_add_str(msg, "method", "updateDvrEntry"); htsmsg_add_u32(msg, "id", timer.iClientIndex); htsmsg_add_str(msg, "title", timer.strTitle); htsmsg_add_u32(msg, "start", timer.startTime); htsmsg_add_u32(msg, "stop", timer.endTime); if ((msg = ReadResult(msg)) == NULL) { XBMC->Log(LOG_DEBUG, "%s - Failed to get updateDvrEntry", __FUNCTION__); return PVR_ERROR_SERVER_ERROR; } unsigned int success; if (htsmsg_get_u32(msg, "success", &success) != 0) { XBMC->Log(LOG_DEBUG, "%s - Failed to parse param", __FUNCTION__); return PVR_ERROR_SERVER_ERROR; } return success > 0 ? PVR_ERROR_NO_ERROR : PVR_ERROR_NOT_SAVED; }
PVR_ERROR CHTSPData::DeleteTimer(const PVR_TIMER &timer, bool bForce) { XBMC->Log(LOG_DEBUG, "%s", __FUNCTION__); htsmsg_t *msg = htsmsg_create_map(); htsmsg_add_str(msg, "method", "cancelDvrEntry"); htsmsg_add_u32(msg, "id", timer.iClientIndex); if ((msg = ReadResult(msg)) == NULL) { XBMC->Log(LOG_DEBUG, "%s - Failed to get cancelDvrEntry", __FUNCTION__); return PVR_ERROR_SERVER_ERROR; } const char *strError = NULL; if ((strError = htsmsg_get_str(msg, "error"))) { XBMC->Log(LOG_DEBUG, "%s - Error deleting timer: '%s'", __FUNCTION__, strError); return PVR_ERROR_SERVER_ERROR; } unsigned int success; if (htsmsg_get_u32(msg, "success", &success) != 0) { XBMC->Log(LOG_DEBUG, "%s - Failed to parse param", __FUNCTION__); return PVR_ERROR_SERVER_ERROR; } return success > 0 ? PVR_ERROR_NO_ERROR : PVR_ERROR_NOT_DELETED; }
bool CHTSPData::GetBackendTime(time_t *utcTime, int *gmtOffset) { htsmsg_t *msg = htsmsg_create_map(); htsmsg_add_str(msg, "method", "getSysTime"); if ((msg = ReadResult(msg)) == NULL) { XBMC->Log(LOG_ERROR, "%s - failed to get sysTime", __FUNCTION__); return false; } unsigned int secs; if (htsmsg_get_u32(msg, "time", &secs) != 0) return false; int offset; if (htsmsg_get_s32(msg, "timezone", &offset) != 0) return false; XBMC->Log(LOG_DEBUG, "%s - tvheadend reported time=%u, timezone=%d, correction=%d" , __FUNCTION__, secs, offset); *utcTime = secs; *gmtOffset = offset; return true; }
JSBool js_createSettings(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { const char *title; const char *icon = NULL; const char *desc = NULL; char spath[URL_MAX]; if(!JS_ConvertArguments(cx, argc, argv, "s/ss", &title, &icon, &desc)) return JS_FALSE; js_plugin_t *jsp = JS_GetPrivate(cx, obj); snprintf(spath, sizeof(spath), "plugins/%s", jsp->jsp_id); js_setting_group_t *jsg = calloc(1, sizeof(js_setting_group_t)); JSObject *robj; jsg->jsg_refcount = 2; LIST_INSERT_HEAD(&jsp->jsp_setting_groups, jsg, jsg_link); jsg->jsg_frozen = 1; jsg->jsg_spath = strdup(spath); jsg->jsg_store = htsmsg_store_load(spath) ?: htsmsg_create_map(); jsg->jsg_root = settings_add_dir(settings_apps, _p(title), NULL, icon, desc ? _p(desc) : NULL); robj = JS_NewObjectWithGivenProto(cx, &setting_group_class, NULL, obj); jsg->jsg_val = *rval = OBJECT_TO_JSVAL(robj); JS_AddNamedRoot(cx, &jsg->jsg_val, "jsg"); JS_SetPrivate(cx, robj, jsg); JS_DefineFunctions(cx, robj, setting_functions); jsg->jsg_frozen = 0; return JS_TRUE; }
htsmsg_t * tvh_input_stream_create_msg ( tvh_input_stream_t *st ) { htsmsg_t *m = htsmsg_create_map(); htsmsg_add_str(m, "uuid", st->uuid); if (st->input_name) htsmsg_add_str(m, "input", st->input_name); if (st->stream_name) htsmsg_add_str(m, "stream", st->stream_name); htsmsg_add_u32(m, "subs", st->subs_count); htsmsg_add_u32(m, "weight", st->max_weight); htsmsg_add_u32(m, "signal", st->stats.signal); htsmsg_add_u32(m, "signal_scale", st->stats.signal_scale); htsmsg_add_u32(m, "ber", st->stats.ber); htsmsg_add_u32(m, "snr", st->stats.snr); htsmsg_add_u32(m, "snr_scale", st->stats.snr_scale); htsmsg_add_u32(m, "unc", st->stats.unc); htsmsg_add_u32(m, "bps", st->stats.bps); htsmsg_add_u32(m, "te", st->stats.te); htsmsg_add_u32(m, "cc", st->stats.cc); htsmsg_add_u32(m, "ec_bit", st->stats.ec_bit); htsmsg_add_u32(m, "tc_bit", st->stats.tc_bit); htsmsg_add_u32(m, "ec_block", st->stats.ec_block); htsmsg_add_u32(m, "tc_block", st->stats.tc_block); return m; }
static htsmsg_t * avt_GetPositionInfo(http_connection_t *hc, htsmsg_t *args, const char *myhost, int myport) { htsmsg_t *out = htsmsg_create_map(); char tbuf[16]; hts_mutex_lock(&upnp_lock); char *didl = build_didl(http_get_my_host(hc), http_get_my_port(hc)); htsmsg_add_u32(out, "Track", upnp_current_track); fmttime(tbuf, sizeof(tbuf), upnp_current_track_duration); htsmsg_add_str(out, "TrackDuration", tbuf); htsmsg_add_str(out, "TrackMetaData", didl); free(didl); htsmsg_add_str(out, "TrackURI", upnp_current_url ?: ""); fmttime(tbuf, sizeof(tbuf), upnp_current_track_time); htsmsg_add_str(out, "RelTime", tbuf); htsmsg_add_str(out, "AbsTime", tbuf); //"NOT_IMPLEMENTED"); htsmsg_add_u32(out, "RelCount", 2147483647); htsmsg_add_u32(out, "AbsCount", 2147483647); hts_mutex_unlock(&upnp_lock); return out; }
void influxdb_put(const char *id, double value) { char url[1024]; cfg_root(root); const char *urlprefix = cfg_get_str(root, CFG("influxdb", "url"), NULL); const char *db = cfg_get_str(root, CFG("influxdb", "db"), NULL); const char *username = cfg_get_str(root, CFG("influxdb", "username"), NULL); const char *password = cfg_get_str(root, CFG("influxdb", "password"), NULL); if(urlprefix == NULL || db == NULL || username == NULL || password == NULL) return; snprintf(url, sizeof(url), "%s/db/%s/series?u=%s&p=%s", urlprefix, db, username, password); htsmsg_t *doc = htsmsg_create_list(); htsmsg_t *item = htsmsg_create_map(); htsmsg_add_str(item, "name", id); htsmsg_t *columns = htsmsg_create_list(); htsmsg_add_str(columns, NULL, "value"); htsmsg_add_msg(item, "columns", columns); htsmsg_t *points = htsmsg_create_list(); htsmsg_t *point = htsmsg_create_list(); htsmsg_add_dbl(point, NULL, value); htsmsg_add_msg(points, NULL, point); htsmsg_add_msg(item, "points", points); htsmsg_add_msg(doc, NULL, item); char *data = htsmsg_json_serialize_to_str(doc, 0); htsmsg_destroy(doc); size_t len = strlen(data); FILE *f = fmemopen(data, len, "r"); CURL *curl = curl_easy_init(); curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &libsvc_curl_waste_output); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); curl_easy_setopt(curl, CURLOPT_READDATA, (void *)f); curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)len); CURLcode result = curl_easy_perform(curl); curl_easy_cleanup(curl); if(result) trace(LOG_ERR, "CURL Failed %s error %d", url, result); fclose(f); free(data); }
static htsmsg_t * rc_ListPresets(struct http_connection *hc, htsmsg_t *args, const char *myhost, int myport) { htsmsg_t *out = htsmsg_create_map(); htsmsg_add_str(out, "CurrentPresetNameList ", ""); return out; }
static void tvhtime_save ( void ) { htsmsg_t *m = htsmsg_create_map(); htsmsg_add_u32(m, "update_enabled", tvhtime_update_enabled); htsmsg_add_u32(m, "ntp_enabled", tvhtime_ntp_enabled); htsmsg_add_u32(m, "tolerance", tvhtime_tolerance); hts_settings_save(m, "tvhtime/config"); }
static void api_channel_key_val(htsmsg_t *dst, const char *key, const char *val) { htsmsg_t *e = htsmsg_create_map(); htsmsg_add_str(e, "key", key); htsmsg_add_str(e, "val", val ?: ""); htsmsg_add_msg(dst, NULL, e); }
/* * Save settings */ static htsmsg_t * timeshift_conf_class_save ( idnode_t *self, char *filename, size_t fsize ) { htsmsg_t *m = htsmsg_create_map(); idnode_save(×hift_conf.idnode, m); snprintf(filename, fsize, "timeshift/config"); return m; }
/* Serialize map */ htsmsg_t *lang_str_serialize_map ( lang_str_t *ls ) { lang_str_ele_t *e; if (!ls) return NULL; htsmsg_t *a = htsmsg_create_map(); RB_FOREACH(e, ls, link) { htsmsg_add_str(a, e->lang, e->str); }