Пример #1
0
bool CAddonDatabase::GetAddon(int id, AddonPtr& addon)
{
  try
  {
    if (NULL == m_pDB.get()) return false;
    if (NULL == m_pDS2.get()) return false;

    CStdString sql = PrepareSQL("select * from addon where id=%i",id);
    m_pDS2->query(sql.c_str());
    if (!m_pDS2->eof())
    {
      AddonProps props(m_pDS2->fv("addonID" ).get_asString(),
                       TranslateType(m_pDS2->fv("type").get_asString()),
                       m_pDS2->fv("version").get_asString());
      props.name = m_pDS2->fv("name").get_asString();
      props.summary = m_pDS2->fv("summary").get_asString();
      props.description = m_pDS2->fv("description").get_asString();
      props.changelog = m_pDS2->fv("changelog").get_asString();
      props.path = m_pDS2->fv("path").get_asString();
      props.icon = m_pDS2->fv("icon").get_asString();
      props.fanart = m_pDS2->fv("fanart").get_asString();
      props.author = m_pDS2->fv("author").get_asString();
      props.disclaimer = m_pDS2->fv("disclaimer").get_asString();
      sql = PrepareSQL("select reason from broken where addonID='%s'",props.id.c_str());
      m_pDS2->query(sql.c_str());
      if (!m_pDS2->eof())
        props.broken = m_pDS2->fv(0).get_asString();

      sql = PrepareSQL("select key,value from addonextra where id=%i", id);
      m_pDS2->query(sql.c_str());
      while (!m_pDS2->eof())
      {
        props.extrainfo.insert(make_pair(m_pDS2->fv(0).get_asString(), m_pDS2->fv(1).get_asString()));
        m_pDS2->next();
      }

      addon = CAddonMgr::AddonFromProps(props);
      return NULL != addon.get();
    }
  }
  catch (...)
  {
    CLog::Log(LOGERROR, "%s failed on addon %i", __FUNCTION__, id);
  }
  addon.reset();
  return false;
}
Пример #2
0
JSONRPC_STATUS CAddonsOperations::ExecuteAddon(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
{
    string id = parameterObject["addonid"].asString();
    AddonPtr addon;
    if (!CAddonMgr::GetInstance().GetAddon(id, addon) || addon.get() == NULL ||
            addon->Type() < ADDON_SKIN || addon->Type() >= ADDON_MAX)
        return InvalidParams;

    string argv;
    CVariant params = parameterObject["params"];
    if (params.isObject())
    {
        for (CVariant::const_iterator_map it = params.begin_map(); it != params.end_map(); it++)
        {
            if (it != params.begin_map())
                argv += ",";
            argv += it->first + "=" + it->second.asString();
        }
    }
    else if (params.isArray())
    {
        for (CVariant::const_iterator_array it = params.begin_array(); it != params.end_array(); it++)
        {
            if (it != params.begin_array())
                argv += ",";
            argv += StringUtils::Paramify(it->asString());
        }
    }
    else if (params.isString())
    {
        if (!params.empty())
            argv = StringUtils::Paramify(params.asString());
    }

    std::string cmd;
    if (params.size() == 0)
        cmd = StringUtils::Format("RunAddon(%s)", id.c_str());
    else
        cmd = StringUtils::Format("RunAddon(%s, %s)", id.c_str(), argv.c_str());

    if (params["wait"].asBoolean())
        CApplicationMessenger::GetInstance().SendMsg(TMSG_EXECUTE_BUILT_IN, -1, -1, nullptr, cmd);
    else
        CApplicationMessenger::GetInstance().PostMsg(TMSG_EXECUTE_BUILT_IN, -1, -1, nullptr, cmd);

    return ACK;
}
Пример #3
0
void CAddonsOperations::FillDetails(AddonPtr addon, const CVariant& fields, CVariant &result, CAddonDatabase &addondb, bool append /* = false */)
{
  if (addon.get() == NULL)
    return;

  CVariant addonInfo = Serialize(addon);

  CVariant object;
  object["addonid"] = addonInfo["addonid"];
  object["type"] = addonInfo["type"];

  for (unsigned int index = 0; index < fields.size(); index++)
  {
    std::string field = fields[index].asString();

    // we need to manually retrieve the enabled / installed state of every addon
    // from the addon database because it can't be read from addon.xml
    if (field == "enabled")
    {
      object[field] = !CServiceBroker::GetAddonMgr().IsAddonDisabled(addon->ID());
    }
    else if (field == "installed")
    {
      object[field] = CServiceBroker::GetAddonMgr().IsAddonInstalled(addon->ID());
    }
    else if (field == "fanart" || field == "thumbnail")
    {
      std::string url = addonInfo[field].asString();
      // We need to check the existence of fanart and thumbnails as the addon simply
      // holds where the art will be, not whether it exists.
      bool needsRecaching;
      std::string image = CTextureCache::GetInstance().CheckCachedImage(url, needsRecaching);
      if (!image.empty() || CFile::Exists(url))
        object[field] = CTextureUtils::GetWrappedImageURL(url);
      else
        object[field] = "";
    }
    else if (addonInfo.isMember(field))
      object[field] = addonInfo[field];
  }

  if (append)
    result.append(object);
  else
    result = object;
}
Пример #4
0
bool CAddonInstaller::CheckDependencies(const AddonPtr &addon,
                                        std::vector<std::string>& preDeps, CAddonDatabase &database)
{
  if (!addon.get())
    return true; // a NULL addon has no dependencies
  ADDONDEPS deps = addon->GetDeps();
  database.Open();
  for (ADDONDEPS::const_iterator i = deps.begin(); i != deps.end(); ++i)
  {
    const CStdString &addonID = i->first;
    const AddonVersion &version = i->second.first;
    bool optional = i->second.second;
    AddonPtr dep;
    bool haveAddon = CAddonMgr::Get().GetAddon(addonID, dep);
    if ((haveAddon && !dep->MeetsVersion(version)) || (!haveAddon && !optional))
    { // we have it but our version isn't good enough, or we don't have it and we need it
      if (!database.GetAddon(addonID, dep) || !dep->MeetsVersion(version))
      { // we don't have it in a repo, or we have it but the version isn't good enough, so dep isn't satisfied.
        CLog::Log(LOGDEBUG, "Addon %s requires %s version %s which is not available", addon->ID().c_str(), addonID.c_str(), version.c_str());
        database.Close();
        return false;
      }
    }
    // at this point we have our dep, or the dep is optional (and we don't have it) so check that it's OK as well
    // TODO: should we assume that installed deps are OK?
    if (dep && std::find(preDeps.begin(), preDeps.end(), dep->ID()) == preDeps.end())
    {
      if (!CheckDependencies(dep, preDeps, database))
      {
        database.Close();
        return false;
      }
      preDeps.push_back(dep->ID());
    }
  }
  database.Close();
  return true;
}
Пример #5
0
bool CAddonDatabase::GetAddon(int id, AddonPtr &addon)
{
  try
  {
    if (NULL == m_pDB.get()) return false;
    if (NULL == m_pDS2.get()) return false;

    std::string sql = "SELECT addon.*,"
                      "       broken.reason,"
                      "       addonextra.key, addonextra.value,"
                      "       dependencies.addon, dependencies.version, dependencies.optional"
                      "  FROM addon"
                      "    LEFT JOIN broken"
                      "      ON broken.addonID = addon.addonID"
                      "    LEFT JOIN addonextra"
                      "      ON addonextra.id = addon.id"
                      "    LEFT JOIN dependencies"
                      "      ON dependencies.id = addon.id";

    sql += PrepareSQL(" WHERE addon.id=%i", id);

    m_pDS2->query(sql.c_str());
    if (!m_pDS2->eof())
    {
      const dbiplus::query_data &data = m_pDS2->get_result_set().records;
      const dbiplus::sql_record* const record = data[0];
      AddonProps props(record->at(addon_addonID).get_asString(),
                       TranslateType(record->at(addon_type).get_asString()),
                       record->at(addon_version).get_asString(),
                       record->at(addon_minversion).get_asString());
      props.name = record->at(addon_name).get_asString();
      props.summary = record->at(addon_summary).get_asString();
      props.description = record->at(addon_description).get_asString();
      props.changelog = record->at(addon_changelog).get_asString();
      props.path = record->at(addon_path).get_asString();
      props.icon = record->at(addon_icon).get_asString();
      props.fanart = record->at(addon_fanart).get_asString();
      props.author = record->at(addon_author).get_asString();
      props.disclaimer = record->at(addon_disclaimer).get_asString();
      props.broken = record->at(broken_reason).get_asString();

      /* while this is a cartesion join and we'll typically get multiple rows, we rely on the fact that
         extrainfo and dependencies are maps, so insert() will insert the first instance only */
      for (dbiplus::query_data::const_iterator i = data.begin(); i != data.end(); ++i)
      {
        const dbiplus::sql_record* const record = *i;
        if (!record->at(addonextra_key).get_asString().empty())
          props.extrainfo.insert(make_pair(record->at(addonextra_key).get_asString(), record->at(addonextra_value).get_asString()));
        if (!m_pDS2->fv(dependencies_addon).get_asString().empty())
          props.dependencies.insert(make_pair(record->at(dependencies_addon).get_asString(), make_pair(AddonVersion(record->at(dependencies_version).get_asString()), record->at(dependencies_optional).get_asBool())));
      }

      addon = CAddonMgr::AddonFromProps(props);
      return NULL != addon.get();
    }
  }
  catch (...)
  {
    CLog::Log(LOGERROR, "%s failed on addon %i", __FUNCTION__, id);
  }
  addon.reset();
  return false;
}
Пример #6
0
bool CAddonDatabase::GetAddon(int id, AddonPtr &addon)
{
  try
  {
    if (NULL == m_pDB.get()) return false;
    if (NULL == m_pDS2.get()) return false;

    std::string sql = "SELECT addon.*,"
                      "       broken.reason,"
                      "       addonextra.key, addonextra.value,"
                      "       dependencies.addon, dependencies.version, dependencies.optional"
                      "  FROM addon"
                      "    LEFT JOIN broken"
                      "      ON broken.addonID = addon.addonID"
                      "    LEFT JOIN addonextra"
                      "      ON addonextra.id = addon.id"
                      "    LEFT JOIN dependencies"
                      "      ON dependencies.id = addon.id";

    sql += PrepareSQL(" WHERE addon.id=%i", id);

    m_pDS2->query(sql);
    if (!m_pDS2->eof())
    {
      const dbiplus::query_data &data = m_pDS2->get_result_set().records;
      const dbiplus::sql_record* const record = data[0];

      CAddonBuilder builder;
      builder.SetId(record->at(addon_addonID).get_asString());
      builder.SetType(TranslateType(record->at(addon_type).get_asString()));
      builder.SetVersion(AddonVersion(record->at(addon_version).get_asString()));
      builder.SetMinVersion(AddonVersion(record->at(addon_minversion).get_asString()));
      builder.SetName(record->at(addon_name).get_asString());
      builder.SetSummary(record->at(addon_summary).get_asString());
      builder.SetDescription(record->at(addon_description).get_asString());
      builder.SetChangelog(record->at(addon_changelog).get_asString());
      builder.SetDisclaimer(record->at(addon_disclaimer).get_asString());
      builder.SetAuthor(record->at(addon_author).get_asString());
      builder.SetBroken(record->at(broken_reason).get_asString());
      builder.SetPath(record->at(addon_path).get_asString());
      builder.SetIcon(record->at(addon_icon).get_asString());
      builder.SetFanart(record->at(addon_fanart).get_asString());

      InfoMap extrainfo;
      ADDONDEPS dependencies;
      /* while this is a cartesion join and we'll typically get multiple rows, we rely on the fact that
         extrainfo and dependencies are maps, so insert() will insert the first instance only */
      for (dbiplus::query_data::const_iterator i = data.begin(); i != data.end(); ++i)
      {
        const dbiplus::sql_record* const record = *i;
        if (!record->at(addonextra_key).get_asString().empty())
          extrainfo.insert(std::make_pair(record->at(addonextra_key).get_asString(), record->at(addonextra_value).get_asString()));
        if (!m_pDS2->fv(dependencies_addon).get_asString().empty())
          dependencies.insert(std::make_pair(record->at(dependencies_addon).get_asString(), std::make_pair(AddonVersion(record->at(dependencies_version).get_asString()), record->at(dependencies_optional).get_asBool())));
      }
      builder.SetExtrainfo(std::move(extrainfo));
      builder.SetDependencies(std::move(dependencies));

      addon = builder.Build();
      return NULL != addon.get();
    }
  }
  catch (...)
  {
    CLog::Log(LOGERROR, "%s failed on addon %i", __FUNCTION__, id);
  }
  addon.reset();
  return false;
}
Пример #7
0
JSONRPC_STATUS CAddonsOperations::GetAddonDetails(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
{
  std::string id = parameterObject["addonid"].asString();
  AddonPtr addon;
  if (!CServiceBroker::GetAddonMgr().GetAddon(id, addon, ADDON::ADDON_UNKNOWN, false) || addon.get() == NULL ||
      addon->Type() <= ADDON_UNKNOWN || addon->Type() >= ADDON_MAX)
    return InvalidParams;

  CAddonDatabase addondb;
  FillDetails(addon, parameterObject["properties"], result["addon"], addondb);

  return OK;
}
Пример #8
0
bool CRetroPlayerDialogs::InstallGameClientDialog(const CFileItem &file, GameClientPtr &result)
{
  VECADDONS addons;
  CGameManager::GetAllGameClients(addons);

  map<string, GameClientPtr> candidates;
  for (VECADDONS::const_iterator itRemote = addons.begin(); itRemote != addons.end(); ++itRemote)
  {
    if (!(*itRemote)->IsType(ADDON_GAMEDLL))
      continue;
    GameClientPtr gc = boost::dynamic_pointer_cast<CGameClient>(*itRemote);

    // Only add game clients to the list if they provide extensions or platforms
    if (!gc || (gc->GetExtensions().empty() /* && gc->GetPlatforms().empty() */))
      continue;

    if (!gc->CanOpen(file))
      continue;

    // If the game client is already installed and enabled, exclude it from the list
    AddonPtr addon;
    if (CAddonMgr::Get().GetAddon(gc->ID(), addon, ADDON_GAMEDLL, true))
      continue;

    // If GetAddon() returns false, but addon is non-NULL, then the add-on exists but is disabled
    bool bEnabled = (addon.get() == NULL);

    bool bBroken = !(*itRemote)->Props().broken.empty();

    if (bEnabled && bBroken)
      continue;

    string strName = gc->Name();

    // Append "(Disabled)" to the name if the add-on is disabled
    if (!bEnabled)
      strName = StringUtils::Format("%s (%s)", strName.c_str(), g_localizeStrings.Get(1223).c_str());

    candidates[strName] = gc;
  }

  if (candidates.empty())
  {
    CLog::Log(LOGDEBUG, "RetroPlayer: No compatible game clients for installation");
    // "Playback failed"
    // "No compatible emulators found for file:"
    // "FILENAME"
    CGUIDialogOK::ShowAndGetInput(16026, 16023, URIUtils::GetFileName(file.GetPath()), 0);
    return false;
  }

  // CContextButtons doesn't support keying by string, only int, so use a
  // parallel array to track the string values (client name)
  CContextButtons choicesInt;
  unsigned int i = 0;

  // Vector to translate button IDs to game client pointers
  vector<string> choicesStr;
  for (map<string, GameClientPtr>::const_iterator it = candidates.begin(); it != candidates.end(); ++it)
  {
    const string& strName = it->first;
    choicesInt.Add(i++, strName);
    choicesStr.push_back(strName);
  }

  int btnid = CGUIDialogContextMenu::ShowAndGetChoice(choicesInt);
  if (btnid < 0 || btnid >= (int)candidates.size())
  {
    CLog::Log(LOGDEBUG, "RetroPlayer: User canceled game client installation selection");
    return false;
  }

  map<string, GameClientPtr>::iterator it = candidates.find(choicesStr[btnid]);
  if (it == candidates.end())
    return false; // Shouldn't happen

  GameClientPtr &gc = it->second;

  // determining disabled status is the same test as earlier
  // TODO: Preserve disabled values in parallel array
  // TODO: Don't use parallel arrays
  AddonPtr addon; // Return value, will be assigned to result
  bool disabled = !CAddonMgr::Get().GetAddon(gc->ID(), addon, ADDON_GAMEDLL, true) && addon;

  if (disabled)
  {
    // TODO: Prompt the user to enable it
    CLog::Log(LOGDEBUG, "RetroPlayer: Game client %s installed but disabled, enabling it", gc->ID().c_str());
    CGameManager::Get().ClearAutoLaunch(); // Don't auto-launch queued game when the add-on is enabled
    CAddonMgr::Get().DisableAddon(gc->ID(), false);

    // Retrieve the newly-enabled add-on
    if (!CAddonMgr::Get().GetAddon(gc->ID(), addon) || !addon)
      return false;
  }
  else
  {
    CLog::Log(LOGDEBUG, "RetroPlayer: Installing game client %s", gc->ID().c_str());
    bool success = CAddonInstaller::Get().PromptForInstall(gc->ID(), addon);
    if (!success || !addon || addon->Type() != ADDON_GAMEDLL)
    {
      CLog::Log(LOGDEBUG, "RetroPlayer: Game client installation failed");
      // "id"
      // "Installation failed"
      // "Check the log file for details."
      CGUIDialogOK::ShowAndGetInput(gc->ID().c_str(), 114, 16029, 0);
      return false;
    }
  }

  GameClientPtr gameClient = boost::dynamic_pointer_cast<CGameClient>(addon);
  if (!gameClient)
  {
    CLog::Log(LOGERROR, "RetroPlayer: Add-on was not a game client!");
    return false;
  }

  result = gameClient;
  return true;
}