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 "FileDirectoryFactory.h"
11 #include "music/MusicFileItemClassify.h"
13 #if defined(HAS_ISO9660PP)
14 #include "ISO9660Directory.h"
16 #if defined(HAS_UDFREAD)
17 #include "UDFDirectory.h"
19 #include "RSSDirectory.h"
20 #include "UDFDirectory.h"
21 #include "utils/URIUtils.h"
22 #if defined(TARGET_ANDROID)
23 #include "platform/android/filesystem/APKDirectory.h"
25 #include "AudioBookFileDirectory.h"
26 #include "Directory.h"
28 #include "PlaylistFileDirectory.h"
29 #include "ServiceBroker.h"
30 #include "SmartPlaylistDirectory.h"
32 #include "XbtDirectory.h"
33 #include "ZipDirectory.h"
34 #include "addons/AudioDecoder.h"
35 #include "addons/ExtsMimeSupportList.h"
36 #include "addons/VFSEntry.h"
37 #include "addons/addoninfo/AddonInfo.h"
38 #include "playlists/PlayListFactory.h"
39 #include "playlists/SmartPlayList.h"
40 #include "utils/StringUtils.h"
41 #include "utils/log.h"
43 using namespace ADDON
;
45 using namespace KODI::ADDONS
;
46 using namespace XFILE
;
47 using namespace PLAYLIST
;
49 CFileDirectoryFactory::CFileDirectoryFactory(void) = default;
51 CFileDirectoryFactory::~CFileDirectoryFactory(void) = default;
53 // return NULL + set pItem->m_bIsFolder to remove it completely from list.
54 IFileDirectory
* CFileDirectoryFactory::Create(const CURL
& url
, CFileItem
* pItem
, const std::string
& strMask
)
56 if (url
.IsProtocol("stack")) // disqualify stack as we need to work with each of the parts instead
60 * Check available binary addons which can contain files with underlaid
62 * Currently in vfs and audiodecoder addons.
64 * @note The file extensions are absolutely necessary for these in order to
65 * identify the associated add-on.
69 // Get file extensions to find addon related to it.
70 std::string strExtension
= URIUtils::GetExtension(url
);
71 StringUtils::ToLower(strExtension
);
73 if (!strExtension
.empty() && CServiceBroker::IsAddonInterfaceUp())
76 * Scan here about audiodecoder addons.
78 * @note: Do not check audio decoder files that are already open, they cannot
79 * contain any further sub-folders.
81 if (!StringUtils::EndsWith(strExtension
, KODI_ADDON_AUDIODECODER_TRACK_EXT
))
83 auto addonInfos
= CServiceBroker::GetExtsMimeSupportList().GetExtensionSupportedAddonInfos(
84 strExtension
, CExtsMimeSupportList::FilterSelect::hasTracks
);
85 for (const auto& addonInfo
: addonInfos
)
87 std::unique_ptr
<CAudioDecoder
> result
= std::make_unique
<CAudioDecoder
>(addonInfo
.second
);
88 if (!result
->CreateDecoder() || !result
->ContainsFiles(url
))
91 "CFileDirectoryFactory::{}: Addon '{}' support extension '{}' but creation "
92 "failed (seems not supported), trying other addons and Kodi",
93 __func__
, addonInfo
.second
->ID(), strExtension
);
96 return result
.release();
101 * Scan here about VFS addons.
103 for (const auto& vfsAddon
: CServiceBroker::GetVFSAddonCache().GetAddonInstances())
105 if (vfsAddon
->HasFileDirectories())
107 auto exts
= StringUtils::Split(vfsAddon
->GetExtensions(), "|");
108 if (std::find(exts
.begin(), exts
.end(), strExtension
) != exts
.end())
110 CVFSEntryIFileDirectoryWrapper
* wrap
= new CVFSEntryIFileDirectoryWrapper(vfsAddon
);
111 if (wrap
->ContainsFiles(url
))
113 if (wrap
->m_items
.Size() == 1)
115 // one STORED file - collapse it down
116 *pItem
= *wrap
->m_items
[0];
120 // compressed or more than one file -> create a dir
121 pItem
->SetPath(wrap
->m_items
.GetPath());
124 // Check for folder, if yes return also wrap.
125 // Needed to fix for e.g. RAR files with only one file inside
126 pItem
->m_bIsFolder
= URIUtils::HasSlashAtEnd(pItem
->GetPath());
127 if (pItem
->m_bIsFolder
)
132 pItem
->m_bIsFolder
= true;
144 return new CRSSDirectory();
147 if (pItem
->IsDiscImage())
149 #if defined(HAS_ISO9660PP)
150 CISO9660Directory
* iso
= new CISO9660Directory();
151 if (iso
->Exists(pItem
->GetURL()))
157 #if defined(HAS_UDFREAD)
158 return new CUDFDirectory();
164 #if defined(TARGET_ANDROID)
165 if (url
.IsFileType("apk"))
167 CURL zipURL
= URIUtils::CreateArchivePath("apk", url
);
170 CDirectory::GetDirectory(zipURL
, items
, strMask
, DIR_FLAG_DEFAULTS
);
171 if (items
.Size() == 0) // no files
172 pItem
->m_bIsFolder
= true;
173 else if (items
.Size() == 1 && items
[0]->m_idepth
== 0 && !items
[0]->m_bIsFolder
)
175 // one STORED file - collapse it down
179 { // compressed or more than one file -> create a apk dir
180 pItem
->SetURL(zipURL
);
181 return new CAPKDirectory
;
186 if (url
.IsFileType("zip"))
188 CURL zipURL
= URIUtils::CreateArchivePath("zip", url
);
191 CDirectory::GetDirectory(zipURL
, items
, strMask
, DIR_FLAG_DEFAULTS
);
192 if (items
.Size() == 0) // no files
193 pItem
->m_bIsFolder
= true;
194 else if (items
.Size() == 1 && items
[0]->m_idepth
== 0 && !items
[0]->m_bIsFolder
)
196 // one STORED file - collapse it down
200 { // compressed or more than one file -> create a zip dir
201 pItem
->SetURL(zipURL
);
202 return new CZipDirectory
;
206 if (url
.IsFileType("xbt"))
208 CURL xbtUrl
= URIUtils::CreateArchivePath("xbt", url
);
209 pItem
->SetURL(xbtUrl
);
211 return new CXbtDirectory();
213 if (url
.IsFileType("xsp"))
214 { // XBMC Smart playlist - just XML renamed to XSP
215 // read the name of the playlist in
216 CSmartPlaylist playlist
;
217 if (playlist
.OpenAndReadName(url
))
219 pItem
->SetLabel(playlist
.GetName());
220 pItem
->SetLabelPreformatted(true);
222 IFileDirectory
* pDir
=new CSmartPlaylistDirectory
;
223 return pDir
; // treat as directory
225 if (CPlayListFactory::IsPlaylist(url
))
227 // currently we only return the directory if it contains
228 // more than one file. Reason is that .pls and .m3u may be used
229 // for links to http streams etc.
230 IFileDirectory
*pDir
= new CPlaylistFileDirectory();
232 if (pDir
->GetDirectory(url
, items
))
234 if (items
.Size() > 1)
241 if (MUSIC::IsAudioBook(*pItem
))
243 if (!pItem
->HasMusicInfoTag() || pItem
->GetEndOffset() <= 0)
245 auto pDir
= std::make_unique
<CAudioBookFileDirectory
>();
246 if (pDir
->ContainsFiles(url
))
247 return pDir
.release();