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 #pragma once
10 
11 #include "TextureDatabase.h"
12 #include "threads/Event.h"
13 #include "utils/JobManager.h"
14 
15 #include <set>
16 #include <string>
17 #include <vector>
18 
19 class CURL;
20 class CTexture;
21 
22 /*!
23  \ingroup textures
24  \brief Texture cache class for handling the caching of images.
25 
26  Manages the caching of images for use as control textures. Images are cached
27  both as originals (direct copies) and as .dds textures for fast loading. Images
28  may be periodically checked for updates and may be purged from the cache if
29  unused for a set period of time.
30 
31  */
32 class CTextureCache : public CJobQueue
33 {
34 public:
35   /*!
36    \brief The only way through which the global instance of the CTextureCache should be accessed.
37    \return the global instance.
38    */
39   static CTextureCache &GetInstance();
40 
41   /*! \brief Initialize the texture cache
42    */
43   void Initialize();
44 
45   /*! \brief Deinitialize the texture cache
46    */
47   void Deinitialize();
48 
49   /*! \brief Check whether we already have this image cached
50 
51    Check and return URL to cached image if it exists; If not, return empty string.
52    If the image is cached, return URL (for original image or .dds version if requested)
53 
54    \param image url of the image to check
55    \param needsRecaching [out] whether the image needs recaching.
56    \return cached url of this image
57    \sa GetCachedImage
58    */
59   std::string CheckCachedImage(const std::string &image, bool &needsRecaching);
60 
61   /*! \brief Cache image (if required) using a background job
62 
63    Checks firstly whether an image is already cached, and return URL if so [see CheckCacheImage]
64    If the image is not yet in the database, a background job is started to
65    cache the image and add to the database [see CTextureCacheJob]
66 
67    \param image url of the image to cache
68    \sa CacheImage
69    */
70   void BackgroundCacheImage(const std::string &image);
71 
72   /*! \brief Cache an image to image cache, optionally return the texture
73 
74    Caches the given image, returning the texture if the caller wants it.
75 
76    \param image url of the image to cache
77    \param texture [out] the loaded image
78    \param details [out] details of the cached image
79    \return cached url of this image
80    \sa CTextureCacheJob::CacheTexture
81    */
82   std::string CacheImage(const std::string& image,
83                          CTexture** texture = NULL,
84                          CTextureDetails* details = NULL);
85 
86   /*! \brief Cache an image to image cache if not already cached, returning the image details.
87    \param image url of the image to cache.
88    \param details [out] the image details.
89    \return true if the image is in the cache, false otherwise.
90    \sa CTextureCacheJob::CacheTexture
91    */
92   bool CacheImage(const std::string &image, CTextureDetails &details);
93 
94   /*! \brief Check whether an image is in the cache
95    Note: If the image url won't normally be cached (eg a skin image) this function will return false.
96    \param image url of the image
97    \return true if the image is cached, false otherwise
98    \sa ClearCachedImage
99    */
100   bool HasCachedImage(const std::string &image);
101 
102   /*! \brief clear the cached version of the given image
103    \param image url of the image
104    \sa GetCachedImage
105    */
106   void ClearCachedImage(const std::string &image, bool deleteSource = false);
107 
108   /*! \brief clear the cached version of the image with given id
109    \param database id of the image
110    \sa GetCachedImage
111    */
112   bool ClearCachedImage(int textureID);
113 
114   /*! \brief retrieve a cache file (relative to the cache path) to associate with the given image, excluding extension
115    Use GetCachedPath(GetCacheFile(url)+extension) for the full path to the file.
116    \param url location of the image
117    \return a "unique" filename for the associated cache file, excluding extension
118    */
119   static std::string GetCacheFile(const std::string &url);
120 
121   /*! \brief retrieve the full path of the given cached file
122    \param file name of the file
123    \return full path of the cached file
124    */
125   static std::string GetCachedPath(const std::string &file);
126 
127   /*! \brief check whether an image:// URL may be cached
128    \param url the URL to the image
129    \return true if the given URL may be cached, false otherwise
130    */
131   static bool CanCacheImageURL(const CURL &url);
132 
133   /*! \brief Add this image to the database
134    Thread-safe wrapper of CTextureDatabase::AddCachedTexture
135    \param image url of the original image
136    \param details the texture details to add
137    \return true if we successfully added to the database, false otherwise.
138    */
139   bool AddCachedTexture(const std::string &image, const CTextureDetails &details);
140 
141   /*! \brief Export a (possibly) cached image to a file
142    \param image url of the original image
143    \param destination url of the destination image, excluding extension.
144    \param overwrite whether to overwrite the destination if it exists (TODO: Defaults to false)
145    \return true if we successfully exported the file, false otherwise.
146    */
147   bool Export(const std::string &image, const std::string &destination, bool overwrite);
148   bool Export(const std::string &image, const std::string &destination); //! @todo BACKWARD COMPATIBILITY FOR MUSIC THUMBS
149 private:
150   // private construction, and no assignments; use the provided singleton methods
151   CTextureCache();
152   CTextureCache(const CTextureCache&) = delete;
153   CTextureCache const& operator=(CTextureCache const&) = delete;
154   ~CTextureCache() override;
155 
156   /*! \brief Check if the given image is a cached image
157    \param image url of the image
158    \return true if this is a cached image, false otherwise.
159    */
160   bool IsCachedImage(const std::string &image) const;
161 
162   /*! \brief retrieve the cached version of the given image (if it exists)
163    \param image url of the image
164    \param details [out] the details of the texture.
165    \param trackUsage whether this call should track usage of the image (defaults to false)
166    \return cached url of this image, empty if none exists
167    \sa ClearCachedImage, CTextureDetails
168    */
169   std::string GetCachedImage(const std::string &image, CTextureDetails &details, bool trackUsage = false);
170 
171   /*! \brief Get an image from the database
172    Thread-safe wrapper of CTextureDatabase::GetCachedTexture
173    \param image url of the original image
174    \param details [out] texture details from the database (if available)
175    \return true if we have a cached version of this image, false otherwise.
176    */
177   bool GetCachedTexture(const std::string &url, CTextureDetails &details);
178 
179   /*! \brief Clear an image from the database
180    Thread-safe wrapper of CTextureDatabase::ClearCachedTexture
181    \param image url of the original image
182    \param cacheFile [out] url of the cached original (if available)
183    \return true if we had a cached version of this image, false otherwise.
184    */
185   bool ClearCachedTexture(const std::string &url, std::string &cacheFile);
186   bool ClearCachedTexture(int textureID, std::string &cacheFile);
187 
188   /*! \brief Increment the use count of a texture
189    Stores locally before calling CTextureDatabase::IncrementUseCount via a CUseCountJob
190    \sa CUseCountJob, CTextureDatabase::IncrementUseCount
191    */
192   void IncrementUseCount(const CTextureDetails &details);
193 
194   /*! \brief Set a previously cached texture as valid in the database
195    Thread-safe wrapper of CTextureDatabase::SetCachedTextureValid
196    \param image url of the original image
197    \param updateable whether this image should be checked for updates
198    \return true if successful, false otherwise.
199    */
200   bool SetCachedTextureValid(const std::string &url, bool updateable);
201 
202   void OnJobComplete(unsigned int jobID, bool success, CJob *job) override;
203   void OnJobProgress(unsigned int jobID, unsigned int progress, unsigned int total, const CJob *job) override;
204 
205   /*! \brief Called when a caching job has completed.
206    Removes the job from our processing list, updates the database
207    and fires a DDS job if appropriate.
208    \param success whether the job was successful.
209    \param job the caching job.
210    */
211   void OnCachingComplete(bool success, CTextureCacheJob *job);
212 
213   CCriticalSection m_databaseSection;
214   CTextureDatabase m_database;
215   std::set<std::string> m_processinglist; ///< currently processing list to avoid 2 jobs being processed at once
216   CCriticalSection     m_processingSection;
217   CEvent               m_completeEvent; ///< Set whenever a job has finished
218   std::vector<CTextureDetails> m_useCounts; ///< Use count tracking
219   CCriticalSection             m_useCountSection;
220 };
221 
222