diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | README | 11 | ||||
-rw-r--r-- | config.c | 23 | ||||
-rw-r--r-- | config.h | 6 | ||||
-rw-r--r-- | libcore/helpers.c | 2 | ||||
-rw-r--r-- | libcore/skinrepo.c | 255 | ||||
-rw-r--r-- | libcore/skinrepo.h | 67 | ||||
-rw-r--r-- | skindesigner.c | 10 | ||||
-rw-r--r-- | skins/skinrepositories.xml | 32 |
9 files changed, 400 insertions, 7 deletions
@@ -74,6 +74,7 @@ OBJS = $(PLUGIN).o \ libcore/imageloader.o \ libcore/recfolderinfo.o \ libcore/skinsetup.o \ + libcore/skinrepo.o \ libcore/extrecinfo.o \ libcore/timers.o \ libtemplate/globals.o \ @@ -65,7 +65,12 @@ After installation you have to care about the paths for the XML skins and epg im The following paths can be set at startup: -s <SKINPATH>, --skinpath=<SKINPATH> - Path to the XML skins (Default: <ResourceDirectory>/plugins/skindesigner/skins/) + Path where XML skins get installed by "make install" or by package manager + (Default: <ResourceDirectory>/plugins/skindesigner/skins/) + +-i <INSTALLERPATH>, --installerpath=<INSTALLERPATH> + Path where XML skins are installed by the Skindesigner Installer + (Default: <ConfigDirectory>/plugins/skindesigner/installerskins/) -l <LOGOPATH>, --logopath=<LOGOPATH> Path to common logo set for all skins (Default: <ResourceDirectory>/plugins/skindesigner/logos/) @@ -73,11 +78,11 @@ The following paths can be set at startup: -e path, --epgimages=path Path to the epgimages (Default: <CacheDirectory>/epgimages/) -ResourceDirectory and CacheDirectory are taken from your VDR configuration +ResourceDirectory, ConfigDirectory and CacheDirectory are taken from your VDR configuration (make.config or vdr.pc). During a "make install" the included skins are automatically copied from -<SkinSourceDirectory>/skins/ to the configured path. +<SkinSourceDirectory>/skins/ to the configured skin path. For S2-6400 Users: Disable High Level OSD, otherwise the plugin will not be loaded because lack of true color support @@ -6,6 +6,7 @@ cDesignerConfig::cDesignerConfig() { tmplGlobals = NULL; epgImagePathSet = false; skinPathSet = false; + installerSkinPathSet = false; logoPathSet = false; //Common numLogosPerSizeInitial = 30; @@ -37,12 +38,15 @@ cDesignerConfig::~cDesignerConfig() { void cDesignerConfig::SetPathes(void) { if (!skinPathSet) skinPath = cString::sprintf("%s/skins/", cPlugin::ResourceDirectory(PLUGIN_NAME_I18N)); + if (!installerSkinPathSet) + installerSkinPath = cString::sprintf("%s/installerskins/", cPlugin::ConfigDirectory(PLUGIN_NAME_I18N)); if (!logoPathSet) logoPath = cString::sprintf("%s/logos/", cPlugin::ResourceDirectory(PLUGIN_NAME_I18N)); if (!epgImagePathSet) epgImagePath = cString::sprintf("%s/epgimages/", cPlugin::CacheDirectory(PLUGIN_NAME_I18N)); dsyslog("skindesigner: using Skin Directory %s", *skinPath); + dsyslog("skindesigner: using Installer Skin Directory %s", *installerSkinPath); dsyslog("skindesigner: using common ChannelLogo Directory %s", *logoPath); dsyslog("skindesigner: using EPG Images Directory %s", *epgImagePath); } @@ -52,6 +56,11 @@ void cDesignerConfig::SetSkinPath(cString path) { skinPathSet = true; } +void cDesignerConfig::SetInstallerSkinPath(cString path) { + installerSkinPath = CheckSlashAtEnd(*path); + installerSkinPathSet = true; +} + void cDesignerConfig::SetLogoPath(cString path) { logoPath = CheckSlashAtEnd(*path); logoPathSet = true; @@ -141,7 +150,6 @@ cSkinSetupMenu* cDesignerConfig::GetSkinSetupMenu(string &skin, string &menu) { cSkinSetup *skinSetup = GetSkinSetup(skin); if (!skinSetup) return NULL; - esyslog("skindesigner: skinsetup found"); return skinSetup->GetMenu(menu); } @@ -195,6 +203,19 @@ void cDesignerConfig::SetSkinSetupParameters(void) { } } +void cDesignerConfig::ReadSkinRepos(void) { + skinRepos.Read(*skinPath); + skinRepos.Debug(); + /* + cSkinRepo *holo = skinRepos.GetRepo("Holo"); + if (holo) { + esyslog("skindesigner: installing Holo"); + holo->Install(*installerSkinPath); + } + */ +} + + void cDesignerConfig::UpdateGlobals(void) { string activeSkin = Setup.OSDSkin; cSkinSetup *skinSetupActiveSkin = GetSkinSetup(activeSkin); @@ -11,6 +11,7 @@ #include "libcore/imagecache.h" #include "libcore/recfolderinfo.h" #include "libcore/skinsetup.h" +#include "libcore/skinrepo.h" #define SCRIPTOUTPUTPATH "/tmp/skindesigner" @@ -19,6 +20,7 @@ private: cString CheckSlashAtEnd(string path); bool epgImagePathSet; bool skinPathSet; + bool installerSkinPathSet; bool logoPathSet; cRect osdSize; string osdSkin; @@ -40,12 +42,14 @@ private: map < string, cSkinSetup* > skinSetups; map < string, cSkinSetup* >::iterator setupIt; vector < pair <string, int> > skinSetupParameters; + cSkinRepos skinRepos; public: cDesignerConfig(); ~cDesignerConfig(); bool SetupParse(const char *Name, const char *Value); void SetPathes(void); void SetSkinPath(cString path); + void SetInstallerSkinPath(cString path); void SetLogoPath(cString path); void SetEpgImagePath(cString path); void ReadSkins(void); @@ -62,6 +66,7 @@ public: void TranslateSetup(void); void SetSkinSetupParameters(void); void UpdateSkinSetupParameter(string name, int value); + void ReadSkinRepos(void); void SetGlobals(cGlobals *globals) { tmplGlobals = globals; }; void UpdateGlobals(void); void CheckDecimalPoint(void); @@ -84,6 +89,7 @@ public: int GetPluginViewElementID(string pluginName, string viewElementName, int viewID); int GetPluginViewGridID(string pluginName, string viewGridName, int viewID); cString skinPath; + cString installerSkinPath; cString logoPath; cString epgImagePath; bool replaceDecPoint; diff --git a/libcore/helpers.c b/libcore/helpers.c index add1f7a..6aef313 100644 --- a/libcore/helpers.c +++ b/libcore/helpers.c @@ -1,6 +1,7 @@ #include <string> #include <sstream> #include <vector> +#include <stdlib.h> #include "helpers.h" #include <vdr/skins.h> @@ -245,4 +246,3 @@ string GetScreenAspectString(double aspect, bool *isWideScreen) { } return name; } - diff --git a/libcore/skinrepo.c b/libcore/skinrepo.c new file mode 100644 index 0000000..1d5e3e4 --- /dev/null +++ b/libcore/skinrepo.c @@ -0,0 +1,255 @@ +#include "skinrepo.h" +#include "../libcore/helpers.h" + +using namespace std; + +// --- cSkinRepo ------------------------------------------------------------- + +cSkinRepo::cSkinRepo(void) { + name = ""; + repoType = rtUndefined; + url = ""; + command = ""; + tempfile = ""; + result = -1; +} + +cSkinRepo::~cSkinRepo() { +} + +void cSkinRepo::Install(string path) { + if (Running()) + return; + if (repoType == rtGit) { + + command = *cString::sprintf("git clone --progress %s %s%s", url.c_str(), path.c_str(), name.c_str()); + tempfile = *cString::sprintf("gitclone_%s_%ld.out", name.c_str(), time(0)); + + Start(); + + } else if (repoType == rtZipUrl) { + + //TODO + + } +} + +void cSkinRepo::Action(void) { + if (command.size() < 1) + return; + if (tempfile.size() > 0) { + command = *cString::sprintf("%s > /tmp/%s 2>&1", command.c_str(), tempfile.c_str()); + } + dsyslog("skindesigner: executing %s", command.c_str()); + result = system (command.c_str()); + dsyslog("skindesigner: execution done, result: %d", result); +} + +void cSkinRepo::Debug() { + string strRepoType = "Undefined"; + if (repoType == rtGit) + strRepoType = "Git"; + else if (repoType == rtZipUrl) + strRepoType = "ZipUrl"; + dsyslog("skindesigner: --- skinrepo %s, Type %s ---", name.c_str(), strRepoType.c_str()); + dsyslog("skindesigner: url %s", url.c_str()); + if (specialFonts.size() > 0) { + for (vector<string>::iterator it = specialFonts.begin(); it != specialFonts.end(); it++) { + dsyslog("skindesigner: special font %s", (*it).c_str()); + } + } + if (supportedPlugins.size() > 0) { + for (vector<string>::iterator it = supportedPlugins.begin(); it != supportedPlugins.end(); it++) { + dsyslog("skindesigner: supported plugin %s", (*it).c_str()); + } + } + if (screenshots.size() > 0) { + for (vector<pair<string,string> >::iterator it = screenshots.begin(); it != screenshots.end(); it++) { + string desc = (it->first).c_str(); + string url = (it->second).c_str(); + dsyslog("skindesigner: screenshot \"%s\", url %s", desc.c_str(), url.c_str()); + } + } +} + +// --- cSkinRepos ------------------------------------------------------------- + +cSkinRepos::cSkinRepos(void) { + repoFile = "skinrepositories.xml"; + doc = NULL; +} + +cSkinRepos::~cSkinRepos() { + for (vector<cSkinRepo*>::iterator it = repos.begin(); it != repos.end(); it++) { + delete (*it); + } +} + +void cSkinRepos::Read(string path) { + string filepath = path + repoFile; + esyslog("skindesigner: reading skinrepos from %s", filepath.c_str()); + xmlParserCtxtPtr ctxt = xmlNewParserCtxt(); + xmlNodePtr root = NULL; + + doc = xmlCtxtReadFile(ctxt, filepath.c_str(), NULL, XML_PARSE_NOENT); + if (doc == NULL) { + esyslog("skindesigner: ERROR: skinrepository file %s not loaded successfully.", filepath.c_str()); + return; + } + + root = xmlDocGetRootElement(doc); + if (root == NULL) { + return; + } + + if (xmlStrcmp(root->name, (const xmlChar *) "skinrepositories")) { + return; + } + + xmlNodePtr node = root->xmlChildrenNode; + while (node != NULL) { + if (node->type != XML_ELEMENT_NODE) { + node = node->next; + continue; + } + if (xmlStrcmp(node->name, (const xmlChar *) "skinrepo")) { + continue; + } + ReadRepository(node->xmlChildrenNode); + node = node->next; + } + + if (doc) xmlFreeDoc(doc); + xmlFreeParserCtxt(ctxt); +} + +cSkinRepo *cSkinRepos::GetRepo(string name) { + for (vector<cSkinRepo*>::iterator it = repos.begin(); it != repos.end(); it++) { + cSkinRepo *repo = (*it); + if (!name.compare(repo->Name())) + return repo; + } + return NULL; +} + + +void cSkinRepos::Debug(void) { + for (vector<cSkinRepo*>::iterator it = repos.begin(); it != repos.end(); it++) { + (*it)->Debug(); + } +} + +void cSkinRepos::ReadRepository(xmlNodePtr node) { + if (!node) + return; + cSkinRepo *repo = new cSkinRepo(); + while (node != NULL) { + if (node->type != XML_ELEMENT_NODE) { + node = node->next; + continue; + } + + xmlChar *value = NULL; + //Repo Name + if (!xmlStrcmp(node->name, (const xmlChar *) "name")) { + value = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if (value) + repo->SetName((const char *)value); + //Repo Type + } else if (!xmlStrcmp(node->name, (const xmlChar *) "type")) { + value = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if (value) { + eRepoType repoType = rtUndefined; + if (!xmlStrcmp(value, (const xmlChar *) "git")) + repoType = rtGit; + else if (!xmlStrcmp(value, (const xmlChar *) "zip")) + repoType = rtZipUrl; + repo->SetRepoType(repoType); + } + //Repo URL + } else if (!xmlStrcmp(node->name, (const xmlChar *) "url")) { + value = xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + if (value) + repo->SetUrl((const char *)value); + //Repo Specialfonts + } else if (!xmlStrcmp(node->name, (const xmlChar *) "specialfonts")) { + xmlNodePtr child = node->xmlChildrenNode; + while (child != NULL) { + if (child->type != XML_ELEMENT_NODE) { + child = child->next; + continue; + } + if (!xmlStrcmp(child->name, (const xmlChar *) "font")) { + xmlChar *fontvalue = NULL; + fontvalue = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); + if (fontvalue) { + repo->SetSpecialFont((const char *)fontvalue); + xmlFree(fontvalue); + } + } + child = child->next; + } + //Repo supported Plugins + } else if (!xmlStrcmp(node->name, (const xmlChar *) "supportedplugins")) { + xmlNodePtr child = node->xmlChildrenNode; + while (child != NULL) { + if (child->type != XML_ELEMENT_NODE) { + child = child->next; + continue; + } + if (!xmlStrcmp(child->name, (const xmlChar *) "plugin")) { + xmlChar *plugvalue = NULL; + plugvalue = xmlNodeListGetString(doc, child->xmlChildrenNode, 1); + if (plugvalue) { + repo->SetSupportedPlugin((const char *)plugvalue); + xmlFree(plugvalue); + } + } + child = child->next; + } + //Repo Screenshots + } else if (!xmlStrcmp(node->name, (const xmlChar *) "screenshots")) { + xmlNodePtr child = node->xmlChildrenNode; + while (child != NULL) { + if (child->type != XML_ELEMENT_NODE) { + child = child->next; + continue; + } + if (!xmlStrcmp(child->name, (const xmlChar *) "screenshot")) { + xmlNodePtr subchild = child->xmlChildrenNode; + string desc = ""; + string url = ""; + while (subchild != NULL) { + if (subchild->type != XML_ELEMENT_NODE) { + subchild = subchild->next; + continue; + } + xmlChar *screenshotvalue = NULL; + if (!xmlStrcmp(subchild->name, (const xmlChar *) "description")) { + screenshotvalue = xmlNodeListGetString(doc, subchild->xmlChildrenNode, 1); + if (screenshotvalue) { + desc = (const char *)screenshotvalue; + xmlFree(screenshotvalue); + } + } else if (!xmlStrcmp(subchild->name, (const xmlChar *) "url")) { + screenshotvalue = xmlNodeListGetString(doc, subchild->xmlChildrenNode, 1); + if (screenshotvalue) { + url = (const char *)screenshotvalue; + xmlFree(screenshotvalue); + } + } + subchild = subchild->next; + } + repo->SetScreenshot(desc, url); + } + child = child->next; + } + } + if (value) + xmlFree(value); + node = node->next; + + } + repos.push_back(repo); +} + diff --git a/libcore/skinrepo.h b/libcore/skinrepo.h new file mode 100644 index 0000000..c3daaf0 --- /dev/null +++ b/libcore/skinrepo.h @@ -0,0 +1,67 @@ +#ifndef __SKINREPO_H +#define __SKINREPO_H + +#include <string> +#include <vector> +#include <map> +#include <set> +#include <libxml/parser.h> +#include <libxml/tree.h> +#include <libxml/xmlerror.h> +#include <vdr/plugin.h> + +using namespace std; + +enum eRepoType { + rtUndefined, + rtGit, + rtZipUrl +}; + +// --- cSkinRepo ------------------------------------------------------------- + +class cSkinRepo : public cThread { +private: + string name; + eRepoType repoType; + string url; + vector<string> specialFonts; + vector<string> supportedPlugins; + vector< pair < string, string > > screenshots; + //helpers for execution + string command; + string tempfile; + int result; + virtual void Action(void); +public: + cSkinRepo(void); + virtual ~cSkinRepo(void); + void SetName(string name) { this->name = name; }; + void SetRepoType(eRepoType type) { this->repoType = type; }; + void SetUrl(string url) { this->url = url; }; + void SetSpecialFont(string font) { specialFonts.push_back(font); }; + void SetSupportedPlugin(string plugin) { supportedPlugins.push_back(plugin); }; + void SetScreenshot(string desc, string url) { screenshots.push_back(pair<string, string>(desc, url)); }; + string Name(void) { return name; }; + void Install(string path); + bool InstallationFinished(void) { return !(Running()); }; + void Debug(void); +}; + +// --- cSkinRepos ------------------------------------------------------------- + +class cSkinRepos { +private: + string repoFile; + xmlDocPtr doc; + vector<cSkinRepo*> repos; + void ReadRepository(xmlNodePtr node); +public: + cSkinRepos(void); + virtual ~cSkinRepos(void); + void Read(string path); + cSkinRepo *GetRepo(string name); + void Debug(void); +}; + +#endif //__SKINREPO_H diff --git a/skindesigner.c b/skindesigner.c index a8aecae..cae0e6e 100644 --- a/skindesigner.c +++ b/skindesigner.c @@ -62,7 +62,8 @@ cPluginSkinDesigner::~cPluginSkinDesigner() { const char *cPluginSkinDesigner::CommandLineHelp(void) { return - " -s <SKINPATH>, --skinpath=<SKINPATH> Set directory where xml skins are stored\n" + " -s <SKINPATH>, --skinpath=<SKINPATH> Set directory where xml skins are stored by Package Manager\n" + " -i <INSTALLERPATH>, --installerpath=<INSTALLERPATH> Set directory where xml skins are stored by Installer\n" " -l <LOGOPATH>, --logopath=<LOGOPATH> Set directory where a common logo set for all skins is stored\n" " -e <EPGIMAGESPATH>, --epgimages=<IMAGESPATH> Set directory where epgimages are stored\n"; } @@ -73,11 +74,12 @@ bool cPluginSkinDesigner::ProcessArgs(int argc, char *argv[]) { { "epgimages", required_argument, NULL, 'e' }, { "logopath", required_argument, NULL, 'l' }, { "skinpath", required_argument, NULL, 's' }, + { "installerpath", required_argument, NULL, 'i' }, { 0, 0, 0, 0 } }; int c; - while ((c = getopt_long(argc, argv, "e:s:l:", long_options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "e:s:l:i:", long_options, NULL)) != -1) { switch (c) { case 'e': config.SetEpgImagePath(cString(optarg)); @@ -88,6 +90,9 @@ bool cPluginSkinDesigner::ProcessArgs(int argc, char *argv[]) { case 's': config.SetSkinPath(cString(optarg)); break; + case 'i': + config.SetInstallerSkinPath(cString(optarg)); + break; default: return false; } @@ -128,6 +133,7 @@ bool cPluginSkinDesigner::Start(void) { } config.TranslateSetup(); config.SetSkinSetupParameters(); + config.ReadSkinRepos(); if (skins.size() == 0) { esyslog("skindesigner: no skins found! Using default Skin LCARS!"); diff --git a/skins/skinrepositories.xml b/skins/skinrepositories.xml new file mode 100644 index 0000000..051471d --- /dev/null +++ b/skins/skinrepositories.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<skinrepositories> + <skinrepo> + <name>Holo</name> + <type>git</type> + <url>https://github.com/CReimer/Holo</url> + <specialfonts> + <font>Roboto</font> + <font>Gedöns</font> + </specialfonts> + </skinrepo> + <skinrepo> + <name>Tryouts</name> + <type>git</type> + <url>https://github.com/BooStars/tryouts</url> + <screenshots> + <screenshot> + <description>Main Menu</description> + <url>http://www.vdr-portal.de/index.php?page=AttachmentattachmentID=37054h=1e3680e599888c373fa21ad2fcbb9e4c2c73a620</url> + </screenshot> + <screenshot> + <description>display Channel</description> + <url>http://www.vdr-portal.de/index.php?page=AttachmentattachmentID=37056h=e7cd1c6d2bd8042b6c08629c8f5d4711e8196e5f</url> + </screenshot> + </screenshots> + <supportedplugins> + <plugin>Weatherforecast</plugin> + <plugin>TVGuideNG</plugin> + </supportedplugins> + </skinrepo> +</skinrepositories> |