From bba1df0377c35d2de3ea9c483c86d5cb75197271 Mon Sep 17 00:00:00 2001 From: Tykayn Date: Thu, 27 Feb 2025 16:18:47 +0100 Subject: [PATCH] convert to gemini avec md2gemini, conversion de plusieurs langues --- gather_tags_in_json.py | 3 + install.sh | 4 +- linking_articles_prev_next.py | 286 ++++++++---------- new_article.py | 61 +++- .../lang_en/2024-11-02-hello-gemini.org | 2 - .../20250227154104__coucou-gemini-en-2025.org | 25 ++ .../20250227154659__coucou-gemini-en-2025.org | 24 ++ test_org_conversion.py | 72 +++++ utils.py | 185 +++++++++-- website_config.py | 2 + 10 files changed, 462 insertions(+), 202 deletions(-) delete mode 100644 sources/dragonfeu_blog/lang_en/2024-11-02-hello-gemini.org create mode 100644 sources/dragonfeu_blog/lang_en/20250227154104__coucou-gemini-en-2025.org create mode 100644 sources/dragonfeu_blog/lang_en/20250227154659__coucou-gemini-en-2025.org create mode 100644 test_org_conversion.py diff --git a/gather_tags_in_json.py b/gather_tags_in_json.py index 6d7a8c38..8fcc99c3 100644 --- a/gather_tags_in_json.py +++ b/gather_tags_in_json.py @@ -67,6 +67,9 @@ def group_files_by_tags(org_files, excluded_tags): for tag in tags: tag_to_files[tag].add(slug) + # Sauvegarder les fichiers sans tags + save_untagged_files(output_file=f"sources/{blog_folder}/build/articles_without_tags.json") + return tag_to_files diff --git a/install.sh b/install.sh index 2c357e24..a3138a90 100644 --- a/install.sh +++ b/install.sh @@ -1,4 +1,4 @@ #!/bin/bash sudo apt install pandoc python3-pip npm -pip install uuid argparse os md2gemini -npm install -g sass \ No newline at end of file +pip install uuid argparse os md2gemini pytest pypandoc +npm install -g sass diff --git a/linking_articles_prev_next.py b/linking_articles_prev_next.py index 74bfef11..2cace799 100644 --- a/linking_articles_prev_next.py +++ b/linking_articles_prev_next.py @@ -42,7 +42,12 @@ def get_basename(file_name): return os.path.splitext(file_name)[0] # Chemin du dossier contenant les fichiers orgmode -directory = f'sources/{args.blog}/lang_fr' +directory_pages = f'sources/{args.blog}/' +directory_fr = f'sources/{args.blog}/lang_fr' +directory_en = f'sources/{args.blog}/lang_en' + +directories_to_scan = [directory_pages, directory_fr, directory_en] + destination_json = f'sources/{args.blog}/build' destination_html = f'html-websites/{args.blog}/' destination_gmi = f'gemini-capsules/{args.blog}/' @@ -64,188 +69,157 @@ else: files_dict = {} -def get_first_picture_url(content): - # Utiliser une expression régulière pour trouver la première URL d'image dans le contenu - pattern = r'\[\[(.*?)\]\]' - match = re.search(pattern, content) - if match: - return match.group(1) - else: - return None -def org_to_gmi(org_text: str, output_filename_slug: str) -> str: - """ - Convertit un texte au format Org en un fichier au format GMI (Gemini) - en utilisant pypandoc. +count_articles = count_files_in_directories(directories_to_scan) - Args: - - org_text (str): Le texte au format Org à convertir. - - output_file (str): Chemin du fichier de sortie au format GMI, sans avoir à préciser l'extension. - """ - output = """ -# mock land output -=========== - -blah blah blah - ------------------ -Tykayn blog mock content ------------------ - -Navigation: - -=> accueil.gmi Accueil -=> a-propos.gmi à propos - """ - # Conversion du texte Org en GMI via Pandoc - try: - output = pypandoc.convert_text(org_text, 'markdown', format='org') - except RuntimeError as e: - print(f"Erreur de conversion : {e}") - return - - # Sauvegarde du contenu GMI dans un fichier - try: - with open(destination_gmi+'/'+output_filename_slug+'.gmi', 'w', encoding='utf-8') as f: - f.write(output) - print(f"Fichier GMI sauvegardé avec succès : {output_filename_slug}") - except OSError as e: - print(f"Erreur lors de la sauvegarde du fichier : {e}") - return output - -count_articles = len(os.listdir(directory)) counter=0 rebuild_counter = 0 pandoc_runs_counter = 0 +lang_folder = global_config.get('lang_default', 'fr') if generate_linkings_json : print(f"Génération des liens entre articles pour {count_articles} articles") print(f"run_pandoc: {run_pandoc}") print(f"run_gemini: {run_gemini}") - + article_type = "article" # Parcourir les fichiers du dossier - for file_name in os.listdir(directory): - if file_name.endswith('.org'): - counter+=1 - if force_html_regen and counter % 10 == 0: - print(f"{time.strftime('%H:%M:%S')} : Articles traités : {counter}/{count_articles}") - file_path = os.path.join(directory, file_name) - with open(file_path, "r", encoding="utf-8") as f: - content = f.read() - date_modified = time.ctime(os.path.getmtime(file_path)) + + for index, directory in enumerate(directories_to_scan): + # Déterminer le type d'article en fonction du chemin + if directory == '/': + article_type = "page" + else: + article_type = "article" + # Extraire la langue du dossier si elle commence par "lang_" + if directory.split('/')[-1].startswith('lang_'): + lang_folder = directory.split('/')[-1][5:] # Prend les caractères après "lang_" + for file_name in os.listdir(directory): + if file_name.endswith('.org'): + counter+=1 + if force_html_regen and counter % 10 == 0: + print(f"{time.strftime('%H:%M:%S')} : Articles traités : {counter}/{count_articles}") + file_path = os.path.join(directory, file_name) + with open(file_path, "r", encoding="utf-8") as f: + content = f.read() + date_modified = time.ctime(os.path.getmtime(file_path)) - basename = get_basename(file_name) - date_str, annee, slug = find_year_and_slug_on_filename(basename) - tags = extract_tags_from_file(file_path, global_config['excluded_tags']) - - # Convertir les tags en liste si c'est un set - if isinstance(tags, set): - tags = list(tags) - boom = basename.split('__') - # Convertir le contenu Org en HTML - title = find_first_level1_title(content) - - # Désactiver les warning d'identifiant dupliqué dans la conversion pandoc - content_without_h1 = re.sub(r'^\*.*?$', '', content, count=1, flags=re.MULTILINE) - - gemini_content = '' - html_content = '' - html_content_without_h1 = '' - # Vérifier l'existence du fichier HTML pour déterminer last_html_build - html_path = f"html-websites/{args.blog}/{annee}/{slug}/index.html" - last_html_build_time = None - if os.path.exists(html_path): - # Obtenir la date de création du fichier HTML - last_html_build_time = os.path.getctime(html_path) - - # print(f"last_html_build: {last_html_build_time} : {html_path}") - else: - print(f"----------- last_html_build html_path: {html_path} n'existe pas") - # Vérifier l'existence du fichier Gemini pour déterminer last_gemini_build - gemini_path = f"gemini-capsules/{args.blog}/{slug}.gmi" - last_gemini_build = None - rebuild_this_article_gemini = False - if os.path.exists(gemini_path): - last_gemini_build = time.ctime(os.path.getmtime(gemini_path)) - # Vérifier si l'article doit être reconstruit en comparant les dates de modification - if last_gemini_build: - file_modified_time = os.path.getmtime(file_path) - last_build_time = time.mktime(time.strptime(last_gemini_build)) - rebuild_this_article_gemini = file_modified_time > last_build_time - else: + basename = get_basename(file_name) + date_str, annee, slug = find_year_and_slug_on_filename(basename) + tags = extract_tags_from_file(file_path, global_config['excluded_tags']) - rebuild_this_article_gemini = True + # Convertir les tags en liste si c'est un set + if isinstance(tags, set): + tags = list(tags) + boom = basename.split('__') + # Convertir le contenu Org en HTML + title = find_first_level1_title(content) - # Vérifier si l'article doit être reconstruit en comparant les dates de modification - rebuild_this_article_html = False - if last_html_build_time: - file_modified_time = os.path.getmtime(file_path) - # print(f"--------- file_modified_time: {file_path} : {file_modified_time}") - # Obtenir l'heure de dernière modification du fichier HTML - - rebuild_this_article_html = file_modified_time > last_html_build_time - # print(f"--------- article modifié après le build de son rendu html: {file_path}, {rebuild_this_article_html}") - else: - # si il n'y a pas de fichier html, on le construit pour la première fois - print('on reconstruit le html de l\'article', file_name) - - rebuild_this_article_html = True - - if rebuild_this_article_html: - rebuild_counter += 1 + # Désactiver les warning d'identifiant dupliqué dans la conversion pandoc + content_without_h1 = re.sub(r'^\*.*?$', '', content, count=1, flags=re.MULTILINE) + gemini_content = '' + html_content = '' + html_content_without_h1 = '' + # Vérifier l'existence du fichier HTML pour déterminer last_html_build + html_path = f"html-websites/{args.blog}/{annee}/{slug}/index.html" + last_html_build_time = None + if os.path.exists(html_path): + # Obtenir la date de création du fichier HTML + last_html_build_time = os.path.getctime(html_path) - # Garder le contenu HTML existant si déjà présent - if f"{annee}/{slug}" in files_dict and 'html_content' in files_dict[f"{annee}/{slug}"]: - print('on reprend le contenu html existant') - if len(files_dict[f"{annee}/{slug}"]['html_content']) > 0: - html_content = files_dict[f"{annee}/{slug}"]['html_content'] - if len(files_dict[f"{annee}/{slug}"]['html_content_without_h1']) > 0: - html_content_without_h1 = files_dict[f"{annee}/{slug}"]['html_content_without_h1'] + # print(f"last_html_build: {last_html_build_time} : {html_path}") else: - html_content_without_h1 = re.sub(r'

.*?

', '', html_content) + print(f"----------- last_html_build html_path: {html_path} n'existe pas") + # Vérifier l'existence du fichier Gemini pour déterminer last_gemini_build + gemini_path = f"gemini-capsules/{args.blog}/{slug}.gmi" + last_gemini_build = None + rebuild_this_article_gemini = False + if os.path.exists(gemini_path): + last_gemini_build = time.ctime(os.path.getmtime(gemini_path)) + # Vérifier si l'article doit être reconstruit en comparant les dates de modification + if last_gemini_build: + file_modified_time = os.path.getmtime(file_path) + last_build_time = time.mktime(time.strptime(last_gemini_build)) + rebuild_this_article_gemini = file_modified_time > last_build_time + else: + + rebuild_this_article_gemini = True - if run_pandoc and rebuild_this_article_html or force_html_regen: - # convertir le contenu d'article org vers html - print(f"\033[91mBRRRRRRRRRRRRR pandoc time {time.strftime('%H:%M:%S')} : Conversion de {file_name} en html\033[0m") + # Vérifier si l'article doit être reconstruit en comparant les dates de modification + rebuild_this_article_html = False + if last_html_build_time: + file_modified_time = os.path.getmtime(file_path) + # print(f"--------- file_modified_time: {file_path} : {file_modified_time}") + # Obtenir l'heure de dernière modification du fichier HTML + + rebuild_this_article_html = file_modified_time > last_html_build_time + # print(f"--------- article modifié après le build de son rendu html: {file_path}, {rebuild_this_article_html}") + else: + # si il n'y a pas de fichier html, on le construit pour la première fois + print('on reconstruit le html de l\'article', file_name) + + rebuild_this_article_html = True - html_content = pypandoc.convert_text(content_without_h1, 'html', format='org') - pandoc_runs_counter += 1 - else: - html_content = content_without_h1 + if rebuild_this_article_html: + rebuild_counter += 1 - if run_gemini and rebuild_this_article_gemini: - os.makedirs(destination_gmi, exist_ok=True) - # convertir le contenu d'article org vers gmi pour la capsule gemini - gemini_content = org_to_gmi(content_without_h1, slug) + + # Garder le contenu HTML existant si déjà présent + if f"{annee}/{slug}" in files_dict and 'html_content' in files_dict[f"{annee}/{slug}"]: + print('on reprend le contenu html existant') + if len(files_dict[f"{annee}/{slug}"]['html_content']) > 0: + html_content = files_dict[f"{annee}/{slug}"]['html_content'] + if len(files_dict[f"{annee}/{slug}"]['html_content_without_h1']) > 0: + html_content_without_h1 = files_dict[f"{annee}/{slug}"]['html_content_without_h1'] + else: + html_content_without_h1 = re.sub(r'

.*?

', '', html_content) + + if run_pandoc and rebuild_this_article_html or force_html_regen: + # convertir le contenu d'article org vers html + # print(f"\033[91mBRRRRRRRRRRRRR pandoc time {time.strftime('%H:%M:%S')} : Conversion de {file_name} en html\033[0m") + print(f"\033[91m.\033[0m", end='', flush=True) + + html_content = pypandoc.convert_text(content_without_h1, 'html', format='org') + pandoc_runs_counter += 1 + else: + html_content = content_without_h1 + + if run_gemini and rebuild_this_article_gemini: + os.makedirs(destination_gmi, exist_ok=True) + # convertir le contenu d'article org vers gmi pour la capsule gemini + print(f"Conversion de {file_name} en gemini") + gemini_content = org_to_gmi(content_without_h1, slug) - files_dict[f"{annee}/{slug}"] = { - 'path': file_path, - 'basename': basename, - 'roam_id': find_org_roam_id(content), - 'slug': f"{slug}/", - 'slug_with_year': f"{annee}/{slug}", - 'date': boom[0], - 'date_modified' : date_modified, - 'first_picture_url' : get_first_picture_url(content), - 'date_formattee': datetime.strptime(date_str, '%Y%m%d%H%M%S').strftime('%d %B %Y à %H:%M:%S') if len(date_str) == 14 else datetime.strptime(date_str, '%Y%m%dT%H%M%S').strftime('%d %B %Y à %H:%M:%S') if len(date_str) == 15 else datetime.strptime(date_str, '%Y-%m-%d').strftime('%d %B %Y'), - 'annee': annee, - 'tags': tags, - 'title': title, - 'next': None, - 'previous': None, - 'last_html_build': last_html_build_time, - 'last_gemini_build': last_gemini_build, - 'org_content': content, # Contenu Org original - 'html_content_without_h1': html_content_without_h1, # Contenu HTML converti sans le titre de premier niveau - 'html_content': html_content # Contenu first_picture_urlHTML converti - } + files_dict[f"{annee}/{slug}"] = { + 'path': file_path, + 'basename': basename, + 'roam_id': find_org_roam_id(content), + 'slug': f"{slug}/", + 'slug_with_year': f"{annee}/{slug}", + 'date': boom[0], + 'lang': lang_folder, + 'article_type': article_type, + 'date_modified' : date_modified, + 'first_picture_url' : get_first_picture_url(content), + 'date_formattee': datetime.strptime(date_str, '%Y%m%d%H%M%S').strftime('%d %B %Y à %H:%M:%S') if len(date_str) == 14 else datetime.strptime(date_str, '%Y%m%dT%H%M%S').strftime('%d %B %Y à %H:%M:%S') if len(date_str) == 15 else datetime.strptime(date_str, '%Y-%m-%d').strftime('%d %B %Y'), + 'annee': annee, + 'tags': tags, + 'title': title, + 'next': None, + 'previous': None, + 'last_html_build': last_html_build_time, + 'last_gemini_build': last_gemini_build, + 'org_content': content, # Contenu Org original + 'html_content_without_h1': html_content_without_h1, # Contenu HTML converti sans le titre de premier niveau + 'html_content': html_content, # Contenu first_picture_urlHTML converti + 'gemini_content': gemini_content, # Contenu gemini + } print(f"======= Nombre d'articles reconstruits: {rebuild_counter}") print(f"======= Nombre de runs de pandoc: {pandoc_runs_counter}") diff --git a/new_article.py b/new_article.py index 21abe043..80409b19 100644 --- a/new_article.py +++ b/new_article.py @@ -89,34 +89,63 @@ def create_uuid_property(): uuid_value = uuid.uuid4() return uuid_value -# Écriture du fichier org -with open(filename, "w") as f: - uuid = create_uuid_property() - f.write(f""" -:PROPERTIES: -:ID: {uuid} +def make_article(config): + """ + Crée le contenu d'un nouvel article avec les propriétés spécifiées. + + Args: + config (dict): Dictionnaire contenant les paramètres de l'article: + - uuid (str): Identifiant unique de l'article + - slug (str): Slug de l'URL de l'article + - title (str): Titre de l'article + - date_string_full (str): Date complète au format YYYY-MM-DD HH:MM:SS + - date_string (str): Date au format YYYYMMDDHHMMSS + - schema_slug (str): Slug avec ou sans préfixe année selon la config + - blog_dir (str): Dossier du blog + + Returns: + str: Contenu formaté de l'article avec les propriétés et métadonnées + """ + + + return f""":PROPERTIES: +:ID: {config.get('uuid')} :END: -#+title: {args.title} +#+title: {config.get('title')} #+post_ID: -#+post_slug: {slug} +#+post_slug: {config.get('slug')} -#+post_url: https://www.ciperbliss.com/{schema_slug} -#+post_title: {args.title} +#+post_url: https://www.ciperbliss.com/{config.get('schema_slug')} +#+post_title: {config.get('title')} #+post_tags: #+post_series: #+post_type: post #+post_status: publish #+post_picture: -#+post_date_published: <{date_string_full}> -#+post_date_modified: <{date_string_full}> -#+post_index_page_roam_id: {uuid} -#+BLOG: {args.blog_dir} +#+post_date_published: <{config.get('date_string_full')}> +#+post_date_modified: <{config.get('date_string_full')}> +#+post_index_page_roam_id: {config.get('uuid')} +#+BLOG: {config.get('blog_dir')} -* {args.title} +* {config.get('title')} -""") +""" + +# Écriture du fichier org +with open(filename, "w") as f: + uuid = create_uuid_property() + config={ + 'uuid': uuid, + 'slug': slug, + 'title': args.title, + 'date_string_full': date_string_full, + 'date_string': date_string, + 'schema_slug': schema_slug, + 'blog_dir': args.blog_dir, + } + f.write(make_article(config)) print(f"Le fichier '{filename}' a été créé avec succès.") diff --git a/sources/dragonfeu_blog/lang_en/2024-11-02-hello-gemini.org b/sources/dragonfeu_blog/lang_en/2024-11-02-hello-gemini.org deleted file mode 100644 index c4e8105e..00000000 --- a/sources/dragonfeu_blog/lang_en/2024-11-02-hello-gemini.org +++ /dev/null @@ -1,2 +0,0 @@ -* Hi, giminiciens -hop hop hello in English diff --git a/sources/dragonfeu_blog/lang_en/20250227154104__coucou-gemini-en-2025.org b/sources/dragonfeu_blog/lang_en/20250227154104__coucou-gemini-en-2025.org new file mode 100644 index 00000000..f66f797a --- /dev/null +++ b/sources/dragonfeu_blog/lang_en/20250227154104__coucou-gemini-en-2025.org @@ -0,0 +1,25 @@ +:PROPERTIES: +:ID: 41decd55-85b9-43a6-9c24-2da4985f2d87 +:END: + +#+title: Coucou gemini en 2025 +#+post_ID: +#+post_slug: coucou-gemini-en-2025 + + +#+post_url: https://www.ciperbliss.com/2025/coucou-gemini-en-2025 +#+post_title: Coucou gemini en 2025 +#+post_tags: +#+post_series: +#+post_type: post +#+post_status: publish +#+post_picture: +#+post_date_published: <2025-02-27 15:41:04> +#+post_date_modified: <2025-02-27 15:41:04> +#+post_index_page_roam_id: 41decd55-85b9-43a6-9c24-2da4985f2d87 +#+BLOG: dragonfeu_blog + +* Hey gemini in 2025 + +hey yoooooooooooo + diff --git a/sources/dragonfeu_blog/lang_en/20250227154659__coucou-gemini-en-2025.org b/sources/dragonfeu_blog/lang_en/20250227154659__coucou-gemini-en-2025.org new file mode 100644 index 00000000..ac359ecb --- /dev/null +++ b/sources/dragonfeu_blog/lang_en/20250227154659__coucou-gemini-en-2025.org @@ -0,0 +1,24 @@ +:PROPERTIES: +:ID: 7a77f219-b581-4a67-be7a-c66588b7e3f7 +:END: + +#+title: Coucou gemini en 2025 +#+post_ID: +#+post_slug: coucou-gemini-en-2025 + + +#+post_url: https://www.ciperbliss.com/2025/coucou-gemini-en-2025 +#+post_title: Coucou gemini en 2025 +#+post_tags: +#+post_series: +#+post_type: post +#+post_status: publish +#+post_picture: +#+post_date_published: <2025-02-27 15:46:59> +#+post_date_modified: <2025-02-27 15:46:59> +#+post_index_page_roam_id: 7a77f219-b581-4a67-be7a-c66588b7e3f7 +#+BLOG: dragonfeu_blog + +* Coucou gemini en 2025 + + diff --git a/test_org_conversion.py b/test_org_conversion.py new file mode 100644 index 00000000..bed8030c --- /dev/null +++ b/test_org_conversion.py @@ -0,0 +1,72 @@ +import pytest +from utils import convert_org_to_gemini + +def test_org_to_gemini_conversion(): + # Exemple de contenu org + org_content = """#+TITLE: Test Article +#+AUTHOR: John Doe +#+DATE: 2024-03-14 + +* Premier titre +Voici du texte simple. + +** Sous-titre +- Liste item 1 +- Liste item 2 + +* Deuxième titre +Un lien [[https://example.com][Example]] +Et du *texte en gras* avec /italique/.""" + + # Convertir le contenu directement + result = convert_org_to_gemini(org_content) + result = result.strip() + print(f"result: {result}") + # Vérifier les éléments clés de la conversion + assert "# Premier titre" in result + assert "## Sous-titre" in result + assert "* Liste item 1" in result + assert "* Liste item 2" in result + assert "=> https://example.com Example" in result + +def test_org_to_gemini_tags(): + """Test de la détection des tags""" + org_content = """#+TITLE: Test Article +#+TAGS: chaton, mignon, félin + +* Un article sur les chatons +Du contenu sur les chatons...""" + + result = find_tags_in_org_content(org_content) + assert "chaton" in result, "Le tag 'chaton' devrait être présent dans le résultat" + + +# def test_org_to_gemini_code_blocks(): +# """Test de la conversion des blocs de code""" +# org_content = """#+BEGIN_SRC python +# def hello(): +# print("Hello, World!") +# #+END_SRC""" + +# result = convert_org_to_gemini(org_content) +# assert "```python" in result +# assert "def hello():" in result +# assert 'print("Hello, World!")' in result +# assert "```" in result + +# def test_org_to_gemini_tables(): +# """Test de la conversion des tableaux""" +# org_content = """| Colonne 1 | Colonne 2 | +# |-----------|-----------| +# | Valeur 1 | Valeur 2 | +# | Valeur 3 | Valeur 4 |""" + +# result = convert_org_to_gemini(org_content) +# # Vérifier que le tableau est converti en texte lisible +# assert "Colonne 1" in result +# assert "Colonne 2" in result +# assert "Valeur 1" in result +# assert "Valeur 2" in result + +if __name__ == '__main__': + pytest.main([__file__]) \ No newline at end of file diff --git a/utils.py b/utils.py index cc057043..eea955a1 100644 --- a/utils.py +++ b/utils.py @@ -5,6 +5,9 @@ import shutil from datetime import datetime import unicodedata import pypandoc +import subprocess +import tempfile +from md2gemini import md2gemini from website_config import * @@ -82,22 +85,23 @@ def get_blog_template_conf(blogname) -> dict: else: return configs_sites[blogname] -def find_year_and_slug_on_filename(fichier): - fichier = fichier.replace('..', '.') - slug = '' - annee = datetime.now().year - date_str = f'{annee}-00-00' - date = f'{annee}-00-00' - boom = fichier.split('__') - - if boom : - date_str = boom[0] - annee = date_str[:4] - slug = boom[1].replace('.org', '') - if "-" in date_str: - slug = enlever_premier_tiret_ou_underscore(slug) - return [date_str, annee, slug] - return [date_str, annee, fichier.replace(' ', '-').replace('.org', '')] +def find_year_and_slug_on_filename(filename): + print(f"Traitement du fichier: {filename}") # Debug + try: + # Supposons que le format attendu est "YYYYMMDDHHMMSS-slug.org" + date_str = filename[:14] # Prend les 14 premiers caractères pour la date + annee = date_str[:4] # Prend les 4 premiers caractères pour l'année + + # Gestion plus robuste du slug + if '-' in filename: + slug = filename.split('-', 1)[1].replace('.org', '') + else: + slug = filename.replace('.org', '') + + return date_str, annee, slug + except Exception as e: + print(f"Format de fichier non standard: {filename}") + return None, None, filename.replace('.org', '') def enlever_premier_tiret_ou_underscore(chaîne): @@ -212,21 +216,42 @@ def add_tags_from_content(tags=None, file_content="", words_to_check=None): tags.add(word) return tags +# Variable globale pour stocker les fichiers sans tags +untagged_files = [] -def extract_tags_from_file(file_path, excluded_tags): +def save_untagged_files(output_file="sources/site_web/build/articles_without_tags.json"): + """ + Sauvegarde la liste des fichiers sans tags dans un fichier JSON. + + :param output_file: Chemin du fichier JSON de sortie + """ + import json + import os + + # Créer le dossier de sortie si nécessaire + os.makedirs(os.path.dirname(output_file), exist_ok=True) + + print('save_untagged_files', len(untagged_files)) + # Sauvegarder la liste dans le fichier JSON + with open(output_file, 'w', encoding='utf-8') as f: + json.dump(untagged_files, f, ensure_ascii=False, indent=4) + + +def extract_tags_from_file(file_path, excluded_tags, auto_detected_tags_list=global_config['auto_tag_terms']): tags = set() with open(file_path, 'r', encoding='utf-8') as file_content: tag_found = False for line in file_content: - if global_config['automatic_tagging_enabled']: - tags = add_tags_from_content(tags, line, global_config['auto_tag_terms']) + if global_config['automatic_tagging_enabled'] and len(auto_detected_tags_list) > 0: + tags = add_tags_from_content(tags, line, auto_detected_tags_list) # Check for orgmode tags :tag1:tag2: - if ':' in line: - for word in line.split(): - if len(word) and word.startswith(':') and word.endswith(':'): - tag = word[1:-1] - if tag not in excluded_tags: - tags.add(tag) + if global_config.get('automatic_tagging_org_files', True): + if ':' in line: + for word in line.split(): + if len(word) > 1 and word.startswith(':') and word.endswith(':'): + tag = word[1:-1] + if tag not in excluded_tags: + tags.add(tag) tag_found = True # Check for #+tags: tag1,tag2 if line.startswith('#+tags:'): @@ -236,7 +261,8 @@ def extract_tags_from_file(file_path, excluded_tags): tags.add(tag) tag_found = True - # if not tag_found: + if not tag_found: + untagged_files.append(file_path) # print('no tag in the article', file_path) return tags @@ -380,3 +406,110 @@ def convert_org_to_html(org_file, output_html_file): print(f"Conversion réussie : {org_file} -> {output_html_file}") except Exception as e: print(f"Erreur lors de la conversion de {org_file} : {e}") + + + +def get_first_picture_url(content): + # Utiliser une expression régulière pour + # trouver la première URL d'image dans le contenu + pattern = r'\[\[(.*?)\]\]' + match = re.search(pattern, content) + if match: + return match.group(1) + else: + return None + + +def org_to_gmi(org_text: str, output_filename_slug: str) -> str: + """ + Convertit un texte au format Org en un fichier au format GMI (Gemini) + en utilisant pypandoc. + + Args: + - org_text (str): Le texte au format Org à convertir. + - output_file (str): Chemin du fichier de sortie au format GMI, sans avoir à préciser l'extension. + """ + output = """ +# mock land output +=========== + +blah blah blah + +----------------- +Tykayn blog mock content +----------------- + +Navigation: + +=> accueil.gmi Accueil +=> a-propos.gmi à propos + """ + # Conversion du texte Org en GMI via Pandoc + try: + output = pypandoc.convert_text(org_text, 'markdown', format='org') + except RuntimeError as e: + print(f"Erreur de conversion : {e}") + return + + # Sauvegarde du contenu GMI dans un fichier + try: + with open(destination_gmi+'/'+output_filename_slug+'.gmi', 'w', encoding='utf-8') as f: + f.write(output) + print(f"Fichier GMI sauvegardé avec succès : {output_filename_slug}") + except OSError as e: + print(f"Erreur lors de la sauvegarde du fichier : {e}") + return output + +def count_files_in_directories(directories): + total_count = 0 + for directory in directories: + for root, dirs, files in os.walk(directory): + total_count += len(files) + return total_count + + +def convert_org_to_gemini(org_content): + """ + Convertit un contenu org en gemini en utilisant pandoc et md2gemini + + Args: + org_content (str): Contenu au format org + + Returns: + str: Contenu converti en format gemini + """ + try: + # Créer un fichier temporaire avec le contenu org + with tempfile.NamedTemporaryFile(mode='w', suffix='.org', encoding='utf-8') as temp_org: + temp_org.write(org_content) + temp_org.flush() + + # Première étape : conversion org vers markdown avec pandoc + pandoc_cmd = [ + 'pandoc', + '-f', 'org', + '-t', 'markdown', + temp_org.name + ] + + markdown_content = subprocess.check_output( + pandoc_cmd, + text=True, + stderr=subprocess.PIPE + ) + + # Deuxième étape : conversion markdown vers gemini avec md2gemini + gemini_content = md2gemini( + markdown_content, + frontmatter=True, + links='inline', + ) + + return gemini_content.strip() + + except subprocess.CalledProcessError as e: + print(f"Erreur lors de la conversion avec pandoc: {e.stderr}") + raise + except Exception as e: + print(f"Erreur lors de la conversion: {str(e)}") + raise diff --git a/website_config.py b/website_config.py index ca65d7da..09542a8c 100644 --- a/website_config.py +++ b/website_config.py @@ -4,7 +4,9 @@ global_config = { "slug_with_year": True, # "show_logs": False, "show_logs": True, + "lang_default": "fr", "automatic_tagging_enabled": True, + "automatic_tagging_org_files": True, "rebuild_files_filter": 2024, "posts_per_page": 10, "source_files_extension": "org",