Merge pull request #24470 from fuzzard/release_20.3
[xbmc.git] / xbmc / settings / MediaSettings.cpp
blob09aad05861282cce1ddad675939f8320681da1f7
1 /*
2 * Copyright (C) 2013-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.
7 */
9 #include "MediaSettings.h"
11 #include "PlayListPlayer.h"
12 #include "ServiceBroker.h"
13 #include "cores/RetroPlayer/RetroPlayerUtils.h"
14 #include "dialogs/GUIDialogFileBrowser.h"
15 #include "guilib/LocalizeStrings.h"
16 #include "interfaces/AnnouncementManager.h"
17 #include "interfaces/builtins/Builtins.h"
18 #include "messaging/helpers/DialogHelper.h"
19 #include "messaging/helpers/DialogOKHelper.h"
20 #include "music/MusicLibraryQueue.h"
21 #include "settings/Settings.h"
22 #include "settings/dialogs/GUIDialogLibExportSettings.h"
23 #include "settings/lib/Setting.h"
24 #include "storage/MediaManager.h"
25 #include "utils/StringUtils.h"
26 #include "utils/Variant.h"
27 #include "utils/XBMCTinyXML.h"
28 #include "utils/XMLUtils.h"
29 #include "utils/log.h"
30 #include "video/VideoDatabase.h"
31 #include "video/VideoLibraryQueue.h"
33 #include <limits.h>
34 #include <mutex>
35 #include <string>
37 using namespace KODI;
38 using namespace KODI::MESSAGING;
40 using KODI::MESSAGING::HELPERS::DialogResponse;
42 CMediaSettings::CMediaSettings()
44 m_watchedModes["files"] = WatchedModeAll;
45 m_watchedModes["movies"] = WatchedModeAll;
46 m_watchedModes["tvshows"] = WatchedModeAll;
47 m_watchedModes["musicvideos"] = WatchedModeAll;
48 m_watchedModes["recordings"] = WatchedModeAll;
50 m_musicPlaylistRepeat = false;
51 m_musicPlaylistShuffle = false;
52 m_videoPlaylistRepeat = false;
53 m_videoPlaylistShuffle = false;
55 m_mediaStartWindowed = false;
56 m_additionalSubtitleDirectoryChecked = 0;
58 m_musicNeedsUpdate = 0;
59 m_videoNeedsUpdate = 0;
62 CMediaSettings::~CMediaSettings() = default;
64 CMediaSettings& CMediaSettings::GetInstance()
66 static CMediaSettings sMediaSettings;
67 return sMediaSettings;
70 bool CMediaSettings::Load(const TiXmlNode *settings)
72 if (settings == NULL)
73 return false;
75 std::unique_lock<CCriticalSection> lock(m_critical);
76 const TiXmlElement *pElement = settings->FirstChildElement("defaultvideosettings");
77 if (pElement != NULL)
79 int interlaceMethod;
80 XMLUtils::GetInt(pElement, "interlacemethod", interlaceMethod, VS_INTERLACEMETHOD_NONE, VS_INTERLACEMETHOD_MAX);
82 m_defaultVideoSettings.m_InterlaceMethod = (EINTERLACEMETHOD)interlaceMethod;
83 int scalingMethod;
84 if (!XMLUtils::GetInt(pElement, "scalingmethod", scalingMethod, VS_SCALINGMETHOD_NEAREST, VS_SCALINGMETHOD_MAX))
85 scalingMethod = (int)VS_SCALINGMETHOD_LINEAR;
86 m_defaultVideoSettings.m_ScalingMethod = (ESCALINGMETHOD)scalingMethod;
88 XMLUtils::GetInt(pElement, "viewmode", m_defaultVideoSettings.m_ViewMode, ViewModeNormal, ViewModeZoom110Width);
89 if (!XMLUtils::GetFloat(pElement, "zoomamount", m_defaultVideoSettings.m_CustomZoomAmount, 0.5f, 2.0f))
90 m_defaultVideoSettings.m_CustomZoomAmount = 1.0f;
91 if (!XMLUtils::GetFloat(pElement, "pixelratio", m_defaultVideoSettings.m_CustomPixelRatio, 0.5f, 2.0f))
92 m_defaultVideoSettings.m_CustomPixelRatio = 1.0f;
93 if (!XMLUtils::GetFloat(pElement, "verticalshift", m_defaultVideoSettings.m_CustomVerticalShift, -2.0f, 2.0f))
94 m_defaultVideoSettings.m_CustomVerticalShift = 0.0f;
95 if (!XMLUtils::GetFloat(pElement, "volumeamplification", m_defaultVideoSettings.m_VolumeAmplification, VOLUME_DRC_MINIMUM * 0.01f, VOLUME_DRC_MAXIMUM * 0.01f))
96 m_defaultVideoSettings.m_VolumeAmplification = VOLUME_DRC_MINIMUM * 0.01f;
97 if (!XMLUtils::GetFloat(pElement, "noisereduction", m_defaultVideoSettings.m_NoiseReduction, 0.0f, 1.0f))
98 m_defaultVideoSettings.m_NoiseReduction = 0.0f;
99 XMLUtils::GetBoolean(pElement, "postprocess", m_defaultVideoSettings.m_PostProcess);
100 if (!XMLUtils::GetFloat(pElement, "sharpness", m_defaultVideoSettings.m_Sharpness, -1.0f, 1.0f))
101 m_defaultVideoSettings.m_Sharpness = 0.0f;
102 XMLUtils::GetBoolean(pElement, "showsubtitles", m_defaultVideoSettings.m_SubtitleOn);
103 if (!XMLUtils::GetFloat(pElement, "brightness", m_defaultVideoSettings.m_Brightness, 0, 100))
104 m_defaultVideoSettings.m_Brightness = 50;
105 if (!XMLUtils::GetFloat(pElement, "contrast", m_defaultVideoSettings.m_Contrast, 0, 100))
106 m_defaultVideoSettings.m_Contrast = 50;
107 if (!XMLUtils::GetFloat(pElement, "gamma", m_defaultVideoSettings.m_Gamma, 0, 100))
108 m_defaultVideoSettings.m_Gamma = 20;
109 if (!XMLUtils::GetFloat(pElement, "audiodelay", m_defaultVideoSettings.m_AudioDelay, -10.0f, 10.0f))
110 m_defaultVideoSettings.m_AudioDelay = 0.0f;
111 if (!XMLUtils::GetFloat(pElement, "subtitledelay", m_defaultVideoSettings.m_SubtitleDelay, -10.0f, 10.0f))
112 m_defaultVideoSettings.m_SubtitleDelay = 0.0f;
113 XMLUtils::GetBoolean(pElement, "nonlinstretch", m_defaultVideoSettings.m_CustomNonLinStretch);
114 if (!XMLUtils::GetInt(pElement, "stereomode", m_defaultVideoSettings.m_StereoMode))
115 m_defaultVideoSettings.m_StereoMode = 0;
116 if (!XMLUtils::GetInt(pElement, "centermixlevel", m_defaultVideoSettings.m_CenterMixLevel))
117 m_defaultVideoSettings.m_CenterMixLevel = 0;
119 int toneMapMethod;
120 if (!XMLUtils::GetInt(pElement, "tonemapmethod", toneMapMethod, VS_TONEMAPMETHOD_OFF,
121 VS_TONEMAPMETHOD_MAX))
122 toneMapMethod = VS_TONEMAPMETHOD_REINHARD;
123 m_defaultVideoSettings.m_ToneMapMethod = static_cast<ETONEMAPMETHOD>(toneMapMethod);
125 if (!XMLUtils::GetFloat(pElement, "tonemapparam", m_defaultVideoSettings.m_ToneMapParam, 0.1f, 5.0f))
126 m_defaultVideoSettings.m_ToneMapParam = 1.0f;
129 m_defaultGameSettings.Reset();
130 pElement = settings->FirstChildElement("defaultgamesettings");
131 if (pElement != nullptr)
133 std::string videoFilter;
134 if (XMLUtils::GetString(pElement, "videofilter", videoFilter))
135 m_defaultGameSettings.SetVideoFilter(videoFilter);
137 std::string stretchMode;
138 if (XMLUtils::GetString(pElement, "stretchmode", stretchMode))
140 RETRO::STRETCHMODE sm = RETRO::CRetroPlayerUtils::IdentifierToStretchMode(stretchMode);
141 m_defaultGameSettings.SetStretchMode(sm);
144 int rotation;
145 if (XMLUtils::GetInt(pElement, "rotation", rotation, 0, 270) && rotation >= 0)
146 m_defaultGameSettings.SetRotationDegCCW(static_cast<unsigned int>(rotation));
149 // mymusic settings
150 pElement = settings->FirstChildElement("mymusic");
151 if (pElement != NULL)
153 const TiXmlElement *pChild = pElement->FirstChildElement("playlist");
154 if (pChild != NULL)
156 XMLUtils::GetBoolean(pChild, "repeat", m_musicPlaylistRepeat);
157 XMLUtils::GetBoolean(pChild, "shuffle", m_musicPlaylistShuffle);
159 if (!XMLUtils::GetInt(pElement, "needsupdate", m_musicNeedsUpdate, 0, INT_MAX))
160 m_musicNeedsUpdate = 0;
163 // Set music playlist player repeat and shuffle from loaded settings
164 if (m_musicPlaylistRepeat)
165 CServiceBroker::GetPlaylistPlayer().SetRepeat(PLAYLIST::TYPE_MUSIC, PLAYLIST::RepeatState::ALL);
166 else
167 CServiceBroker::GetPlaylistPlayer().SetRepeat(PLAYLIST::TYPE_MUSIC,
168 PLAYLIST::RepeatState::NONE);
169 CServiceBroker::GetPlaylistPlayer().SetShuffle(PLAYLIST::TYPE_MUSIC, m_musicPlaylistShuffle);
171 // Read the watchmode settings for the various media views
172 pElement = settings->FirstChildElement("myvideos");
173 if (pElement != NULL)
175 int tmp;
176 if (XMLUtils::GetInt(pElement, "watchmodemovies", tmp, (int)WatchedModeAll, (int)WatchedModeWatched))
177 m_watchedModes["movies"] = (WatchedMode)tmp;
178 if (XMLUtils::GetInt(pElement, "watchmodetvshows", tmp, (int)WatchedModeAll, (int)WatchedModeWatched))
179 m_watchedModes["tvshows"] = (WatchedMode)tmp;
180 if (XMLUtils::GetInt(pElement, "watchmodemusicvideos", tmp, (int)WatchedModeAll, (int)WatchedModeWatched))
181 m_watchedModes["musicvideos"] = (WatchedMode)tmp;
182 if (XMLUtils::GetInt(pElement, "watchmoderecordings", tmp, static_cast<int>(WatchedModeAll), static_cast<int>(WatchedModeWatched)))
183 m_watchedModes["recordings"] = static_cast<WatchedMode>(tmp);
185 const TiXmlElement *pChild = pElement->FirstChildElement("playlist");
186 if (pChild != NULL)
188 XMLUtils::GetBoolean(pChild, "repeat", m_videoPlaylistRepeat);
189 XMLUtils::GetBoolean(pChild, "shuffle", m_videoPlaylistShuffle);
191 if (!XMLUtils::GetInt(pElement, "needsupdate", m_videoNeedsUpdate, 0, INT_MAX))
192 m_videoNeedsUpdate = 0;
195 // Set video playlist player repeat and shuffle from loaded settings
196 if (m_videoPlaylistRepeat)
197 CServiceBroker::GetPlaylistPlayer().SetRepeat(PLAYLIST::TYPE_VIDEO, PLAYLIST::RepeatState::ALL);
198 else
199 CServiceBroker::GetPlaylistPlayer().SetRepeat(PLAYLIST::TYPE_VIDEO,
200 PLAYLIST::RepeatState::NONE);
201 CServiceBroker::GetPlaylistPlayer().SetShuffle(PLAYLIST::TYPE_VIDEO, m_videoPlaylistShuffle);
203 return true;
206 bool CMediaSettings::Save(TiXmlNode *settings) const
208 if (settings == NULL)
209 return false;
211 std::unique_lock<CCriticalSection> lock(m_critical);
212 // default video settings
213 TiXmlElement videoSettingsNode("defaultvideosettings");
214 TiXmlNode *pNode = settings->InsertEndChild(videoSettingsNode);
215 if (pNode == NULL)
216 return false;
218 XMLUtils::SetInt(pNode, "interlacemethod", m_defaultVideoSettings.m_InterlaceMethod);
219 XMLUtils::SetInt(pNode, "scalingmethod", m_defaultVideoSettings.m_ScalingMethod);
220 XMLUtils::SetFloat(pNode, "noisereduction", m_defaultVideoSettings.m_NoiseReduction);
221 XMLUtils::SetBoolean(pNode, "postprocess", m_defaultVideoSettings.m_PostProcess);
222 XMLUtils::SetFloat(pNode, "sharpness", m_defaultVideoSettings.m_Sharpness);
223 XMLUtils::SetInt(pNode, "viewmode", m_defaultVideoSettings.m_ViewMode);
224 XMLUtils::SetFloat(pNode, "zoomamount", m_defaultVideoSettings.m_CustomZoomAmount);
225 XMLUtils::SetFloat(pNode, "pixelratio", m_defaultVideoSettings.m_CustomPixelRatio);
226 XMLUtils::SetFloat(pNode, "verticalshift", m_defaultVideoSettings.m_CustomVerticalShift);
227 XMLUtils::SetFloat(pNode, "volumeamplification", m_defaultVideoSettings.m_VolumeAmplification);
228 XMLUtils::SetBoolean(pNode, "showsubtitles", m_defaultVideoSettings.m_SubtitleOn);
229 XMLUtils::SetFloat(pNode, "brightness", m_defaultVideoSettings.m_Brightness);
230 XMLUtils::SetFloat(pNode, "contrast", m_defaultVideoSettings.m_Contrast);
231 XMLUtils::SetFloat(pNode, "gamma", m_defaultVideoSettings.m_Gamma);
232 XMLUtils::SetFloat(pNode, "audiodelay", m_defaultVideoSettings.m_AudioDelay);
233 XMLUtils::SetFloat(pNode, "subtitledelay", m_defaultVideoSettings.m_SubtitleDelay);
234 XMLUtils::SetBoolean(pNode, "nonlinstretch", m_defaultVideoSettings.m_CustomNonLinStretch);
235 XMLUtils::SetInt(pNode, "stereomode", m_defaultVideoSettings.m_StereoMode);
236 XMLUtils::SetInt(pNode, "centermixlevel", m_defaultVideoSettings.m_CenterMixLevel);
237 XMLUtils::SetInt(pNode, "tonemapmethod", m_defaultVideoSettings.m_ToneMapMethod);
238 XMLUtils::SetFloat(pNode, "tonemapparam", m_defaultVideoSettings.m_ToneMapParam);
240 // default audio settings for dsp addons
241 TiXmlElement audioSettingsNode("defaultaudiosettings");
242 pNode = settings->InsertEndChild(audioSettingsNode);
243 if (pNode == NULL)
244 return false;
246 // Default game settings
247 TiXmlElement gameSettingsNode("defaultgamesettings");
248 pNode = settings->InsertEndChild(gameSettingsNode);
249 if (pNode == nullptr)
250 return false;
252 XMLUtils::SetString(pNode, "videofilter", m_defaultGameSettings.VideoFilter());
253 std::string sm = RETRO::CRetroPlayerUtils::StretchModeToIdentifier(m_defaultGameSettings.StretchMode());
254 XMLUtils::SetString(pNode, "stretchmode", sm);
255 XMLUtils::SetInt(pNode, "rotation", m_defaultGameSettings.RotationDegCCW());
257 // mymusic
258 pNode = settings->FirstChild("mymusic");
259 if (pNode == NULL)
261 TiXmlElement videosNode("mymusic");
262 pNode = settings->InsertEndChild(videosNode);
263 if (pNode == NULL)
264 return false;
267 TiXmlElement musicPlaylistNode("playlist");
268 TiXmlNode *playlistNode = pNode->InsertEndChild(musicPlaylistNode);
269 if (playlistNode == NULL)
270 return false;
271 XMLUtils::SetBoolean(playlistNode, "repeat", m_musicPlaylistRepeat);
272 XMLUtils::SetBoolean(playlistNode, "shuffle", m_musicPlaylistShuffle);
274 XMLUtils::SetInt(pNode, "needsupdate", m_musicNeedsUpdate);
276 // myvideos
277 pNode = settings->FirstChild("myvideos");
278 if (pNode == NULL)
280 TiXmlElement videosNode("myvideos");
281 pNode = settings->InsertEndChild(videosNode);
282 if (pNode == NULL)
283 return false;
286 XMLUtils::SetInt(pNode, "watchmodemovies", m_watchedModes.find("movies")->second);
287 XMLUtils::SetInt(pNode, "watchmodetvshows", m_watchedModes.find("tvshows")->second);
288 XMLUtils::SetInt(pNode, "watchmodemusicvideos", m_watchedModes.find("musicvideos")->second);
289 XMLUtils::SetInt(pNode, "watchmoderecordings", m_watchedModes.find("recordings")->second);
291 TiXmlElement videoPlaylistNode("playlist");
292 playlistNode = pNode->InsertEndChild(videoPlaylistNode);
293 if (playlistNode == NULL)
294 return false;
295 XMLUtils::SetBoolean(playlistNode, "repeat", m_videoPlaylistRepeat);
296 XMLUtils::SetBoolean(playlistNode, "shuffle", m_videoPlaylistShuffle);
298 XMLUtils::SetInt(pNode, "needsupdate", m_videoNeedsUpdate);
300 return true;
303 void CMediaSettings::OnSettingAction(const std::shared_ptr<const CSetting>& setting)
305 if (setting == NULL)
306 return;
308 const std::string &settingId = setting->GetId();
309 if (settingId == CSettings::SETTING_MUSICLIBRARY_CLEANUP)
311 if (HELPERS::ShowYesNoDialogText(CVariant{313}, CVariant{333}) == DialogResponse::CHOICE_YES)
313 if (CMusicLibraryQueue::GetInstance().IsRunning())
314 HELPERS::ShowOKDialogText(CVariant{700}, CVariant{703});
315 else
316 CMusicLibraryQueue::GetInstance().CleanLibrary(true);
319 else if (settingId == CSettings::SETTING_MUSICLIBRARY_EXPORT)
321 CLibExportSettings m_musicExportSettings;
322 if (CGUIDialogLibExportSettings::Show(m_musicExportSettings))
324 // Export music library showing progress dialog
325 CMusicLibraryQueue::GetInstance().ExportLibrary(m_musicExportSettings, true);
328 else if (settingId == CSettings::SETTING_MUSICLIBRARY_IMPORT)
330 std::string path;
331 VECSOURCES shares;
332 CServiceBroker::GetMediaManager().GetLocalDrives(shares);
333 CServiceBroker::GetMediaManager().GetNetworkLocations(shares);
334 CServiceBroker::GetMediaManager().GetRemovableDrives(shares);
336 if (CGUIDialogFileBrowser::ShowAndGetFile(shares, "musicdb.xml", g_localizeStrings.Get(651) , path))
338 // Import data to music library showing progress dialog
339 CMusicLibraryQueue::GetInstance().ImportLibrary(path, true);
342 else if (settingId == CSettings::SETTING_VIDEOLIBRARY_CLEANUP)
344 if (HELPERS::ShowYesNoDialogText(CVariant{313}, CVariant{333}) == DialogResponse::CHOICE_YES)
346 if (!CVideoLibraryQueue::GetInstance().CleanLibraryModal())
347 HELPERS::ShowOKDialogText(CVariant{700}, CVariant{703});
350 else if (settingId == CSettings::SETTING_VIDEOLIBRARY_EXPORT)
351 CBuiltins::GetInstance().Execute("exportlibrary(video)");
352 else if (settingId == CSettings::SETTING_VIDEOLIBRARY_IMPORT)
354 std::string path;
355 VECSOURCES shares;
356 CServiceBroker::GetMediaManager().GetLocalDrives(shares);
357 CServiceBroker::GetMediaManager().GetNetworkLocations(shares);
358 CServiceBroker::GetMediaManager().GetRemovableDrives(shares);
360 if (CGUIDialogFileBrowser::ShowAndGetDirectory(shares, g_localizeStrings.Get(651) , path))
362 CVideoDatabase videodatabase;
363 videodatabase.Open();
364 videodatabase.ImportFromXML(path);
365 videodatabase.Close();
370 void CMediaSettings::OnSettingChanged(const std::shared_ptr<const CSetting>& setting)
372 if (setting == nullptr)
373 return;
375 if (setting->GetId() == CSettings::SETTING_VIDEOLIBRARY_SHOWUNWATCHEDPLOTS)
376 CServiceBroker::GetAnnouncementManager()->Announce(ANNOUNCEMENT::VideoLibrary, "OnRefresh");
379 int CMediaSettings::GetWatchedMode(const std::string &content) const
381 std::unique_lock<CCriticalSection> lock(m_critical);
382 WatchedModes::const_iterator it = m_watchedModes.find(GetWatchedContent(content));
383 if (it != m_watchedModes.end())
384 return it->second;
386 return WatchedModeAll;
389 void CMediaSettings::SetWatchedMode(const std::string &content, WatchedMode mode)
391 std::unique_lock<CCriticalSection> lock(m_critical);
392 WatchedModes::iterator it = m_watchedModes.find(GetWatchedContent(content));
393 if (it != m_watchedModes.end())
394 it->second = mode;
397 void CMediaSettings::CycleWatchedMode(const std::string &content)
399 std::unique_lock<CCriticalSection> lock(m_critical);
400 WatchedModes::iterator it = m_watchedModes.find(GetWatchedContent(content));
401 if (it != m_watchedModes.end())
403 it->second = (WatchedMode)((int)it->second + 1);
404 if (it->second > WatchedModeWatched)
405 it->second = WatchedModeAll;
409 std::string CMediaSettings::GetWatchedContent(const std::string &content)
411 if (content == "seasons" || content == "episodes")
412 return "tvshows";
414 return content;