Merge pull request #4763 from wsoltys/Gotham
[vuplus_xbmc] / xbmc / settings / MediaSettings.cpp
1 /*
2  *      Copyright (C) 2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include <limits.h>
22
23 #include "MediaSettings.h"
24 #include "Application.h"
25 #include "PlayListPlayer.h"
26 #include "Util.h"
27 #include "dialogs/GUIDialogContextMenu.h"
28 #include "dialogs/GUIDialogFileBrowser.h"
29 #include "dialogs/GUIDialogYesNo.h"
30 #include "guilib/WindowIDs.h"
31 #include "interfaces/Builtins.h"
32 #include "music/MusicDatabase.h"
33 #include "profiles/ProfilesManager.h"
34 #include "settings/lib/Setting.h"
35 #include "storage/MediaManager.h"
36 #include "threads/SingleLock.h"
37 #include "utils/log.h"
38 #include "utils/URIUtils.h"
39 #include "utils/XBMCTinyXML.h"
40 #include "utils/XMLUtils.h"
41 #include "video/VideoDatabase.h"
42
43 using namespace std;
44
45 CMediaSettings::CMediaSettings()
46 {
47   m_watchedModes["movies"] = WatchedModeAll;
48   m_watchedModes["tvshows"] = WatchedModeAll;
49   m_watchedModes["musicvideos"] = WatchedModeAll;
50
51   m_musicPlaylistRepeat = false;
52   m_musicPlaylistShuffle = false;
53   m_videoPlaylistRepeat = false;
54   m_videoPlaylistShuffle = false;
55
56   m_videoStartWindowed = false;
57   m_additionalSubtitleDirectoryChecked = 0;
58
59   m_musicNeedsUpdate = 0;
60   m_videoNeedsUpdate = 0;
61 }
62
63 CMediaSettings::~CMediaSettings()
64 { }
65
66 CMediaSettings& CMediaSettings::Get()
67 {
68   static CMediaSettings sMediaSettings;
69   return sMediaSettings;
70 }
71
72 bool CMediaSettings::Load(const TiXmlNode *settings)
73 {
74   if (settings == NULL)
75     return false;
76
77   CSingleLock lock(m_critical);
78   const TiXmlElement *pElement = settings->FirstChildElement("defaultvideosettings");
79   if (pElement != NULL)
80   {
81     int deinterlaceMode;
82     bool deinterlaceModePresent = XMLUtils::GetInt(pElement, "deinterlacemode", deinterlaceMode, VS_DEINTERLACEMODE_OFF, VS_DEINTERLACEMODE_FORCE);
83     int interlaceMethod;
84     bool interlaceMethodPresent = XMLUtils::GetInt(pElement, "interlacemethod", interlaceMethod, VS_INTERLACEMETHOD_AUTO, VS_INTERLACEMETHOD_MAX);
85     // For smooth conversion of settings stored before the deinterlaceMode existed
86     if (!deinterlaceModePresent && interlaceMethodPresent)
87     {
88       if (interlaceMethod == VS_INTERLACEMETHOD_NONE)
89       {
90         deinterlaceMode = VS_DEINTERLACEMODE_OFF;
91         interlaceMethod = VS_INTERLACEMETHOD_AUTO;
92       }
93       else if (interlaceMethod == VS_INTERLACEMETHOD_AUTO)
94         deinterlaceMode = VS_DEINTERLACEMODE_AUTO;
95       else
96         deinterlaceMode = VS_DEINTERLACEMODE_FORCE;
97     }
98     m_defaultVideoSettings.m_DeinterlaceMode = (EDEINTERLACEMODE)deinterlaceMode;
99     m_defaultVideoSettings.m_InterlaceMethod = (EINTERLACEMETHOD)interlaceMethod;
100     int scalingMethod;
101     if (!XMLUtils::GetInt(pElement, "scalingmethod", scalingMethod, VS_SCALINGMETHOD_NEAREST, VS_SCALINGMETHOD_MAX))
102       scalingMethod = (int)VS_SCALINGMETHOD_LINEAR;
103     m_defaultVideoSettings.m_ScalingMethod = (ESCALINGMETHOD)scalingMethod;
104
105     XMLUtils::GetInt(pElement, "viewmode", m_defaultVideoSettings.m_ViewMode, ViewModeNormal, ViewModeCustom);
106     if (!XMLUtils::GetFloat(pElement, "zoomamount", m_defaultVideoSettings.m_CustomZoomAmount, 0.5f, 2.0f))
107       m_defaultVideoSettings.m_CustomZoomAmount = 1.0f;
108     if (!XMLUtils::GetFloat(pElement, "pixelratio", m_defaultVideoSettings.m_CustomPixelRatio, 0.5f, 2.0f))
109       m_defaultVideoSettings.m_CustomPixelRatio = 1.0f;
110     if (!XMLUtils::GetFloat(pElement, "verticalshift", m_defaultVideoSettings.m_CustomVerticalShift, -2.0f, 2.0f))
111       m_defaultVideoSettings.m_CustomVerticalShift = 0.0f;
112     if (!XMLUtils::GetFloat(pElement, "volumeamplification", m_defaultVideoSettings.m_VolumeAmplification, VOLUME_DRC_MINIMUM * 0.01f, VOLUME_DRC_MAXIMUM * 0.01f))
113       m_defaultVideoSettings.m_VolumeAmplification = VOLUME_DRC_MINIMUM * 0.01f;
114     if (!XMLUtils::GetFloat(pElement, "noisereduction", m_defaultVideoSettings.m_NoiseReduction, 0.0f, 1.0f))
115       m_defaultVideoSettings.m_NoiseReduction = 0.0f;
116     XMLUtils::GetBoolean(pElement, "postprocess", m_defaultVideoSettings.m_PostProcess);
117     if (!XMLUtils::GetFloat(pElement, "sharpness", m_defaultVideoSettings.m_Sharpness, -1.0f, 1.0f))
118       m_defaultVideoSettings.m_Sharpness = 0.0f;
119     XMLUtils::GetBoolean(pElement, "outputtoallspeakers", m_defaultVideoSettings.m_OutputToAllSpeakers);
120     XMLUtils::GetBoolean(pElement, "showsubtitles", m_defaultVideoSettings.m_SubtitleOn);
121     if (!XMLUtils::GetFloat(pElement, "brightness", m_defaultVideoSettings.m_Brightness, 0, 100))
122       m_defaultVideoSettings.m_Brightness = 50;
123     if (!XMLUtils::GetFloat(pElement, "contrast", m_defaultVideoSettings.m_Contrast, 0, 100))
124       m_defaultVideoSettings.m_Contrast = 50;
125     if (!XMLUtils::GetFloat(pElement, "gamma", m_defaultVideoSettings.m_Gamma, 0, 100))
126       m_defaultVideoSettings.m_Gamma = 20;
127     if (!XMLUtils::GetFloat(pElement, "audiodelay", m_defaultVideoSettings.m_AudioDelay, -10.0f, 10.0f))
128       m_defaultVideoSettings.m_AudioDelay = 0.0f;
129     if (!XMLUtils::GetFloat(pElement, "subtitledelay", m_defaultVideoSettings.m_SubtitleDelay, -10.0f, 10.0f))
130       m_defaultVideoSettings.m_SubtitleDelay = 0.0f;
131     XMLUtils::GetBoolean(pElement, "autocrop", m_defaultVideoSettings.m_Crop);
132     XMLUtils::GetBoolean(pElement, "nonlinstretch", m_defaultVideoSettings.m_CustomNonLinStretch);
133     if (!XMLUtils::GetInt(pElement, "stereomode", m_defaultVideoSettings.m_StereoMode))
134       m_defaultVideoSettings.m_StereoMode = 0;
135
136     m_defaultVideoSettings.m_SubtitleCached = false;
137   }
138
139   // mymusic settings
140   pElement = settings->FirstChildElement("mymusic");
141   if (pElement != NULL)
142   {
143     const TiXmlElement *pChild = pElement->FirstChildElement("playlist");
144     if (pChild != NULL)
145     {
146       XMLUtils::GetBoolean(pChild, "repeat", m_musicPlaylistRepeat);
147       XMLUtils::GetBoolean(pChild, "shuffle", m_musicPlaylistShuffle);
148     }
149     if (!XMLUtils::GetInt(pElement, "needsupdate", m_musicNeedsUpdate, 0, INT_MAX))
150       m_musicNeedsUpdate = 0;
151   }
152   
153   // Read the watchmode settings for the various media views
154   pElement = settings->FirstChildElement("myvideos");
155   if (pElement != NULL)
156   {
157     int tmp;
158     if (XMLUtils::GetInt(pElement, "watchmodemovies", tmp, (int)WatchedModeAll, (int)WatchedModeWatched))
159       m_watchedModes["movies"] = (WatchedMode)tmp;
160     if (XMLUtils::GetInt(pElement, "watchmodetvshows", tmp, (int)WatchedModeAll, (int)WatchedModeWatched))
161       m_watchedModes["tvshows"] = (WatchedMode)tmp;
162     if (XMLUtils::GetInt(pElement, "watchmodemusicvideos", tmp, (int)WatchedModeAll, (int)WatchedModeWatched))
163       m_watchedModes["musicvideos"] = (WatchedMode)tmp;
164
165     const TiXmlElement *pChild = pElement->FirstChildElement("playlist");
166     if (pChild != NULL)
167     {
168       XMLUtils::GetBoolean(pChild, "repeat", m_videoPlaylistRepeat);
169       XMLUtils::GetBoolean(pChild, "shuffle", m_videoPlaylistShuffle);
170     }
171     if (!XMLUtils::GetInt(pElement, "needsupdate", m_videoNeedsUpdate, 0, INT_MAX))
172       m_videoNeedsUpdate = 0;
173   }
174
175   return true;
176 }
177
178 void CMediaSettings::OnSettingsLoaded()
179 {
180   g_playlistPlayer.SetRepeat(PLAYLIST_MUSIC, m_musicPlaylistRepeat ? PLAYLIST::REPEAT_ALL : PLAYLIST::REPEAT_NONE);
181   g_playlistPlayer.SetShuffle(PLAYLIST_MUSIC, m_musicPlaylistShuffle);
182   g_playlistPlayer.SetRepeat(PLAYLIST_VIDEO, m_videoPlaylistRepeat ? PLAYLIST::REPEAT_ALL : PLAYLIST::REPEAT_NONE);
183   g_playlistPlayer.SetShuffle(PLAYLIST_VIDEO, m_videoPlaylistShuffle);
184 }
185
186 bool CMediaSettings::Save(TiXmlNode *settings) const
187 {
188   if (settings == NULL)
189     return false;
190
191   CSingleLock lock(m_critical);
192   // default video settings
193   TiXmlElement videoSettingsNode("defaultvideosettings");
194   TiXmlNode *pNode = settings->InsertEndChild(videoSettingsNode);
195   if (pNode == NULL)
196     return false;
197
198   XMLUtils::SetInt(pNode, "deinterlacemode", m_defaultVideoSettings.m_DeinterlaceMode);
199   XMLUtils::SetInt(pNode, "interlacemethod", m_defaultVideoSettings.m_InterlaceMethod);
200   XMLUtils::SetInt(pNode, "scalingmethod", m_defaultVideoSettings.m_ScalingMethod);
201   XMLUtils::SetFloat(pNode, "noisereduction", m_defaultVideoSettings.m_NoiseReduction);
202   XMLUtils::SetBoolean(pNode, "postprocess", m_defaultVideoSettings.m_PostProcess);
203   XMLUtils::SetFloat(pNode, "sharpness", m_defaultVideoSettings.m_Sharpness);
204   XMLUtils::SetInt(pNode, "viewmode", m_defaultVideoSettings.m_ViewMode);
205   XMLUtils::SetFloat(pNode, "zoomamount", m_defaultVideoSettings.m_CustomZoomAmount);
206   XMLUtils::SetFloat(pNode, "pixelratio", m_defaultVideoSettings.m_CustomPixelRatio);
207   XMLUtils::SetFloat(pNode, "verticalshift", m_defaultVideoSettings.m_CustomVerticalShift);
208   XMLUtils::SetFloat(pNode, "volumeamplification", m_defaultVideoSettings.m_VolumeAmplification);
209   XMLUtils::SetBoolean(pNode, "outputtoallspeakers", m_defaultVideoSettings.m_OutputToAllSpeakers);
210   XMLUtils::SetBoolean(pNode, "showsubtitles", m_defaultVideoSettings.m_SubtitleOn);
211   XMLUtils::SetFloat(pNode, "brightness", m_defaultVideoSettings.m_Brightness);
212   XMLUtils::SetFloat(pNode, "contrast", m_defaultVideoSettings.m_Contrast);
213   XMLUtils::SetFloat(pNode, "gamma", m_defaultVideoSettings.m_Gamma);
214   XMLUtils::SetFloat(pNode, "audiodelay", m_defaultVideoSettings.m_AudioDelay);
215   XMLUtils::SetFloat(pNode, "subtitledelay", m_defaultVideoSettings.m_SubtitleDelay);
216   XMLUtils::SetBoolean(pNode, "autocrop", m_defaultVideoSettings.m_Crop); 
217   XMLUtils::SetBoolean(pNode, "nonlinstretch", m_defaultVideoSettings.m_CustomNonLinStretch);
218   XMLUtils::SetInt(pNode, "stereomode", m_defaultVideoSettings.m_StereoMode);
219
220   // mymusic
221   pNode = settings->FirstChild("mymusic");
222   if (pNode == NULL)
223   {
224     TiXmlElement videosNode("mymusic");
225     pNode = settings->InsertEndChild(videosNode);
226     if (pNode == NULL)
227       return false;
228   }
229
230   TiXmlElement musicPlaylistNode("playlist");
231   TiXmlNode *playlistNode = pNode->InsertEndChild(musicPlaylistNode);
232   if (playlistNode == NULL)
233     return false;
234   XMLUtils::SetBoolean(playlistNode, "repeat", m_musicPlaylistRepeat);
235   XMLUtils::SetBoolean(playlistNode, "shuffle", m_musicPlaylistShuffle);
236
237   XMLUtils::SetInt(pNode, "needsupdate", m_musicNeedsUpdate);
238
239   // myvideos
240   pNode = settings->FirstChild("myvideos");
241   if (pNode == NULL)
242   {
243     TiXmlElement videosNode("myvideos");
244     pNode = settings->InsertEndChild(videosNode);
245     if (pNode == NULL)
246       return false;
247   }
248
249   XMLUtils::SetInt(pNode, "watchmodemovies", m_watchedModes.find("movies")->second);
250   XMLUtils::SetInt(pNode, "watchmodetvshows", m_watchedModes.find("tvshows")->second);
251   XMLUtils::SetInt(pNode, "watchmodemusicvideos", m_watchedModes.find("musicvideos")->second);
252
253   TiXmlElement videoPlaylistNode("playlist");
254   playlistNode = pNode->InsertEndChild(videoPlaylistNode);
255   if (playlistNode == NULL)
256     return false;
257   XMLUtils::SetBoolean(playlistNode, "repeat", m_videoPlaylistRepeat);
258   XMLUtils::SetBoolean(playlistNode, "shuffle", m_videoPlaylistShuffle);
259
260   XMLUtils::SetInt(pNode, "needsupdate", m_videoNeedsUpdate);
261
262   return true;
263 }
264
265 void CMediaSettings::OnSettingAction(const CSetting *setting)
266 {
267   if (setting == NULL)
268     return;
269
270   const std::string &settingId = setting->GetId();
271   if (settingId == "karaoke.export")
272   {
273     CContextButtons choices;
274     choices.Add(1, g_localizeStrings.Get(22034));
275     choices.Add(2, g_localizeStrings.Get(22035));
276
277     int retVal = CGUIDialogContextMenu::ShowAndGetChoice(choices);
278     if ( retVal > 0 )
279     {
280       CStdString path(CProfilesManager::Get().GetDatabaseFolder());
281       VECSOURCES shares;
282       g_mediaManager.GetLocalDrives(shares);
283       if (CGUIDialogFileBrowser::ShowAndGetDirectory(shares, g_localizeStrings.Get(661), path, true))
284       {
285         CMusicDatabase musicdatabase;
286         musicdatabase.Open();
287
288         if ( retVal == 1 )
289         {
290           path = URIUtils::AddFileToFolder(path, "karaoke.html");
291           musicdatabase.ExportKaraokeInfo( path, true );
292         }
293         else
294         {
295           path = URIUtils::AddFileToFolder(path, "karaoke.csv");
296           musicdatabase.ExportKaraokeInfo( path, false );
297         }
298         musicdatabase.Close();
299       }
300     }
301   }
302   else if (settingId == "karaoke.importcsv")
303   {
304     CStdString path(CProfilesManager::Get().GetDatabaseFolder());
305     VECSOURCES shares;
306     g_mediaManager.GetLocalDrives(shares);
307     if (CGUIDialogFileBrowser::ShowAndGetFile(shares, "karaoke.csv", g_localizeStrings.Get(651) , path))
308     {
309       CMusicDatabase musicdatabase;
310       musicdatabase.Open();
311       musicdatabase.ImportKaraokeInfo(path);
312       musicdatabase.Close();
313     }
314   }
315   else if (settingId == "musiclibrary.cleanup")
316   {
317     CMusicDatabase musicdatabase;
318     musicdatabase.Clean();
319     CUtil::DeleteMusicDatabaseDirectoryCache();
320   }
321   else if (settingId == "musiclibrary.export")
322     CBuiltins::Execute("exportlibrary(music)");
323   else if (settingId == "musiclibrary.import")
324   {
325     CStdString path;
326     VECSOURCES shares;
327     g_mediaManager.GetLocalDrives(shares);
328     if (CGUIDialogFileBrowser::ShowAndGetFile(shares, "musicdb.xml", g_localizeStrings.Get(651) , path))
329     {
330       CMusicDatabase musicdatabase;
331       musicdatabase.Open();
332       musicdatabase.ImportFromXML(path);
333       musicdatabase.Close();
334     }
335   }
336   else if (settingId == "videolibrary.cleanup")
337   {
338     if (CGUIDialogYesNo::ShowAndGetInput(313, 333, 0, 0))
339       g_application.StartVideoCleanup();
340   }
341   else if (settingId == "videolibrary.export")
342     CBuiltins::Execute("exportlibrary(video)");
343   else if (settingId == "videolibrary.import")
344   {
345     CStdString path;
346     VECSOURCES shares;
347     g_mediaManager.GetLocalDrives(shares);
348     if (CGUIDialogFileBrowser::ShowAndGetDirectory(shares, g_localizeStrings.Get(651) , path))
349     {
350       CVideoDatabase videodatabase;
351       videodatabase.Open();
352       videodatabase.ImportFromXML(path);
353       videodatabase.Close();
354     }
355   }
356 }
357
358 int CMediaSettings::GetWatchedMode(const std::string &content) const
359 {
360   CSingleLock lock(m_critical);
361   WatchedModes::const_iterator it = m_watchedModes.find(GetWatchedContent(content));
362   if (it != m_watchedModes.end())
363     return it->second;
364
365   return WatchedModeAll;
366 }
367
368 void CMediaSettings::SetWatchedMode(const std::string &content, WatchedMode mode)
369 {
370   CSingleLock lock(m_critical);
371   WatchedModes::iterator it = m_watchedModes.find(GetWatchedContent(content));
372   if (it != m_watchedModes.end())
373     it->second = mode;
374 }
375
376 void CMediaSettings::CycleWatchedMode(const std::string &content)
377 {
378   CSingleLock lock(m_critical);
379   WatchedModes::iterator it = m_watchedModes.find(GetWatchedContent(content));
380   if (it != m_watchedModes.end())
381   {
382     it->second = (WatchedMode)((int)it->second + 1);
383     if (it->second > WatchedModeWatched)
384       it->second = WatchedModeAll;
385   }
386 }
387
388 std::string CMediaSettings::GetWatchedContent(const std::string &content)
389 {
390   if (content == "seasons" || content == "episodes")
391     return "tvshows";
392
393   return content;
394 }