1 /*
2  *  Copyright (C) 2005-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #include "PlayerSelectionRule.h"
10 
11 #include "ServiceBroker.h"
12 #include "URL.h"
13 #include "settings/Settings.h"
14 #include "settings/SettingsComponent.h"
15 #include "utils/RegExp.h"
16 #include "utils/StreamDetails.h"
17 #include "utils/XBMCTinyXML.h"
18 #include "utils/XMLUtils.h"
19 #include "utils/log.h"
20 #include "video/VideoInfoTag.h"
21 
22 #include <algorithm>
23 
CPlayerSelectionRule(TiXmlElement * pRule)24 CPlayerSelectionRule::CPlayerSelectionRule(TiXmlElement* pRule)
25 {
26   Initialize(pRule);
27 }
28 
~CPlayerSelectionRule()29 CPlayerSelectionRule::~CPlayerSelectionRule()
30 {
31   for (unsigned int i = 0; i < vecSubRules.size(); i++)
32   {
33     delete vecSubRules[i];
34   }
35   vecSubRules.clear();
36 }
37 
Initialize(TiXmlElement * pRule)38 void CPlayerSelectionRule::Initialize(TiXmlElement* pRule)
39 {
40   m_name = XMLUtils::GetAttribute(pRule, "name");
41   if (m_name.empty())
42     m_name = "un-named";
43 
44   CLog::Log(LOGDEBUG, "CPlayerSelectionRule::Initialize: creating rule: %s", m_name.c_str());
45 
46   m_tInternetStream = GetTristate(pRule->Attribute("internetstream"));
47   m_tRemote = GetTristate(pRule->Attribute("remote"));
48   m_tAudio = GetTristate(pRule->Attribute("audio"));
49   m_tVideo = GetTristate(pRule->Attribute("video"));
50   m_tGame = GetTristate(pRule->Attribute("game"));
51 
52   m_tBD = GetTristate(pRule->Attribute("bd"));
53   m_tDVD = GetTristate(pRule->Attribute("dvd"));
54   m_tDVDFile = GetTristate(pRule->Attribute("dvdfile"));
55   m_tDiscImage = GetTristate(pRule->Attribute("discimage"));
56   if (m_tDiscImage < 0)
57   {
58     m_tDiscImage = GetTristate(pRule->Attribute("dvdimage"));
59     if (m_tDiscImage >= 0)
60       CLog::Log(LOGWARNING, "\"dvdimage\" tag is deprecated. use \"discimage\"");
61   }
62 
63   m_protocols = XMLUtils::GetAttribute(pRule, "protocols");
64   m_fileTypes = XMLUtils::GetAttribute(pRule, "filetypes");
65   m_mimeTypes = XMLUtils::GetAttribute(pRule, "mimetypes");
66   m_fileName = XMLUtils::GetAttribute(pRule, "filename");
67 
68   m_audioCodec = XMLUtils::GetAttribute(pRule, "audiocodec");
69   m_audioChannels = XMLUtils::GetAttribute(pRule, "audiochannels");
70   m_videoCodec = XMLUtils::GetAttribute(pRule, "videocodec");
71   m_videoResolution = XMLUtils::GetAttribute(pRule, "videoresolution");
72   m_videoAspect = XMLUtils::GetAttribute(pRule, "videoaspect");
73 
74   m_bStreamDetails = m_audioCodec.length() > 0 || m_audioChannels.length() > 0 ||
75     m_videoCodec.length() > 0 || m_videoResolution.length() > 0 || m_videoAspect.length() > 0;
76 
77   if (m_bStreamDetails && !CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_MYVIDEOS_EXTRACTFLAGS))
78   {
79       CLog::Log(LOGWARNING, "CPlayerSelectionRule::Initialize: rule: %s needs media flagging, which is disabled", m_name.c_str());
80   }
81 
82   m_playerName = XMLUtils::GetAttribute(pRule, "player");
83 
84   TiXmlElement* pSubRule = pRule->FirstChildElement("rule");
85   while (pSubRule)
86   {
87     vecSubRules.push_back(new CPlayerSelectionRule(pSubRule));
88     pSubRule = pSubRule->NextSiblingElement("rule");
89   }
90 }
91 
GetTristate(const char * szValue)92 int CPlayerSelectionRule::GetTristate(const char* szValue)
93 {
94   if (szValue)
95   {
96     if (StringUtils::CompareNoCase(szValue, "true") == 0)
97       return 1;
98     if (StringUtils::CompareNoCase(szValue, "false") == 0)
99       return 0;
100   }
101   return -1;
102 }
103 
CompileRegExp(const std::string & str,CRegExp & regExp)104 bool CPlayerSelectionRule::CompileRegExp(const std::string& str, CRegExp& regExp)
105 {
106   return !str.empty() && regExp.RegComp(str.c_str());
107 }
108 
MatchesRegExp(const std::string & str,CRegExp & regExp)109 bool CPlayerSelectionRule::MatchesRegExp(const std::string& str, CRegExp& regExp)
110 {
111   return regExp.RegFind(str, 0) == 0;
112 }
113 
GetPlayers(const CFileItem & item,std::vector<std::string> & validPlayers,std::vector<std::string> & players)114 void CPlayerSelectionRule::GetPlayers(const CFileItem& item, std::vector<std::string>&validPlayers, std::vector<std::string>&players)
115 {
116   CLog::Log(LOGDEBUG, "CPlayerSelectionRule::GetPlayers: considering rule: %s", m_name.c_str());
117 
118   if (m_bStreamDetails && !item.HasVideoInfoTag())
119     return;
120   if (m_tAudio >= 0 && (m_tAudio > 0) != item.IsAudio())
121     return;
122   if (m_tVideo >= 0 && (m_tVideo > 0) != item.IsVideo())
123     return;
124   if (m_tGame >= 0 && (m_tGame > 0) != item.IsGame())
125     return;
126   if (m_tInternetStream >= 0 && (m_tInternetStream > 0) != item.IsInternetStream())
127     return;
128   if (m_tRemote >= 0 && (m_tRemote > 0) != item.IsRemote())
129     return;
130 
131   if (m_tBD >= 0 && (m_tBD > 0) != (item.IsBDFile() && item.IsOnDVD()))
132     return;
133   if (m_tDVD >= 0 && (m_tDVD > 0) != item.IsDVD())
134     return;
135   if (m_tDVDFile >= 0 && (m_tDVDFile > 0) != item.IsDVDFile())
136     return;
137   if (m_tDiscImage >= 0 && (m_tDiscImage > 0) != item.IsDiscImage())
138     return;
139 
140   CRegExp regExp(false, CRegExp::autoUtf8);
141 
142   if (m_bStreamDetails)
143   {
144     if (!item.GetVideoInfoTag()->HasStreamDetails())
145     {
146       CLog::Log(LOGDEBUG, "CPlayerSelectionRule::GetPlayers: cannot check rule: %s, no StreamDetails", m_name.c_str());
147       return;
148     }
149 
150     CStreamDetails streamDetails = item.GetVideoInfoTag()->m_streamDetails;
151 
152     if (CompileRegExp(m_audioCodec, regExp) && !MatchesRegExp(streamDetails.GetAudioCodec(), regExp))
153       return;
154 
155     std::stringstream itoa;
156     itoa << streamDetails.GetAudioChannels();
157     std::string audioChannelsstr = itoa.str();
158 
159     if (CompileRegExp(m_audioChannels, regExp) && !MatchesRegExp(audioChannelsstr, regExp))
160       return;
161 
162     if (CompileRegExp(m_videoCodec, regExp) && !MatchesRegExp(streamDetails.GetVideoCodec(), regExp))
163       return;
164 
165     if (CompileRegExp(m_videoResolution, regExp) &&
166         !MatchesRegExp(CStreamDetails::VideoDimsToResolutionDescription(streamDetails.GetVideoWidth(), streamDetails.GetVideoHeight()), regExp))
167       return;
168 
169     if (CompileRegExp(m_videoAspect, regExp) &&
170         !MatchesRegExp(CStreamDetails::VideoAspectToAspectDescription(streamDetails.GetVideoAspect()),  regExp))
171       return;
172   }
173 
174   CURL url(item.GetDynPath());
175 
176   if (CompileRegExp(m_fileTypes, regExp) && !MatchesRegExp(url.GetFileType(), regExp))
177     return;
178 
179   if (CompileRegExp(m_protocols, regExp) && !MatchesRegExp(url.GetProtocol(), regExp))
180     return;
181 
182   if (CompileRegExp(m_mimeTypes, regExp) && !MatchesRegExp(item.GetMimeType(), regExp))
183     return;
184 
185   if (CompileRegExp(m_fileName, regExp) && !MatchesRegExp(item.GetDynPath(), regExp))
186     return;
187 
188   CLog::Log(LOGDEBUG, "CPlayerSelectionRule::GetPlayers: matches rule: %s", m_name.c_str());
189 
190   for (unsigned int i = 0; i < vecSubRules.size(); i++)
191     vecSubRules[i]->GetPlayers(item, validPlayers, players);
192 
193   if (std::find(validPlayers.begin(), validPlayers.end(), m_playerName) != validPlayers.end())
194   {
195     CLog::Log(LOGDEBUG, "CPlayerSelectionRule::GetPlayers: adding player: %s for rule: %s", m_playerName.c_str(), m_name.c_str());
196     players.push_back(m_playerName);
197   }
198 }
199 
200 
201