From 307eba0677093f6255492a602004c9788ed209fe Mon Sep 17 00:00:00 2001 From: Andreas Smas Date: Mon, 17 Dec 2018 17:22:59 -0800 Subject: [PATCH 01/17] Remove in-app news from movian.tv website --- src/main.c | 3 - src/notifications.c | 192 -------------------------------------------- src/notifications.h | 2 - 3 files changed, 197 deletions(-) diff --git a/src/main.c b/src/main.c index 3c15ebdc2a..c6d1c0d003 100644 --- a/src/main.c +++ b/src/main.c @@ -253,8 +253,6 @@ swthread(void *aux) navigator_can_start(); } - load_site_news(); - hts_mutex_lock(&gconf.state_mutex); gconf.swrefresh = 0; @@ -276,7 +274,6 @@ swthread(void *aux) plugins_upgrade_check(); #endif upgrade_refresh(); - load_site_news(); hts_mutex_lock(&gconf.state_mutex); } hts_mutex_unlock(&gconf.state_mutex); diff --git a/src/notifications.c b/src/notifications.c index 96f62df1cc..61e95a6f2c 100644 --- a/src/notifications.c +++ b/src/notifications.c @@ -32,18 +32,12 @@ #include "misc/time.h" #include "settings.h" -#if ENABLE_WEBPOPUP -#include "ui/webpopup.h" -#endif - static prop_t *notify_prop_entries; static hts_mutex_t news_mutex; static htsmsg_t *dismissed_news_in; static htsmsg_t *dismissed_news_out; -static int shownews; - /** * */ @@ -58,18 +52,6 @@ notifications_init(void) dismissed_news_out = htsmsg_create_map(); notify_prop_entries = prop_create(root, "nodes"); - -#if ENABLE_WEBPOPUP - - prop_t *dir = setting_get_dir("general:misc"); - - setting_create(SETTING_BOOL, dir, SETTINGS_INITIAL_UPDATE, - SETTING_TITLE(_p("Show news on home screen")), - SETTING_VALUE(1), - SETTING_WRITE_BOOL(&shownews), - SETTING_STORE("notifications", "shownews"), - NULL); -#endif } @@ -440,177 +422,3 @@ add_news(const char *id, const char *message, hts_mutex_unlock(&news_mutex); return p; } - -#if ENABLE_WEBPOPUP - -/** - * - */ -static void -open_news(void *opaque, prop_event_t event, ...) -{ - prop_t *p = opaque; - event_t *e; - va_list ap; - - va_start(ap, event); - - switch(event) { - case PROP_DESTROYED: - prop_unsubscribe(va_arg(ap, prop_sub_t *)); - prop_ref_dec(p); - break; - - case PROP_EXT_EVENT: - e = va_arg(ap, event_t *); - if(event_is_type(e, EVENT_DYNAMIC_ACTION)) { - const event_payload_t *ep = (const event_payload_t *)e; - const char *id = mystrbegins(ep->payload, "sitenews:"); - if(id != NULL) { - - dismis_news(ep->payload); - char url[512]; -#ifdef PS3 - // PS3 browser is really bad when it comes to HTTPS - snprintf(url, sizeof(url), "http://www2.movian.tv/news/%s", id); -#else - snprintf(url, sizeof(url), "https://movian.tv/news/%s", id); -#endif - TRACE(TRACE_DEBUG, "NEWS", "Opening %s", url); - webbrowser_open(url, APPNAMEUSER); - } - } - break; - - default: - break; - } - va_end(ap); -} - -/** - * - */ -static int -parse_created_on_time(time_t *tp, const char *d) -{ - int year; - int month; - int day; - int hour; - int min; - int sec; - - if(sscanf(d, "%d-%d-%dT%d:%d:%dZ", - &year, &month, &day, &hour, &min, &sec) != 6) - return -1; - - return mktime_utc(tp, year, month-1, day, hour, min, sec); -} - -#endif - - -/** - * - */ -void -load_site_news(void) -{ - if(!shownews) - return; - -#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 servertime; - - if(http_ctime(&servertime, dateheader)) { - buf_release(b); - htsmsg_release(newsinfo); - return; - } - - if(newsinfo == NULL) - newsinfo = htsmsg_create_map(); - - time_t no_news_before = - htsmsg_get_u32_or_default(newsinfo, "nothingbefore", 0); - - if(no_news_before == 0) { - no_news_before = servertime; - 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 || t < servertime - 86400 * 30) - 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); - } - } - } - - hts_mutex_unlock(&news_mutex); - htsmsg_release(doc); - TRACE(TRACE_DEBUG, "News", "News loaded and updated"); -#endif -} diff --git a/src/notifications.h b/src/notifications.h index 43fd059a2d..01bad53f45 100644 --- a/src/notifications.h +++ b/src/notifications.h @@ -53,6 +53,4 @@ int text_dialog(const char *message, char** string, int flags); struct prop *add_news(const char *id, const char *message, const char *location, const char *caption); -void load_site_news(void); - #endif // NOTIFICATIONS_H__ From 72d6f6015f1c00b97c02ad5856d3d245465a1382 Mon Sep 17 00:00:00 2001 From: Andreas Smas Date: Mon, 17 Dec 2018 17:23:50 -0800 Subject: [PATCH 02/17] Delete trailing whitespace --- src/plugins.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/plugins.c b/src/plugins.c index 12fe7f5a32..1f88f8aa69 100644 --- a/src/plugins.c +++ b/src/plugins.c @@ -56,7 +56,7 @@ typedef enum { } plugin_type_t; static struct strtab catnames[] = { - { "tv", PLUGIN_CAT_TV }, + { "tv", PLUGIN_CAT_TV }, { "video", PLUGIN_CAT_VIDEO }, { "music", PLUGIN_CAT_MUSIC }, { "cloud", PLUGIN_CAT_CLOUD }, @@ -195,7 +195,7 @@ repo_url(void) * */ static void -set_alt_repo_url(void *opaque, const char *value) +set_alt_repo_url(void *opaque, const char *value) { mystrset(&plugin_alt_repo_url, value); } @@ -205,7 +205,7 @@ set_alt_repo_url(void *opaque, const char *value) * */ static void -set_beta_passwords(void *opaque, const char *value) +set_beta_passwords(void *opaque, const char *value) { mystrset(&plugin_beta_passwords, value); } @@ -215,7 +215,7 @@ set_beta_passwords(void *opaque, const char *value) * */ static void -set_autoupgrade(void *opaque, int value) +set_autoupgrade(void *opaque, int value) { autoupgrade = value; plugin_autoupgrade(); @@ -234,7 +234,7 @@ plugin_find(const char *id, int create) return pl; if(!create) return NULL; - + pl = calloc(1, sizeof(plugin_t)); pl->pl_id = strdup(id); @@ -839,7 +839,7 @@ repo_get(const char *repo, char *errbuf, size_t errlen) htsmsg_release(json); return NULL; } - + return json; } @@ -949,7 +949,7 @@ plugin_load_repo(void) break; if(pl != NULL) { - notify_add(NULL, NOTIFY_ERROR, NULL, 10, + notify_add(NULL, NOTIFY_ERROR, NULL, 10, _("Plugin %s %s has been uninstalled because it may cause problems.\nYou may try reinstalling a different version manually."), pl->pl_title, pl->pl_inst_ver); plugin_remove(pl); } @@ -984,7 +984,7 @@ plugin_autoupgrade(void) continue; if(plugin_install(pl, NULL)) continue; - notify_add(NULL, NOTIFY_INFO, NULL, 5, + notify_add(NULL, NOTIFY_INFO, NULL, 5, _("Upgraded plugin %s to version %s"), pl->pl_title, pl->pl_inst_ver); } @@ -1015,7 +1015,7 @@ plugin_setup_start_model(void) // Top items prop_t *sta = prop_create_root(NULL); - + p = prop_create(sta, NULL); prop_set_string(prop_create(p, "type"), "store"); prop_link(_p("Browse available plugins"), From 08ff8e10e4ef323b817d913c8b9e877fcef1391b Mon Sep 17 00:00:00 2001 From: Andreas Smas Date: Mon, 17 Dec 2018 17:38:43 -0800 Subject: [PATCH 03/17] Extract GEO from ifconfig.co --- src/main.c | 35 +++++++++++++++++++++++++++++++++++ src/plugins.c | 6 ------ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/main.c b/src/main.c index c6d1c0d003..a016f3717d 100644 --- a/src/main.c +++ b/src/main.c @@ -50,6 +50,7 @@ #include "subtitles/subtitles.h" #include "db/db_support.h" #include "htsmsg/htsmsg_store.h" +#include "htsmsg/htsmsg_json.h" #include "db/kvstore.h" #include "upgrade.h" #include "usage.h" @@ -214,6 +215,39 @@ navigator_can_start(void) } +/** + * + */ +static void * +geothread(void *aux) +{ + for(int i = 0; i < 10; i++) { + + buf_t *b = fa_load("http://ifconfig.co/json", NULL); + if(b == NULL) { + sleep(i * 2); + continue; + } + htsmsg_t *msg = htsmsg_json_deserialize(buf_cstr(b)); + buf_release(b); + if(msg != NULL) { + const char *cc = htsmsg_get_str(msg, "country_iso"); + if(cc != NULL) { + TRACE(TRACE_DEBUG, "GEO", "Current country: %s", cc); + prop_setv(prop_get_global(), "location", "cc", NULL, + PROP_SET_STRING, cc); + } + + htsmsg_release(msg); + } + break; + } + return NULL; +} + + + + /** * */ @@ -455,6 +489,7 @@ main_init(void) TRACE(TRACE_DEBUG, "SYSTEM", "Device type: %s", gconf.device_type); /* Start software installer thread (plugins, upgrade, etc) */ + hts_thread_create_detached("geothread", geothread, NULL, THREAD_PRIO_BGTASK); hts_thread_create_detached("swinst", swthread, NULL, THREAD_PRIO_BGTASK); /* Internationalization */ diff --git a/src/plugins.c b/src/plugins.c index 1f88f8aa69..e22fa86699 100644 --- a/src/plugins.c +++ b/src/plugins.c @@ -957,12 +957,6 @@ plugin_load_repo(void) } - const char *cc = htsmsg_get_str(msg, "cc"); - if(cc != NULL) { - TRACE(TRACE_DEBUG, "GEO", "Current country: %s", cc); - prop_setv(prop_get_global(), "location", "cc", NULL, PROP_SET_STRING, cc); - } - htsmsg_release(msg); return 0; } From 689680d1c6d8fd2cbc0e75e8801bd5430a9aedfc Mon Sep 17 00:00:00 2001 From: Andreas Smas Date: Mon, 17 Dec 2018 18:02:09 -0800 Subject: [PATCH 04/17] Add scoped_char and fmt() --- src/misc/str.c | 28 ++++++++++++++++++++++++++++ src/misc/str.h | 8 ++++++++ 2 files changed, 36 insertions(+) diff --git a/src/misc/str.c b/src/misc/str.c index 9cfe67476c..403c539228 100644 --- a/src/misc/str.c +++ b/src/misc/str.c @@ -17,6 +17,7 @@ * This program is also available under a commercial proprietary license. * For more information, contact andreas@lonelycoder.com */ +#define _GNU_SOURCE #include #include #include @@ -1806,3 +1807,30 @@ pattern_match(const char *str, const char *pat) } while (*str++); return 0; } + +void +freecharp(char **ptr) +{ + free(*ptr); + *ptr = NULL; +} + +char * +fmtv(const char *fmt, va_list ap) +{ + char *ret; + if(vasprintf(&ret, fmt, ap) == -1) + abort(); + return ret; +} + +char * +fmt(const char *fmt, ...) +{ + va_list ap; + char *ret; + va_start(ap, fmt); + ret = fmtv(fmt, ap); + va_end(ap); + return ret; +} diff --git a/src/misc/str.h b/src/misc/str.h index 5a41136cfb..60366edaa6 100644 --- a/src/misc/str.h +++ b/src/misc/str.h @@ -145,4 +145,12 @@ void rgbstr_to_floatvec(const char *s, float *out); int pattern_match(const char *str, const char *pat); +void freecharp(char **ptr); + +#define scoped_char char __attribute__((cleanup(freecharp))) + +char *fmtv(const char *fmt, va_list ap); + +char *fmt(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); + #endif From 2cd22fe6a095e003475eb475688e5ec4fd8c635b Mon Sep 17 00:00:00 2001 From: Andreas Smas Date: Mon, 17 Dec 2018 18:51:47 -0800 Subject: [PATCH 05/17] Add support for multiple plugin domains --- src/plugins.c | 137 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 83 insertions(+), 54 deletions(-) diff --git a/src/plugins.c b/src/plugins.c index e22fa86699..e5857b1789 100644 --- a/src/plugins.c +++ b/src/plugins.c @@ -88,7 +88,8 @@ static struct plugin_list plugins; typedef struct plugin { LIST_ENTRY(plugin) pl_link; - char *pl_id; + char *pl_fqid; + char *pl_domain; char *pl_package; char *pl_title; @@ -226,17 +227,18 @@ set_autoupgrade(void *opaque, int value) * */ static plugin_t * -plugin_find(const char *id, int create) +plugin_make(const char *id, const char *domain) { plugin_t *pl; + scoped_char *fqid = fmt("%s@%s", id, domain); + LIST_FOREACH(pl, &plugins, pl_link) - if(!strcmp(pl->pl_id, id)) + if(!strcmp(pl->pl_fqid, fqid)) return pl; - if(!create) - return NULL; pl = calloc(1, sizeof(plugin_t)); - pl->pl_id = strdup(id); + pl->pl_fqid = strdup(fqid); + pl->pl_domain = strdup(domain); pl->pl_status = prop_create_root(NULL); @@ -245,6 +247,20 @@ plugin_find(const char *id, int create) } +/** + * + */ +static plugin_t * +plugin_find(const char *fqid) +{ + plugin_t *pl; + LIST_FOREACH(pl, &plugins, pl_link) + if(!strcmp(pl->pl_fqid, fqid)) + return pl; + return NULL; +} + + /** * */ @@ -385,7 +401,7 @@ static void plugin_fill_prop(struct htsmsg *pm, struct prop *p, const char *basepath, plugin_t *pl) { - const char *title = htsmsg_get_str(pm, "title") ?: pl->pl_id; + const char *title = htsmsg_get_str(pm, "title") ?: pl->pl_fqid; const char *icon = htsmsg_get_str(pm, "icon"); const char *cat = htsmsg_get_str(pm, "category"); @@ -470,9 +486,7 @@ plugin_props_from_file(prop_t *prop, const char *zipfile) if(id != NULL) { hts_mutex_lock(&plugin_mutex); - plugin_t *pl = plugin_find(id, 1); - - + plugin_t *pl = plugin_make(id, "local"); snprintf(path, sizeof(path), "zip://%s", zipfile); plugin_fill_prop(pm, prop, path, pl); prop_set(prop, "package", PROP_SET_STRING, zipfile); @@ -492,8 +506,8 @@ plugin_prop_setup(htsmsg_t *pm, plugin_t *pl, const char *basepath) { prop_t *p; hts_mutex_assert(&plugin_mutex); - p = prop_create(plugin_root_list, pl->pl_id); - mystrset(&pl->pl_title, htsmsg_get_str(pm, "title") ?: pl->pl_id); + p = prop_create(plugin_root_list, pl->pl_fqid); + mystrset(&pl->pl_title, htsmsg_get_str(pm, "title") ?: pl->pl_fqid); prop_set(p, "type", PROP_SET_STRING, "plugin"); plugin_fill_prop(pm, p, basepath, pl); if(basepath == NULL) { @@ -509,7 +523,7 @@ plugin_prop_setup(htsmsg_t *pm, plugin_t *pl, const char *basepath) static void plugin_unload_ecmascript(plugin_t *pl) { - ecmascript_plugin_unload(pl->pl_id); + ecmascript_plugin_unload(pl->pl_fqid); } @@ -520,7 +534,7 @@ plugin_unload_ecmascript(plugin_t *pl) static void plugin_unload_vmir(plugin_t *pl) { - np_plugin_unload(pl->pl_id); + np_plugin_unload(pl->pl_fqid); } #endif @@ -549,7 +563,8 @@ plugin_unload(plugin_t *pl) * */ static int -plugin_load(const char *url, char *errbuf, size_t errlen, int flags) +plugin_load(const char *url, char *errbuf, size_t errlen, int flags, + const char *domain) { char ctrlfile[URL_MAX]; char errbuf2[1024]; @@ -570,7 +585,7 @@ plugin_load(const char *url, char *errbuf, size_t errlen, int flags) goto bad; const char *type = htsmsg_get_str(ctrl, "type"); - const char *id = htsmsg_get_str(ctrl, "id"); + const char *ext_id = htsmsg_get_str(ctrl, "id"); const char *version = htsmsg_get_str(ctrl, "version"); if(type == NULL) { snprintf(errbuf, errlen, "Missing \"type\" element in control file %s", @@ -578,19 +593,18 @@ plugin_load(const char *url, char *errbuf, size_t errlen, int flags) goto bad; } - if(id == NULL) { + if(ext_id == NULL) { snprintf(errbuf, errlen, "Missing \"id\" element in control file %s", ctrlfile); goto bad; } - plugin_t *pl = plugin_find(id, 1); - + plugin_t *pl = plugin_make(ext_id, domain); if(version != NULL) { rstr_t *notifymsg; - if(is_plugin_blacklisted(id, version, ¬ifymsg)) { - const char *title = htsmsg_get_str(ctrl, "title") ?: id; + if(is_plugin_blacklisted(ext_id, version, ¬ifymsg)) { + const char *title = htsmsg_get_str(ctrl, "title") ?: ext_id; char tmp[512]; rstr_t *fmt = _("Plugin %s has been uninstalled - %s"); snprintf(tmp, sizeof(tmp), rstr_get(fmt), title, rstr_get(notifymsg)); @@ -602,7 +616,7 @@ plugin_load(const char *url, char *errbuf, size_t errlen, int flags) } if(!(flags & PLUGIN_LOAD_FORCE) && pl->pl_loaded) { - snprintf(errbuf, errlen, "Plugin \"%s\" already loaded", id); + snprintf(errbuf, errlen, "Plugin \"%s\" already loaded", pl->pl_fqid); goto bad; } @@ -632,7 +646,7 @@ plugin_load(const char *url, char *errbuf, size_t errlen, int flags) int stack_size = htsmsg_get_u32_or_default(ctrl, "stack-size", 64); hts_mutex_unlock(&plugin_mutex); - r = np_plugin_load(id, fullpath, errbuf, errlen, version, 0, + r = np_plugin_load(pl->pl_fqid, fullpath, errbuf, errlen, version, 0, memory_size * 1024, stack_size * 1024); hts_mutex_lock(&plugin_mutex); if(!r) @@ -664,7 +678,7 @@ plugin_load(const char *url, char *errbuf, size_t errlen, int flags) pflags |= ECMASCRIPT_FILE_BYPASS_ACL_WRITE; } hts_mutex_unlock(&plugin_mutex); - r = ecmascript_plugin_load(id, fullpath, errbuf, errlen, version, + r = ecmascript_plugin_load(pl->pl_fqid, fullpath, errbuf, errlen, version, buf_cstr(b), pflags); hts_mutex_lock(&plugin_mutex); if(!r) @@ -722,10 +736,10 @@ plugin_load(const char *url, char *errbuf, size_t errlen, int flags) pl->pl_installed = 1; mystrset(&pl->pl_inst_ver, htsmsg_get_str(ctrl, "version")); - autoplugin_set_installed(pl->pl_id, 1); + autoplugin_set_installed(pl->pl_fqid, 1); } - mystrset(&pl->pl_title, htsmsg_get_str(ctrl, "title") ?: id); + mystrset(&pl->pl_title, htsmsg_get_str(ctrl, "title") ?: pl->pl_fqid); pl->pl_loaded = 1; } @@ -754,15 +768,23 @@ plugin_load_installed(void) char errbuf[200]; fa_dir_entry_t *fde; - snprintf(path, sizeof(path), "%s/installedplugins", gconf.persistent_path); + snprintf(path, sizeof(path), "%s/pluginsv2/installed", gconf.persistent_path); fa_dir_t *fd = fa_scandir(path, NULL, 0); if(fd != NULL) { RB_FOREACH(fde, &fd->fd_entries, fde_link) { + scoped_char *d0 = strdup(rstr_get(fde->fde_filename)); + char *domain = strchr(d0, '@'); + if(domain != NULL) { + domain++; + char *dot = strchr(domain, '.'); + if(dot != NULL) + *dot = 0; + } snprintf(path, sizeof(path), "zip://%s", rstr_get(fde->fde_url)); if(plugin_load(path, errbuf, sizeof(errbuf), - PLUGIN_LOAD_AS_INSTALLED)) { + PLUGIN_LOAD_AS_INSTALLED, domain)) { TRACE(TRACE_ERROR, "plugins", "Unable to load %s\n%s", path, errbuf); } } @@ -853,6 +875,8 @@ plugin_load_repo(void) { plugin_t *pl, *next; char errbuf[512]; + const char *domain = "mainrepo"; + htsmsg_t *msg = repo_get(repo_url(), errbuf, sizeof(errbuf)); if(msg == REPO_ERROR_NETWORK || msg == NULL) { @@ -895,7 +919,7 @@ plugin_load_repo(void) if(is_plugin_blacklisted(id, version, NULL)) continue; - pl = plugin_find(id, 1); + pl = plugin_make(id, domain); pl->pl_mark = 0; plugin_prop_setup(pm, pl, NULL); mystrset(&pl->pl_repo_ver, version); @@ -940,11 +964,13 @@ plugin_load_repo(void) const char *id = htsmsg_get_str(pm, "id"); const char *version = htsmsg_get_str(pm, "version"); + scoped_char *fqid = fmt("%s@%s", id, domain); + if(id == NULL || version == NULL) continue; LIST_FOREACH(pl, &plugins, pl_link) - if(!strcmp(id, pl->pl_id) && pl->pl_installed && pl->pl_inst_ver && + if(!strcmp(fqid, pl->pl_fqid) && pl->pl_installed && pl->pl_inst_ver && !strcmp(version, pl->pl_inst_ver)) break; @@ -1239,7 +1265,7 @@ plugins_init(char **devplugs) strvec_addp(&devplugins, path); if(plugin_load(path, errbuf, sizeof(errbuf), - PLUGIN_LOAD_FORCE | PLUGIN_LOAD_DEBUG)) { + PLUGIN_LOAD_FORCE | PLUGIN_LOAD_DEBUG, "dev")) { TRACE(TRACE_ERROR, "plugins", "Unable to load development plugin: %s\n%s", path, errbuf); } else { @@ -1267,7 +1293,8 @@ plugins_reload_dev_plugin(void) for(int i = 0; (path = devplugins[i]) != NULL; i++) { if(plugin_load(path, errbuf, sizeof(errbuf), - PLUGIN_LOAD_FORCE | PLUGIN_LOAD_DEBUG | PLUGIN_LOAD_BY_USER)) + PLUGIN_LOAD_FORCE | PLUGIN_LOAD_DEBUG | PLUGIN_LOAD_BY_USER, + "dev")) TRACE(TRACE_ERROR, "plugins", "Unable to reload development plugin: %s\n%s", path, errbuf); else @@ -1285,19 +1312,19 @@ plugin_remove(plugin_t *pl) { char path[PATH_MAX]; - autoplugin_set_installed(pl->pl_id, 0); + autoplugin_set_installed(pl->pl_fqid, 0); usage_event("Plugin remove", 1, - USAGE_SEG("plugin", pl->pl_id)); + USAGE_SEG("plugin", pl->pl_fqid)); - TRACE(TRACE_DEBUG, "plugin", "Uninstalling %s", pl->pl_id); + TRACE(TRACE_DEBUG, "plugin", "Uninstalling %s", pl->pl_fqid); - snprintf(path, sizeof(path), "%s/installedplugins/%s.zip", - gconf.persistent_path, pl->pl_id); + snprintf(path, sizeof(path), "%s/pluginsv2/installed/%s.zip", + gconf.persistent_path, pl->pl_fqid); fa_unlink(path, NULL, 0); - snprintf(path, sizeof(path), "%s/plugins/%s", - gconf.persistent_path, pl->pl_id); + snprintf(path, sizeof(path), "%s/pluginsv2/settings/%s", + gconf.persistent_path, pl->pl_fqid); fa_unlink_recursive(path, NULL, 0, 0); plugin_unload(pl); @@ -1319,7 +1346,7 @@ plugin_install(plugin_t *pl, const char *package) char path[200]; usage_event(pl->pl_can_upgrade ? "Plugin upgrade" : "Plugin install", 1, - USAGE_SEG("plugin", pl->pl_id, + USAGE_SEG("plugin", pl->pl_fqid, "source", package ? "File" : "Repo")); if(package == NULL) @@ -1335,7 +1362,7 @@ plugin_install(plugin_t *pl, const char *package) } TRACE(TRACE_INFO, "plugins", "Downloading plugin %s from %s", - pl->pl_id, package); + pl->pl_fqid, package); prop_link(_p("Downloading"), status); prop_set(pl->pl_status, "canInstall", PROP_SET_INT, 0); @@ -1350,7 +1377,7 @@ plugin_install(plugin_t *pl, const char *package) prop_unlink(status); prop_set_string(status, errbuf); TRACE(TRACE_INFO, "plugins", "Failed to download plugin %s from %s -- %s", - pl->pl_id, package, errbuf); + pl->pl_fqid, package, errbuf); cleanup: prop_set(pl->pl_status, "canInstall", PROP_SET_INT, 1); @@ -1364,23 +1391,25 @@ plugin_install(plugin_t *pl, const char *package) buf[0] != 0x50 || buf[1] != 0x4b || buf[2] != 0x03 || buf[3] != 0x04) { prop_link(_p("Corrupt plugin bundle"), status); TRACE(TRACE_INFO, "plugins", "Plugin %s from %s -- not a valid bundle", - pl->pl_id, package); + pl->pl_fqid, package); hexdump("BUNDLE", buf, MIN(b->b_size, 64)); goto cleanup; } TRACE(TRACE_INFO, "plugins", "Plugin %s valid ZIP archive %d bytes", - pl->pl_id, (int)b->b_size); + pl->pl_fqid, (int)b->b_size); - snprintf(path, sizeof(path), "%s/installedplugins", gconf.persistent_path); + snprintf(path, sizeof(path), "%s/pluginsv2", gconf.persistent_path); + fa_makedir(path); + snprintf(path, sizeof(path), "%s/pluginsv2/installed", gconf.persistent_path); fa_makedir(path); plugin_unload(pl); prop_link(_p("Installing"), status); - snprintf(path, sizeof(path), "%s/installedplugins/%s.zip", - gconf.persistent_path, pl->pl_id); + snprintf(path, sizeof(path), "%s/pluginsv2/installed/%s.zip", + gconf.persistent_path, pl->pl_fqid); if(fa_unlink(path, errbuf, sizeof(errbuf))) { TRACE(TRACE_DEBUG, "plugins", "First unlinking %s -- %s", @@ -1407,8 +1436,8 @@ plugin_install(plugin_t *pl, const char *package) } snprintf(path, sizeof(path), - "zip://%s/installedplugins/%s.zip", gconf.persistent_path, - pl->pl_id); + "zip://%s/pluginsv2/installed/%s.zip", gconf.persistent_path, + pl->pl_fqid); #ifdef STOS arch_sync_path(path); @@ -1416,7 +1445,7 @@ plugin_install(plugin_t *pl, const char *package) if(plugin_load(path, errbuf, sizeof(errbuf), PLUGIN_LOAD_FORCE | PLUGIN_LOAD_AS_INSTALLED | - PLUGIN_LOAD_BY_USER)) { + PLUGIN_LOAD_BY_USER, pl->pl_domain)) { prop_unlink(status); TRACE(TRACE_ERROR, "plugins", "Unable to load %s -- %s", path, errbuf); prop_set_string(status, errbuf); @@ -1603,7 +1632,7 @@ plugin_open_file(prop_t *page, const char *url) if(id != NULL) { hts_mutex_lock(&plugin_mutex); - plugin_t *pl = plugin_find(id, 1); + plugin_t *pl = plugin_make(id, "local"); plugin_install(pl, url); hts_mutex_unlock(&plugin_mutex); } else { @@ -1769,7 +1798,7 @@ plugin_select_view(const char *plugin_id, const char *filename) hts_mutex_lock(&plugin_mutex); LIST_FOREACH(pl, &plugins, pl_link) - if(!strcmp(pl->pl_id, plugin_id)) + if(!strcmp(pl->pl_fqid, plugin_id)) break; if(pl != NULL) { @@ -1814,7 +1843,7 @@ void plugin_uninstall(const char *id) { hts_mutex_lock(&plugin_mutex); - plugin_t *pl = plugin_find(id, 0); + plugin_t *pl = plugin_find(id); if(pl != NULL) { plugin_remove(pl); } @@ -2028,7 +2057,7 @@ plugin_autoinstall(const char *id) { int errcode = -1; hts_mutex_lock(&plugin_mutex); - plugin_t *pl = plugin_find(id, 0); + plugin_t *pl = plugin_find(id); if(pl != NULL) { errcode = plugin_install(pl, NULL); From f2ee410857ddd3b907aee8d8c3d2ffc2ab10b6be Mon Sep 17 00:00:00 2001 From: Andreas Smas Date: Thu, 20 Dec 2018 15:12:10 -0800 Subject: [PATCH 06/17] settings: Add subtype to action item --- src/blobcache_file.c | 2 +- src/keyring.c | 2 +- src/metadata/metadb.c | 2 +- src/runcontrol.c | 10 +++++----- src/settings.c | 3 ++- src/settings.h | 1 + src/text/fontstash.c | 6 +++--- 7 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/blobcache_file.c b/src/blobcache_file.c index ccaa35477d..68845ae93e 100644 --- a/src/blobcache_file.c +++ b/src/blobcache_file.c @@ -986,7 +986,7 @@ blobcache_init(void) prop_t *dir = setting_get_dir("general:resets"); - settings_create_action(dir, _p("Clear cached files"), + settings_create_action(dir, _p("Clear cached files"), NULL, cache_clear, NULL, 0, NULL); hts_thread_create_joinable("blobcache", &bcthread, flushthread, NULL, diff --git a/src/keyring.c b/src/keyring.c index d93bc3bea0..45a7e67ed9 100644 --- a/src/keyring.c +++ b/src/keyring.c @@ -63,7 +63,7 @@ keyring_init(void) prop_t *dir = setting_get_dir("general:resets"); settings_create_action(dir, - _p("Forget remembered passwords"), + _p("Forget remembered passwords"), NULL, keyring_clear, NULL, 0, NULL); } diff --git a/src/metadata/metadb.c b/src/metadata/metadb.c index 96b464b950..975e5011c8 100644 --- a/src/metadata/metadb.c +++ b/src/metadata/metadb.c @@ -128,7 +128,7 @@ metadb_init(void) metadb_pool = NULL; // Disable } else { prop_t *dir = setting_get_dir("general:resets"); - settings_create_action(dir, _p("Clear all metadata"), + settings_create_action(dir, _p("Clear all metadata"), NULL, items_clear, NULL, 0, NULL); } } diff --git a/src/runcontrol.c b/src/runcontrol.c index 6bf42b5814..c36353df62 100644 --- a/src/runcontrol.c +++ b/src/runcontrol.c @@ -293,24 +293,24 @@ runcontrol_init(void) if(gconf.can_standby) { init_autostandby(); init_sleeptimer(rc); - settings_create_action(dir, _p("Standby"), + settings_create_action(dir, _p("Standby"), NULL, do_standby, NULL, 0, NULL); } if(gconf.can_poweroff) - settings_create_action(dir, _p("Power off system"), + settings_create_action(dir, _p("Power off system"), NULL, do_power_off, NULL, 0, NULL); if(gconf.can_logout) - settings_create_action(dir, _p("Logout"), + settings_create_action(dir, _p("Logout"), NULL, do_logout, NULL, 0, NULL); if(gconf.can_open_shell) - settings_create_action(dir, _p("Open shell"), + settings_create_action(dir, _p("Open shell"), NULL, do_open_shell, NULL, 0, NULL); if(!gconf.can_not_exit) - settings_create_action(dir, _p("Quit"), + settings_create_action(dir, _p("Quit"), NULL, do_exit, NULL, 0, NULL); if(gconf.shell_fd > 0) { diff --git a/src/settings.c b/src/settings.c index 5d647b1cfe..5b9465c52d 100644 --- a/src/settings.c +++ b/src/settings.c @@ -298,11 +298,12 @@ settings_create_separator(prop_t *parent, prop_t *caption) * */ setting_t * -settings_create_action(prop_t *parent, prop_t *title, +settings_create_action(prop_t *parent, prop_t *title, const char *subtype, prop_callback_t *cb, void *opaque, int flags, prop_courier_t *pc) { setting_t *s = setting_create_leaf(parent, title, "action", "action", flags); + prop_set(s->s_root, "subtype", PROP_SET_STRING, subtype); s->s_sub = prop_subscribe(PROP_SUB_NO_INITIAL_UPDATE, PROP_TAG_CALLBACK, cb, opaque, PROP_TAG_NAMED_ROOT, s->s_root, "node", diff --git a/src/settings.h b/src/settings.h index 0238b6c3f2..8002a0d7eb 100644 --- a/src/settings.h +++ b/src/settings.h @@ -56,6 +56,7 @@ void settings_add_int(setting_t *s, int delta); int settings_get_type(const setting_t *s); setting_t *settings_create_action(prop_t *parent, prop_t *title, + const char *subtype, prop_callback_t *cb, void *opaque, int flags, prop_courier_t *pc); diff --git a/src/text/fontstash.c b/src/text/fontstash.c index 23473014ec..8cf5896b62 100644 --- a/src/text/fontstash.c +++ b/src/text/fontstash.c @@ -343,11 +343,11 @@ fontstash_init(void) pc = prop_concat_create(fontstash_browse_nodes); prop_t *top = prop_create_root(NULL); - settings_create_action(top, _p("Reset main font to default"), + settings_create_action(top, _p("Reset main font to default"), NULL, reset_main, NULL, SETTINGS_RAW_NODES, NULL); - settings_create_action(top, _p("Reset narrow font to default"), + settings_create_action(top, _p("Reset narrow font to default"), NULL, reset_cond, NULL, SETTINGS_RAW_NODES, NULL); - settings_create_action(top, _p("Reset subtitle font to default"), + settings_create_action(top, _p("Reset subtitle font to default"), NULL, reset_subs, NULL, SETTINGS_RAW_NODES, NULL); prop_t *x = prop_create_root(NULL); From c1b8b29e4bd75a1bf51c6a84cb2c11e6ed9d6c5f Mon Sep 17 00:00:00 2001 From: Andreas Smas Date: Thu, 20 Dec 2018 16:35:15 -0800 Subject: [PATCH 07/17] Add support for configuring multiple plugin repos --- src/plugins.c | 344 ++++++++++++++++++++++++++++++------------------- src/settings.c | 2 +- 2 files changed, 210 insertions(+), 136 deletions(-) diff --git a/src/plugins.c b/src/plugins.c index e5857b1789..5d0338cb35 100644 --- a/src/plugins.c +++ b/src/plugins.c @@ -24,6 +24,7 @@ #include "htsmsg/htsmsg_json.h" #include "htsmsg/htsmsg_store.h" #include "backend/backend.h" +#include "backend/backend_prop.h" #include "misc/str.h" #include "misc/minmax.h" #include "prop/prop_nodefilter.h" @@ -33,6 +34,7 @@ #include "arch/arch.h" #include "usage.h" #include "backend/search.h" +#include "misc/md5.h" #include "ecmascript/ecmascript.h" @@ -68,9 +70,6 @@ static struct strtab catnames[] = { }; -static const char *plugin_repo_url = PLUGINREPO; -static char *plugin_alt_repo_url; -static char *plugin_beta_passwords; static HTS_MUTEX_DECL(plugin_mutex); static HTS_MUTEX_DECL(autoplugin_mutex); @@ -79,8 +78,10 @@ static char **devplugins; static prop_t *plugin_root_list; static prop_t *plugin_start_model; static prop_t *plugin_repo_model; +static prop_t *plugin_repos_settings; LIST_HEAD(plugin_list, plugin); +LIST_HEAD(plugin_repo_list, plugin_repo); LIST_HEAD(plugin_view_list, plugin_view); LIST_HEAD(plugin_view_entry_list, plugin_view_entry); @@ -113,6 +114,19 @@ typedef struct plugin { } plugin_t; +static struct plugin_repo_list plugin_repos; + +typedef struct plugin_repo { + LIST_ENTRY(plugin_repo) pr_link; + char *pr_url; + char *pr_domain; + prop_t *pr_root; + prop_t *pr_title; + int pr_autoupgrade; + int pr_initialized; +} plugin_repo_t; + + static int plugin_install(plugin_t *pl, const char *package); static void plugin_remove(plugin_t *pl); static void plugin_autoupgrade(void); @@ -128,8 +142,9 @@ static void autoplugin_create_from_control(const char *id, htsmsg_t *ctrl, static void autoplugin_set_installed(const char *id, int is_installed); -static int autoupgrade; -static int autoinstall; +static void plugin_repo_create(const char *url, const char *title, int load); + +static int plugins_upgrade_check_locked(plugin_repo_t *pr); #define VERSION_ENCODE(a,b,c) ((a) * 10000000 + (b) * 100000 + (c)) @@ -176,53 +191,6 @@ is_plugin_blacklisted(const char *id, const char *version, rstr_t **reason) } - - - - - - -/** - * - */ -static const char * -repo_url(void) -{ - return plugin_alt_repo_url && *plugin_alt_repo_url ? - plugin_alt_repo_url : plugin_repo_url; -} - -/** - * - */ -static void -set_alt_repo_url(void *opaque, const char *value) -{ - mystrset(&plugin_alt_repo_url, value); -} - - -/** - * - */ -static void -set_beta_passwords(void *opaque, const char *value) -{ - mystrset(&plugin_beta_passwords, value); -} - - -/** - * - */ -static void -set_autoupgrade(void *opaque, int value) -{ - autoupgrade = value; - plugin_autoupgrade(); -} - - /** * */ @@ -399,7 +367,7 @@ plugin_event(void *opaque, prop_event_t event, ...) */ static void plugin_fill_prop(struct htsmsg *pm, struct prop *p, - const char *basepath, plugin_t *pl) + const char *baseurl, plugin_t *pl) { const char *title = htsmsg_get_str(pm, "title") ?: pl->pl_fqid; const char *icon = htsmsg_get_str(pm, "icon"); @@ -437,21 +405,9 @@ plugin_fill_prop(struct htsmsg *pm, struct prop *p, prop_set(metadata, "version", PROP_SET_STRING, htsmsg_get_str(pm, "version")); - unsigned int popularity; - - if(!htsmsg_get_u32(pm, "popularity", &popularity)) - prop_set(metadata, "popularity", PROP_SET_INT, popularity); - if(icon != NULL) { - if(basepath != NULL) { - char url[512]; - snprintf(url, sizeof(url), "%s/%s", basepath, icon); - prop_set(metadata, "icon", PROP_SET_STRING,url); - } else { - char *iconurl = url_resolve_relative_from_base(repo_url(), icon); - prop_set(metadata, "icon", PROP_SET_STRING, iconurl); - free(iconurl); - } + scoped_char *iconurl = url_resolve_relative_from_base(baseurl, icon); + prop_set(metadata, "icon", PROP_SET_STRING, iconurl); } prop_ref_dec(metadata); } @@ -803,29 +759,12 @@ repo_get(const char *repo, char *errbuf, size_t errlen) { buf_t *b; htsmsg_t *json; - const char *qargs[32]; - int qp = 0; TRACE(TRACE_DEBUG, "plugins", "Loading repo from %s", repo); - if(plugin_beta_passwords != NULL) { - char *pws = mystrdupa(plugin_beta_passwords); - char *tmp = NULL; - - while(qp < 30) { - const char *p = strtok_r(pws, " ", &tmp); - if(p == NULL) - break; - qargs[qp++] = "betapassword"; - qargs[qp++] = p; - pws = NULL; - } - } - qargs[qp] = 0; hts_mutex_unlock(&plugin_mutex); b = fa_load(repo, FA_LOAD_ERRBUF(errbuf, errlen), - FA_LOAD_QUERY_ARGVEC(qargs), FA_LOAD_FLAGS(FA_COMPRESSION | FA_DISABLE_AUTH), NULL); @@ -841,7 +780,6 @@ repo_get(const char *repo, char *errbuf, size_t errlen) snprintf(errbuf, errlen, "Malformed JSON in repository"); fa_load(repo, - FA_LOAD_QUERY_ARGVEC(qargs), FA_LOAD_CACHE_EVICT(), NULL); return REPO_ERROR_NETWORK; @@ -871,29 +809,36 @@ repo_get(const char *repo, char *errbuf, size_t errlen) * */ static int -plugin_load_repo(void) +plugin_load_repo(plugin_repo_t *pr) { plugin_t *pl, *next; char errbuf[512]; - const char *domain = "mainrepo"; + const char *url = pr->pr_url; - htsmsg_t *msg = repo_get(repo_url(), errbuf, sizeof(errbuf)); + htsmsg_t *msg = repo_get(url, errbuf, sizeof(errbuf)); if(msg == REPO_ERROR_NETWORK || msg == NULL) { TRACE(TRACE_ERROR, "plugins", "Unable to load repo %s -- %s", - repo_url(), errbuf); + url, errbuf); return msg == REPO_ERROR_NETWORK ? -1 : 0; } hts_mutex_lock(&autoplugin_mutex); autoplugin_clear(); + const char *title = htsmsg_get_str(msg, "title"); + if(title != NULL) + prop_set_string(pr->pr_title, title); + htsmsg_t *r = htsmsg_get_list(msg, "plugins"); if(r != NULL) { htsmsg_field_t *f; - LIST_FOREACH(pl, &plugins, pl_link) - pl->pl_mark = 1; + LIST_FOREACH(pl, &plugins, pl_link) { + if(!strcmp(pl->pl_domain, pr->pr_domain)) { + pl->pl_mark = 1; + } + } HTSMSG_FOREACH(f, r) { htsmsg_t *pm; @@ -919,9 +864,9 @@ plugin_load_repo(void) if(is_plugin_blacklisted(id, version, NULL)) continue; - pl = plugin_make(id, domain); + pl = plugin_make(id, pr->pr_domain); pl->pl_mark = 0; - plugin_prop_setup(pm, pl, NULL); + plugin_prop_setup(pm, pl, url); mystrset(&pl->pl_repo_ver, version); mystrset(&pl->pl_app_min_version, htsmsg_get_str(pm, "showtimeVersion")); @@ -929,7 +874,7 @@ plugin_load_repo(void) const char *dlurl = htsmsg_get_str(pm, "downloadURL"); if(dlurl != NULL) { - char *package = url_resolve_relative_from_base(repo_url(), dlurl); + char *package = url_resolve_relative_from_base(url, dlurl); free(pl->pl_package); pl->pl_package = package; } @@ -964,7 +909,7 @@ plugin_load_repo(void) const char *id = htsmsg_get_str(pm, "id"); const char *version = htsmsg_get_str(pm, "version"); - scoped_char *fqid = fmt("%s@%s", id, domain); + scoped_char *fqid = fmt("%s@%s", id, pr->pr_domain); if(id == NULL || version == NULL) continue; @@ -995,11 +940,17 @@ static void plugin_autoupgrade(void) { plugin_t *pl; - - if(!autoupgrade) - return; + plugin_repo_t *pr; LIST_FOREACH(pl, &plugins, pl_link) { + + LIST_FOREACH(pr, &plugin_repos, pr_link) { + if(!strcmp(pr->pr_domain, pl->pl_domain)) + break; + } + if(!pr->pr_autoupgrade) + continue; + if(!pl->pl_can_upgrade) continue; if(plugin_install(pl, NULL)) @@ -1145,8 +1096,7 @@ plugin_setup_repo_model(void) prop_nf_pred_int_add(pnf, "node.status.inRepo", PROP_NF_CMP_NEQ, 1, NULL, PROP_NF_MODE_EXCLUDE); - // prop_nf_sort(pnf, "node.metadata.title", 0, 0, NULL, 1); - prop_nf_sort(pnf, "node.metadata.popularity", 1, 0, NULL, 1); + prop_nf_sort(pnf, "node.metadata.title", 0, 0, NULL, 1); prop_nf_release(pnf); prop_t *header = prop_create_root(NULL); @@ -1159,6 +1109,22 @@ plugin_setup_repo_model(void) } + +static void +plugins_add_repo_popup(void *opaque, prop_event_t event, ...) +{ + rstr_t *msg = _("Enter URL of plugin repository"); + scoped_char *url = NULL; + int x = text_dialog(rstr_get(msg), &url, + MESSAGE_POPUP_OK | MESSAGE_POPUP_CANCEL); + rstr_release(msg); + if(x) + return; + + plugin_repo_create(url, NULL, 1); +} + + /** * */ @@ -1175,38 +1141,19 @@ plugins_setup_root_props(void) // Settings prop_t *dir = setting_get_dir("general:plugins"); + prop_concat_t *pc = prop_concat_create(prop_create(dir, "nodes")); - setting_create(SETTING_STRING, dir, - SETTINGS_INITIAL_UPDATE, - SETTING_STORE("pluginconf", "alt_repo"), - SETTING_TITLE(_p("Alternate plugin Repository URL")), - SETTING_CALLBACK(set_alt_repo_url, NULL), - SETTING_MUTEX(&plugin_mutex), - NULL); + plugin_repos_settings = prop_create_root(NULL); + prop_concat_add_source(pc, plugin_repos_settings, NULL); - setting_create(SETTING_STRING, dir, - SETTINGS_INITIAL_UPDATE, - SETTING_STORE("pluginconf", "betapasswords"), - SETTING_TITLE(_p("Beta testing passwords")), - SETTING_CALLBACK(set_beta_passwords, NULL), - SETTING_MUTEX(&plugin_mutex), - NULL); + prop_t *add = prop_create_root(NULL); + prop_concat_add_source(pc, add, NULL); - setting_create(SETTING_BOOL, dir, SETTINGS_INITIAL_UPDATE, - SETTING_STORE("pluginconf", "autoupgrade"), - SETTING_TITLE(_p("Automatically upgrade plugins")), - SETTING_VALUE(1), - SETTING_CALLBACK(set_autoupgrade, NULL), - SETTING_MUTEX(&plugin_mutex), - NULL); + settings_create_action(add, _p("Subscribe to plugin repository feed"), "add", + plugins_add_repo_popup, NULL, SETTINGS_RAW_NODES, + NULL); - setting_create(SETTING_BOOL, dir, SETTINGS_INITIAL_UPDATE, - SETTING_STORE("pluginconf", "autoupgrade"), - SETTING_TITLE(_p("Auto install plugins on demand")), - SETTING_VALUE(1), - SETTING_WRITE_INT(&autoinstall), - SETTING_MUTEX(&plugin_mutex), - NULL); + prop_print_tree(dir, 1); } @@ -1222,6 +1169,25 @@ plugins_init2(void) } +static int +plugins_upgrade_check_locked(plugin_repo_t *pr) +{ + int r = 0; + if(pr != NULL) { + r = plugin_load_repo(pr); + } else { + LIST_FOREACH(pr, &plugin_repos, pr_link) { + r |= plugin_load_repo(pr); + } + } + if(!r) { + update_global_state(); + plugin_autoupgrade(); + } + return r; +} + + /** * */ @@ -1229,16 +1195,120 @@ int plugins_upgrade_check(void) { hts_mutex_lock(&plugin_mutex); - int r = plugin_load_repo(); - if(!r) { - update_global_state(); - plugin_autoupgrade(); - } + int r = plugins_upgrade_check_locked(NULL); hts_mutex_unlock(&plugin_mutex); return r; } +static char * +plugin_repo_hash(const char *url) +{ + md5_decl(md5); + md5_init(md5); + md5_update(md5, (const void *)url, strlen(url)); + uint8_t hash[16]; + md5_final(md5, hash); + + return fmt("%02x%02x%02x%02x%02x%02x%02x%02x", + hash[0], hash[1], hash[2], hash[3], + hash[4], hash[5], hash[6], hash[7]); +} + + +static void +set_autoupgrade(void *opaque, int value) +{ + plugin_repo_t *pr = opaque; + pr->pr_autoupgrade = value; + if(value && pr->pr_initialized) + plugins_upgrade_check_locked(pr); +} + + +static void +plugin_repo_delete(void *opaque, event_t *e) +{ + plugin_repo_t *pr = opaque; + + free(pr->pr_url); + free(pr->pr_domain); + LIST_REMOVE(pr, pr_link); + prop_destroy(pr->pr_root); + prop_ref_dec(pr->pr_title); + prop_ref_dec(pr->pr_root); + free(pr); + if(e->e_nav != NULL) { + event_t *be = event_create_action(ACTION_NAV_BACK); + prop_t *eventsink = prop_create_r(e->e_nav, "eventSink"); + prop_send_ext_event(eventsink, be); + prop_ref_dec(eventsink); + event_release(be); + } +} + + +static void +plugin_repo_create(const char *url, const char *title, int load) +{ + hts_mutex_lock(&plugin_mutex); + + plugin_repo_t *pr = calloc(1, sizeof(plugin_repo_t)); + LIST_INSERT_HEAD(&plugin_repos, pr, pr_link); + + pr->pr_url = strdup(url); + pr->pr_domain = plugin_repo_hash(pr->pr_url); + pr->pr_root = prop_create_r(plugin_repos_settings, NULL); + + pr->pr_title = prop_ref_inc(prop_create_multi(pr->pr_root, "metadata", + "title", NULL)); + prop_set_string(pr->pr_title, title ?: url); + prop_set(pr->pr_root, "type", PROP_SET_STRING, "directory"); + prop_set(pr->pr_root, "subtype", PROP_SET_STRING, "plugins"); + prop_t *m = prop_create(pr->pr_root, "model"); + prop_set(pr->pr_root, "url", PROP_ADOPT_RSTRING, backend_prop_make(m, NULL)); + + prop_set(m, "type", PROP_SET_STRING, "settings"); + prop_t *md = prop_create(m, "metadata"); + prop_set(md, "title", PROP_SET_LINK, pr->pr_title); + + prop_t *nodes = prop_create(m, "nodes"); + + prop_t *info = prop_create(nodes, NULL); + prop_setv(info, "type", NULL, PROP_SET_STRING, "info"); + scoped_char *infostr = fmt("URL: %s", pr->pr_url); + prop_setv(info, "description", NULL, PROP_SET_STRING, infostr); + + setting_create(SETTING_SEPARATOR, m, 0, + NULL); + + setting_create(SETTING_BOOL, m, SETTINGS_INITIAL_UPDATE, + SETTING_STORE("pluginconf", "autoupgrade"), + SETTING_TITLE(_p("Automatically upgrade plugins")), + SETTING_VALUE(1), + SETTING_KVSTORE(url, "autoupgrade"), + SETTING_CALLBACK(set_autoupgrade, pr), + SETTING_MUTEX(&plugin_mutex), + NULL); + + setting_create(SETTING_SEPARATOR, m, 0, + NULL); + + setting_create(SETTING_ACTION, m, 0, + SETTING_TITLE(_p("Stop subscribing to repository feed")), + SETTING_CALLBACK(plugin_repo_delete, pr), + SETTING_MUTEX(&plugin_mutex), + NULL); + + if(load) + plugin_load_repo(pr); + pr->pr_initialized = 1; + hts_mutex_unlock(&plugin_mutex); + prop_print_tree(plugin_repos_settings, 1); +} + + + /** * */ @@ -1251,6 +1321,10 @@ plugins_init(char **devplugs) plugins_setup_root_props(); + if(gconf.plugin_repo) + plugin_repo_create(gconf.plugin_repo, NULL, 0); + + hts_mutex_lock(&plugin_mutex); if(devplugs != NULL) { @@ -2084,7 +2158,7 @@ plugin_probe_for_autoinstall(fa_handle_t *fh, const uint8_t *buf, size_t len, autoplugin_t *ap; const char *installme = NULL; - if(!autoinstall) + if(!0) return; hts_mutex_lock(&autoplugin_mutex); @@ -2124,7 +2198,7 @@ plugin_check_prefix_for_autoinstall(const char *uri) autoplugin_t *ap; const char *installme = NULL; - if(!autoinstall || devplugins) + if(!0 || devplugins) return -1; hts_mutex_lock(&autoplugin_mutex); diff --git a/src/settings.c b/src/settings.c index 5b9465c52d..98cbbb60ec 100644 --- a/src/settings.c +++ b/src/settings.c @@ -1721,7 +1721,7 @@ setting_get_dir(const char *key) upgrade = addgroup(pc, _p("Software upgrade")); filebrowse = addgroup(pc, _p("File browsing")); runcontrol = addgroup(pc, _p("Starting and stopping")); - plugins = addgroup(pc, _p("Plugins")); + plugins = addgroup(pc, _p("Plugin repositories")); resets = addgroup(pc, _p("Reset")); } From 6763e91935d326935d2be8c1e9e36b5d7806748e Mon Sep 17 00:00:00 2001 From: Andreas Smas Date: Thu, 20 Dec 2018 16:35:28 -0800 Subject: [PATCH 08/17] glw: Pass navigator in event_t --- src/ui/glw/glw.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ui/glw/glw.c b/src/ui/glw/glw.c index e83f955c29..3c531e1859 100644 --- a/src/ui/glw/glw.c +++ b/src/ui/glw/glw.c @@ -1785,6 +1785,7 @@ glw_focus_step(glw_t *w, int forward) return 0; e = event_create_action(forward ? ACTION_DOWN : ACTION_UP); + e->e_nav = prop_ref_inc(w->glw_root->gr_prop_nav); while(w->glw_focused != NULL) { w = w->glw_focused; @@ -2017,6 +2018,7 @@ glw_pointer_event_deliver(glw_t *w, glw_pointer_event_t *gpe) case GLW_POINTER_RIGHT_PRESS: e = event_create_action(ACTION_ITEMMENU); + e->e_nav = prop_ref_inc(gr->gr_prop_nav); e->e_flags |= EVENT_MOUSE | EVENT_SCREEN_POSITION; e->e_screen_x = gpe->screen_x; e->e_screen_y = gpe->screen_y; @@ -2043,6 +2045,7 @@ glw_pointer_event_deliver(glw_t *w, glw_pointer_event_t *gpe) glw_path_modify(w, 0, GLW_IN_PRESSED_PATH, NULL); e = event_create_action_multi((const action_type_t[]){ ACTION_CLICK, ACTION_ACTIVATE}, 2); + e->e_nav = prop_ref_inc(gr->gr_prop_nav); e->e_flags |= flags | EVENT_SCREEN_POSITION; e->e_screen_x = gpe->screen_x; e->e_screen_y = gpe->screen_y; @@ -2068,6 +2071,7 @@ glw_touch_longpress(glw_root_t *gr) gr->gr_pointer_press_time = 0; glw_t *w = gr->gr_pointer_press; event_t *e = event_create_action(ACTION_ITEMMENU); + e->e_nav = prop_ref_inc(gr->gr_prop_nav); int r = glw_event_to_widget(w, e); event_release(e); if(r) { @@ -3171,6 +3175,7 @@ glw_osk_done(glw_root_t *gr, int submit) if(w != NULL) { if(submit) { event_t *e = event_create_action(ACTION_SUBMIT); + e->e_nav = prop_ref_inc(gr->gr_prop_nav); glw_event_to_widget(w, e); event_release(e); } else { From bc3e6d182f7e3c258751685e8f9a10941de4d61f Mon Sep 17 00:00:00 2001 From: Andreas Smas Date: Thu, 20 Dec 2018 17:26:19 -0800 Subject: [PATCH 09/17] plugins: Remove some debug prints --- src/plugins.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/plugins.c b/src/plugins.c index 5d0338cb35..6b7d201531 100644 --- a/src/plugins.c +++ b/src/plugins.c @@ -1152,8 +1152,6 @@ plugins_setup_root_props(void) settings_create_action(add, _p("Subscribe to plugin repository feed"), "add", plugins_add_repo_popup, NULL, SETTINGS_RAW_NODES, NULL); - - prop_print_tree(dir, 1); } @@ -1304,7 +1302,6 @@ plugin_repo_create(const char *url, const char *title, int load) plugin_load_repo(pr); pr->pr_initialized = 1; hts_mutex_unlock(&plugin_mutex); - prop_print_tree(plugin_repos_settings, 1); } From e7345b2261043529d451793d629ee7e51393e6e9 Mon Sep 17 00:00:00 2001 From: Andreas Smas Date: Thu, 20 Dec 2018 17:52:10 -0800 Subject: [PATCH 10/17] zip: Allow stat()ing for an item which ends with a slash --- src/fileaccess/fa_zip.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/fileaccess/fa_zip.c b/src/fileaccess/fa_zip.c index cb65b8eabc..a6b0c94acb 100644 --- a/src/fileaccess/fa_zip.c +++ b/src/fileaccess/fa_zip.c @@ -164,6 +164,7 @@ zip_archive_find_file(zip_archive_t *za, zip_file_t *parent, const char *s, *n = name; char *b; int l; + int must_be_dir = 0; if(parent == NULL) return NULL; @@ -174,8 +175,7 @@ zip_archive_find_file(zip_archive_t *za, zip_file_t *parent, if(s != NULL) { l = s - name; s++; - if(*s == 0) - return NULL; + must_be_dir = *s == 0; n = b = alloca(l + 1); memcpy(b, name, l); b[l] = 0; @@ -195,7 +195,13 @@ zip_archive_find_file(zip_archive_t *za, zip_file_t *parent, zf->zf_name = strdup(n); zf->zf_type = s ? CONTENT_DIR : CONTENT_FILE; LIST_INSERT_HEAD(&parent->zf_files, zf, zf_link); - } + } + + if(must_be_dir) { + if(zf->zf_type != CONTENT_DIR) + return NULL; + return zf; + } return s != NULL ? zip_archive_find_file(za, zf, s, create) : zf; } From a233576f8e2d2cc65c5e9e993c7292eb12473a43 Mon Sep 17 00:00:00 2001 From: Andreas Smas Date: Thu, 20 Dec 2018 17:53:05 -0800 Subject: [PATCH 11/17] plugins: Support loading plugins where the plugin is in a sub folder inside the zipfile --- src/plugins.c | 106 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 86 insertions(+), 20 deletions(-) diff --git a/src/plugins.c b/src/plugins.c index 6b7d201531..3bfafcbe8a 100644 --- a/src/plugins.c +++ b/src/plugins.c @@ -406,30 +406,78 @@ plugin_fill_prop(struct htsmsg *pm, struct prop *p, htsmsg_get_str(pm, "version")); if(icon != NULL) { - scoped_char *iconurl = url_resolve_relative_from_base(baseurl, icon); - prop_set(metadata, "icon", PROP_SET_STRING, iconurl); + if(mystrbegins(icon, "http://") || mystrbegins(icon, "https://")) { + prop_set(metadata, "icon", PROP_SET_STRING, icon); + } else if(mystrbegins(baseurl, "http://") || + mystrbegins(baseurl, "https://")) { + scoped_char *iconurl = url_resolve_relative_from_base(baseurl, icon); + prop_set(metadata, "icon", PROP_SET_STRING, iconurl); + } else { + scoped_char *iconurl = fmt("%s/%s", baseurl, icon); + prop_set(metadata, "icon", PROP_SET_STRING, iconurl); + } } prop_ref_dec(metadata); } +static char * +plugin_resolve_zip_path(const char *zipfile) +{ + scoped_char *zp = fmt("zip://%s", zipfile); + fa_dir_t *fd = fa_scandir(zp, NULL, 0); + if(fd == NULL) { + return NULL; + } + fa_dir_entry_t *fde; + RB_FOREACH(fde, &fd->fd_entries, fde_link) { + if(!strcmp(rstr_get(fde->fde_filename), "plugin.json")) { + fa_dir_free(fd); + return strdup(zp); + } + } + + fde = RB_FIRST(&fd->fd_entries); + if(fde != NULL && fde->fde_type == CONTENT_DIR) { + scoped_char *zp2 = fmt("zip://%s/%s/plugin.json", zipfile, + rstr_get(fde->fde_filename)); + + struct fa_stat buf; + if(!fa_stat(zp2, &buf, NULL, 0)) { + char *r = fmt("zip://%s/%s", zipfile, rstr_get(fde->fde_filename)); + fa_dir_free(fd); + return r; + } + } + + fa_dir_free(fd); + return NULL; +} + + /** * */ void plugin_props_from_file(prop_t *prop, const char *zipfile) { - char path[200]; char errbuf[200]; buf_t *b; - snprintf(path, sizeof(path), "zip://%s/plugin.json", zipfile); - b = fa_load(path, + scoped_char *zippath = plugin_resolve_zip_path(zipfile); + if(zippath == NULL) { + TRACE(TRACE_ERROR, "plugins", + "Unable to open %s -- Not a valid plugin archive", zipfile); + return; + } + scoped_char *plugin_json = fmt("%s/plugin.json", zippath); + b = fa_load(plugin_json, FA_LOAD_ERRBUF(errbuf, sizeof(errbuf)), NULL); if(b == NULL) { - TRACE(TRACE_ERROR, "plugins", "Unable to open %s -- %s", path, errbuf); + TRACE(TRACE_ERROR, "plugins", "Unable to open %s -- %s", + plugin_json, errbuf); return; } htsmsg_t *pm = htsmsg_json_deserialize(buf_cstr(b)); @@ -443,8 +491,7 @@ plugin_props_from_file(prop_t *prop, const char *zipfile) if(id != NULL) { hts_mutex_lock(&plugin_mutex); plugin_t *pl = plugin_make(id, "local"); - snprintf(path, sizeof(path), "zip://%s", zipfile); - plugin_fill_prop(pm, prop, path, pl); + plugin_fill_prop(pm, prop, zippath, pl); prop_set(prop, "package", PROP_SET_STRING, zipfile); update_state(pl); hts_mutex_unlock(&plugin_mutex); @@ -738,8 +785,14 @@ plugin_load_installed(void) if(dot != NULL) *dot = 0; } - snprintf(path, sizeof(path), "zip://%s", rstr_get(fde->fde_url)); - if(plugin_load(path, errbuf, sizeof(errbuf), + scoped_char *zippath = plugin_resolve_zip_path(rstr_get(fde->fde_url)); + if(zippath == NULL) { + TRACE(TRACE_ERROR, "plugins", + "Unable to load %s -- Not a valid plugin archive", path); + continue; + } + + if(plugin_load(zippath, errbuf, sizeof(errbuf), PLUGIN_LOAD_AS_INSTALLED, domain)) { TRACE(TRACE_ERROR, "plugins", "Unable to load %s\n%s", path, errbuf); } @@ -1415,6 +1468,7 @@ plugin_install(plugin_t *pl, const char *package) { char errbuf[200]; char path[200]; + scoped_char *zippath = NULL; usage_event(pl->pl_can_upgrade ? "Plugin upgrade" : "Plugin install", 1, USAGE_SEG("plugin", pl->pl_fqid, @@ -1506,15 +1560,20 @@ plugin_install(plugin_t *pl, const char *package) goto cleanup; } - snprintf(path, sizeof(path), - "zip://%s/pluginsv2/installed/%s.zip", gconf.persistent_path, - pl->pl_fqid); - #ifdef STOS arch_sync_path(path); #endif - if(plugin_load(path, errbuf, sizeof(errbuf), + zippath = plugin_resolve_zip_path(path); + if(zippath == NULL) { + prop_unlink(status); + TRACE(TRACE_ERROR, "plugins", "Unable to load %s -- %s", path, + "Not a valid plugin archive"); + prop_set_string(status, errbuf); + goto cleanup; + } + + if(plugin_load(zippath, errbuf, sizeof(errbuf), PLUGIN_LOAD_FORCE | PLUGIN_LOAD_AS_INSTALLED | PLUGIN_LOAD_BY_USER, pl->pl_domain)) { prop_unlink(status); @@ -1678,14 +1737,21 @@ BE_REGISTER(plugin); void plugin_open_file(prop_t *page, const char *url) { - char path[200]; char errbuf[200]; buf_t *b; - snprintf(path, sizeof(path), "zip://%s/plugin.json", url); - b = fa_load(path, - FA_LOAD_ERRBUF(errbuf, sizeof(errbuf)), - NULL); + + scoped_char *zippath = plugin_resolve_zip_path(url); + if(zippath == NULL) { + nav_open_errorf(page, _("Unable to load plugin.json: %s"), + "Not a valid plugin archive"); + return; + } + + scoped_char *plugin_json = fmt("%s/plugin.json", zippath); + b = fa_load(plugin_json, + FA_LOAD_ERRBUF(errbuf, sizeof(errbuf)), + NULL); if(b == NULL) { nav_open_errorf(page, _("Unable to load plugin.json: %s"), errbuf); return; From a4267b86b4bba03c957adfbb70dc0a2cb285c728 Mon Sep 17 00:00:00 2001 From: Andreas Smas Date: Thu, 20 Dec 2018 20:03:46 -0800 Subject: [PATCH 12/17] Rework so plugin origin is computed from plugin's origin URL --- src/plugins.c | 241 ++++++++++++++++++++++---------------------------- 1 file changed, 108 insertions(+), 133 deletions(-) diff --git a/src/plugins.c b/src/plugins.c index 3bfafcbe8a..edefe0b734 100644 --- a/src/plugins.c +++ b/src/plugins.c @@ -69,6 +69,7 @@ static struct strtab catnames[] = { { "subtitles", PLUGIN_CAT_SUBTITLES }, }; +const char *storage_prefix = "mrp"; // multi-repo plugins static HTS_MUTEX_DECL(plugin_mutex); static HTS_MUTEX_DECL(autoplugin_mutex); @@ -90,7 +91,7 @@ static struct plugin_list plugins; typedef struct plugin { LIST_ENTRY(plugin) pl_link; char *pl_fqid; - char *pl_domain; + char *pl_origin; char *pl_package; char *pl_title; @@ -107,6 +108,7 @@ typedef struct plugin { char pl_loaded; char pl_installed; char pl_can_upgrade; + char pl_auto_upgrade; char pl_new_version_avail; char pl_mark; @@ -119,7 +121,6 @@ static struct plugin_repo_list plugin_repos; typedef struct plugin_repo { LIST_ENTRY(plugin_repo) pr_link; char *pr_url; - char *pr_domain; prop_t *pr_root; prop_t *pr_title; int pr_autoupgrade; @@ -144,8 +145,6 @@ static void autoplugin_set_installed(const char *id, int is_installed); static void plugin_repo_create(const char *url, const char *title, int load); -static int plugins_upgrade_check_locked(plugin_repo_t *pr); - #define VERSION_ENCODE(a,b,c) ((a) * 10000000 + (b) * 100000 + (c)) static const struct { @@ -190,15 +189,29 @@ is_plugin_blacklisted(const char *id, const char *version, rstr_t **reason) return 0; } +static char * +origin_hash(const char *url) +{ + md5_decl(md5); + md5_init(md5); + md5_update(md5, (const void *)url, strlen(url)); + uint8_t hash[16]; + md5_final(md5, hash); + + return fmt("%02x%02x%02x%02x%02x%02x%02x%02x", + hash[0], hash[1], hash[2], hash[3], + hash[4], hash[5], hash[6], hash[7]); +} + /** * */ static plugin_t * -plugin_make(const char *id, const char *domain) +plugin_make(const char *id, const char *origin) { plugin_t *pl; - scoped_char *fqid = fmt("%s@%s", id, domain); + scoped_char *fqid = fmt("%s@%s", id, origin); LIST_FOREACH(pl, &plugins, pl_link) if(!strcmp(pl->pl_fqid, fqid)) @@ -206,7 +219,7 @@ plugin_make(const char *id, const char *domain) pl = calloc(1, sizeof(plugin_t)); pl->pl_fqid = strdup(fqid); - pl->pl_domain = strdup(domain); + pl->pl_origin = strdup(origin); pl->pl_status = prop_create_root(NULL); @@ -566,8 +579,8 @@ plugin_unload(plugin_t *pl) * */ static int -plugin_load(const char *url, char *errbuf, size_t errlen, int flags, - const char *domain) +plugin_load(const char *url, const char *origin, + char *errbuf, size_t errlen, int flags) { char ctrlfile[URL_MAX]; char errbuf2[1024]; @@ -602,7 +615,7 @@ plugin_load(const char *url, char *errbuf, size_t errlen, int flags, goto bad; } - plugin_t *pl = plugin_make(ext_id, domain); + plugin_t *pl = plugin_make(ext_id, origin); if(version != NULL) { rstr_t *notifymsg; @@ -771,17 +784,18 @@ plugin_load_installed(void) char errbuf[200]; fa_dir_entry_t *fde; - snprintf(path, sizeof(path), "%s/pluginsv2/installed", gconf.persistent_path); + snprintf(path, sizeof(path), "%s/%s/installed", + gconf.persistent_path, storage_prefix); fa_dir_t *fd = fa_scandir(path, NULL, 0); if(fd != NULL) { RB_FOREACH(fde, &fd->fd_entries, fde_link) { scoped_char *d0 = strdup(rstr_get(fde->fde_filename)); - char *domain = strchr(d0, '@'); - if(domain != NULL) { - domain++; - char *dot = strchr(domain, '.'); + char *origin = strchr(d0, '@'); + if(origin != NULL) { + origin++; + char *dot = strchr(origin, '.'); if(dot != NULL) *dot = 0; } @@ -792,8 +806,8 @@ plugin_load_installed(void) continue; } - if(plugin_load(zippath, errbuf, sizeof(errbuf), - PLUGIN_LOAD_AS_INSTALLED, domain)) { + if(plugin_load(zippath, origin, errbuf, sizeof(errbuf), + PLUGIN_LOAD_AS_INSTALLED)) { TRACE(TRACE_ERROR, "plugins", "Unable to load %s\n%s", path, errbuf); } } @@ -857,6 +871,34 @@ repo_get(const char *repo, char *errbuf, size_t errlen) } +static void +plugin_mark(void) +{ + plugin_t *pl; + + LIST_FOREACH(pl, &plugins, pl_link) { + pl->pl_mark = 1; + } +} + + +static void +plugin_sweep(void) +{ + plugin_t *pl, *next; + + for(pl = LIST_FIRST(&plugins); pl != NULL; pl = next) { + next = LIST_NEXT(pl, pl_link); + prop_set(pl->pl_status, "inRepo", PROP_SET_INT, !pl->pl_mark); + if(pl->pl_mark) { + prop_ref_dec(pl->pl_repo_model); + pl->pl_repo_model = NULL; + pl->pl_mark = 0; + } + } +} + + /** * @@ -864,7 +906,7 @@ repo_get(const char *repo, char *errbuf, size_t errlen) static int plugin_load_repo(plugin_repo_t *pr) { - plugin_t *pl, *next; + plugin_t *pl; char errbuf[512]; const char *url = pr->pr_url; @@ -887,12 +929,6 @@ plugin_load_repo(plugin_repo_t *pr) if(r != NULL) { htsmsg_field_t *f; - LIST_FOREACH(pl, &plugins, pl_link) { - if(!strcmp(pl->pl_domain, pr->pr_domain)) { - pl->pl_mark = 1; - } - } - HTSMSG_FOREACH(f, r) { htsmsg_t *pm; if((pm = htsmsg_get_map_by_field(f)) == NULL) @@ -917,7 +953,16 @@ plugin_load_repo(plugin_repo_t *pr) if(is_plugin_blacklisted(id, version, NULL)) continue; - pl = plugin_make(id, pr->pr_domain); + const char *relurl = htsmsg_get_str(pm, "downloadURL"); + if(relurl == NULL) + continue; + + char *package_url = url_resolve_relative_from_base(url, relurl); + + scoped_char *origin = origin_hash(package_url); + pl = plugin_make(id, origin); + free(pl->pl_package); + pl->pl_package = package_url; pl->pl_mark = 0; plugin_prop_setup(pm, pl, url); mystrset(&pl->pl_repo_ver, version); @@ -925,62 +970,15 @@ plugin_load_repo(plugin_repo_t *pr) htsmsg_get_str(pm, "showtimeVersion")); update_state(pl); - const char *dlurl = htsmsg_get_str(pm, "downloadURL"); - if(dlurl != NULL) { - char *package = url_resolve_relative_from_base(url, dlurl); - free(pl->pl_package); - pl->pl_package = package; - } - htsmsg_t *ctrl = htsmsg_get_map(pm, "control"); if(ctrl != NULL) { autoplugin_create_from_control(id, ctrl, pl->pl_installed); } } - - for(pl = LIST_FIRST(&plugins); pl != NULL; pl = next) { - next = LIST_NEXT(pl, pl_link); - prop_set(pl->pl_status, "inRepo", PROP_SET_INT, !pl->pl_mark); - if(pl->pl_mark) { - prop_ref_dec(pl->pl_repo_model); - pl->pl_repo_model = NULL; - pl->pl_mark = 0; - } - } } hts_mutex_unlock(&autoplugin_mutex); - r = htsmsg_get_list(msg, "blacklist"); - if(r != NULL) { - htsmsg_field_t *f; - HTSMSG_FOREACH(f, r) { - htsmsg_t *pm; - if((pm = htsmsg_get_map_by_field(f)) == NULL) - continue; - - const char *id = htsmsg_get_str(pm, "id"); - const char *version = htsmsg_get_str(pm, "version"); - - scoped_char *fqid = fmt("%s@%s", id, pr->pr_domain); - - if(id == NULL || version == NULL) - continue; - - LIST_FOREACH(pl, &plugins, pl_link) - if(!strcmp(fqid, pl->pl_fqid) && pl->pl_installed && pl->pl_inst_ver && - !strcmp(version, pl->pl_inst_ver)) - break; - - if(pl != NULL) { - notify_add(NULL, NOTIFY_ERROR, NULL, 10, - _("Plugin %s %s has been uninstalled because it may cause problems.\nYou may try reinstalling a different version manually."), pl->pl_title, pl->pl_inst_ver); - plugin_remove(pl); - } - } - } - - htsmsg_release(msg); return 0; } @@ -993,18 +991,9 @@ static void plugin_autoupgrade(void) { plugin_t *pl; - plugin_repo_t *pr; LIST_FOREACH(pl, &plugins, pl_link) { - - LIST_FOREACH(pr, &plugin_repos, pr_link) { - if(!strcmp(pr->pr_domain, pl->pl_domain)) - break; - } - if(!pr->pr_autoupgrade) - continue; - - if(!pl->pl_can_upgrade) + if(!pl->pl_can_upgrade || !pl->pl_auto_upgrade) continue; if(plugin_install(pl, NULL)) continue; @@ -1220,24 +1209,6 @@ plugins_init2(void) } -static int -plugins_upgrade_check_locked(plugin_repo_t *pr) -{ - int r = 0; - if(pr != NULL) { - r = plugin_load_repo(pr); - } else { - LIST_FOREACH(pr, &plugin_repos, pr_link) { - r |= plugin_load_repo(pr); - } - } - if(!r) { - update_global_state(); - plugin_autoupgrade(); - } - return r; -} - /** * @@ -1245,26 +1216,28 @@ plugins_upgrade_check_locked(plugin_repo_t *pr) int plugins_upgrade_check(void) { + int r = 0; + plugin_repo_t *pr; hts_mutex_lock(&plugin_mutex); - int r = plugins_upgrade_check_locked(NULL); + + plugin_mark(); + + LIST_FOREACH(pr, &plugin_repos, pr_link) { + r |= plugin_load_repo(pr); + } + + plugin_sweep(); + + if(!r) { + update_global_state(); + plugin_autoupgrade(); + } + hts_mutex_unlock(&plugin_mutex); return r; } -static char * -plugin_repo_hash(const char *url) -{ - md5_decl(md5); - md5_init(md5); - md5_update(md5, (const void *)url, strlen(url)); - uint8_t hash[16]; - md5_final(md5, hash); - - return fmt("%02x%02x%02x%02x%02x%02x%02x%02x", - hash[0], hash[1], hash[2], hash[3], - hash[4], hash[5], hash[6], hash[7]); -} static void @@ -1272,8 +1245,11 @@ set_autoupgrade(void *opaque, int value) { plugin_repo_t *pr = opaque; pr->pr_autoupgrade = value; - if(value && pr->pr_initialized) - plugins_upgrade_check_locked(pr); + if(value && pr->pr_initialized) { + if(!plugin_load_repo(pr)) { + update_global_state(); + } + } } @@ -1283,7 +1259,6 @@ plugin_repo_delete(void *opaque, event_t *e) plugin_repo_t *pr = opaque; free(pr->pr_url); - free(pr->pr_domain); LIST_REMOVE(pr, pr_link); prop_destroy(pr->pr_root); prop_ref_dec(pr->pr_title); @@ -1308,7 +1283,6 @@ plugin_repo_create(const char *url, const char *title, int load) LIST_INSERT_HEAD(&plugin_repos, pr, pr_link); pr->pr_url = strdup(url); - pr->pr_domain = plugin_repo_hash(pr->pr_url); pr->pr_root = prop_create_r(plugin_repos_settings, NULL); pr->pr_title = prop_ref_inc(prop_create_multi(pr->pr_root, "metadata", @@ -1388,8 +1362,8 @@ plugins_init(char **devplugs) strvec_addp(&devplugins, path); - if(plugin_load(path, errbuf, sizeof(errbuf), - PLUGIN_LOAD_FORCE | PLUGIN_LOAD_DEBUG, "dev")) { + if(plugin_load(path, "dev", errbuf, sizeof(errbuf), + PLUGIN_LOAD_FORCE | PLUGIN_LOAD_DEBUG)) { TRACE(TRACE_ERROR, "plugins", "Unable to load development plugin: %s\n%s", path, errbuf); } else { @@ -1416,9 +1390,8 @@ plugins_reload_dev_plugin(void) const char *path; for(int i = 0; (path = devplugins[i]) != NULL; i++) { - if(plugin_load(path, errbuf, sizeof(errbuf), - PLUGIN_LOAD_FORCE | PLUGIN_LOAD_DEBUG | PLUGIN_LOAD_BY_USER, - "dev")) + if(plugin_load(path, "dev", errbuf, sizeof(errbuf), + PLUGIN_LOAD_FORCE | PLUGIN_LOAD_DEBUG | PLUGIN_LOAD_BY_USER)) TRACE(TRACE_ERROR, "plugins", "Unable to reload development plugin: %s\n%s", path, errbuf); else @@ -1443,12 +1416,12 @@ plugin_remove(plugin_t *pl) TRACE(TRACE_DEBUG, "plugin", "Uninstalling %s", pl->pl_fqid); - snprintf(path, sizeof(path), "%s/pluginsv2/installed/%s.zip", - gconf.persistent_path, pl->pl_fqid); + snprintf(path, sizeof(path), "%s/%s/installed/%s.zip", + gconf.persistent_path, storage_prefix, pl->pl_fqid); fa_unlink(path, NULL, 0); - snprintf(path, sizeof(path), "%s/pluginsv2/settings/%s", - gconf.persistent_path, pl->pl_fqid); + snprintf(path, sizeof(path), "%s/%s/settings/%s", + gconf.persistent_path, storage_prefix, pl->pl_fqid); fa_unlink_recursive(path, NULL, 0, 0); plugin_unload(pl); @@ -1524,17 +1497,19 @@ plugin_install(plugin_t *pl, const char *package) TRACE(TRACE_INFO, "plugins", "Plugin %s valid ZIP archive %d bytes", pl->pl_fqid, (int)b->b_size); - snprintf(path, sizeof(path), "%s/pluginsv2", gconf.persistent_path); + snprintf(path, sizeof(path), "%s/%s", gconf.persistent_path, + storage_prefix); fa_makedir(path); - snprintf(path, sizeof(path), "%s/pluginsv2/installed", gconf.persistent_path); + snprintf(path, sizeof(path), "%s/%s/installed", gconf.persistent_path, + storage_prefix); fa_makedir(path); plugin_unload(pl); prop_link(_p("Installing"), status); - snprintf(path, sizeof(path), "%s/pluginsv2/installed/%s.zip", - gconf.persistent_path, pl->pl_fqid); + snprintf(path, sizeof(path), "%s/%s/installed/%s.zip", + gconf.persistent_path, storage_prefix, pl->pl_fqid); if(fa_unlink(path, errbuf, sizeof(errbuf))) { TRACE(TRACE_DEBUG, "plugins", "First unlinking %s -- %s", @@ -1573,9 +1548,9 @@ plugin_install(plugin_t *pl, const char *package) goto cleanup; } - if(plugin_load(zippath, errbuf, sizeof(errbuf), + if(plugin_load(zippath, pl->pl_origin, errbuf, sizeof(errbuf), PLUGIN_LOAD_FORCE | PLUGIN_LOAD_AS_INSTALLED | - PLUGIN_LOAD_BY_USER, pl->pl_domain)) { + PLUGIN_LOAD_BY_USER)) { prop_unlink(status); TRACE(TRACE_ERROR, "plugins", "Unable to load %s -- %s", path, errbuf); prop_set_string(status, errbuf); From a08e02ee1f239549e016b82ba6e400eaf6bd8f89 Mon Sep 17 00:00:00 2001 From: Andreas Smas Date: Thu, 20 Dec 2018 21:02:54 -0800 Subject: [PATCH 13/17] plugins: Load/save list of repos. Create plugin service on-demand --- src/main.c | 2 +- src/plugins.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++- src/plugins.h | 2 +- src/service.c | 6 +---- 4 files changed, 76 insertions(+), 8 deletions(-) diff --git a/src/main.c b/src/main.c index a016f3717d..13289fd41c 100644 --- a/src/main.c +++ b/src/main.c @@ -255,7 +255,7 @@ static void * swthread(void *aux) { #if ENABLE_PLUGINS - plugins_init2(); + plugins_load_all(); #endif upgrade_init(); diff --git a/src/plugins.c b/src/plugins.c index edefe0b734..07051c4850 100644 --- a/src/plugins.c +++ b/src/plugins.c @@ -35,6 +35,7 @@ #include "usage.h" #include "backend/search.h" #include "misc/md5.h" +#include "service.h" #include "ecmascript/ecmascript.h" @@ -81,6 +82,8 @@ static prop_t *plugin_start_model; static prop_t *plugin_repo_model; static prop_t *plugin_repos_settings; +static service_t *plugin_service; + LIST_HEAD(plugin_list, plugin); LIST_HEAD(plugin_repo_list, plugin_repo); LIST_HEAD(plugin_view_list, plugin_view); @@ -155,6 +158,29 @@ static const struct { { "xperience", VERSION_ENCODE(1,0,0) } }; + +static void +plugin_update_service(void) +{ + const int should_show = LIST_FIRST(&plugin_repos) || LIST_FIRST(&plugins); + + if(should_show && plugin_service == NULL) { + plugin_service = service_createp("showtime:plugin", + _p("Plugins"), "plugin:start", + "plugin", NULL, 0, 1, SVC_ORIGIN_SYSTEM); + return; + } + + if(!should_show && plugin_service != NULL) { + service_destroy(plugin_service); + plugin_service = NULL; + return; + } +} + + + + /** * */ @@ -224,6 +250,9 @@ plugin_make(const char *id, const char *origin) pl->pl_status = prop_create_root(NULL); LIST_INSERT_HEAD(&plugins, pl, pl_link); + + plugin_update_service(); + return pl; } @@ -1147,7 +1176,38 @@ plugin_setup_repo_model(void) prop_concat_add_source(pc, cat, header); } +} + +static void +plguin_repo_save(void) +{ + htsmsg_t *m = htsmsg_create_list(); + plugin_repo_t *pr; + LIST_FOREACH(pr, &plugin_repos, pr_link) { + htsmsg_t *e = htsmsg_create_map(); + htsmsg_add_str(e, "url", pr->pr_url); + htsmsg_add_msg(m, NULL, e); + } + htsmsg_store_save(m, "pluginrepos"); + htsmsg_release(m); +} + + +static void +plguin_repo_load(void) +{ + htsmsg_t *m; + if((m = htsmsg_store_load("pluginrepos")) != NULL) { + htsmsg_field_t *f; + HTSMSG_FOREACH(f, m) { + htsmsg_t *e; + if((e = htsmsg_get_map_by_field(f)) == NULL) + continue; + const char *url = htsmsg_get_str(e, "url"); + plugin_repo_create(url, NULL, 0); + } + } } @@ -1164,6 +1224,7 @@ plugins_add_repo_popup(void *opaque, prop_event_t event, ...) return; plugin_repo_create(url, NULL, 1); + plguin_repo_save(); } @@ -1201,7 +1262,7 @@ plugins_setup_root_props(void) * */ void -plugins_init2(void) +plugins_load_all(void) { hts_mutex_lock(&plugin_mutex); plugin_load_installed(); @@ -1271,6 +1332,10 @@ plugin_repo_delete(void *opaque, event_t *e) prop_ref_dec(eventsink); event_release(be); } + + plugin_update_service(); + + plguin_repo_save(); } @@ -1279,6 +1344,8 @@ plugin_repo_create(const char *url, const char *title, int load) { hts_mutex_lock(&plugin_mutex); + plugin_update_service(); + plugin_repo_t *pr = calloc(1, sizeof(plugin_repo_t)); LIST_INSERT_HEAD(&plugin_repos, pr, pr_link); @@ -1328,6 +1395,9 @@ plugin_repo_create(const char *url, const char *title, int load) if(load) plugin_load_repo(pr); pr->pr_initialized = 1; + + plugin_update_service(); + hts_mutex_unlock(&plugin_mutex); } @@ -1372,6 +1442,8 @@ plugins_init(char **devplugs) } } hts_mutex_unlock(&plugin_mutex); + + plguin_repo_load(); } diff --git a/src/plugins.h b/src/plugins.h index bff6a0e6d6..d993f0e73a 100644 --- a/src/plugins.h +++ b/src/plugins.h @@ -25,7 +25,7 @@ struct prop; void plugins_init(char **devplugins); -void plugins_init2(void); +void plugins_load_all(void); int plugins_upgrade_check(void); diff --git a/src/service.c b/src/service.c index c2142444c8..17fd49f902 100644 --- a/src/service.c +++ b/src/service.c @@ -103,11 +103,7 @@ service_init(void) // $global.service.all all_services = prop_create(gs, "all"); -#if ENABLE_PLUGINS - service_create0("showtime:plugin", - NULL, _p("Plugins"), "plugin:start", - "plugin", NULL, 0, 1, SVC_ORIGIN_SYSTEM); -#endif + service_create0("showtime:discovered", NULL, _p("Local network"), "discovered:", "network", NULL, 0, 1, SVC_ORIGIN_SYSTEM); From 094e2da443356f28d8649a426abcb28e1086bd76 Mon Sep 17 00:00:00 2001 From: Andreas Smas Date: Fri, 21 Dec 2018 12:22:27 -0800 Subject: [PATCH 14/17] Drop GTK dependency and the GTK based UI --- configure.linux | 68 ------------------ src/arch/linux/linux.h | 7 +- src/arch/linux/linux.mk | 1 - src/arch/linux/linux_main.c | 137 ++++-------------------------------- src/event.c | 4 +- src/event.h | 2 - src/ui/glw/glw_x11.c | 34 ++------- 7 files changed, 22 insertions(+), 231 deletions(-) diff --git a/configure.linux b/configure.linux index 8351ed8147..09a9c74e83 100755 --- a/configure.linux +++ b/configure.linux @@ -91,10 +91,8 @@ enable libfontconfig enable libpulse enable lirc enable stdin -enable gu enable avahi enable libxss -enable libxv enable openssl enable locatedb enable vdpau @@ -385,57 +383,6 @@ if enabled libpulse; then fi -# -# GTK2 UI -# -if enabled gu; then - if pkg-config gtk+-2.0 && pkg-config gthread-2.0; then - - if disabled libx11; then - echo "GU depends on libx11" - die - fi - - if disabled libxext; then - echo "GU depends on libxext" - die - fi - - - echo >>${CONFIG_MAK} "LDFLAGS_cfg += " `pkg-config --libs gtk+-2.0` - echo >>${CONFIG_MAK} "CFLAGS_GTK += " `pkg-config --cflags gtk+-2.0` - echo "Using GTK+: `pkg-config --modversion gtk+-2.0`" - - echo >>${CONFIG_MAK} "LDFLAGS_cfg += " `pkg-config --libs gthread-2.0` - echo >>${CONFIG_MAK} "CFLAGS_GTK += " `pkg-config --cflags gthread-2.0` - echo "Using GTK Threading: `pkg-config --modversion gthread-2.0`" - - else - echo "GTK2 not found. Unable to build GU (GTK user interface)." - echo "To compile without it, configure with: --disable-gu" - die - fi -else - disable libxv -fi - -# -# webkit -# -if enabled webkit; then - if pkg-config webkit-1.0; then - echo >>${CONFIG_MAK} "LDFLAGS_cfg += " `pkg-config --libs webkit-1.0` - echo >>${CONFIG_MAK} "CFLAGS_GTK += " `pkg-config --cflags webkit-1.0` - echo "Using WebKit: `pkg-config --modversion webkit-1.0`" - enable webpopup - else - echo "libwebkitgtk development files not found." - echo "To compile without it, configure with: --disable-webkit" - die - fi -fi - - # # libXss (Screen saver control library) # @@ -481,21 +428,6 @@ if enabled libxrandr; then fi -# -# libxv (Xvideo) -# -if enabled libxv; then - if pkg-config xv; then - echo >>${CONFIG_MAK} "CFLAGS_cfg += " `pkg-config --cflags xv` - echo >>${CONFIG_MAK} "LDFLAGS_cfg += " `pkg-config --libs xv` - echo "Using libXv: `pkg-config --modversion xv`" - else - echo "libXv not found. Unable to build with Xv support." - die - fi -fi - - # # AVAHI # diff --git a/src/arch/linux/linux.h b/src/arch/linux/linux.h index 0a9a092a16..f503920dbc 100644 --- a/src/arch/linux/linux.h +++ b/src/arch/linux/linux.h @@ -28,9 +28,4 @@ void linux_webpopup_check(void); void linux_init_monitors(void); -struct prop; - -typedef struct linux_ui { - void *(*start)(struct prop *nav); - struct prop *(*stop)(void *ui); -} linux_ui_t; +void glw_x11_main(int *running); diff --git a/src/arch/linux/linux.mk b/src/arch/linux/linux.mk index 6e67a5bd36..4ad9fe8c50 100644 --- a/src/arch/linux/linux.mk +++ b/src/arch/linux/linux.mk @@ -14,7 +14,6 @@ SRCS += src/arch/linux/linux_main.c \ src/networking/net_ifaddr.c \ src/fileaccess/fa_opencookie.c \ src/fileaccess/fa_fs.c \ - src/prop/prop_glib_courier.c \ src/arch/linux/linux_process_monitor.c \ SRCS += src/htsmsg/persistent_file.c diff --git a/src/arch/linux/linux_main.c b/src/arch/linux/linux_main.c index 10606e3d71..985c0590f7 100644 --- a/src/arch/linux/linux_main.c +++ b/src/arch/linux/linux_main.c @@ -18,8 +18,6 @@ * For more information, contact andreas@lonelycoder.com */ #include -#include -#include #include "main.h" #include "arch/arch.h" @@ -28,113 +26,12 @@ #include "prop/prop.h" #include "navigator.h" #include "service.h" -#include "prop/prop_glib_courier.h" -hts_mutex_t gdk_mutex; -prop_courier_t *glibcourier; +// https://www.uninformativ.de/blog/postings/2017-04-02/0/POSTING-en.html static void add_xdg_paths(void); -/** - * - */ -static void -gdk_obtain(void) -{ - hts_mutex_lock(&gdk_mutex); -} - - -/** - * - */ -static void -gdk_release(void) -{ - hts_mutex_unlock(&gdk_mutex); -} - -static int running; -extern const linux_ui_t ui_glw, ui_gu; -static const linux_ui_t *ui_wanted = &ui_glw, *ui_current; - - -/** - * - */ -int -arch_stop_req(void) -{ - running = 0; - g_main_context_wakeup(g_main_context_default()); - return 0; -} - - -/** - * - */ -static void -switch_ui(void) -{ - if(ui_current == &ui_glw) - ui_wanted = &ui_gu; - else - ui_wanted = &ui_glw; -} - - -/** - * - */ -static void -mainloop(void) -{ - void *aux = NULL; - - running = 1; - - while(running) { - - if(ui_current != ui_wanted) { - - prop_t *nav; - - if(ui_current != NULL) { - nav = ui_current->stop(aux); - } else { - nav = NULL; - } - - ui_current = ui_wanted; - - aux= ui_current->start(nav); - } - -#if ENABLE_WEBPOPUP - linux_webpopup_check(); -#endif - gtk_main_iteration(); - } - - if(ui_current != NULL) { - prop_t *nav = ui_current->stop(aux); - if(nav != NULL) - prop_destroy(nav); - } -} - - -/** - * - */ -static void -linux_global_eventsink(void *opaque, event_t *e) -{ - if(event_is_action(e, ACTION_SWITCH_UI)) - switch_ui(); -} - +static int running = 1; /** * Linux main @@ -147,14 +44,8 @@ main(int argc, char **argv) posix_init(); XInitThreads(); - hts_mutex_init(&gdk_mutex); - g_thread_init(NULL); - gdk_threads_set_lock_functions(gdk_obtain, gdk_release); - - gdk_threads_init(); - gdk_threads_enter(); - gtk_init(&argc, &argv); + // g_thread_init(NULL); parse_opts(argc, argv); @@ -162,20 +53,9 @@ main(int argc, char **argv) main_init(); - if(gconf.ui && !strcmp(gconf.ui, "gu")) - ui_wanted = &ui_gu; - - glibcourier = glib_courier_create(g_main_context_default()); - - prop_subscribe(0, - PROP_TAG_NAME("global", "eventSink"), - PROP_TAG_CALLBACK_EVENT, linux_global_eventsink, NULL, - PROP_TAG_COURIER, glibcourier, - NULL); - add_xdg_paths(); - mainloop(); + glw_x11_main(&running); main_fini(); @@ -193,6 +73,15 @@ arch_exit(void) } +int +arch_stop_req(void) +{ + running = 0; + return 0; +} + + + /** * */ diff --git a/src/event.c b/src/event.c index 7064d6a6ba..8d9a66a27f 100644 --- a/src/event.c +++ b/src/event.c @@ -196,8 +196,6 @@ static struct strtab actionnames[] = { { "Playqueue", ACTION_PLAYQUEUE }, { "Sysinfo", ACTION_SYSINFO }, - { "SwitchUI", ACTION_SWITCH_UI }, - }; @@ -637,7 +635,7 @@ const static int action_from_fkey[13][2] = { { ACTION_SWITCH_VIEW, ACTION_SEEK_FORWARD }, { 0, ACTION_VOLUME_MUTE_TOGGLE }, { ACTION_FULLSCREEN_TOGGLE, ACTION_VOLUME_DOWN }, - { ACTION_SWITCH_UI, ACTION_VOLUME_UP }, + { 0, ACTION_VOLUME_UP }, }; diff --git a/src/event.h b/src/event.h index 9f240ab428..236857d72a 100644 --- a/src/event.h +++ b/src/event.h @@ -128,8 +128,6 @@ typedef enum { ACTION_SYSINFO, - ACTION_SWITCH_UI, - ACTION_RECORD_UI, ACTION_mappable_end, diff --git a/src/ui/glw/glw_x11.c b/src/ui/glw/glw_x11.c index 1510699edf..ec69cf3089 100644 --- a/src/ui/glw/glw_x11.c +++ b/src/ui/glw/glw_x11.c @@ -58,7 +58,7 @@ typedef struct glw_x11 { glw_root_t gr; - int running; + int *running; hts_thread_t thread; Display *display; @@ -989,7 +989,7 @@ glw_x11_mainloop(glw_x11_t *gx11) glw_set_fullscreen(&gx11->gr, gx11->is_fullscreen); - while(gx11->running) { + while(*gx11->running) { autohide_cursor(gx11); @@ -1323,40 +1323,20 @@ glw_x11_thread(void *aux) /** * */ -static void * -glw_x11_start(struct prop *nav) +void +glw_x11_main(int *running) { glw_x11_t *gx11 = calloc(1, sizeof(glw_x11_t)); gx11->gr.gr_prop_ui = prop_create_root("ui"); - gx11->gr.gr_prop_nav = nav ?: nav_spawn(); - gx11->running = 1; + gx11->gr.gr_prop_nav = nav_spawn(); + gx11->running = running; + glw_x11_thread(gx11); hts_thread_create_joinable("glw", &gx11->thread, glw_x11_thread, gx11, 0); - return gx11; -} - -/** - * - */ -static prop_t * -glw_x11_stop(void *aux) -{ - glw_x11_t *gx11 = aux; glw_root_t *gr = &gx11->gr; - prop_t *nav = gr->gr_prop_nav; - gx11->running = 0; - hts_thread_join(&gx11->thread); prop_destroy(gr->gr_prop_ui); glw_release_root(gr); - return nav; } - - - -const linux_ui_t ui_glw = { - .start = glw_x11_start, - .stop = glw_x11_stop, -}; From 1ab6dfdefe00389e572c7f418973ef5d7efaf87a Mon Sep 17 00:00:00 2001 From: Andreas Smas Date: Sat, 22 Dec 2018 08:47:34 -0800 Subject: [PATCH 15/17] Support for building snap --- Makefile | 3 + src/arch/linux/linux.mk | 103 +++++++++++++++++++++++++++++++++ src/arch/posix/posix.c | 13 ++++- support/artwork/movian-128.png | Bin 0 -> 10801 bytes support/command-movian.wrapper | 7 +++ support/movian.desktop | 10 ++++ support/snap.yaml | 20 +++++++ 7 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 support/artwork/movian-128.png create mode 100755 support/command-movian.wrapper create mode 100644 support/movian.desktop create mode 100644 support/snap.yaml diff --git a/Makefile b/Makefile index 072258db1c..15354e7e93 100644 --- a/Makefile +++ b/Makefile @@ -838,6 +838,9 @@ ${PROG}: $(OBJS) $(ALLDEPS) ${BUILDDIR}/support/dataroot/wd.o ${PROG}.bundle: $(OBJS) $(BUNDLE_OBJS) $(ALLDEPS) ${BUILDDIR}/support/dataroot/bundle.o $(LINKER) -o $@ $(OBJS) ${BUILDDIR}/support/dataroot/bundle.o $(BUNDLE_OBJS) $(LDFLAGS) ${LDFLAGS_cfg} +${PROG}.sbundle: ${PROG}.bundle $(ALLDEPS) + $(STRIP) -o $@ $< + ${PROG}.datadir: $(OBJS) $(ALLDEPS) ${BUILDDIR}/support/dataroot/datadir.o $(LINKER) -o $@ $(OBJS) ${BUILDDIR}/support/dataroot/datadir.o $(LDFLAGS) ${LDFLAGS_cfg} diff --git a/src/arch/linux/linux.mk b/src/arch/linux/linux.mk index 4ad9fe8c50..9fc80cfbb6 100644 --- a/src/arch/linux/linux.mk +++ b/src/arch/linux/linux.mk @@ -66,3 +66,106 @@ uninstall: # gtk-update-icon-cache $(prefix)/share/icons/hicolor/ +# +# +# + +SNAPROOT=$(BUILDDIR)/snaproot + +SNAPDEPS = \ + $(SNAPROOT)/bin/movian \ + $(SNAPROOT)/bin/xdg-user-dir \ + $(SNAPROOT)/meta/snap.yaml \ + $(SNAPROOT)/meta/gui/movian.desktop \ + $(SNAPROOT)/usr/share/movian/icons/movian-128.png \ + $(SNAPROOT)/command-movian.wrapper \ + $(SNAPROOT)/lib/libfontconfig.so.1 \ + $(SNAPROOT)/lib/libX11.so.6 \ + $(SNAPROOT)/lib/libX11-xcb.so.1 \ + $(SNAPROOT)/lib/libelf.so.1 \ + $(SNAPROOT)/lib/libLLVM-6.0.so.1 \ + $(SNAPROOT)/lib/libdrm.so.2 \ + $(SNAPROOT)/lib/libdrm_radeon.so.1 \ + $(SNAPROOT)/lib/libdrm_nouveau.so.2 \ + $(SNAPROOT)/lib/libdrm_intel.so.1 \ + $(SNAPROOT)/lib/libdrm_amdgpu.so.1 \ + $(SNAPROOT)/lib/libxcb.so.1 \ + $(SNAPROOT)/lib/libxcb-glx.so.0 \ + $(SNAPROOT)/lib/libxcb-dri2.so.0 \ + $(SNAPROOT)/lib/libxcb-dri3.so.0 \ + $(SNAPROOT)/lib/libxcb-present.so.0 \ + $(SNAPROOT)/lib/libxcb-sync.so.1 \ + $(SNAPROOT)/lib/libxshmfence.so.1 \ + $(SNAPROOT)/lib/libglapi.so.0 \ + $(SNAPROOT)/lib/libXdamage.so.1 \ + $(SNAPROOT)/lib/libXfixes.so.3 \ + $(SNAPROOT)/lib/libXau.so.6 \ + $(SNAPROOT)/lib/libXdmcp.so.6 \ + $(SNAPROOT)/lib/libXext.so.6 \ + $(SNAPROOT)/lib/libpulse.so.0 \ + $(SNAPROOT)/lib/libXss.so.1 \ + $(SNAPROOT)/lib/libXxf86vm.so.1 \ + $(SNAPROOT)/lib/libsndfile.so.1 \ + $(SNAPROOT)/lib/libasyncns.so.0 \ + $(SNAPROOT)/lib/libFLAC.so.8 \ + $(SNAPROOT)/lib/libogg.so.0 \ + $(SNAPROOT)/lib/libvorbisenc.so.2 \ + $(SNAPROOT)/lib/libvorbis.so.0 \ + $(SNAPROOT)/lib/libsensors.so.4 \ + $(SNAPROOT)/lib/libpciaccess.so.0 \ + $(SNAPROOT)/lib/mesa/libGL.so.1 \ + $(SNAPROOT)/lib/mesa/dri/i915_dri.so \ + $(SNAPROOT)/lib/mesa/dri/i965_dri.so \ + $(SNAPROOT)/lib/mesa/dri/kms_swrast_dri.so \ + $(SNAPROOT)/lib/mesa/dri/nouveau_dri.so \ + $(SNAPROOT)/lib/mesa/dri/nouveau_vieux_dri.so \ + $(SNAPROOT)/lib/mesa/dri/r200_dri.so \ + $(SNAPROOT)/lib/mesa/dri/r300_dri.so \ + $(SNAPROOT)/lib/mesa/dri/r600_dri.so \ + $(SNAPROOT)/lib/mesa/dri/radeon_dri.so \ + $(SNAPROOT)/lib/mesa/dri/radeonsi_dri.so \ + $(SNAPROOT)/lib/mesa/dri/swrast_dri.so \ + $(SNAPROOT)/lib/mesa/dri/virtio_gpu_dri.so \ + $(SNAPROOT)/lib/mesa/dri/vmwgfx_dri.so \ + $(SNAPROOT)/lib/pulseaudio/libpulsecommon-8.0.so \ + +$(SNAPROOT)/meta/snap.yaml: support/snap.yaml + @mkdir -p $(dir $@) + sed >$@ -e s/@@VERSION@@/${VERSION}/g -e s/@@APPNAME@@/${APPNAMEUSER}/g -e s/@@VERCODE@@/${NUMVER}/g $< + + +$(SNAPROOT)/lib/%: /usr/lib/x86_64-linux-gnu/% + @mkdir -p $(dir $@) + cp $< $@ + +$(SNAPROOT)/lib/mesa/dri/%.so: /usr/lib/x86_64-linux-gnu/dri/%.so + @mkdir -p $(dir $@) + cp $< $@ + +$(SNAPROOT)/bin/movian: $(BUILDDIR)/movian.sbundle + @mkdir -p $(dir $@) + cp $< $@ + +$(SNAPROOT)/bin/xdg-user-dir: /usr/bin/xdg-user-dir + @mkdir -p $(dir $@) + cp $< $@ + +$(SNAPROOT)/command-movian.wrapper: support/command-movian.wrapper + @mkdir -p $(dir $@) + cp $< $@ + +$(SNAPROOT)/meta/gui/movian.desktop: support/movian.desktop + @mkdir -p $(dir $@) + cp $< $@ + +$(SNAPROOT)/usr/share/movian/icons/movian-128.png: support/artwork/movian-128.png + @mkdir -p $(dir $@) + cp $< $@ + + +$(BUILDDIR)/movian.snap: $(SNAPDEPS) + rm -f $@ + mksquashfs $(SNAPROOT) $@ -comp xz + +snap: $(BUILDDIR)/movian.snap + diff --git a/src/arch/posix/posix.c b/src/arch/posix/posix.c index c146d1480f..7e9ff42266 100644 --- a/src/arch/posix/posix.c +++ b/src/arch/posix/posix.c @@ -154,6 +154,17 @@ posix_init(void) } } +#ifdef linux + const char *snap_user_common = getenv("SNAP_USER_COMMON"); + if(snap_user_common != NULL) { + char buf[PATH_MAX]; + snprintf(buf, sizeof(buf), "%s/cache", snap_user_common); + gconf.cache_path = strdup(buf); + + snprintf(buf, sizeof(buf), "%s/persistent", snap_user_common); + gconf.persistent_path = strdup(buf); + } +#endif setlocale(LC_ALL, ""); #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR @@ -161,7 +172,7 @@ posix_init(void) #else decorate_trace = isatty(2); #endif - + signal(SIGPIPE, SIG_IGN); #ifdef RLIMIT_AS diff --git a/support/artwork/movian-128.png b/support/artwork/movian-128.png new file mode 100644 index 0000000000000000000000000000000000000000..40ee4e250bd45d6a839e5327f680832c1b85843f GIT binary patch literal 10801 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 literal 0 HcmV?d00001 diff --git a/support/command-movian.wrapper b/support/command-movian.wrapper new file mode 100755 index 0000000000..01d6eec6b4 --- /dev/null +++ b/support/command-movian.wrapper @@ -0,0 +1,7 @@ +#!/bin/bash +export PATH="$SNAP/bin:$PATH" +export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$SNAP/lib:$SNAP/lib/pulseaudio:$SNAP/lib/mesa:$SNAP/lib/dri" +export LD_LIBRARY_PATH=$SNAP_LIBRARY_PATH:$LD_LIBRARY_PATH +export LIBGL_DRIVERS_PATH=$SNAP/lib/mesa/dri +export HOME=`getent passwd $UID | cut -d ':' -f 6` +exec "$SNAP/bin/movian" "$@" diff --git a/support/movian.desktop b/support/movian.desktop new file mode 100644 index 0000000000..9ac756311c --- /dev/null +++ b/support/movian.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Type=Application +Name=Movian +GenericName=Media Player +Icon=${SNAP}/usr/share/movian/icons/movian-128.png +TryExec=movian +Exec=movian %U +Terminal=false +Categories=Audio;Music;Player;AudioVideo; +StartupWMClass=movian diff --git a/support/snap.yaml b/support/snap.yaml new file mode 100644 index 0000000000..513e0dfb81 --- /dev/null +++ b/support/snap.yaml @@ -0,0 +1,20 @@ +name: movian +version: @@VERSION@@ +summary: Media player +architectures: +- amd64 +confinement: strict +grade: stable +apps: + movian: + command: command-movian.wrapper + environment: + TMPDIR: $XDG_RUNTIME_DIR + plugs: + - desktop + - home + - network + - network-bind + - opengl + - pulseaudio + - x11 From 4f902e4681a8a5ff803408c82405505416e641d1 Mon Sep 17 00:00:00 2001 From: Andreas Smas Date: Sun, 23 Dec 2018 21:22:27 -0800 Subject: [PATCH 16/17] snap: Depend on gnome-3-26-1604 for stuff --- src/arch/linux/linux.mk | 57 ---------------------------------- support/command-movian.wrapper | 9 +++--- support/snap.yaml | 5 +++ 3 files changed, 10 insertions(+), 61 deletions(-) diff --git a/src/arch/linux/linux.mk b/src/arch/linux/linux.mk index 9fc80cfbb6..513ff74d58 100644 --- a/src/arch/linux/linux.mk +++ b/src/arch/linux/linux.mk @@ -74,60 +74,11 @@ SNAPROOT=$(BUILDDIR)/snaproot SNAPDEPS = \ $(SNAPROOT)/bin/movian \ - $(SNAPROOT)/bin/xdg-user-dir \ $(SNAPROOT)/meta/snap.yaml \ $(SNAPROOT)/meta/gui/movian.desktop \ $(SNAPROOT)/usr/share/movian/icons/movian-128.png \ $(SNAPROOT)/command-movian.wrapper \ - $(SNAPROOT)/lib/libfontconfig.so.1 \ - $(SNAPROOT)/lib/libX11.so.6 \ - $(SNAPROOT)/lib/libX11-xcb.so.1 \ - $(SNAPROOT)/lib/libelf.so.1 \ - $(SNAPROOT)/lib/libLLVM-6.0.so.1 \ - $(SNAPROOT)/lib/libdrm.so.2 \ - $(SNAPROOT)/lib/libdrm_radeon.so.1 \ - $(SNAPROOT)/lib/libdrm_nouveau.so.2 \ - $(SNAPROOT)/lib/libdrm_intel.so.1 \ - $(SNAPROOT)/lib/libdrm_amdgpu.so.1 \ - $(SNAPROOT)/lib/libxcb.so.1 \ - $(SNAPROOT)/lib/libxcb-glx.so.0 \ - $(SNAPROOT)/lib/libxcb-dri2.so.0 \ - $(SNAPROOT)/lib/libxcb-dri3.so.0 \ - $(SNAPROOT)/lib/libxcb-present.so.0 \ - $(SNAPROOT)/lib/libxcb-sync.so.1 \ - $(SNAPROOT)/lib/libxshmfence.so.1 \ - $(SNAPROOT)/lib/libglapi.so.0 \ - $(SNAPROOT)/lib/libXdamage.so.1 \ - $(SNAPROOT)/lib/libXfixes.so.3 \ - $(SNAPROOT)/lib/libXau.so.6 \ - $(SNAPROOT)/lib/libXdmcp.so.6 \ - $(SNAPROOT)/lib/libXext.so.6 \ - $(SNAPROOT)/lib/libpulse.so.0 \ $(SNAPROOT)/lib/libXss.so.1 \ - $(SNAPROOT)/lib/libXxf86vm.so.1 \ - $(SNAPROOT)/lib/libsndfile.so.1 \ - $(SNAPROOT)/lib/libasyncns.so.0 \ - $(SNAPROOT)/lib/libFLAC.so.8 \ - $(SNAPROOT)/lib/libogg.so.0 \ - $(SNAPROOT)/lib/libvorbisenc.so.2 \ - $(SNAPROOT)/lib/libvorbis.so.0 \ - $(SNAPROOT)/lib/libsensors.so.4 \ - $(SNAPROOT)/lib/libpciaccess.so.0 \ - $(SNAPROOT)/lib/mesa/libGL.so.1 \ - $(SNAPROOT)/lib/mesa/dri/i915_dri.so \ - $(SNAPROOT)/lib/mesa/dri/i965_dri.so \ - $(SNAPROOT)/lib/mesa/dri/kms_swrast_dri.so \ - $(SNAPROOT)/lib/mesa/dri/nouveau_dri.so \ - $(SNAPROOT)/lib/mesa/dri/nouveau_vieux_dri.so \ - $(SNAPROOT)/lib/mesa/dri/r200_dri.so \ - $(SNAPROOT)/lib/mesa/dri/r300_dri.so \ - $(SNAPROOT)/lib/mesa/dri/r600_dri.so \ - $(SNAPROOT)/lib/mesa/dri/radeon_dri.so \ - $(SNAPROOT)/lib/mesa/dri/radeonsi_dri.so \ - $(SNAPROOT)/lib/mesa/dri/swrast_dri.so \ - $(SNAPROOT)/lib/mesa/dri/virtio_gpu_dri.so \ - $(SNAPROOT)/lib/mesa/dri/vmwgfx_dri.so \ - $(SNAPROOT)/lib/pulseaudio/libpulsecommon-8.0.so \ $(SNAPROOT)/meta/snap.yaml: support/snap.yaml @mkdir -p $(dir $@) @@ -138,18 +89,10 @@ $(SNAPROOT)/lib/%: /usr/lib/x86_64-linux-gnu/% @mkdir -p $(dir $@) cp $< $@ -$(SNAPROOT)/lib/mesa/dri/%.so: /usr/lib/x86_64-linux-gnu/dri/%.so - @mkdir -p $(dir $@) - cp $< $@ - $(SNAPROOT)/bin/movian: $(BUILDDIR)/movian.sbundle @mkdir -p $(dir $@) cp $< $@ -$(SNAPROOT)/bin/xdg-user-dir: /usr/bin/xdg-user-dir - @mkdir -p $(dir $@) - cp $< $@ - $(SNAPROOT)/command-movian.wrapper: support/command-movian.wrapper @mkdir -p $(dir $@) cp $< $@ diff --git a/support/command-movian.wrapper b/support/command-movian.wrapper index 01d6eec6b4..545e26ffb5 100755 --- a/support/command-movian.wrapper +++ b/support/command-movian.wrapper @@ -1,7 +1,8 @@ #!/bin/bash -export PATH="$SNAP/bin:$PATH" -export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$SNAP/lib:$SNAP/lib/pulseaudio:$SNAP/lib/mesa:$SNAP/lib/dri" -export LD_LIBRARY_PATH=$SNAP_LIBRARY_PATH:$LD_LIBRARY_PATH -export LIBGL_DRIVERS_PATH=$SNAP/lib/mesa/dri +export PATH="$SNAP/bin:$SNAP/gnome-platform/usr/bin:$PATH" +export LD_LIBRARY_PATH="$SNAP_LIBRARY_PATH:$SNAP/gnome-platform/usr/lib/x86_64-linux-gnu:$SNAP/gnome-platform/usr/lib/x86_64-linux-gnu/mesa:$SNAP/gnome-platform/usr/lib/x86_64-linux-gnu/pulseaudio:$SNAP/lib" +export LIBGL_DRIVERS_PATH="$SNAP/gnome-platform/usr/lib/x86_64-linux-gnu/dri" +export XLOCALEDIR="$SNAP/gnome-platform/usr/share/X11/locale" +export XCURSOR_PATH="$SNAP/gnome-platform/usr/share/icons" export HOME=`getent passwd $UID | cut -d ':' -f 6` exec "$SNAP/bin/movian" "$@" diff --git a/support/snap.yaml b/support/snap.yaml index 513e0dfb81..a5f5822a48 100644 --- a/support/snap.yaml +++ b/support/snap.yaml @@ -5,6 +5,11 @@ architectures: - amd64 confinement: strict grade: stable +plugs: + gnome-3-26-1604: + default-provider: gnome-3-26-1604 + interface: content + target: $SNAP/gnome-platform apps: movian: command: command-movian.wrapper From dadb94b1c8c650a2c2b25d85d9640b03048c0f7b Mon Sep 17 00:00:00 2001 From: czz78 Date: Sun, 30 Dec 2018 12:48:10 +0100 Subject: [PATCH 17/17] Update libcec.c Add support for libcec >= 4 --- src/ipc/libcec.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 3 deletions(-) diff --git a/src/ipc/libcec.c b/src/ipc/libcec.c index abd6ca2fe6..0dfe3314cb 100644 --- a/src/ipc/libcec.c +++ b/src/ipc/libcec.c @@ -31,6 +31,7 @@ static int longpress_select; static libcec_configuration cec_config; static libcec_connection_t conn; +#if CEC_LIB_VERSION_MAJOR < 4 static int log_message(void *lib, const cec_log_message message) { @@ -54,6 +55,31 @@ log_message(void *lib, const cec_log_message message) TRACE(level, "CEC", "%s", message.message); return 1; } +#else +static void +log_message(void *lib, const cec_log_message *message) +{ + int level; + switch (message->level) { + case CEC_LOG_ERROR: + level = TRACE_ERROR; + break; + + case CEC_LOG_WARNING: + case CEC_LOG_NOTICE: + level = TRACE_INFO; + break; + + default: + if(!gconf.enable_cec_debug) + return; + level = TRACE_DEBUG; + break; + } + TRACE(level, "CEC", "%s", message->message); + return; +} +#endif #define AVEC(x...) (const action_type_t []){x, ACTION_NONE} @@ -80,13 +106,13 @@ const static action_type_t *btn_to_action[256] = { [CEC_USER_CONTROL_CODE_CHANNEL_DOWN]= AVEC(ACTION_PREV_CHANNEL), [CEC_USER_CONTROL_CODE_F1_BLUE] = AVEC(ACTION_SYSINFO), - [CEC_USER_CONTROL_CODE_F2_RED] = AVEC(ACTION_SWITCH_VIEW), [CEC_USER_CONTROL_CODE_F4_YELLOW] = AVEC(ACTION_SHOW_MEDIA_STATS), [CEC_USER_CONTROL_CODE_SUB_PICTURE] = AVEC(ACTION_CYCLE_SUBTITLE), }; +#if CEC_LIB_VERSION_MAJOR < 4 static int keypress(void *aux, const cec_keypress kp) { @@ -127,7 +153,48 @@ keypress(void *aux, const cec_keypress kp) } return 1; } +#else +static void +keypress(void *aux, const cec_keypress *kp) +{ + event_t *e = NULL; + if(gconf.enable_cec_debug) + TRACE(TRACE_DEBUG, "CEC", "Got keypress code=0x%x duration=0x%x", + kp->keycode, kp->duration); + + if(longpress_select) { + if(kp->keycode == CEC_USER_CONTROL_CODE_SELECT) { + if(kp->duration == 0) + return; + + if(kp->duration < 500) + e = event_create_action(ACTION_ACTIVATE); + else + e = event_create_action(ACTION_ITEMMENU); + } + } + if(e == NULL) { + const action_type_t *avec = NULL; + if(kp->duration == 0 || kp->keycode == cec_config.comboKey) { + avec = btn_to_action[kp->keycode]; + } + + if(avec != NULL) { + int i = 0; + while(avec[i] != 0) + i++; + e = event_create_action_multi(avec, i); + } + } + + if(e != NULL) { + e->e_flags |= EVENT_KEYPRESS; + event_to_ui(e); + } + return; +} +#endif static void source_activated(void *aux, const cec_logical_address la, const uint8_t on) @@ -136,7 +203,7 @@ source_activated(void *aux, const cec_logical_address la, const uint8_t on) la, on ? "active" : "inactive"); } - +#if CEC_LIB_VERSION_MAJOR < 4 static int handle_cec_command(void *aux, const cec_command cmd) { @@ -151,13 +218,35 @@ handle_cec_command(void *aux, const cec_command cmd) } return 1; } - +#else +static void +handle_cec_command(void *aux, const cec_command *cmd) +{ + switch(cmd->opcode) { + case CEC_OPCODE_STANDBY: + if(cmd->initiator == CECDEVICE_TV) { + TRACE(TRACE_INFO, "CEC", "TV STANDBY"); + } + break; + default: + break; + } + return; +} +#endif static ICECCallbacks g_callbacks = { +#if CEC_LIB_VERSION_MAJOR < 4 .CBCecLogMessage = log_message, .CBCecKeyPress = keypress, .CBCecSourceActivated = source_activated, .CBCecCommand = handle_cec_command, +#else + .logMessage = log_message, + .keyPress = keypress, + .sourceActivated = source_activated, + .commandReceived = handle_cec_command, +#endif };