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 "StackDirectory.h"
12 #include "FileItemList.h"
13 #include "ServiceBroker.h"
15 #include "settings/AdvancedSettings.h"
16 #include "settings/SettingsComponent.h"
17 #include "utils/StringUtils.h"
18 #include "utils/URIUtils.h"
19 #include "utils/log.h"
25 CStackDirectory::CStackDirectory() = default;
27 CStackDirectory::~CStackDirectory() = default;
29 bool CStackDirectory::GetDirectory(const CURL
& url
, CFileItemList
& items
)
32 std::vector
<std::string
> files
;
33 const std::string
pathToUrl(url
.Get());
34 if (!GetPaths(pathToUrl
, files
))
35 return false; // error in path
37 for (const std::string
& i
: files
)
39 CFileItemPtr
item(new CFileItem(i
));
41 item
->m_bIsFolder
= false;
47 std::string
CStackDirectory::GetStackedTitlePath(const std::string
&strPath
)
51 CRegExp
tempRE(true, CRegExp::autoUtf8
);
52 const std::vector
<std::string
>& strRegExps
= CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_videoStackRegExps
;
53 std::vector
<std::string
>::const_iterator itRegExp
= strRegExps
.begin();
54 while (itRegExp
!= strRegExps
.end())
56 (void)tempRE
.RegComp(*itRegExp
);
57 if (tempRE
.GetCaptureTotal() == 4)
58 RegExps
.push_back(tempRE
);
60 CLog::Log(LOGERROR
, "Invalid video stack RE ({}). Must have exactly 4 captures.",
64 return GetStackedTitlePath(strPath
, RegExps
);
67 std::string
CStackDirectory::GetStackedTitlePath(const std::string
&strPath
, VECCREGEXP
& RegExps
)
69 CStackDirectory stack
;
71 std::string strStackTitlePath
,
72 strCommonDir
= URIUtils::GetParentPath(strPath
);
74 const CURL
pathToUrl(strPath
);
75 stack
.GetDirectory(pathToUrl
, files
);
79 std::string strStackTitle
;
81 std::string File1
= URIUtils::GetFileName(files
[0]->GetPath());
82 std::string File2
= URIUtils::GetFileName(files
[1]->GetPath());
83 // Check if source path uses URL encoding
84 if (URIUtils::HasEncodedFilename(CURL(strCommonDir
)))
86 File1
= CURL::Decode(File1
);
87 File2
= CURL::Decode(File2
);
90 std::vector
<CRegExp
>::iterator itRegExp
= RegExps
.begin();
93 while (itRegExp
!= RegExps
.end())
95 if (itRegExp
->RegFind(File1
, offset
) != -1)
97 std::string Title1
= itRegExp
->GetMatch(1),
98 Volume1
= itRegExp
->GetMatch(2),
99 Ignore1
= itRegExp
->GetMatch(3),
100 Extension1
= itRegExp
->GetMatch(4);
102 Title1
= File1
.substr(0, itRegExp
->GetSubStart(2));
103 if (itRegExp
->RegFind(File2
, offset
) != -1)
105 std::string Title2
= itRegExp
->GetMatch(1),
106 Volume2
= itRegExp
->GetMatch(2),
107 Ignore2
= itRegExp
->GetMatch(3),
108 Extension2
= itRegExp
->GetMatch(4);
110 Title2
= File2
.substr(0, itRegExp
->GetSubStart(2));
111 if (StringUtils::EqualsNoCase(Title1
, Title2
))
113 if (!StringUtils::EqualsNoCase(Volume1
, Volume2
))
115 if (StringUtils::EqualsNoCase(Ignore1
, Ignore2
) &&
116 StringUtils::EqualsNoCase(Extension1
, Extension2
))
119 strStackTitle
= Title1
+ Ignore1
+ Extension1
;
120 // Check if source path uses URL encoding
121 if (URIUtils::HasEncodedFilename(CURL(strCommonDir
)))
122 strStackTitle
= CURL::Encode(strStackTitle
);
124 itRegExp
= RegExps
.end();
127 else // Invalid stack
130 else // Early match, retry with offset
132 offset
= itRegExp
->GetSubStart(3);
141 if (!strCommonDir
.empty() && !strStackTitle
.empty())
142 strStackTitlePath
= strCommonDir
+ strStackTitle
;
145 return strStackTitlePath
;
148 std::string
CStackDirectory::GetFirstStackedFile(const std::string
&strPath
)
150 // the stacked files are always in volume order, so just get up to the first filename
151 // occurrence of " , "
152 std::string file
, folder
;
153 size_t pos
= strPath
.find(" , ");
154 if (pos
!= std::string::npos
)
155 URIUtils::Split(strPath
.substr(0, pos
), folder
, file
);
157 URIUtils::Split(strPath
, folder
, file
); // single filed stacks - should really not happen
159 // remove "stack://" from the folder
160 folder
= folder
.substr(8);
161 StringUtils::Replace(file
, ",,", ",");
163 return URIUtils::AddFileToFolder(folder
, file
);
166 bool CStackDirectory::GetPaths(const std::string
& strPath
, std::vector
<std::string
>& vecPaths
)
169 // stack://file1 , file2 , file3 , file4
170 // filenames with commas are double escaped (ie replaced with ,,), thus the " , " separator used.
171 std::string path
= strPath
;
172 // remove stack:// from the beginning
173 path
= path
.substr(8);
175 vecPaths
= StringUtils::Split(path
, " , ");
176 if (vecPaths
.empty())
179 // because " , " is used as a separator any "," in the real paths are double escaped
180 for (std::string
& itPath
: vecPaths
)
181 StringUtils::Replace(itPath
, ",,", ",");
186 std::string
CStackDirectory::ConstructStackPath(const CFileItemList
&items
, const std::vector
<int> &stack
)
188 // no checks on the range of stack here.
189 // we replace all instances of comma's with double comma's, then separate
190 // the files using " , ".
191 std::string stackedPath
= "stack://";
192 std::string folder
, file
;
193 URIUtils::Split(items
[stack
[0]]->GetPath(), folder
, file
);
194 stackedPath
+= folder
;
195 // double escape any occurrence of commas
196 StringUtils::Replace(file
, ",", ",,");
198 for (unsigned int i
= 1; i
< stack
.size(); ++i
)
200 stackedPath
+= " , ";
201 file
= items
[stack
[i
]]->GetPath();
203 // double escape any occurrence of commas
204 StringUtils::Replace(file
, ",", ",,");
210 bool CStackDirectory::ConstructStackPath(const std::vector
<std::string
> &paths
, std::string
& stackedPath
)
212 if (paths
.size() < 2)
214 stackedPath
= "stack://";
215 std::string folder
, file
;
216 URIUtils::Split(paths
[0], folder
, file
);
217 stackedPath
+= folder
;
218 // double escape any occurrence of commas
219 StringUtils::Replace(file
, ",", ",,");
221 for (unsigned int i
= 1; i
< paths
.size(); ++i
)
223 stackedPath
+= " , ";
226 // double escape any occurrence of commas
227 StringUtils::Replace(file
, ",", ",,");