mirror of
https://forge.chapril.org/tykayn/orgmode-to-gemini-blog
synced 2025-06-20 09:04:42 +02:00
add quality control for links in a blog source
This commit is contained in:
parent
7b12ef533b
commit
22285e44ae
3 changed files with 424 additions and 8 deletions
174
scan_links.py
Normal file
174
scan_links.py
Normal file
|
@ -0,0 +1,174 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
Scanne les fichiers Org d'un dossier pour répertorier les liens.
|
||||
Génère un JSON listant pour chaque article ses liens et statistiques par domaine.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
import argparse
|
||||
import urllib.parse
|
||||
from datetime import datetime
|
||||
from collections import Counter, defaultdict
|
||||
|
||||
def extract_links_from_org(file_path):
|
||||
"""Extrait tous les liens d'un fichier Org"""
|
||||
links = []
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as file:
|
||||
content = file.read()
|
||||
|
||||
# Pattern pour trouver les liens Org-mode: [[url][description]] ou [[url]]
|
||||
pattern = r'\[\[((?:https?:\/\/|www\.)[^\]]+)\](?:\[([^\]]*)\])?'
|
||||
matches = re.finditer(pattern, content)
|
||||
|
||||
for match in matches:
|
||||
url = match.group(1)
|
||||
description = match.group(2) if match.group(2) else ""
|
||||
links.append({"url": url, "description": description})
|
||||
|
||||
# Chercher aussi les liens simples http:// ou https:// qui ne sont pas dans la syntaxe [[]]
|
||||
simple_pattern = r'(?<!\[)(?:https?:\/\/)[^\s\]]+(?!\])'
|
||||
simple_matches = re.finditer(simple_pattern, content)
|
||||
|
||||
for match in simple_matches:
|
||||
url = match.group(0)
|
||||
links.append({"url": url, "description": ""})
|
||||
|
||||
except Exception as e:
|
||||
print(f"Erreur lors de la lecture de {file_path}: {e}")
|
||||
|
||||
return links
|
||||
|
||||
def extract_domain(url):
|
||||
"""Extrait le nom de domaine d'une URL"""
|
||||
try:
|
||||
parsed_url = urllib.parse.urlparse(url)
|
||||
domain = parsed_url.netloc
|
||||
|
||||
# Supprimer www. si présent
|
||||
if domain.startswith('www.'):
|
||||
domain = domain[4:]
|
||||
|
||||
return domain
|
||||
except Exception:
|
||||
return url
|
||||
|
||||
def scan_directory(directory):
|
||||
"""Scanne un répertoire et ses sous-répertoires pour trouver des fichiers Org"""
|
||||
article_links = {}
|
||||
domain_counter = Counter()
|
||||
|
||||
# Parcourir tous les sous-dossiers
|
||||
for root, _, files in os.walk(directory):
|
||||
for file in files:
|
||||
if file.endswith('.org'):
|
||||
file_path = os.path.join(root, file)
|
||||
file_links = extract_links_from_org(file_path)
|
||||
|
||||
if file_links:
|
||||
relative_path = os.path.relpath(file_path, os.path.dirname(directory))
|
||||
article_links[relative_path] = file_links
|
||||
|
||||
# Compter les domaines
|
||||
for link in file_links:
|
||||
domain = extract_domain(link["url"])
|
||||
if domain:
|
||||
domain_counter[domain] += 1
|
||||
|
||||
print(f"Trouvé {len(file_links)} liens dans {relative_path}")
|
||||
|
||||
return article_links, domain_counter
|
||||
|
||||
def merge_scan_results(results1, results2):
|
||||
"""Combine les résultats de deux scans"""
|
||||
merged_article_links = {**results1[0], **results2[0]}
|
||||
merged_domain_counter = results1[1] + results2[1]
|
||||
return merged_article_links, merged_domain_counter
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Scanner les liens dans les fichiers Org")
|
||||
parser.add_argument("source_dir", help="Dossier source contenant les fichiers Org")
|
||||
parser.add_argument("--output", default="links_report.json",
|
||||
help="Fichier JSON de sortie (défaut: links_report.json)")
|
||||
args = parser.parse_args()
|
||||
|
||||
# Construire le nom du fichier de sortie avec le nom du dossier source
|
||||
if args.output == "links_report.json":
|
||||
args.output = f"links_report_{args.source_dir}.json"
|
||||
|
||||
folder_fr = f'sources/{args.source_dir}/lang_fr'
|
||||
folder_en = f'sources/{args.source_dir}/lang_en'
|
||||
|
||||
if not os.path.exists(folder_fr) and not os.path.exists(folder_en):
|
||||
print(f"Les dossiers {folder_fr} et {folder_en} n'existent pas.")
|
||||
return
|
||||
|
||||
# Initialiser des résultats vides
|
||||
combined_article_links = {}
|
||||
combined_domain_counter = Counter()
|
||||
|
||||
# Scanner le dossier français s'il existe
|
||||
if os.path.exists(folder_fr):
|
||||
print(f"Scan des liens dans {folder_fr}...")
|
||||
fr_results = scan_directory(folder_fr)
|
||||
combined_article_links, combined_domain_counter = fr_results
|
||||
|
||||
print(f"Trouvé {len(combined_article_links)} articles en français avec {sum(len(links) for links in combined_article_links.values())} liens")
|
||||
|
||||
# Scanner le dossier anglais s'il existe
|
||||
if os.path.exists(folder_en):
|
||||
print(f"Scan des liens dans {folder_en}...")
|
||||
en_results = scan_directory(folder_en)
|
||||
|
||||
# Si nous avons déjà des résultats en français, les combiner
|
||||
if combined_article_links:
|
||||
combined_article_links, combined_domain_counter = merge_scan_results(
|
||||
(combined_article_links, combined_domain_counter),
|
||||
en_results
|
||||
)
|
||||
else:
|
||||
# Sinon, utiliser directement les résultats anglais
|
||||
combined_article_links, combined_domain_counter = en_results
|
||||
|
||||
print(f"Total cumulé: {len(combined_article_links)} articles avec {sum(len(links) for links in combined_article_links.values())} liens")
|
||||
|
||||
# Préparer les données pour le JSON
|
||||
output_data = {
|
||||
"meta": {
|
||||
"generated_at": datetime.now().isoformat(),
|
||||
"source_directory": args.source_dir,
|
||||
"total_articles": len(combined_article_links),
|
||||
"total_links": sum(len(links) for links in combined_article_links.values()),
|
||||
"total_domains": len(combined_domain_counter)
|
||||
},
|
||||
"article_links": combined_article_links,
|
||||
"domains": {
|
||||
domain: count for domain, count in sorted(
|
||||
combined_domain_counter.items(), key=lambda x: x[1], reverse=True
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
# Créer le dossier de sortie si nécessaire
|
||||
output_dir = os.path.dirname(args.output)
|
||||
if output_dir and not os.path.exists(output_dir):
|
||||
os.makedirs(output_dir)
|
||||
|
||||
# Sauvegarder les données dans un fichier JSON
|
||||
with open(args.output, 'w', encoding='utf-8') as f:
|
||||
json.dump(output_data, f, ensure_ascii=False, indent=2)
|
||||
|
||||
print(f"Rapport généré avec succès dans {args.output}")
|
||||
print(f"Total articles: {len(combined_article_links)}")
|
||||
print(f"Total liens: {sum(len(links) for links in combined_article_links.values())}")
|
||||
print(f"Total domaines: {len(combined_domain_counter)}")
|
||||
|
||||
# Afficher les 10 domaines les plus fréquents
|
||||
print("\nTop 10 des domaines les plus fréquents:")
|
||||
for domain, count in list(combined_domain_counter.most_common(10)):
|
||||
print(f" {domain}: {count} liens")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Add table
Add a link
Reference in a new issue