55# ##################################
66
77# standard library
8+ import json
9+ from hashlib import md5
810from pathlib import Path
911
1012# 3rd party
@@ -39,6 +41,7 @@ class IntegrationMaterialSocialCards:
3941 IS_SOCIAL_PLUGIN_CARDS_ENABLED : bool = True
4042 IS_THEME_MATERIAL : bool = False
4143 IS_INSIDERS : bool = False
44+ CARDS_MANIFEST : dict | None = None
4245
4346 def __init__ (self , mkdocs_config : MkDocsConfig , switch_force : bool = True ) -> None :
4447 """Integration instanciation.
@@ -62,7 +65,6 @@ def __init__(self, mkdocs_config: MkDocsConfig, switch_force: bool = True) -> No
6265 self .IS_SOCIAL_PLUGIN_CARDS_ENABLED ,
6366 ]
6467 )
65- self .IS_INSIDERS = self .is_mkdocs_theme_material_insiders ()
6668
6769 # except if the end-user wants to disable it
6870 if switch_force is False :
@@ -82,6 +84,12 @@ def __init__(self, mkdocs_config: MkDocsConfig, switch_force: bool = True) -> No
8284 self .social_cards_cache_dir = self .get_social_cards_cache_dir (
8385 mkdocs_config = mkdocs_config
8486 )
87+ if self .is_mkdocs_theme_material_insiders ():
88+ self .load_cache_cards_manifest ()
89+
90+ # store some attributes used to compute social card hash
91+ self .site_name = mkdocs_config .site_name
92+ self .site_description = mkdocs_config .site_description or ""
8593
8694 def is_mkdocs_theme_material (self , mkdocs_config : MkDocsConfig ) -> bool :
8795 """Check if the theme set in mkdocs.yml is material or not.
@@ -107,9 +115,11 @@ def is_mkdocs_theme_material_insiders(self) -> bool | None:
107115
108116 if material_version is not None and "insiders" in material_version :
109117 logger .debug ("Material theme edition INSIDERS" )
118+ self .IS_INSIDERS = True
110119 return True
111120 else :
112121 logger .debug ("Material theme edition COMMUNITY" )
122+ self .IS_INSIDERS = False
113123 return False
114124
115125 def is_social_plugin_enabled_mkdocs (self , mkdocs_config : MkDocsConfig ) -> bool :
@@ -126,17 +136,17 @@ def is_social_plugin_enabled_mkdocs(self, mkdocs_config: MkDocsConfig) -> bool:
126136 return False
127137
128138 if not mkdocs_config .plugins .get ("material/social" ):
129- logger .debug ("Social plugin not listed in configuration." )
139+ logger .debug ("Material Social plugin not listed in configuration." )
130140 return False
131141
132142 social_plugin_cfg = mkdocs_config .plugins .get ("material/social" )
133143
134144 if not social_plugin_cfg .config .enabled :
135- logger .debug ("Social plugin is installed but disabled." )
145+ logger .debug ("Material Social plugin is installed but disabled." )
136146 self .IS_SOCIAL_PLUGIN_ENABLED = False
137147 return False
138148
139- logger .debug ("Social plugin is enabled in Mkdocs configuration." )
149+ logger .debug ("Material Social plugin is enabled in Mkdocs configuration." )
140150 self .IS_SOCIAL_PLUGIN_CARDS_ENABLED = True
141151 return True
142152
@@ -157,19 +167,21 @@ def is_social_plugin_and_cards_enabled_mkdocs(
157167 social_plugin_cfg = mkdocs_config .plugins .get ("material/social" )
158168
159169 if not social_plugin_cfg .config .cards :
160- logger .debug ("Social plugin is installed, present but cards are disabled." )
170+ logger .debug (
171+ "Material Social plugin is installed, present but cards are disabled."
172+ )
161173 self .IS_SOCIAL_PLUGIN_CARDS_ENABLED = False
162174 return False
163175
164- logger .debug ("Social cards are enabled in Mkdocs configuration." )
176+ logger .debug ("Material Social cards are enabled in Mkdocs configuration." )
165177 self .IS_SOCIAL_PLUGIN_CARDS_ENABLED = True
166178 return True
167179
168180 def is_social_plugin_enabled_page (
169181 self , mkdocs_page : Page , fallback_value : bool = True
170182 ) -> bool :
171183 """Check if the social plugin is enabled or disabled for a specific page. Plugin
172- has to enabled in Mkdocs configuration before.
184+ has to be enabled in Mkdocs configuration before.
173185
174186 Args:
175187 mkdocs_page (Page): Mkdocs page object.
@@ -183,7 +195,31 @@ def is_social_plugin_enabled_page(
183195 "cards" , fallback_value
184196 )
185197
186- def get_social_cards_build_dir (self , mkdocs_config : MkDocsConfig ) -> str :
198+ def load_cache_cards_manifest (self ) -> dict | None :
199+ """Load social cards manifest if the file exists.
200+
201+ Returns:
202+ dict | None: manifest as dict or None if the file does not exist
203+ """
204+ cache_cards_manifest = Path (self .social_cards_cache_dir ).joinpath (
205+ "manifest.json"
206+ )
207+ if not cache_cards_manifest .is_file ():
208+ logger .debug (
209+ "Material Social Cards cache manifest file not found: "
210+ f"{ cache_cards_manifest } "
211+ )
212+ return None
213+
214+ with cache_cards_manifest .open (mode = "r" , encoding = "UTF-8" ) as manifest :
215+ self .CARDS_MANIFEST = json .load (manifest )
216+ logger .debug (
217+ f"Material Social Cards cache manifest loaded from { cache_cards_manifest } "
218+ )
219+
220+ return self .CARDS_MANIFEST
221+
222+ def get_social_cards_build_dir (self , mkdocs_config : MkDocsConfig ) -> Path :
187223 """Get Social Cards folder within Mkdocs site_dir.
188224 See: https://squidfunk.github.io/mkdocs-material/plugins/social/#config.cards_dir
189225
@@ -196,13 +232,13 @@ def get_social_cards_build_dir(self, mkdocs_config: MkDocsConfig) -> str:
196232 social_plugin_cfg = mkdocs_config .plugins .get ("material/social" )
197233
198234 logger .debug (
199- "Social cards folder in Mkdocs build directory: "
235+ "Material Social cards folder in Mkdocs build directory: "
200236 f"{ social_plugin_cfg .config .cards_dir } ."
201237 )
202238
203- return social_plugin_cfg .config .cards_dir
239+ return Path ( social_plugin_cfg .config .cards_dir ). resolve ()
204240
205- def get_social_cards_cache_dir (self , mkdocs_config : MkDocsConfig ) -> str :
241+ def get_social_cards_cache_dir (self , mkdocs_config : MkDocsConfig ) -> Path :
206242 """Get Social Cards folder within Mkdocs site_dir.
207243 See: https://squidfunk.github.io/mkdocs-material/plugins/social/#config.cards_dir
208244
@@ -213,16 +249,17 @@ def get_social_cards_cache_dir(self, mkdocs_config: MkDocsConfig) -> str:
213249 str: True if the theme material and the plugin social cards is enabled.
214250 """
215251 social_plugin_cfg = mkdocs_config .plugins .get ("material/social" )
252+ self .social_cards_cache_dir = Path (social_plugin_cfg .config .cache_dir ).resolve ()
216253
217254 logger .debug (
218- "Social cards cache folder: " f"{ social_plugin_cfg . config . cache_dir } ."
255+ "Material Social cards cache folder: " f"{ self . social_cards_cache_dir } ."
219256 )
220257
221- return social_plugin_cfg . config . cache_dir
258+ return self . social_cards_cache_dir
222259
223260 def get_social_card_build_path_for_page (
224261 self , mkdocs_page : Page , mkdocs_site_dir : str | None = None
225- ) -> Path :
262+ ) -> Path | None :
226263 """Get social card path in Mkdocs build dir for a specific page.
227264
228265 Args:
@@ -231,31 +268,80 @@ def get_social_card_build_path_for_page(
231268 'class.mkdocs_site_build_dir' is used. is Defaults to None.
232269
233270 Returns:
234- str : path to the image once published
271+ Path : path to the image once published
235272 """
236273 if mkdocs_site_dir is None and self .mkdocs_site_build_dir :
237274 mkdocs_site_dir = self .mkdocs_site_build_dir
238275
239- return Path (
276+ expected_built_card_path = Path (
240277 f"{ mkdocs_site_dir } /{ self .social_cards_assets_dir } /"
241278 f"{ Path (mkdocs_page .file .src_uri ).with_suffix ('.png' )} "
242279 )
243280
244- def get_social_card_cache_path_for_page (self , mkdocs_page : Page ) -> Path :
281+ if expected_built_card_path .is_file ():
282+ logger .debug (
283+ f"Social card file found in cache folder: { expected_built_card_path } "
284+ )
285+ return expected_built_card_path
286+ else :
287+ logger .debug (f"Not found: { expected_built_card_path } " )
288+ return None
289+
290+ def get_social_card_cache_path_for_page (self , mkdocs_page : Page ) -> Path | None :
245291 """Get social card path in social plugin cache folder for a specific page.
246292
293+ Note:
294+ As we write this code (June 2024), the cache mechanism in Insiders edition
295+ has stores images directly with the corresponding Page's path and name and
296+ keep a correspondance matrix with hashes in a manifest.json;
297+ the cache mechanism in Community edition uses the hash as file names without
298+ any exposed matching criteria.
299+
247300 Args:
248301 mkdocs_page (Page): Mkdocs page object.
249- social_plugin_cache_dir (Optional[str], optional): Mkdocs build site dir. If None, the
250- 'class.mkdocs_site_build_dir' is used. is Defaults to None.
251302
252303 Returns:
253- str : path to the image once published
304+ Path : path to the image in local cache folder if it exists
254305 """
255- return Path (
256- f"{ self .social_cards_assets_dir } /"
257- f"{ Path (mkdocs_page .file .src_uri ).with_suffix ('.png' )} "
258- )
306+ if self .IS_INSIDERS :
307+ expected_cached_card_path = self .social_cards_cache_dir .joinpath (
308+ f"assets/images/social/{ Path (mkdocs_page .file .src_uri ).with_suffix ('.png' )} "
309+ )
310+ if expected_cached_card_path .is_file ():
311+ logger .debug (
312+ f"Social card file found in cache folder: { expected_cached_card_path } "
313+ )
314+ return expected_cached_card_path
315+ else :
316+ logger .debug (f"Not found: { expected_cached_card_path } " )
317+
318+ else :
319+ if "description" in mkdocs_page .meta :
320+ description = mkdocs_page .meta ["description" ]
321+ else :
322+ description = self .site_description
323+
324+ page_hash = md5 (
325+ "" .join (
326+ [
327+ self .site_name ,
328+ str (mkdocs_page .meta .get ("title" , mkdocs_page .title )),
329+ description ,
330+ ]
331+ ).encode ("utf-8" )
332+ )
333+ expected_cached_card_path = self .social_cards_cache_dir .joinpath (
334+ f"{ page_hash .hexdigest ()} .png"
335+ )
336+
337+ if expected_cached_card_path .is_file ():
338+ logger .debug (
339+ f"Social card file found in cache folder: { expected_cached_card_path } "
340+ )
341+ return expected_cached_card_path
342+ else :
343+ logger .debug (f"Not found: { expected_cached_card_path } " )
344+ return None
259345
260346 def get_social_card_url_for_page (
261347 self ,
0 commit comments