int CGUIWindowAddonBrowser::SelectAddonID(const std::vector<ADDON::TYPE> &types, std::vector<std::string> &addonIDs, bool showNone /* = false */, bool showDetails /* = true */, bool multipleSelection /* = true */, bool showInstalled /* = true */, bool showInstallable /* = false */, bool showMore /* = true */) { // if we shouldn't show neither installed nor installable addons the list will be empty if (!showInstalled && !showInstallable) return 0; // can't show the "Get More" button if we already show installable addons if (showInstallable) showMore = false; CGUIDialogSelect *dialog = (CGUIDialogSelect*)g_windowManager.GetWindow(WINDOW_DIALOG_SELECT); if (!dialog) return 0; // get rid of any invalid addon types std::vector<ADDON::TYPE> validTypes(types.size()); std::copy_if(types.begin(), types.end(), validTypes.begin(), [](ADDON::TYPE type) { return type != ADDON_UNKNOWN; }); if (validTypes.empty()) return 0; // get all addons to show VECADDONS addons; if (showInstalled) { for (std::vector<ADDON::TYPE>::const_iterator type = validTypes.begin(); type != validTypes.end(); ++type) { VECADDONS typeAddons; if (*type == ADDON_AUDIO) CAddonsDirectory::GetScriptsAndPlugins("audio", typeAddons); else if (*type == ADDON_EXECUTABLE) CAddonsDirectory::GetScriptsAndPlugins("executable", typeAddons); else if (*type == ADDON_IMAGE) CAddonsDirectory::GetScriptsAndPlugins("image", typeAddons); else if (*type == ADDON_VIDEO) CAddonsDirectory::GetScriptsAndPlugins("video", typeAddons); else CAddonMgr::GetInstance().GetAddons(*type, typeAddons); addons.insert(addons.end(), typeAddons.begin(), typeAddons.end()); } } if (showInstallable || showMore) { VECADDONS installableAddons; CAddonDatabase database; if (database.Open() && database.GetAddons(installableAddons)) { for (ADDON::IVECADDONS addon = installableAddons.begin(); addon != installableAddons.end();) { AddonPtr pAddon = *addon; // check if the addon matches one of the provided addon types bool matchesType = false; for (std::vector<ADDON::TYPE>::const_iterator type = validTypes.begin(); type != validTypes.end(); ++type) { if (pAddon->IsType(*type)) { matchesType = true; break; } } // only show addons that match one of the provided addon types and that aren't disabled if (matchesType && !CAddonMgr::GetInstance().IsAddonDisabled(pAddon->ID())) { // check if the addon is installed bool isInstalled = CAddonMgr::GetInstance().IsAddonInstalled(pAddon->ID()); // check if the addon is installed or can be installed if ((showInstallable || showMore) && !isInstalled && CAddonMgr::GetInstance().CanAddonBeInstalled(pAddon)) { ++addon; continue; } } addon = installableAddons.erase(addon); } if (showInstallable) addons.insert(addons.end(), installableAddons.begin(), installableAddons.end()); else if (showMore) showMore = !installableAddons.empty(); } } if (addons.empty() && !showNone) return 0; // turn the addons into items std::map<std::string, AddonPtr> addonMap; CFileItemList items; for (ADDON::IVECADDONS addon = addons.begin(); addon != addons.end(); ++addon) { CFileItemPtr item(CAddonsDirectory::FileItemFromAddon(*addon, (*addon)->ID())); if (!items.Contains(item->GetPath())) { #if defined(TARGET_ANDROID) // only show "skin.re-touched" on fire tables and iOS. if ((*addon)->ID() == "skin.re-touched") { if (!CAndroidFeatures::HasTouchScreen()) continue; } #endif items.Add(item); addonMap.insert(std::make_pair(item->GetPath(), *addon)); } } if (items.IsEmpty() && !showNone) return 0; std::string heading; for (std::vector<ADDON::TYPE>::const_iterator type = validTypes.begin(); type != validTypes.end(); ++type) { if (!heading.empty()) heading += ", "; heading += TranslateType(*type, true); } dialog->SetHeading(CVariant{std::move(heading)}); dialog->Reset(); dialog->SetUseDetails(showDetails); if (multipleSelection) { showNone = false; showMore = false; dialog->EnableButton(true, 186); } else if (showMore) dialog->EnableButton(true, 21452); if (showNone) { CFileItemPtr item(new CFileItem("", false)); item->SetLabel(g_localizeStrings.Get(231)); item->SetLabel2(g_localizeStrings.Get(24040)); item->SetIconImage("DefaultAddonNone.png"); item->SetSpecialSort(SortSpecialOnTop); items.Add(item); } items.Sort(SortByLabel, SortOrderAscending); if (addonIDs.size() > 0) { for (std::vector<std::string>::const_iterator it = addonIDs.begin(); it != addonIDs.end() ; ++it) { CFileItemPtr item = items.Get(*it); if (item) item->Select(true); } } dialog->SetItems(items); dialog->SetMultiSelection(multipleSelection); dialog->Open(); // if the "Get More" button has been pressed and we haven't shown the // installable addons so far show a list of installable addons if (showMore&& dialog->IsButtonPressed()) return SelectAddonID(types, addonIDs, showNone, showDetails, multipleSelection, false, true, false); if (!dialog->IsConfirmed()) return 0; addonIDs.clear(); for (int i : dialog->GetSelectedItems()) { const CFileItemPtr& item = items.Get(i); // check if one of the selected addons needs to be installed if (showInstallable) { std::map<std::string, AddonPtr>::const_iterator itAddon = addonMap.find(item->GetPath()); if (itAddon != addonMap.end()) { const AddonPtr& addon = itAddon->second; // if the addon isn't installed we need to install it if (!CAddonMgr::GetInstance().IsAddonInstalled(addon->ID())) { AddonPtr installedAddon; if (!CAddonInstaller::GetInstance().InstallModal(addon->ID(), installedAddon, false)) continue; } // if the addon is disabled we need to enable it if (CAddonMgr::GetInstance().IsAddonDisabled(addon->ID())) CAddonMgr::GetInstance().EnableAddon(addon->ID()); } } addonIDs.push_back(item->GetPath()); } return 1; }
void CPVRDatabase::UpdateTables(int iVersion) { if (iVersion < 13) m_pDS->exec("ALTER TABLE channels ADD idEpg integer;"); if (iVersion < 20) m_pDS->exec("ALTER TABLE channels ADD bIsUserSetIcon bool"); if (iVersion < 21) m_pDS->exec("ALTER TABLE channelgroups ADD iGroupType integer"); if (iVersion < 22) m_pDS->exec("ALTER TABLE channels ADD bIsLocked bool"); if (iVersion < 23) m_pDS->exec("ALTER TABLE channelgroups ADD iLastWatched integer"); if (iVersion < 24) m_pDS->exec("ALTER TABLE channels ADD bIsUserSetName bool"); if (iVersion < 25) m_pDS->exec("DROP TABLE IF EXISTS channelsettings"); if (iVersion < 26) { m_pDS->exec("ALTER TABLE channels ADD iClientSubChannelNumber integer"); m_pDS->exec("UPDATE channels SET iClientSubChannelNumber = 0"); m_pDS->exec("ALTER TABLE map_channelgroups_channels ADD iSubChannelNumber integer"); m_pDS->exec("UPDATE map_channelgroups_channels SET iSubChannelNumber = 0"); } if (iVersion < 27) m_pDS->exec("ALTER TABLE channelgroups ADD bIsHidden bool"); if (iVersion < 28) { VECADDONS addons; CAddonDatabase database; if (database.Open() && CAddonMgr::Get().GetAddons(ADDON_PVRDLL, addons, true)) { /** find all old client IDs */ std::string strQuery(PrepareSQL("SELECT idClient, sUid FROM clients")); m_pDS->query(strQuery); while (!m_pDS->eof() && !addons.empty()) { /** try to find an add-on that matches the sUid */ for (VECADDONS::iterator it = addons.begin(); it != addons.end(); ++it) { if ((*it)->ID() == m_pDS->fv(1).get_asString()) { /** try to get the current ID from the database */ int iAddonId = database.GetAddonId(*it); /** register a new id if it didn't exist */ if (iAddonId <= 0) iAddonId = database.AddAddon(*it, 0); if (iAddonId > 0) { // this fails when an id becomes the id of one that's being replaced next iteration // but since almost everyone only has 1 add-on enabled... /** update the iClientId in the channels table */ strQuery = PrepareSQL("UPDATE channels SET iClientId = %u WHERE iClientId = %u", iAddonId, m_pDS->fv(0).get_asInt()); m_pDS->exec(strQuery); /** no need to check this add-on again */ it = addons.erase(it); break; } } } m_pDS->next(); } } m_pDS->exec("DROP TABLE clients"); } if (iVersion < 29) m_pDS->exec("ALTER TABLE channelgroups ADD iPosition integer"); }
bool CPVRClients::UpdateAndInitialiseClients(bool bInitialiseAllClients /* = false */) { bool bReturn(true); VECADDONS map; VECADDONS disableAddons; { CSingleLock lock(m_critSection); map = m_addons; } if (map.empty()) return false; for (VECADDONS::iterator it = map.begin(); it != map.end(); ++it) { bool bEnabled = (*it)->Enabled() && !CAddonMgr::GetInstance().IsAddonDisabled((*it)->ID()); if (!bEnabled && IsKnownClient(*it)) { CSingleLock lock(m_critSection); /* stop the client and remove it from the db */ StopClient(*it, false); disableAddons.push_back(*it); } else if (bEnabled && (bInitialiseAllClients || !IsKnownClient(*it) || !IsConnectedClient(*it))) { bool bDisabled(false); // register the add-on in the pvr db, and create the CPVRClient instance int iClientId = RegisterClient(*it); if (iClientId <= 0) { // failed to register or create the add-on, disable it CLog::Log(LOGWARNING, "%s - failed to register add-on %s, disabling it", __FUNCTION__, (*it)->Name().c_str()); disableAddons.push_back(*it); bDisabled = true; } else { ADDON_STATUS status(ADDON_STATUS_UNKNOWN); PVR_CLIENT addon; { CSingleLock lock(m_critSection); if (!GetClient(iClientId, addon)) { CLog::Log(LOGWARNING, "%s - failed to find add-on %s, disabling it", __FUNCTION__, (*it)->Name().c_str()); disableAddons.push_back(*it); bDisabled = true; } } // throttle connection attempts, no more than 1 attempt per 5 seconds if (!bDisabled && addon->Enabled()) { time_t now; CDateTime::GetCurrentDateTime().GetAsTime(now); std::map<int, time_t>::iterator it = m_connectionAttempts.find(iClientId); if (it != m_connectionAttempts.end() && now < it->second) continue; m_connectionAttempts[iClientId] = now + 5; } // re-check the enabled status. newly installed clients get disabled when they're added to the db if (!bDisabled && addon->Enabled() && (status = addon->Create(iClientId)) != ADDON_STATUS_OK) { CLog::Log(LOGWARNING, "%s - failed to create add-on %s, status = %d", __FUNCTION__, (*it)->Name().c_str(), status); if (!addon.get() || !addon->DllLoaded() || status == ADDON_STATUS_PERMANENT_FAILURE) { // failed to load the dll of this add-on, disable it CLog::Log(LOGWARNING, "%s - failed to load the dll for add-on %s, disabling it", __FUNCTION__, (*it)->Name().c_str()); disableAddons.push_back(*it); bDisabled = true; } } } if (bDisabled && (g_PVRManager.IsStarted() || g_PVRManager.IsInitialising())) CGUIDialogOK::ShowAndGetInput(CVariant{24070}, CVariant{16029}); } } // disable add-ons that failed to initialise if (!disableAddons.empty()) { CSingleLock lock(m_critSection); for (VECADDONS::iterator it = disableAddons.begin(); it != disableAddons.end(); ++it) { // disable in the add-on db CAddonMgr::GetInstance().DisableAddon((*it)->ID()); // remove from the pvr add-on list VECADDONS::iterator addonPtr = std::find(m_addons.begin(), m_addons.end(), *it); if (addonPtr != m_addons.end()) m_addons.erase(addonPtr); } } return bReturn; }
bool CPVRClients::AutoconfigureClients(void) { bool bReturn(false); std::vector<PVR_CLIENT> autoConfigAddons; PVR_CLIENT addon; VECADDONS map; CAddonMgr::GetInstance().GetAddons(ADDON_PVRDLL, map, false); /** get the auto-configurable add-ons */ for (VECADDONS::iterator it = map.begin(); it != map.end(); ++it) { if (CAddonMgr::GetInstance().IsAddonDisabled((*it)->ID())) { addon = std::dynamic_pointer_cast<CPVRClient>(*it); if (addon->CanAutoconfigure()) autoConfigAddons.push_back(addon); } } /** no configurable add-ons found */ if (autoConfigAddons.size() == 0) return bReturn; /** display a progress bar while trying to auto-configure add-ons */ CGUIDialogExtendedProgressBar *loadingProgressDialog = (CGUIDialogExtendedProgressBar *)g_windowManager.GetWindow(WINDOW_DIALOG_EXT_PROGRESS); CGUIDialogProgressBarHandle* progressHandle = loadingProgressDialog->GetHandle(g_localizeStrings.Get(19688)); // Scanning for PVR services progressHandle->SetPercentage(0); progressHandle->SetText(g_localizeStrings.Get(19688)); //Scanning for PVR services /** start zeroconf and wait a second to get some responses */ CZeroconfBrowser::GetInstance()->Start(); for (std::vector<PVR_CLIENT>::iterator it = autoConfigAddons.begin(); !bReturn && it != autoConfigAddons.end(); ++it) (*it)->AutoconfigureRegisterType(); unsigned iIterations(0); float percentage(0.0f); float percentageStep(100.0f / PVR_CLIENT_AVAHI_SCAN_ITERATIONS); progressHandle->SetPercentage(percentage); /** while no add-ons were configured within 20 iterations */ while (!bReturn && iIterations++ < PVR_CLIENT_AVAHI_SCAN_ITERATIONS) { /** check each disabled add-on */ for (std::vector<PVR_CLIENT>::iterator it = autoConfigAddons.begin(); !bReturn && it != autoConfigAddons.end(); ++it) { if (addon->Autoconfigure()) { progressHandle->SetPercentage(100.0f); progressHandle->MarkFinished(); /** enable the add-on */ CAddonMgr::GetInstance().EnableAddon((*it)->ID()); CSingleLock lock(m_critSection); m_addons.push_back(*it); bReturn = true; } } /** wait a while and try again */ if (!bReturn) { percentage += percentageStep; progressHandle->SetPercentage(percentage); Sleep(PVR_CLIENT_AVAHI_SLEEP_TIME_MS); } } progressHandle->SetPercentage(100.0f); progressHandle->MarkFinished(); return bReturn; }
JSONRPC_STATUS CAddonsOperations::GetAddons(const std::string &method, ITransportLayer *transport, IClient *client, const CVariant ¶meterObject, CVariant &result) { vector<TYPE> addonTypes; TYPE addonType = TranslateType(parameterObject["type"].asString()); CPluginSource::Content content = CPluginSource::Translate(parameterObject["content"].asString()); CVariant enabled = parameterObject["enabled"]; // ignore the "content" parameter if the type is specified but not a plugin or script if (addonType != ADDON_UNKNOWN && addonType != ADDON_PLUGIN && addonType != ADDON_SCRIPT) content = CPluginSource::UNKNOWN; if (addonType >= ADDON_VIDEO && addonType <= ADDON_EXECUTABLE) { addonTypes.push_back(ADDON_PLUGIN); addonTypes.push_back(ADDON_SCRIPT); switch (addonType) { case ADDON_VIDEO: content = CPluginSource::VIDEO; break; case ADDON_AUDIO: content = CPluginSource::AUDIO; break; case ADDON_IMAGE: content = CPluginSource::IMAGE; break; case ADDON_EXECUTABLE: content = CPluginSource::EXECUTABLE; break; default: break; } } else addonTypes.push_back(addonType); VECADDONS addons; for (vector<TYPE>::const_iterator typeIt = addonTypes.begin(); typeIt != addonTypes.end(); ++typeIt) { VECADDONS typeAddons; if (*typeIt == ADDON_UNKNOWN) { if (!enabled.isBoolean()) { CAddonMgr::Get().GetAllAddons(typeAddons, false); CAddonMgr::Get().GetAllAddons(typeAddons, true); } else CAddonMgr::Get().GetAllAddons(typeAddons, enabled.asBoolean()); } else { if (!enabled.isBoolean()) { CAddonMgr::Get().GetAddons(*typeIt, typeAddons, false); VECADDONS enabledAddons; CAddonMgr::Get().GetAddons(*typeIt, enabledAddons, true); typeAddons.insert(typeAddons.end(), enabledAddons.begin(), enabledAddons.end()); } else CAddonMgr::Get().GetAddons(*typeIt, typeAddons, enabled.asBoolean()); } addons.insert(addons.end(), typeAddons.begin(), typeAddons.end()); } // remove library addons for (int index = 0; index < (int)addons.size(); index++) { PluginPtr plugin; if (content != CPluginSource::UNKNOWN) plugin = boost::dynamic_pointer_cast<CPluginSource>(addons.at(index)); if ((addons.at(index)->Type() <= ADDON_UNKNOWN || addons.at(index)->Type() >= ADDON_MAX) || ((content != CPluginSource::UNKNOWN && plugin == NULL) || (plugin != NULL && !plugin->Provides(content)))) { addons.erase(addons.begin() + index); index--; } } int start, end; HandleLimits(parameterObject, result, addons.size(), start, end); CAddonDatabase addondb; for (int index = start; index < end; index++) FillDetails(addons.at(index), parameterObject["properties"], result["addons"], addondb, true); return OK; }