From 143cdaa9cecbf530ebdddcd61bcb9855941f6134 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Torben=20B=C3=B6hnke?= <torben.boehnke-makerspace@rub.de>
Date: Thu, 11 Jul 2024 12:29:26 +0200
Subject: [PATCH] add requirements.txt & customPlugins

---
 .../lib/mkdocs_rss_deduplicate/__init__.py    |   1 +
 .../mkdocs_rss_deduplicate/rss_deduplicate.py |  47 +++++++
 .../mkdocs_rss_deduplicate/__init__.py        |   1 +
 .../__pycache__/__init__.cpython-310.pyc      | Bin 0 -> 264 bytes
 .../rss_deduplicate.cpython-310.pyc           | Bin 0 -> 1723 bytes
 .../mkdocs_rss_deduplicate/rss_deduplicate.py |  47 +++++++
 .../rss_deduplicate.egg-info/PKG-INFO         |  16 +++
 .../rss_deduplicate.egg-info/SOURCES.txt      |   9 ++
 .../dependency_links.txt                      |   1 +
 .../rss_deduplicate.egg-info/entry_points.txt |   2 +
 .../rss_deduplicate.egg-info/requires.txt     |   1 +
 .../rss_deduplicate.egg-info/top_level.txt    |   1 +
 customPlugins/mkdocs-rss-deduplicate/setup.py |  29 +++++
 .../lib/mkdocs_exclude_snippets/__init__.py   |   0
 .../exclude_snippets_plugin.py                | 120 ++++++++++++++++++
 .../mkdocs_exclude_snippets.egg-info/PKG-INFO |   3 +
 .../SOURCES.txt                               |   9 ++
 .../dependency_links.txt                      |   1 +
 .../entry_points.txt                          |   2 +
 .../requires.txt                              |   2 +
 .../top_level.txt                             |   1 +
 .../mkdocs_exclude_snippets/__init__.py       |   0
 .../__pycache__/__init__.cpython-310.pyc      | Bin 0 -> 206 bytes
 .../__pycache__/__init__.cpython-311.pyc      | Bin 0 -> 182 bytes
 .../exclude_snippets_plugin.cpython-310.pyc   | Bin 0 -> 4616 bytes
 .../exclude_snippets_plugin.cpython-311.pyc   | Bin 0 -> 7126 bytes
 .../exclude_snippets_plugin.py                | 120 ++++++++++++++++++
 .../mkdocs_exclude_snippets/setup.py          |  17 +++
 requirements.txt                              |  50 ++++++++
 29 files changed, 480 insertions(+)
 create mode 100755 customPlugins/mkdocs-rss-deduplicate/build/lib/mkdocs_rss_deduplicate/__init__.py
 create mode 100755 customPlugins/mkdocs-rss-deduplicate/build/lib/mkdocs_rss_deduplicate/rss_deduplicate.py
 create mode 100755 customPlugins/mkdocs-rss-deduplicate/mkdocs_rss_deduplicate/__init__.py
 create mode 100644 customPlugins/mkdocs-rss-deduplicate/mkdocs_rss_deduplicate/__pycache__/__init__.cpython-310.pyc
 create mode 100644 customPlugins/mkdocs-rss-deduplicate/mkdocs_rss_deduplicate/__pycache__/rss_deduplicate.cpython-310.pyc
 create mode 100755 customPlugins/mkdocs-rss-deduplicate/mkdocs_rss_deduplicate/rss_deduplicate.py
 create mode 100755 customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/PKG-INFO
 create mode 100755 customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/SOURCES.txt
 create mode 100755 customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/dependency_links.txt
 create mode 100755 customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/entry_points.txt
 create mode 100755 customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/requires.txt
 create mode 100755 customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/top_level.txt
 create mode 100755 customPlugins/mkdocs-rss-deduplicate/setup.py
 create mode 100755 customPlugins/mkdocs_exclude_snippets/build/lib/mkdocs_exclude_snippets/__init__.py
 create mode 100755 customPlugins/mkdocs_exclude_snippets/build/lib/mkdocs_exclude_snippets/exclude_snippets_plugin.py
 create mode 100755 customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/PKG-INFO
 create mode 100755 customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/SOURCES.txt
 create mode 100755 customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/dependency_links.txt
 create mode 100755 customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/entry_points.txt
 create mode 100755 customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/requires.txt
 create mode 100755 customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/top_level.txt
 create mode 100755 customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets/__init__.py
 create mode 100644 customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets/__pycache__/__init__.cpython-310.pyc
 create mode 100755 customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets/__pycache__/__init__.cpython-311.pyc
 create mode 100644 customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets/__pycache__/exclude_snippets_plugin.cpython-310.pyc
 create mode 100755 customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets/__pycache__/exclude_snippets_plugin.cpython-311.pyc
 create mode 100755 customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets/exclude_snippets_plugin.py
 create mode 100755 customPlugins/mkdocs_exclude_snippets/setup.py
 create mode 100644 requirements.txt

diff --git a/customPlugins/mkdocs-rss-deduplicate/build/lib/mkdocs_rss_deduplicate/__init__.py b/customPlugins/mkdocs-rss-deduplicate/build/lib/mkdocs_rss_deduplicate/__init__.py
new file mode 100755
index 000000000..5d3e80ca5
--- /dev/null
+++ b/customPlugins/mkdocs-rss-deduplicate/build/lib/mkdocs_rss_deduplicate/__init__.py
@@ -0,0 +1 @@
+from .rss_deduplicate import RssDeduplicatePlugin
\ No newline at end of file
diff --git a/customPlugins/mkdocs-rss-deduplicate/build/lib/mkdocs_rss_deduplicate/rss_deduplicate.py b/customPlugins/mkdocs-rss-deduplicate/build/lib/mkdocs_rss_deduplicate/rss_deduplicate.py
new file mode 100755
index 000000000..26377f069
--- /dev/null
+++ b/customPlugins/mkdocs-rss-deduplicate/build/lib/mkdocs_rss_deduplicate/rss_deduplicate.py
@@ -0,0 +1,47 @@
+from mkdocs.plugins import BasePlugin
+from mkdocs.config import config_options
+from xml.etree import ElementTree as ET
+import re
+
+class RssDeduplicatePlugin(BasePlugin):
+
+    def on_post_build(self, config):
+        # Paths to your RSS feed files
+        rss_created_path = config['site_dir'] + '/feed_rss_created.xml'
+        rss_updated_path = config['site_dir'] + '/feed_rss_updated.xml'
+
+        # Call the deduplication function on both RSS feed files
+        self.remove_duplicates_from_rss(rss_created_path)
+        self.remove_duplicates_from_rss(rss_updated_path)
+        self.clean_image_tags(rss_created_path)
+        self.clean_image_tags(rss_updated_path)
+
+    def clean_image_tags(self, feed_path):
+        tree = ET.parse(feed_path)
+        root = tree.getroot()
+
+        for item in root.findall('./channel/item'):
+            description = item.find('description').text
+            # Use regex to remove the width attribute snippet from the description
+            cleaned_description = re.sub(r'{\s*width="45%"\s*}', '', description)
+            # Update the description text with the cleaned version
+            item.find('description').text = cleaned_description
+
+        tree.write(feed_path, encoding='utf-8', xml_declaration=True)
+
+    def remove_duplicates_from_rss(self, feed_path):
+        # Parse the XML file
+        tree = ET.parse(feed_path)
+        root = tree.getroot()
+
+        # Function to remove duplicate entries based on <title> tag
+        seen_titles = set()
+        for item in root.findall('./channel/item'):
+            title = item.find('title').text
+            if title in seen_titles:
+                root.find('./channel').remove(item)
+            else:
+                seen_titles.add(title)
+
+        # Save the deduplicated XML to the same file
+        tree.write(feed_path, encoding='utf-8', xml_declaration=True)
diff --git a/customPlugins/mkdocs-rss-deduplicate/mkdocs_rss_deduplicate/__init__.py b/customPlugins/mkdocs-rss-deduplicate/mkdocs_rss_deduplicate/__init__.py
new file mode 100755
index 000000000..5d3e80ca5
--- /dev/null
+++ b/customPlugins/mkdocs-rss-deduplicate/mkdocs_rss_deduplicate/__init__.py
@@ -0,0 +1 @@
+from .rss_deduplicate import RssDeduplicatePlugin
\ No newline at end of file
diff --git a/customPlugins/mkdocs-rss-deduplicate/mkdocs_rss_deduplicate/__pycache__/__init__.cpython-310.pyc b/customPlugins/mkdocs-rss-deduplicate/mkdocs_rss_deduplicate/__pycache__/__init__.cpython-310.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..0d8711d70b605d63fd8e9b56e3b4b7ab636b644b
GIT binary patch
literal 264
zcmZ8bu?oU46inJh1hIo3;M$=EcM*rqBD!@6wFz2ml9HDUev-e`RT2CJCtp;s_~6}f
z_u$@{(P&6;?zdddk*`7YCql8pg#<wmK^vlIK`9Z@j->H}qMg!ivIWSc@NH99rIVY+
zA8Nf$qhf3UxcFUc2)qy*Bfa5i*wHA-+@9s8@=9t4%$8ahHFXkD1k4n$%7ZiN6AetA
lgsC9I_^cQIwfWyy#(Ax4$N8*1cY}p8!Z&gmx<lxbkQdeDOVt1X

literal 0
HcmV?d00001

diff --git a/customPlugins/mkdocs-rss-deduplicate/mkdocs_rss_deduplicate/__pycache__/rss_deduplicate.cpython-310.pyc b/customPlugins/mkdocs-rss-deduplicate/mkdocs_rss_deduplicate/__pycache__/rss_deduplicate.cpython-310.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..baee6f7007dfb93ce6fbf5dddde24fc5fe40cfdb
GIT binary patch
literal 1723
zcmZ`)OK&4Z5bo}I`niuJEE@!bh($6|><dU70Ik3)ZWdZ{8Z8=4rrXYhc{tteY%t@~
z?iKMDoa6qbzH-{XkP}rsPVll}q%K!~)6-R5-`C};*J~4a{(3tWmjNMv<7E4BVe%A)
zLc<BCIVosFDf%pDg%df}cXGGzBH#LM9z?-UgnQh7O}H=UD<=xM`wJNaZ($cQpr-vp
zqQuYnVwROK>!(#Y&1P{m*I896KswKIQHW9>OCcsHezg5Cm^_7{J_jR6L^+8Vr<}be
zk;5JC!mrzek31eg;Lz+oS86QyVxDJdqBpTq-09}QqdG8tgrUY@YRc(jIOZd=VjJH9
z->J!()a(k1U_EE!(OZnx7UKjWyAu<tOpBOja=AB}3c+KkRGdlyY4G7?k#EC`IlqAi
z%<M~1R2T5=P1-7+%BsK(%>6VMNf~EFG83^*W@_LXSBZRT{HC1I{jE6hJkh5OvI$|4
zH$-;eq}Lat)2a|7eKHzX=>jXSMlvaRRUBxcV1o9jP@{CAbX7FWsZsG8uTpgcagO-E
zwcWt>nA<R>vo#;ie>c6VjOUfo@yQ~~d5D$og6Xm@Z98q+rhU3Re0~RW!*@P>hewbx
z@nKjVUx1^@n%4A+0*h?Tu8=`z?QlTG<k!8GTf1wQ1D|K!%G3TjKn2y_m9z3||K?rn
zo%d^Y7J?2y);##r${v+9x$X}~>1k4yA|C<Kh3RmiQkhvXFL(ZUp}u^XaeeyT;a6Wj
zIfU8DkZW(Dr$^r$zhNd6Wm@s9oSA!|1t?IOCo;i{FlZU}?AUnoL@Hr|nb5MTv<aqJ
z$&)-cE;`25;!+zXg>ls4#CR_yBrynN3r=oYR&U5Xtb@B`T)TyfdCGgRBHFPs0#R-y
zZ8gytWJ4k^J1|rqOq+(Z5B&65pY5{clRMe@uQuN!$b+3MK{+_@6QrG21c-5fn1-hP
zl~;Rf&(h>K#9R>h1+4HmT()%pgu#V8e*lDqwZHM%SqliWt>BihU?TAt#?zV3#j<rv
zo_qlCv3v-2(3X4fBR@d%2n^H~s{bKQAEVhv%x`X|aT3nu$AE0AE<eE~pQ1Sc6Lpjj
zWo*MK`5D58Xz=1~6&YoF07GE{Z5C4B>C-M0`yuVJU1vGEv(W$FASMIfgmGLZg@|L*
zj^m=@iyZxK9G@?eym=#g5Y93zF@vqFY<`x1BnxkpLLr1CWMQY<lZXylQNL*d!@2F|
zN@7cmdK<9mL=xL-)B<@Ap^8FCY_&~=KSB?8x+|~=zipEKp27-+|5RPlwME%w{{VEk
Bz;FNn

literal 0
HcmV?d00001

diff --git a/customPlugins/mkdocs-rss-deduplicate/mkdocs_rss_deduplicate/rss_deduplicate.py b/customPlugins/mkdocs-rss-deduplicate/mkdocs_rss_deduplicate/rss_deduplicate.py
new file mode 100755
index 000000000..26377f069
--- /dev/null
+++ b/customPlugins/mkdocs-rss-deduplicate/mkdocs_rss_deduplicate/rss_deduplicate.py
@@ -0,0 +1,47 @@
+from mkdocs.plugins import BasePlugin
+from mkdocs.config import config_options
+from xml.etree import ElementTree as ET
+import re
+
+class RssDeduplicatePlugin(BasePlugin):
+
+    def on_post_build(self, config):
+        # Paths to your RSS feed files
+        rss_created_path = config['site_dir'] + '/feed_rss_created.xml'
+        rss_updated_path = config['site_dir'] + '/feed_rss_updated.xml'
+
+        # Call the deduplication function on both RSS feed files
+        self.remove_duplicates_from_rss(rss_created_path)
+        self.remove_duplicates_from_rss(rss_updated_path)
+        self.clean_image_tags(rss_created_path)
+        self.clean_image_tags(rss_updated_path)
+
+    def clean_image_tags(self, feed_path):
+        tree = ET.parse(feed_path)
+        root = tree.getroot()
+
+        for item in root.findall('./channel/item'):
+            description = item.find('description').text
+            # Use regex to remove the width attribute snippet from the description
+            cleaned_description = re.sub(r'{\s*width="45%"\s*}', '', description)
+            # Update the description text with the cleaned version
+            item.find('description').text = cleaned_description
+
+        tree.write(feed_path, encoding='utf-8', xml_declaration=True)
+
+    def remove_duplicates_from_rss(self, feed_path):
+        # Parse the XML file
+        tree = ET.parse(feed_path)
+        root = tree.getroot()
+
+        # Function to remove duplicate entries based on <title> tag
+        seen_titles = set()
+        for item in root.findall('./channel/item'):
+            title = item.find('title').text
+            if title in seen_titles:
+                root.find('./channel').remove(item)
+            else:
+                seen_titles.add(title)
+
+        # Save the deduplicated XML to the same file
+        tree.write(feed_path, encoding='utf-8', xml_declaration=True)
diff --git a/customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/PKG-INFO b/customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/PKG-INFO
new file mode 100755
index 000000000..8e608bbb1
--- /dev/null
+++ b/customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/PKG-INFO
@@ -0,0 +1,16 @@
+Metadata-Version: 2.1
+Name: rss-deduplicate
+Version: 0.1
+Summary: An MkDocs plugin to deduplicate RSS feed items (generated by the i18n-plugin) and clean up image tags post-build.
+Author: tb
+Keywords: rss_deduplicate
+
+
+    This MkDocs plugin performs two key functions to enhance the quality of RSS feeds generated from MkDocs sites:
+
+    1. Deduplicates entries in the RSS feed that may arise due to localization (i18n) or other site generation artifacts, ensuring each item is unique.
+
+    2. Cleans up image tags within the RSS feed descriptions to remove any site-specific markup or styling that is not compatible with RSS feed standards or display conventions in common RSS readers.
+
+    This ensures that the RSS feeds are clean, concise, and compliant with RSS specifications, providing a better experience for subscribers of the feed.
+    
diff --git a/customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/SOURCES.txt b/customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/SOURCES.txt
new file mode 100755
index 000000000..eda862a77
--- /dev/null
+++ b/customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/SOURCES.txt
@@ -0,0 +1,9 @@
+setup.py
+mkdocs_rss_deduplicate/__init__.py
+mkdocs_rss_deduplicate/rss_deduplicate.py
+rss_deduplicate.egg-info/PKG-INFO
+rss_deduplicate.egg-info/SOURCES.txt
+rss_deduplicate.egg-info/dependency_links.txt
+rss_deduplicate.egg-info/entry_points.txt
+rss_deduplicate.egg-info/requires.txt
+rss_deduplicate.egg-info/top_level.txt
\ No newline at end of file
diff --git a/customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/dependency_links.txt b/customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/dependency_links.txt
new file mode 100755
index 000000000..8b1378917
--- /dev/null
+++ b/customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/entry_points.txt b/customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/entry_points.txt
new file mode 100755
index 000000000..5cb292d02
--- /dev/null
+++ b/customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/entry_points.txt
@@ -0,0 +1,2 @@
+[mkdocs.plugins]
+rss_deduplicate = mkdocs_rss_deduplicate.rss_deduplicate:RssDeduplicatePlugin
diff --git a/customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/requires.txt b/customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/requires.txt
new file mode 100755
index 000000000..b135365ab
--- /dev/null
+++ b/customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/requires.txt
@@ -0,0 +1 @@
+mkdocs>=1.0.4
diff --git a/customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/top_level.txt b/customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/top_level.txt
new file mode 100755
index 000000000..1651e24c4
--- /dev/null
+++ b/customPlugins/mkdocs-rss-deduplicate/rss_deduplicate.egg-info/top_level.txt
@@ -0,0 +1 @@
+mkdocs_rss_deduplicate
diff --git a/customPlugins/mkdocs-rss-deduplicate/setup.py b/customPlugins/mkdocs-rss-deduplicate/setup.py
new file mode 100755
index 000000000..4f9d2114a
--- /dev/null
+++ b/customPlugins/mkdocs-rss-deduplicate/setup.py
@@ -0,0 +1,29 @@
+from setuptools import setup, find_packages
+
+setup(
+    name='rss_deduplicate',
+    version='0.1',
+    packages=find_packages(),
+    include_package_data=True,
+    install_requires=[
+        'mkdocs>=1.0.4'
+    ],
+    entry_points={
+        'mkdocs.plugins': [
+            'rss_deduplicate = mkdocs_rss_deduplicate.rss_deduplicate:RssDeduplicatePlugin',
+        ]
+    },
+    author='tb',
+    description='An MkDocs plugin to deduplicate RSS feed items (generated by the i18n-plugin) and clean up image tags post-build.',
+    long_description="""
+    This MkDocs plugin performs two key functions to enhance the quality of RSS feeds generated from MkDocs sites:
+
+    1. Deduplicates entries in the RSS feed that may arise due to localization (i18n) or other site generation artifacts, ensuring each item is unique.
+
+    2. Cleans up image tags within the RSS feed descriptions to remove any site-specific markup or styling that is not compatible with RSS feed standards or display conventions in common RSS readers.
+
+    This ensures that the RSS feeds are clean, concise, and compliant with RSS specifications, providing a better experience for subscribers of the feed.
+    """,
+
+    keywords='rss_deduplicate'
+)
\ No newline at end of file
diff --git a/customPlugins/mkdocs_exclude_snippets/build/lib/mkdocs_exclude_snippets/__init__.py b/customPlugins/mkdocs_exclude_snippets/build/lib/mkdocs_exclude_snippets/__init__.py
new file mode 100755
index 000000000..e69de29bb
diff --git a/customPlugins/mkdocs_exclude_snippets/build/lib/mkdocs_exclude_snippets/exclude_snippets_plugin.py b/customPlugins/mkdocs_exclude_snippets/build/lib/mkdocs_exclude_snippets/exclude_snippets_plugin.py
new file mode 100755
index 000000000..fe9dde61d
--- /dev/null
+++ b/customPlugins/mkdocs_exclude_snippets/build/lib/mkdocs_exclude_snippets/exclude_snippets_plugin.py
@@ -0,0 +1,120 @@
+from mkdocs.plugins import BasePlugin, event_priority
+import json
+import os
+
+class ExcludeStandaloneSnippetsPlugin(BasePlugin):
+    """
+    A MkDocs plugin that excludes standalone snippet pages not listed in the site's navigation from the search index.
+    """
+    
+    def flatten_nav(self, nav_items, parent_dir=''):
+        """
+        Recursively flattens the navigation structure to a list of Markdown file paths.
+        
+        Args:
+            nav_items (list): The navigation items to process, which can be a mix of dictionaries (for nested navigation) and strings (for direct links).
+            parent_dir (str): The current parent directory path to prepend to nested navigation items, ensuring the full path is captured.
+            
+        Returns:
+            list: A list of strings, where each string is a path to a Markdown file included in the site's navigation.
+        """
+        pages = []
+        for item in nav_items:
+            if isinstance(item, dict):  # Process nested navigation items
+                for nested_items in item.values():
+                    if isinstance(nested_items, list):
+                        # Recurse into the list, carrying the current parent_dir
+                        pages += self.flatten_nav(nested_items, parent_dir)
+                    elif isinstance(nested_items, str) and nested_items.endswith('.md'):
+                        # Add direct .md file references, prepending parent_dir if present
+                        md_path = os.path.join(parent_dir, nested_items)
+                        pages.append(md_path)
+            elif isinstance(item, str) and item.endswith('.md'):  # Handle top-level .md files
+                md_path = os.path.join(parent_dir, item)
+                pages.append(md_path)
+        return pages
+
+    @event_priority(-100)  # Run this plugin's on_post_build event last
+    def on_post_build(self, config, **kwargs):
+        """
+        The method called by MkDocs after the site has been built, to filter out standalone snippets from the search index.
+        
+        Args:
+            config (dict): The MkDocs config object containing site configuration details.
+        """
+        search_index_path = os.path.join(config['site_dir'], 'search', 'search_index.json')
+        
+        with open(search_index_path, 'r') as file:
+            search_index = json.load(file)
+        
+        # Generate a list of normalized navigation paths for comparison
+        navigation_pages = [os.path.splitext(page)[0] for page in self.flatten_nav(config['nav'])]
+
+        initial_count = len(search_index['docs'])
+
+        filtered_docs = []
+        for doc in search_index['docs']:
+            # Normalize the document's location for comparison, removing localization and section identifiers
+            parts = doc['location'].split('/')
+            normalized_parts = [part for part in parts if not part.startswith('#') and part != 'en']
+            normalized_doc_path = '/'.join(normalized_parts).rstrip('/').replace('.md', '')
+
+            # Include the document if its normalized path matches any navigation path
+            if normalized_doc_path in navigation_pages or any(normalized_doc_path.startswith(nav + '/') for nav in navigation_pages):
+                filtered_docs.append(doc)
+            # Optionally, for debugging purposes, you could uncomment the following lines to log
+            # documents that are identified for exclusion. This can be helpful during development
+            # and testing to verify that the plugin is correctly identifying documents to exclude.    
+            # else:
+               # print(f"Exclude_Snippets: Excluding from search index: {doc['location']}")
+
+        final_count = len(filtered_docs)
+
+        # Update the search index if any documents were excluded
+        if initial_count != final_count:
+            search_index['docs'] = filtered_docs
+            with open(search_index_path, 'w') as file:
+                json.dump(search_index, file)
+            print("Exclude_Snippets: Successfully updated search_index.json with filtered documents.")
+
+            # Optionally create a debug copy of the updated search index for comparison
+            # debug_search_index_path = os.path.join(config['site_dir'], 'search', 'search_index_debug.json')
+            # with open(debug_search_index_path, 'w') as debug_file:
+            #     json.dump(search_index, debug_file)
+            # print("Exclude_Snippets: Created a debug copy of the updated search_index.json at 'search/search_index_debug.json'.")
+
+
+    def is_standalone_snippet(self, doc, navigation_pages):
+        """
+        Determines if a document should be excluded from the search index.
+        
+        This method checks if the normalized path of a document is not present in the list
+        of navigation pages. The normalization process involves removing the '.md' extension
+        from the document's location for a consistent comparison with the navigation paths.
+        
+        Args:
+            doc (dict): A dictionary representing a document in the search index, where
+                        'location' is a key pointing to the document's path.
+            navigation_pages (list): A list of strings representing the paths of documents
+                                    included in the site's navigation, as normalized by
+                                    the flatten_nav method.
+        
+        Returns:
+            bool: True if the document is not found in the navigation pages and should be
+                excluded from the search index; False otherwise.
+        """
+        # Normalize the document location by removing the '.md' extension. This step is crucial
+        # for ensuring that the document's path can be directly compared against the list of
+        # navigation paths, which have been similarly normalized.
+        normalized_doc_path = doc['location'].rstrip('.md')
+
+        # Check if the normalized document path exists within the list of navigation pages.
+        # If the path is not found, the document is considered a standalone snippet that is not
+        # directly accessible through the site's navigation and thus should be excluded from
+        # the search index to avoid leading users to potentially orphaned or unintended pages.
+        is_excluded = normalized_doc_path not in navigation_pages
+
+        return is_excluded
+
+
+
diff --git a/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/PKG-INFO b/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/PKG-INFO
new file mode 100755
index 000000000..8cb8f0912
--- /dev/null
+++ b/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/PKG-INFO
@@ -0,0 +1,3 @@
+Metadata-Version: 2.1
+Name: mkdocs-exclude-snippets
+Version: 0.1
diff --git a/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/SOURCES.txt b/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/SOURCES.txt
new file mode 100755
index 000000000..d157cd5d9
--- /dev/null
+++ b/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/SOURCES.txt
@@ -0,0 +1,9 @@
+setup.py
+mkdocs_exclude_snippets/__init__.py
+mkdocs_exclude_snippets/exclude_snippets_plugin.py
+mkdocs_exclude_snippets.egg-info/PKG-INFO
+mkdocs_exclude_snippets.egg-info/SOURCES.txt
+mkdocs_exclude_snippets.egg-info/dependency_links.txt
+mkdocs_exclude_snippets.egg-info/entry_points.txt
+mkdocs_exclude_snippets.egg-info/requires.txt
+mkdocs_exclude_snippets.egg-info/top_level.txt
\ No newline at end of file
diff --git a/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/dependency_links.txt b/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/dependency_links.txt
new file mode 100755
index 000000000..8b1378917
--- /dev/null
+++ b/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/entry_points.txt b/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/entry_points.txt
new file mode 100755
index 000000000..e458d2f7a
--- /dev/null
+++ b/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/entry_points.txt
@@ -0,0 +1,2 @@
+[mkdocs.plugins]
+exclude_snippets = mkdocs_exclude_snippets.exclude_snippets_plugin:ExcludeStandaloneSnippetsPlugin
diff --git a/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/requires.txt b/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/requires.txt
new file mode 100755
index 000000000..d912869d8
--- /dev/null
+++ b/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/requires.txt
@@ -0,0 +1,2 @@
+mkdocs
+pyyaml
diff --git a/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/top_level.txt b/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/top_level.txt
new file mode 100755
index 000000000..12de9a895
--- /dev/null
+++ b/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets.egg-info/top_level.txt
@@ -0,0 +1 @@
+mkdocs_exclude_snippets
diff --git a/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets/__init__.py b/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets/__init__.py
new file mode 100755
index 000000000..e69de29bb
diff --git a/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets/__pycache__/__init__.cpython-310.pyc b/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets/__pycache__/__init__.cpython-310.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..d7a728b0594613b716c96437833f1da151edb280
GIT binary patch
literal 206
zcmd1j<>g`k0`dMksUZ3>h(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o5j-KO;XkRlg)j
z-z7h}G&eP`q*%WwF)t-QSD_@e7{~#Uy1B*r$)&|5`MCi(rRkY@#rnC~Df!98@u?Nb
wIi)G7@x^(W1qG=<)wsmt<1_OzOXB183My}L*yQG?l;)(`ft*sz1SD7(09@iZi2wiq

literal 0
HcmV?d00001

diff --git a/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets/__pycache__/__init__.cpython-311.pyc b/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets/__pycache__/__init__.cpython-311.pyc
new file mode 100755
index 0000000000000000000000000000000000000000..6f663430ae53d28aa1b27bc1dce79669837fa27c
GIT binary patch
literal 182
zcmZ3^%ge<81mgX7QbF`%5CH>>P{wCAAY(d13PUi1CZpd<h9V{)|1(JPmuHGqOm1R!
zYEf}PVsdIsZgxt3a&dfWMRHDQN@{#@US>f-YDqCp@%Z@6yv&mLc)fzkUmP~M`6;D2
dsdh!IK$Ags7xM#&56p~=j2{?aL=iJk3;@%=FQotg

literal 0
HcmV?d00001

diff --git a/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets/__pycache__/exclude_snippets_plugin.cpython-310.pyc b/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets/__pycache__/exclude_snippets_plugin.cpython-310.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..309803a909356ed964b2e67f49cc9aaa9b9e2a86
GIT binary patch
literal 4616
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

literal 0
HcmV?d00001

diff --git a/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets/__pycache__/exclude_snippets_plugin.cpython-311.pyc b/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets/__pycache__/exclude_snippets_plugin.cpython-311.pyc
new file mode 100755
index 0000000000000000000000000000000000000000..50a5190a4802b7ad596c5c0a0a7d4cc33388af2d
GIT binary patch
literal 7126
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
U6fn7Yp1u6gX!&M~c7vV&08N)I&;S4c

literal 0
HcmV?d00001

diff --git a/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets/exclude_snippets_plugin.py b/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets/exclude_snippets_plugin.py
new file mode 100755
index 000000000..fe9dde61d
--- /dev/null
+++ b/customPlugins/mkdocs_exclude_snippets/mkdocs_exclude_snippets/exclude_snippets_plugin.py
@@ -0,0 +1,120 @@
+from mkdocs.plugins import BasePlugin, event_priority
+import json
+import os
+
+class ExcludeStandaloneSnippetsPlugin(BasePlugin):
+    """
+    A MkDocs plugin that excludes standalone snippet pages not listed in the site's navigation from the search index.
+    """
+    
+    def flatten_nav(self, nav_items, parent_dir=''):
+        """
+        Recursively flattens the navigation structure to a list of Markdown file paths.
+        
+        Args:
+            nav_items (list): The navigation items to process, which can be a mix of dictionaries (for nested navigation) and strings (for direct links).
+            parent_dir (str): The current parent directory path to prepend to nested navigation items, ensuring the full path is captured.
+            
+        Returns:
+            list: A list of strings, where each string is a path to a Markdown file included in the site's navigation.
+        """
+        pages = []
+        for item in nav_items:
+            if isinstance(item, dict):  # Process nested navigation items
+                for nested_items in item.values():
+                    if isinstance(nested_items, list):
+                        # Recurse into the list, carrying the current parent_dir
+                        pages += self.flatten_nav(nested_items, parent_dir)
+                    elif isinstance(nested_items, str) and nested_items.endswith('.md'):
+                        # Add direct .md file references, prepending parent_dir if present
+                        md_path = os.path.join(parent_dir, nested_items)
+                        pages.append(md_path)
+            elif isinstance(item, str) and item.endswith('.md'):  # Handle top-level .md files
+                md_path = os.path.join(parent_dir, item)
+                pages.append(md_path)
+        return pages
+
+    @event_priority(-100)  # Run this plugin's on_post_build event last
+    def on_post_build(self, config, **kwargs):
+        """
+        The method called by MkDocs after the site has been built, to filter out standalone snippets from the search index.
+        
+        Args:
+            config (dict): The MkDocs config object containing site configuration details.
+        """
+        search_index_path = os.path.join(config['site_dir'], 'search', 'search_index.json')
+        
+        with open(search_index_path, 'r') as file:
+            search_index = json.load(file)
+        
+        # Generate a list of normalized navigation paths for comparison
+        navigation_pages = [os.path.splitext(page)[0] for page in self.flatten_nav(config['nav'])]
+
+        initial_count = len(search_index['docs'])
+
+        filtered_docs = []
+        for doc in search_index['docs']:
+            # Normalize the document's location for comparison, removing localization and section identifiers
+            parts = doc['location'].split('/')
+            normalized_parts = [part for part in parts if not part.startswith('#') and part != 'en']
+            normalized_doc_path = '/'.join(normalized_parts).rstrip('/').replace('.md', '')
+
+            # Include the document if its normalized path matches any navigation path
+            if normalized_doc_path in navigation_pages or any(normalized_doc_path.startswith(nav + '/') for nav in navigation_pages):
+                filtered_docs.append(doc)
+            # Optionally, for debugging purposes, you could uncomment the following lines to log
+            # documents that are identified for exclusion. This can be helpful during development
+            # and testing to verify that the plugin is correctly identifying documents to exclude.    
+            # else:
+               # print(f"Exclude_Snippets: Excluding from search index: {doc['location']}")
+
+        final_count = len(filtered_docs)
+
+        # Update the search index if any documents were excluded
+        if initial_count != final_count:
+            search_index['docs'] = filtered_docs
+            with open(search_index_path, 'w') as file:
+                json.dump(search_index, file)
+            print("Exclude_Snippets: Successfully updated search_index.json with filtered documents.")
+
+            # Optionally create a debug copy of the updated search index for comparison
+            # debug_search_index_path = os.path.join(config['site_dir'], 'search', 'search_index_debug.json')
+            # with open(debug_search_index_path, 'w') as debug_file:
+            #     json.dump(search_index, debug_file)
+            # print("Exclude_Snippets: Created a debug copy of the updated search_index.json at 'search/search_index_debug.json'.")
+
+
+    def is_standalone_snippet(self, doc, navigation_pages):
+        """
+        Determines if a document should be excluded from the search index.
+        
+        This method checks if the normalized path of a document is not present in the list
+        of navigation pages. The normalization process involves removing the '.md' extension
+        from the document's location for a consistent comparison with the navigation paths.
+        
+        Args:
+            doc (dict): A dictionary representing a document in the search index, where
+                        'location' is a key pointing to the document's path.
+            navigation_pages (list): A list of strings representing the paths of documents
+                                    included in the site's navigation, as normalized by
+                                    the flatten_nav method.
+        
+        Returns:
+            bool: True if the document is not found in the navigation pages and should be
+                excluded from the search index; False otherwise.
+        """
+        # Normalize the document location by removing the '.md' extension. This step is crucial
+        # for ensuring that the document's path can be directly compared against the list of
+        # navigation paths, which have been similarly normalized.
+        normalized_doc_path = doc['location'].rstrip('.md')
+
+        # Check if the normalized document path exists within the list of navigation pages.
+        # If the path is not found, the document is considered a standalone snippet that is not
+        # directly accessible through the site's navigation and thus should be excluded from
+        # the search index to avoid leading users to potentially orphaned or unintended pages.
+        is_excluded = normalized_doc_path not in navigation_pages
+
+        return is_excluded
+
+
+
diff --git a/customPlugins/mkdocs_exclude_snippets/setup.py b/customPlugins/mkdocs_exclude_snippets/setup.py
new file mode 100755
index 000000000..8d34d2fc3
--- /dev/null
+++ b/customPlugins/mkdocs_exclude_snippets/setup.py
@@ -0,0 +1,17 @@
+from setuptools import setup, find_packages
+
+setup(
+    name='mkdocs-exclude-snippets',
+    version='0.1',
+    packages=find_packages(),
+    include_package_data=True,
+    install_requires=[
+        'mkdocs',
+        'pyyaml',  # Ensure you include all necessary dependencies
+    ],
+    entry_points={
+        'mkdocs.plugins': [
+            'exclude_snippets = mkdocs_exclude_snippets.exclude_snippets_plugin:ExcludeStandaloneSnippetsPlugin',
+        ]
+    }
+)
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 000000000..e1692cfe5
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,50 @@
+Babel==2.13.1
+bracex==2.4
+certifi==2023.7.22
+charset-normalizer==3.3.2
+click==8.1.7
+colorama==0.4.6
+ghp-import==2.1.0
+gitdb==4.0.11
+GitPython==3.1.40
+idna==3.4
+Jinja2==3.1.2
+lxml==4.9.3
+Markdown==3.5.1
+MarkupSafe==2.1.3
+mergedeep==1.3.4
+mkdocs==1.5.3
+mkdocs-footermatter==1.3.2
+mkdocs-git-revision-date-localized-plugin==1.2.1
+mkdocs-glightbox==0.3.4
+mkdocs-material==9.4.7
+mkdocs-material-extensions==1.3
+mkdocs-rss-plugin==1.8.0
+mkdocs-static-i18n==1.2.0
+mkdocs-table-reader-plugin==2.0.3
+mkdocs-video==1.5.0
+numpy==1.26.1
+packaging==23.2
+paginate==0.5.6
+pandas==2.1.2
+pathspec==0.11.2
+pendulum==2.1.2
+platformdirs==3.11.0
+Pygments==2.16.1
+pymdown-extensions==10.3.1
+python-dateutil==2.8.2
+pytz==2023.3.post1
+pytzdata==2020.1
+PyYAML==6.0.1
+pyyaml_env_tag==0.1
+regex==2023.10.3
+requests==2.31.0
+six==1.16.0
+smmap==5.0.1
+tabulate==0.9.0
+tzdata==2023.3
+urllib3==2.0.7
+watchdog==3.0.0
+wcmatch==8.5.2
+-e ./customPlugins/mkdocs_exclude_snippets
+-e ./customPlugins/mkdocs-rss-deduplicate
-- 
GitLab