static htsmsg_t * hts_settings_load_one(const char *filename) { ssize_t n; char *mem; fb_file *fp; htsmsg_t *r = NULL; /* Open */ if (!(fp = fb_open(filename, 1, 0))) return NULL; /* Load data */ mem = malloc(fb_size(fp)+1); n = fb_read(fp, mem, fb_size(fp)); if (n >= 0) mem[n] = 0; /* Decode */ if(n == fb_size(fp)) r = htsmsg_json_deserialize(mem); /* Close */ fb_close(fp); free(mem); return r; }
static JSBool js_appendItem(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { const char *url; const char *type = NULL; JSObject *metaobj = NULL; js_model_t *model = JS_GetPrivate(cx, obj); const char *canonical_url = NULL; htsmsg_t *m = NULL; JSBool r; if(!JS_ConvertArguments(cx, argc, argv, "s/so", &url, &type, &metaobj)) return JS_FALSE; if(!strncmp(url, "videoparams:", strlen("videoparams:"))) { m = htsmsg_json_deserialize(url + strlen("videoparams:")); if(m != NULL) { canonical_url = htsmsg_get_str(m, "canonicalUrl"); if(canonical_url == NULL) { htsmsg_t *sources; if((sources = htsmsg_get_list(m, "sources")) == NULL) { htsmsg_field_t *f; HTSMSG_FOREACH(f, sources) { htsmsg_t *src = &f->hmf_msg; canonical_url = htsmsg_get_str(src, "url"); if(canonical_url != NULL) break; }
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; }
static loaded_msg_t * htsmsg_store_obtain(const char *key, int create) { char errbuf[512]; htsmsg_t *r = NULL; loaded_msg_t *lm; LIST_FOREACH(lm, &loaded_msgs, lm_link) if(!strcmp(lm->lm_key, key)) return lm; buf_t *b = persistent_load("settings", key, errbuf, sizeof(errbuf)); if(b == NULL) { if(!create) { return NULL; } } else { r = htsmsg_json_deserialize(buf_cstr(b)); buf_release(b); if(r == NULL && !create) return NULL; } if(r == NULL) r = htsmsg_create_map(); 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); lm->lm_msg = r; callout_arm_managed(&lm->lm_timer, htsmsg_store_timer_cb, lm, SETTINGS_CACHE_DELAY, htsmsg_store_lockmgr); return lm; }
struct pixmap * backend_imageloader(rstr_t *url0, const image_meta_t *im0, const char **vpaths, char *errbuf, size_t errlen, int *cache_control, cancellable_t *c) { const char *url = rstr_get(url0); htsmsg_t *m = NULL; if(im0->im_req_width < -1 || im0->im_req_height < -1) { snprintf(errbuf, errlen, "Invalid dimensions"); return NULL; } image_meta_t im = *im0; if(!strncmp(url, "thumb://", 8)) { url += 8; im.im_want_thumb = 1; } if(!strncmp(url, "imageset:", 9)) { m = htsmsg_json_deserialize(url+9); if(m == NULL) { snprintf(errbuf, errlen, "Invalid JSON"); return NULL; } htsmsg_field_t *f; const char *best = NULL; int best_width = -1; int best_height = -1; HTSMSG_FOREACH(f, m) { htsmsg_t *img = htsmsg_get_map_by_field(f); if(img == NULL) continue; int w = htsmsg_get_u32_or_default(img, "width", 10000); int h = htsmsg_get_u32_or_default(img, "height", 10000); const char *u = htsmsg_get_str(img, "url"); if(!u) continue; if(best != NULL) { if(im.im_req_width != -1) { if(w >= im.im_req_width && (w < best_width || best_width < im.im_req_width)) goto gotone; if(w < im.im_req_width && w > best_width) goto gotone; } else if(im.im_req_height != -1) { if(h >= im.im_req_height && (h < best_height || best_height < im.im_req_height)) goto gotone; if(h < im.im_req_height && h > best_height) goto gotone; } else { if(w > best_width) goto gotone; if(h > best_height) goto gotone; } continue; } gotone: best = u; best_width = w; best_height = h; }
/** * Probe file by checking its header * * pb is guaranteed to point to at least 256 bytes of valid data */ static int fa_probe_header(metadata_t *md, const char *url, fa_handle_t *fh, const char *filename) { uint16_t flags; uint8_t buf[256]; if(fa_read(fh, buf, sizeof(buf)) != sizeof(buf)) return 0; if(!memcmp(buf, "SNES-SPC700 Sound File Data", 27)) { fa_probe_spc(md, buf, filename); md->md_contenttype = CONTENT_AUDIO; return 1; } if(!memcmp(buf, "PSID", 4) || !memcmp(buf, "RSID", 4)) { fa_probe_psid(md, buf); md->md_contenttype = CONTENT_ALBUM; metdata_set_redirect(md, "sidfile://%s/", url); return 1; } if(buf[0] == 'R' && buf[1] == 'a' && buf[2] == 'r' && buf[3] == '!' && buf[4] == 0x1a && buf[5] == 0x07 && buf[6] == 0x0 && buf[9] == 0x73) { flags = buf[10] | buf[11] << 8; if((flags & 0x101) == 1) { /* Don't include slave volumes */ md->md_contenttype = CONTENT_UNKNOWN; return 1; } metdata_set_redirect(md, "rar://%s", url); md->md_contenttype = CONTENT_ARCHIVE; return 1; } if(buf[0] == 0x50 && buf[1] == 0x4b && buf[2] == 0x03 && buf[3] == 0x04) { char path[256]; char *buf; snprintf(path, sizeof(path), "zip://%s/plugin.json", url); buf = fa_load(path, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL); if(buf != NULL) { htsmsg_t *json = htsmsg_json_deserialize(buf); free(buf); if(json != NULL) { const char *title = htsmsg_get_str(json, "title"); if(title != NULL && htsmsg_get_str(json, "id") != NULL && htsmsg_get_str(json, "type") != NULL) { md->md_title = rstr_alloc(title); md->md_contenttype = CONTENT_PLUGIN; htsmsg_destroy(json); return 1; } htsmsg_destroy(json); } } metdata_set_redirect(md, "zip://%s", url); md->md_contenttype = CONTENT_ARCHIVE; return 1; } #if 0 if(!strncasecmp((char *)buf, "[playlist]", 10)) { /* Playlist */ fa_probe_playlist(md, url, buf, sizeof(buf)); md->md_contenttype = CONTENT_PLAYLIST; return 1; } #endif if((buf[6] == 'J' && buf[7] == 'F' && buf[8] == 'I' && buf[9] == 'F') || (buf[6] == 'E' && buf[7] == 'x' && buf[8] == 'i' && buf[9] == 'f')) { /* JPEG image */ md->md_contenttype = CONTENT_IMAGE; fa_probe_exif(md, url, buf, fh); // Try to get more info return 1; } if(!memcmp(buf, "<showtimeplaylist", strlen("<showtimeplaylist"))) { /* Ugly playlist thing (see fa_video.c) */ md->md_contenttype = CONTENT_VIDEO; return 1; } if(!memcmp(buf, pngsig, 8)) { /* PNG */ md->md_contenttype = CONTENT_IMAGE; return 1; } if(!memcmp(buf, gifsig, sizeof(gifsig))) { /* GIF */ md->md_contenttype = CONTENT_IMAGE; return 1; } if(buf[0] == '%' && buf[1] == 'P' && buf[2] == 'D' && buf[3] == 'F') { md->md_contenttype = CONTENT_UNKNOWN; return 1; } if(!memcmp(buf, ttfsig, sizeof(ttfsig)) || !memcmp(buf, otfsig, sizeof(otfsig))) { /* TTF or OTF */ md->md_contenttype = CONTENT_FONT; return 1; } return 0; }
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); } }
static int http_github(http_connection_t *hc, const char *remain, void *opaque) { const char *pid = http_arg_get(&hc->hc_req_args, "project"); const char *key = http_arg_get(&hc->hc_req_args, "key"); if(pid == NULL) { trace(LOG_WARNING, "github: Missing 'project' in request"); return 400; } if(key == NULL) { trace(LOG_WARNING, "github: Missing 'key' in request"); return 400; } project_cfg(pc, pid); if(pc == NULL) { trace(LOG_DEBUG, "github: Project '%s' not configured", pid); return 404; } const char *mykey = cfg_get_str(pc, CFG("github", "key"), ""); if(strcmp(mykey, key)) { trace(LOG_WARNING, "github: Invalid key received (%s) for project %s", key, pid); return 403; } project_t *p = project_get(pid); const char *json = http_arg_get(&hc->hc_req_args, "payload"); if(json == NULL) { plog(p, "github", "github: Missing payload in request"); return 400; } char errbuf[256]; htsmsg_t *msg = htsmsg_json_deserialize(json, errbuf, sizeof(errbuf)); if(msg == NULL) { plog(p, "github", "github: Malformed JSON in github request -- %s", errbuf); return 400; } const char *ref = htsmsg_get_str(msg, "ref"); if(ref != NULL && !strncmp(ref, "refs/heads/", strlen("refs/heads/"))) ref += strlen("refs/heads/"); htsmsg_t *list = htsmsg_get_list(msg, "commits"); if(ref != NULL && list != NULL) { htsmsg_field_t *f; HTSMSG_FOREACH(f, list) { htsmsg_t *c = htsmsg_get_map_by_field(f); if(c == NULL) continue; const char *url = htsmsg_get_str(c, "url"); const char *msg = htsmsg_get_str(c, "message"); htsmsg_t *a = htsmsg_get_map(c, "author"); const char *author = a ? htsmsg_get_str(a, "name") : NULL; int added = count_list(c, "added"); int removed = count_list(c, "removed"); int modified = count_list(c, "modified"); int len; char buf[512]; char ctx[128]; url = url ? urlshorten(url) : NULL; snprintf(ctx, sizeof(ctx), "changes/%s", ref); len = snprintf(buf, sizeof(buf), "Commit in '"COLOR_BLUE"%s"COLOR_OFF"' by "COLOR_PURPLE"%s"COLOR_OFF" [", ref, author ?: "???"); if(added) len += snprintf(buf + len, sizeof(buf) - len, COLOR_GREEN "%d file%s added", added, added == 1 ? "" : "s"); if(modified) len += snprintf(buf + len, sizeof(buf) - len, COLOR_YELLOW "%s%d file%s modified", added ? ", " : "", modified, modified == 1 ? "" : "s"); if(removed) len += snprintf(buf + len, sizeof(buf) - len, COLOR_RED "%s%d file%s removed", added || modified ? ", " : "", removed, removed == 1 ? "" : "s"); snprintf(buf + len, sizeof(buf) - len, COLOR_OFF"]%s%s", url ? " " : "", url ?: ""); plog(p, ctx, "%s", buf); plog(p, ctx, "%s", msg); }
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); }
static void check_upgrade(int set_news) { char url[1024]; char *result; htsmsg_t *json; char errbuf[1024]; if(inhibit_checks) return; if(upgrade_track == NULL) { prop_set_string(upgrade_error, "No release track specified"); goto err; } prop_set_string(upgrade_status, "checking"); TRACE(TRACE_DEBUG, "Upgrade", "Checking upgrades for %s-%s", upgrade_track, archname); snprintf(url, sizeof(url), "%s/%s-%s.json", ctrlbase, upgrade_track, archname); result = fa_load(url, NULL, NULL, errbuf, sizeof(errbuf), NULL, 0, NULL, NULL); if(result == NULL) { prop_set_string(upgrade_error, errbuf); err: prop_set_string(upgrade_status, "checkError"); return; } json = htsmsg_json_deserialize(result); free(result); if(json == NULL) { prop_set_string(upgrade_error, "Malformed JSON in repository"); goto err; } // Find an artifact for us const char *dlurl = NULL; const char *sha1 = NULL; int dlsize = 0; const char *ver; htsmsg_t *artifacts = htsmsg_get_list(json, "artifacts"); if(artifacts != NULL) { htsmsg_field_t *f; HTSMSG_FOREACH(f, artifacts) { htsmsg_t *a; if((a = htsmsg_get_map_by_field(f)) == NULL) continue; const char *type = htsmsg_get_str(a, "type"); if(type == NULL || strcmp(artifact_type, type)) continue; dlurl = htsmsg_get_str(a, "url"); sha1 = htsmsg_get_str(a, "sha1"); dlsize = htsmsg_get_u32_or_default(a, "size", 0); break; }
static void plugin_load(const char *url) { char ctrlfile[URL_MAX]; char *json; struct fa_stat fs; char errbuf[256]; htsmsg_t *ctrl; snprintf(ctrlfile, sizeof(ctrlfile), "%s/plugin.json", url); json = fa_quickload(ctrlfile, &fs, NULL, errbuf, sizeof(errbuf)); if(json == NULL) { TRACE(TRACE_ERROR, "plugins", "Unable to load plugin control file %s -- %s", ctrlfile, errbuf); return; } ctrl = htsmsg_json_deserialize(json); if(ctrl != NULL) { const char *type = htsmsg_get_str(ctrl, "type"); const char *file = htsmsg_get_str(ctrl, "file"); const char *id = htsmsg_get_str(ctrl, "id"); if(type == NULL) TRACE(TRACE_ERROR, "plugins", "Missing \"type\" element in control file %s", ctrlfile); if(file == NULL) TRACE(TRACE_ERROR, "plugins", "Missing \"file\" element in control file %s", ctrlfile); if(id == NULL) TRACE(TRACE_ERROR, "plugins", "Missing \"id\" element in control file %s", ctrlfile); if(type && file && id) { char fullpath[URL_MAX]; snprintf(fullpath, sizeof(fullpath), "%s/%s", url, file); if(!strcmp(type, "javascript")) { plugin_load_js(id, fullpath); } else { TRACE(TRACE_ERROR, "plugins", "Unknown type \"%s\" in control file %s", type, ctrlfile); } } htsmsg_destroy(ctrl); } else { TRACE(TRACE_ERROR, "plugins", "Unable parse JSON control file %s", ctrlfile); } free(json); }