2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "SettingsComponent.h"
11 #include "CompileInfo.h"
12 #include "ServiceBroker.h"
14 #include "application/AppParams.h"
15 #include "filesystem/Directory.h"
16 #include "filesystem/SpecialProtocol.h"
17 #ifdef TARGET_DARWIN_EMBEDDED
18 #include "platform/darwin/ios-common/DarwinEmbedUtils.h"
21 #include "platform/Environment.h"
23 #include "profiles/ProfileManager.h"
24 #include "settings/AdvancedSettings.h"
25 #include "settings/Settings.h"
26 #include "settings/SubtitlesSettings.h"
27 #include "utils/StringUtils.h"
28 #include "utils/URIUtils.h"
29 #include "utils/log.h"
31 #include "win32util.h"
34 CSettingsComponent::CSettingsComponent()
35 : m_settings(new CSettings()),
36 m_advancedSettings(new CAdvancedSettings()),
37 m_subtitlesSettings(new KODI::SUBTITLES::CSubtitlesSettings(m_settings
)),
38 m_profileManager(new CProfileManager())
42 CSettingsComponent::~CSettingsComponent()
46 void CSettingsComponent::Initialize()
48 if (m_state
== State::DEINITED
)
50 const auto params
= CServiceBroker::GetAppParams();
52 // only the InitDirectories* for the current platform should return true
53 bool inited
= InitDirectoriesLinux(params
->HasPlatformDirectories());
55 inited
= InitDirectoriesOSX(params
->HasPlatformDirectories());
57 inited
= InitDirectoriesWin32(params
->HasPlatformDirectories());
59 m_settings
->Initialize();
61 m_advancedSettings
->Initialize(*m_settings
->GetSettingsManager());
62 URIUtils::RegisterAdvancedSettings(*m_advancedSettings
);
64 m_profileManager
->Initialize(m_settings
);
66 m_state
= State::INITED
;
70 bool CSettingsComponent::Load()
72 if (m_state
== State::INITED
)
74 if (!m_profileManager
->Load())
76 CLog::Log(LOGFATAL
, "unable to load profile");
80 CSpecialProtocol::RegisterProfileManager(*m_profileManager
);
81 XFILE::IDirectory::RegisterProfileManager(*m_profileManager
);
83 if (!m_settings
->Load())
85 CLog::Log(LOGFATAL
, "unable to load settings");
89 m_settings
->SetLoaded();
91 m_state
= State::LOADED
;
94 else if (m_state
== State::LOADED
)
104 void CSettingsComponent::Deinitialize()
106 if (m_state
>= State::INITED
)
108 if (m_state
== State::LOADED
)
110 m_subtitlesSettings
.reset();
112 m_settings
->Unload();
114 XFILE::IDirectory::UnregisterProfileManager();
115 CSpecialProtocol::UnregisterProfileManager();
117 m_profileManager
->Uninitialize();
119 URIUtils::UnregisterAdvancedSettings();
120 m_advancedSettings
->Uninitialize(*m_settings
->GetSettingsManager());
122 m_settings
->Uninitialize();
124 m_state
= State::DEINITED
;
127 std::shared_ptr
<CSettings
> CSettingsComponent::GetSettings()
132 std::shared_ptr
<CAdvancedSettings
> CSettingsComponent::GetAdvancedSettings()
134 return m_advancedSettings
;
137 std::shared_ptr
<KODI::SUBTITLES::CSubtitlesSettings
> CSettingsComponent::GetSubtitlesSettings()
139 return m_subtitlesSettings
;
142 std::shared_ptr
<CProfileManager
> CSettingsComponent::GetProfileManager()
144 return m_profileManager
;
147 bool CSettingsComponent::InitDirectoriesLinux(bool bPlatformDirectories
)
150 The following is the directory mapping for Platform Specific Mode:
152 special://xbmc/ => [read-only] system directory (/usr/share/kodi)
153 special://home/ => [read-write] user's directory that will override special://kodi/ system-wide
154 installations like skins, screensavers, etc.
156 NOTE: XBMC will look in both special://xbmc/addons and special://home/addons for addons.
157 special://masterprofile/ => [read-write] userdata of master profile. It will by default be
158 mapped to special://home/userdata ($HOME/.kodi/userdata)
159 special://profile/ => [read-write] current profile's userdata directory.
160 Generally special://masterprofile for the master profile or
161 special://masterprofile/profiles/<profile_name> for other profiles.
163 NOTE: All these root directories are lowercase. Some of the sub-directories
167 #if defined(TARGET_POSIX) && !defined(TARGET_DARWIN)
169 std::string appName
= CCompileInfo::GetAppName();
170 std::string dotLowerAppName
= "." + appName
;
171 StringUtils::ToLower(dotLowerAppName
);
172 const char* envAppHome
= "KODI_HOME";
173 const char* envAppBinHome
= "KODI_BIN_HOME";
174 const char* envAppTemp
= "KODI_TEMP";
176 std::string userHome
;
177 if (getenv("KODI_DATA"))
178 userHome
= getenv("KODI_DATA");
179 else if (getenv("HOME"))
181 userHome
= getenv("HOME");
182 userHome
.append("/" + dotLowerAppName
);
187 userHome
.append("/" + dotLowerAppName
);
190 std::string strTempPath
;
191 if (getenv(envAppTemp
))
192 strTempPath
= getenv(envAppTemp
);
194 strTempPath
= userHome
+ "/temp";
197 std::string binaddonAltDir
;
198 if (getenv("KODI_BINADDON_PATH"))
199 binaddonAltDir
= getenv("KODI_BINADDON_PATH");
201 auto appBinPath
= CUtil::GetHomePath(envAppBinHome
);
202 // overridden by user
203 if (getenv(envAppHome
))
204 appPath
= getenv(envAppHome
);
207 // use build time default
208 appPath
= INSTALL_PATH
;
209 /* Check if binaries and arch independent data files are being kept in
210 * separate locations. */
211 if (!XFILE::CDirectory::Exists(URIUtils::AddFileToFolder(appPath
, "userdata")))
213 /* Attempt to locate arch independent data files. */
214 appPath
= CUtil::GetHomePath(appBinPath
);
215 if (!XFILE::CDirectory::Exists(URIUtils::AddFileToFolder(appPath
, "userdata")))
217 fprintf(stderr
, "Unable to find path to %s data files!\n", appName
.c_str());
223 /* Set some environment variables */
224 setenv(envAppBinHome
, appBinPath
.c_str(), 0);
225 setenv(envAppHome
, appPath
.c_str(), 0);
227 if (bPlatformDirectories
)
229 // map our special drives
230 CSpecialProtocol::SetXBMCBinPath(appBinPath
);
231 CSpecialProtocol::SetXBMCAltBinAddonPath(binaddonAltDir
);
232 CSpecialProtocol::SetXBMCPath(appPath
);
233 CSpecialProtocol::SetHomePath(userHome
);
234 CSpecialProtocol::SetMasterProfilePath(userHome
+ "/userdata");
235 CSpecialProtocol::SetTempPath(strTempPath
);
236 CSpecialProtocol::SetLogPath(strTempPath
);
243 URIUtils::AddSlashAtEnd(appPath
);
245 CSpecialProtocol::SetXBMCBinPath(appBinPath
);
246 CSpecialProtocol::SetXBMCAltBinAddonPath(binaddonAltDir
);
247 CSpecialProtocol::SetXBMCPath(appPath
);
248 CSpecialProtocol::SetHomePath(URIUtils::AddFileToFolder(appPath
, "portable_data"));
249 CSpecialProtocol::SetMasterProfilePath(URIUtils::AddFileToFolder(appPath
, "portable_data/userdata"));
251 std::string strTempPath
= appPath
;
252 strTempPath
= URIUtils::AddFileToFolder(strTempPath
, "portable_data/temp");
253 if (getenv(envAppTemp
))
254 strTempPath
= getenv(envAppTemp
);
255 CSpecialProtocol::SetTempPath(strTempPath
);
256 CSpecialProtocol::SetLogPath(strTempPath
);
259 CSpecialProtocol::SetXBMCBinAddonPath(appBinPath
+ "/addons");
267 bool CSettingsComponent::InitDirectoriesOSX(bool bPlatformDirectories
)
269 #if defined(TARGET_DARWIN)
270 std::string userHome
;
272 userHome
= getenv("HOME");
276 std::string binaddonAltDir
;
277 if (getenv("KODI_BINADDON_PATH"))
278 binaddonAltDir
= getenv("KODI_BINADDON_PATH");
280 std::string appPath
= CUtil::GetHomePath();
281 setenv("KODI_HOME", appPath
.c_str(), 0);
283 #if defined(TARGET_DARWIN_EMBEDDED)
284 std::string fontconfigPath
;
285 fontconfigPath
= appPath
+ "/system/players/VideoPlayer/etc/fonts/fonts.conf";
286 setenv("FONTCONFIG_FILE", fontconfigPath
.c_str(), 0);
289 // setup path to our internal dylibs so loader can find them
290 std::string frameworksPath
= CUtil::GetFrameworksPath();
291 CSpecialProtocol::SetXBMCFrameworksPath(frameworksPath
);
293 if (bPlatformDirectories
)
295 // map our special drives
296 CSpecialProtocol::SetXBMCBinPath(appPath
);
297 CSpecialProtocol::SetXBMCAltBinAddonPath(binaddonAltDir
);
298 CSpecialProtocol::SetXBMCPath(appPath
);
299 #if defined(TARGET_DARWIN_EMBEDDED)
300 std::string appName
= CCompileInfo::GetAppName();
301 CSpecialProtocol::SetHomePath(userHome
+ "/" + CDarwinEmbedUtils::GetAppRootFolder() + "/" +
303 CSpecialProtocol::SetMasterProfilePath(userHome
+ "/" + CDarwinEmbedUtils::GetAppRootFolder() +
304 "/" + appName
+ "/userdata");
306 std::string appName
= CCompileInfo::GetAppName();
307 CSpecialProtocol::SetHomePath(userHome
+ "/Library/Application Support/" + appName
);
308 CSpecialProtocol::SetMasterProfilePath(userHome
+ "/Library/Application Support/" + appName
+ "/userdata");
311 std::string dotLowerAppName
= "." + appName
;
312 StringUtils::ToLower(dotLowerAppName
);
313 // location for temp files
314 #if defined(TARGET_DARWIN_EMBEDDED)
315 std::string strTempPath
= URIUtils::AddFileToFolder(
316 userHome
, std::string(CDarwinEmbedUtils::GetAppRootFolder()) + "/" + appName
+ "/temp");
318 std::string strTempPath
= URIUtils::AddFileToFolder(userHome
, dotLowerAppName
+ "/");
319 XFILE::CDirectory::Create(strTempPath
);
320 strTempPath
= URIUtils::AddFileToFolder(userHome
, dotLowerAppName
+ "/temp");
322 CSpecialProtocol::SetTempPath(strTempPath
);
324 // xbmc.log file location
325 #if defined(TARGET_DARWIN_EMBEDDED)
326 strTempPath
= userHome
+ "/" + std::string(CDarwinEmbedUtils::GetAppRootFolder());
328 strTempPath
= userHome
+ "/Library/Logs";
330 CSpecialProtocol::SetLogPath(strTempPath
);
335 URIUtils::AddSlashAtEnd(appPath
);
337 CSpecialProtocol::SetXBMCBinPath(appPath
);
338 CSpecialProtocol::SetXBMCAltBinAddonPath(binaddonAltDir
);
339 CSpecialProtocol::SetXBMCPath(appPath
);
340 CSpecialProtocol::SetHomePath(URIUtils::AddFileToFolder(appPath
, "portable_data"));
341 CSpecialProtocol::SetMasterProfilePath(URIUtils::AddFileToFolder(appPath
, "portable_data/userdata"));
343 std::string strTempPath
= URIUtils::AddFileToFolder(appPath
, "portable_data/temp");
344 CSpecialProtocol::SetTempPath(strTempPath
);
345 CSpecialProtocol::SetLogPath(strTempPath
);
348 CSpecialProtocol::SetXBMCBinAddonPath(appPath
+ "/addons");
355 bool CSettingsComponent::InitDirectoriesWin32(bool bPlatformDirectories
)
357 #ifdef TARGET_WINDOWS
358 std::string xbmcPath
= CUtil::GetHomePath();
359 CEnvironment::setenv("KODI_HOME", xbmcPath
);
360 CSpecialProtocol::SetXBMCBinPath(xbmcPath
);
361 CSpecialProtocol::SetXBMCPath(xbmcPath
);
362 CSpecialProtocol::SetXBMCBinAddonPath(xbmcPath
+ "/addons");
364 std::string strWin32UserFolder
= CWIN32Util::GetProfilePath(bPlatformDirectories
);
365 CSpecialProtocol::SetLogPath(strWin32UserFolder
);
366 CSpecialProtocol::SetHomePath(strWin32UserFolder
);
367 CSpecialProtocol::SetMasterProfilePath(URIUtils::AddFileToFolder(strWin32UserFolder
, "userdata"));
368 CSpecialProtocol::SetTempPath(URIUtils::AddFileToFolder(strWin32UserFolder
,"cache"));
370 CEnvironment::setenv("KODI_PROFILE_USERDATA", CSpecialProtocol::TranslatePath("special://masterprofile/"));
380 void CSettingsComponent::CreateUserDirs() const
382 XFILE::CDirectory::Create("special://home/");
383 XFILE::CDirectory::Create("special://home/addons");
384 XFILE::CDirectory::Create("special://home/addons/packages");
385 XFILE::CDirectory::Create("special://home/addons/temp");
386 XFILE::CDirectory::Create("special://home/media");
387 XFILE::CDirectory::Create("special://home/system");
388 XFILE::CDirectory::Create("special://masterprofile/");
389 XFILE::CDirectory::Create("special://temp/");
390 XFILE::CDirectory::Create("special://logpath");
391 XFILE::CDirectory::Create("special://temp/temp"); // temp directory for python and dllGetTempPathA
393 //Let's clear our archive cache before starting up anything more
394 auto archiveCachePath
= CSpecialProtocol::TranslatePath("special://temp/archive_cache/");
395 if (XFILE::CDirectory::Exists(archiveCachePath
))
396 if (!XFILE::CDirectory::RemoveRecursive(archiveCachePath
))
397 CLog::Log(LOGWARNING
, "Failed to remove the archive cache at {}", archiveCachePath
);
398 XFILE::CDirectory::Create(archiveCachePath
);